diff --git a/app/bd_helper/bd_helper.py b/app/bd_helper/bd_helper.py
index 0af9723f..36989a71 100644
--- a/app/bd_helper/bd_helper.py
+++ b/app/bd_helper/bd_helper.py
@@ -174,6 +174,13 @@ def get_checks_pdf(checks_id):
return None
+def find_pdf_by_file_id(file_id):
+ try:
+ return fs.open_download_stream(file_id)
+ except NoFile:
+ return None
+
+
# Deletes checks with given id, returns presentation
def delete_check(presentation, checks_id):
if checks_id in presentation.checks:
diff --git a/app/lti_session_passback/lti/utils.py b/app/lti_session_passback/lti/utils.py
index 707bed26..15c27ea9 100644
--- a/app/lti_session_passback/lti/utils.py
+++ b/app/lti_session_passback/lti/utils.py
@@ -61,7 +61,10 @@ def get_criteria_from_launch(data):
detect_additional = custom.get('detect_additional', 'True')
criteria = dict((k, custom[k]) for k in all_checks if k in custom)
eval_criteria = dict((key, eval(value)) for key, value in criteria.items() if key != 'slides_number')
- eval_criteria['slides_number'] = {'sld_num': sld_num[criteria.get('slides_number', 'bsc')], 'detect_additional': eval(detect_additional)}
+ if criteria.get('slides_number') not in ['bsc', 'msc']:
+ eval_criteria['slides_number'] = {'sld_num': eval(criteria.get('slides_number')), 'detect_additional': eval(detect_additional)}
+ else:
+ eval_criteria['slides_number'] = {'sld_num': sld_num[criteria.get('slides_number', 'bsc')], 'detect_additional': eval(detect_additional)}
return eval_criteria
def extract_passback_params(data):
diff --git a/app/main/checker.py b/app/main/checker.py
index e058b37b..70648820 100644
--- a/app/main/checker.py
+++ b/app/main/checker.py
@@ -12,9 +12,9 @@
def check(presentation, checks, presentation_name):
check_names = checks.get_checks().keys()
- check_classes = [SldNumCheck(presentation, checks.slides_number), SldEnumCheck(presentation), TitleFormatCheck(presentation), \
- FindDefSld(presentation, key_slide.goals_and_tasks), FindDefSld(presentation, key_slide.approbation), \
- SearchKeyWord(presentation, key_slide.relevance), FindDefSld(presentation, key_slide.conclusion), \
+ check_classes = [SldNumCheck(presentation, checks.slides_number), SldEnumCheck(presentation, checks.conv_pdf_fs_id), TitleFormatCheck(presentation, checks.conv_pdf_fs_id), \
+ FindDefSld(presentation, key_slide.goals_and_tasks, checks.conv_pdf_fs_id), FindDefSld(presentation, key_slide.approbation, checks.conv_pdf_fs_id), \
+ SearchKeyWord(presentation, key_slide.relevance, checks.conv_pdf_fs_id), FindDefSld(presentation, key_slide.conclusion, checks.conv_pdf_fs_id), \
FindTasks(presentation, key_slide.goals_and_tasks, checks.slide_every_task), \
SldSimilarity(presentation, key_slide.goals_and_tasks, key_slide.conclusion, checks.conclusion_actual),
FurtherDev(presentation, key_slide.goals_and_tasks, key_slide.conclusion)]
diff --git a/app/main/checks/base_check.py b/app/main/checks/base_check.py
index 45d72d4d..947691e0 100644
--- a/app/main/checks/base_check.py
+++ b/app/main/checks/base_check.py
@@ -1,3 +1,5 @@
+from flask import url_for
+
def answer(mod, value, *args):
return {
'pass': bool(mod),
@@ -11,3 +13,8 @@ def __init__(self, presentation):
def check(self):
raise NotImplementedError()
+
+ def format_page_link(self, error):
+ base_pdf_link = url_for('get_pdf', _id=self.pdf_id)
+ page = lambda err: f'{base_pdf_link}#page={str(err)}'
+ return [f'{str(e)}' for e in error]
diff --git a/app/main/checks/find_def_sld.py b/app/main/checks/find_def_sld.py
index 111149d9..c0211c67 100644
--- a/app/main/checks/find_def_sld.py
+++ b/app/main/checks/find_def_sld.py
@@ -1,9 +1,10 @@
from app.main.checks.base_check import BaseCheck, answer
class FindDefSld(BaseCheck):
- def __init__(self, presentation, type_of_slide):
+ def __init__(self, presentation, type_of_slide, pdf_id):
super().__init__(presentation)
self.type_of_slide = type_of_slide
+ self.pdf_id = pdf_id
def check(self):
found_slides, found_idxs = [], []
@@ -14,4 +15,5 @@ def check(self):
if len(found_slides) == 0:
return answer(False, None, 'Слайд не найден')
else:
+ found_idxs = self.format_page_link(found_idxs)
return answer(True, found_idxs, 'Найден под номером: {}'.format(', '.join(map(str, found_idxs))))
diff --git a/app/main/checks/search_keyword.py b/app/main/checks/search_keyword.py
index b9b3427f..a3ab25b9 100644
--- a/app/main/checks/search_keyword.py
+++ b/app/main/checks/search_keyword.py
@@ -1,12 +1,14 @@
from app.main.checks.base_check import BaseCheck, answer
class SearchKeyWord(BaseCheck):
- def __init__(self, presentation, key_slide):
+ def __init__(self, presentation, key_slide, pdf_id):
super().__init__(presentation)
self.key_slide = key_slide
+ self.pdf_id = pdf_id
def check(self):
for i, text in enumerate(self.presentation.get_text_from_slides(), 1):
if self.key_slide.lower() in str(text).lower():
- return answer(True, i, 'Найден под номером: {}'.format(i))
+ found = self.format_page_link([i])
+ return answer(True, i, 'Найден под номером: {}'.format(', '.join(map(str, found))))
return answer(False, None, 'Слайд не найден')
diff --git a/app/main/checks/sld_enum.py b/app/main/checks/sld_enum.py
index 6c96eba4..c68c6653 100644
--- a/app/main/checks/sld_enum.py
+++ b/app/main/checks/sld_enum.py
@@ -3,8 +3,9 @@
class SldEnumCheck(BaseCheck):
- def __init__(self, presentation):
+ def __init__(self, presentation, pdf_id):
super().__init__(presentation)
+ self.pdf_id = pdf_id
def check(self):
error = []
@@ -16,5 +17,6 @@ def check(self):
if not error:
return answer(True, error, "Пройдена!")
else:
+ error = self.format_page_link(error)
return answer(False, error, 'Не пройдена, проблемные слайды: {}'.format(', '.join(map(str, error))), \
'Убедитесь в корректности формата номеров слайдов')
diff --git a/app/main/checks/title_format.py b/app/main/checks/title_format.py
index 03ecc083..4c0df18a 100644
--- a/app/main/checks/title_format.py
+++ b/app/main/checks/title_format.py
@@ -3,17 +3,18 @@
import itertools
class TitleFormatCheck(BaseCheck):
- def __init__(self, presentation):
+ def __init__(self, presentation, pdf_id):
super().__init__(presentation)
self.empty_headers = []
self.len_exceeded = []
+ self.pdf_id = pdf_id
def exceeded_verdict(self):
- return 'Превышение длины: {}'.format(', '.join(map(str, self.len_exceeded))), \
+ return 'Превышение длины: {}'.format(', '.join(map(str, self.format_page_link(self.len_exceeded)))), \
'Убедитесь в корректности заголовка и текста слайда'
def empty_verdict(self):
- return 'Заголовки не найдены: {}.'.format(', '.join(map(str, self.empty_headers))), \
+ return 'Заголовки не найдены: {}.'.format(', '.join(map(str, self.format_page_link(self.empty_headers)))), \
'Убедитесь, что слайд озаглавлен соответстующим элементом'
def get_failing_headers(self):
diff --git a/app/servants/data.py b/app/servants/data.py
index fd37e9b5..d2851853 100644
--- a/app/servants/data.py
+++ b/app/servants/data.py
@@ -46,8 +46,8 @@ def upload(request, upload_folder):
presentation = get_presentation(presentation_id)
checks = create_check(current_user)
- check(parse(filename), checks, presentation_name)
checks.conv_pdf_fs_id = converted_id
+ check(parse(filename), checks, presentation_name)
presentation, checks_id = add_check(presentation, checks, filename)
if delete and exists(filename):
diff --git a/app/server.py b/app/server.py
index db053fa6..636ae70b 100644
--- a/app/server.py
+++ b/app/server.py
@@ -171,7 +171,7 @@ def checks(_id):
@login_required
def get_pdf(_id):
try:
- file = bd_helper.get_checks_pdf(ObjectId(_id))
+ file = bd_helper.find_pdf_by_file_id(ObjectId(_id))
except bson.errors.InvalidId:
logger.error('_id exception in fetching pdf occured:', exc_info=True)
return render_template("./404.html")
diff --git a/assets/scripts/main.js b/assets/scripts/main.js
index d8cb99ba..16e435e2 100644
--- a/assets/scripts/main.js
+++ b/assets/scripts/main.js
@@ -13,6 +13,7 @@ import 'bootstrap-datepicker';
import 'bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css'
import * as CryptoJS from "crypto-js";
+import * as pdfjsLib from 'pdfjs-dist';
import '../styles/main.css';
diff --git a/assets/scripts/results.js b/assets/scripts/results.js
index 3c8d9ca1..6a0ea2d2 100644
--- a/assets/scripts/results.js
+++ b/assets/scripts/results.js
@@ -1 +1,87 @@
import '../styles/results.css';
+import * as pdfjsLib from 'pdfjs-dist';
+import pdfjsWorker from "pdfjs-dist/build/pdf.worker.entry";
+
+let pdfDoc,
+ pageNum,
+ pageIsRendering,
+ pageNumIsPending,
+ scale,
+ canvas,
+ ctx,
+ currentPage;
+
+pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;
+
+const renderPage = num => {
+ pageIsRendering = true;
+
+ pdfDoc.getPage(num).then(page => {
+ const viewport = page.getViewport({ scale });
+ canvas.height = viewport.height;
+ canvas.width = viewport.width;
+
+ const renderCtx = {
+ canvasContext: ctx,
+ viewport
+ };
+
+ page.render(renderCtx).promise.then(() => {
+ pageIsRendering = false;
+
+ if (pageNumIsPending !== null) {
+ renderPage(pageNumIsPending);
+ pageNumIsPending = null;
+ }
+ });
+
+ $('#page-num')[0].textContent = num;
+ });
+};
+
+const queueRenderPage = num => {
+ if (pageIsRendering) {
+ pageNumIsPending = num;
+ } else {
+ renderPage(num);
+ }
+};
+
+const showPrevPage = () => {
+ if (pageNum <= 1) {
+ return;
+ }
+ pageNum--;
+ queueRenderPage(pageNum);
+};
+
+const showNextPage = () => {
+ if (pageNum >= pdfDoc.numPages) {
+ return;
+ }
+ pageNum++;
+ queueRenderPage(pageNum);
+};
+
+if ($("#pdf").length !== 0){
+ var href = $("#pdf").attr('href');
+ pdfDoc = null;
+ pageNum = 1;
+ pageIsRendering = false,
+ pageNumIsPending = null;
+ scale = 1.1;
+ canvas = $("#the-canvas")[0];
+ ctx = canvas.getContext("2d");
+
+ pdfjsLib
+ .getDocument(href)
+ .promise.then(pdfDoc_ => {
+ pdfDoc = pdfDoc_;
+
+ $('#page-count')[0].textContent = pdfDoc.numPages;
+ renderPage(pageNum);
+ });
+
+ $('#prev-page').click(showPrevPage);
+ $('#next-page').click(showNextPage);
+}
diff --git a/db_versioning/versions.py b/db_versioning/versions.py
index 05701861..42498f70 100644
--- a/db_versioning/versions.py
+++ b/db_versioning/versions.py
@@ -8,13 +8,13 @@ class Version:
@classmethod
def update_database(cls, collections, prev_version):
"""
- must contains (objects from pymongo)
+ must contains (objects from pymongo)
- users
- presentations
- checks
"""
raise NotImplementedError()
-
+
@classmethod
def to_dict(cls):
return dict(
@@ -27,7 +27,7 @@ def get_version(version_name):
for version in VERSIONS:
if version.version == version_name:
return version
- return None
+ return None
class Version10(Version):
@@ -69,7 +69,7 @@ class Version20(Version):
@classmethod
def update_database(cls, collections, prev_version):
if prev_version in (Version10.VERSION_NAME, Version11.VERSION_NAME):
- # process all checks of pres and set filename + user
+ # process all checks of pres and set filename + user
for presentation in collections['presentations'].find({}):
filename = presentation['name']
user_doc = collections['users'].find_one({'presentations': presentation['_id'] })
@@ -79,7 +79,7 @@ def update_database(cls, collections, prev_version):
{"_id": check_id},
{ '$set': { 'filename': filename, 'user': user } }
)
-
+
# if we have checks without presentation == after prev loop it doesn't include filename/user field
# set default user='moevm', filename='_.pptx'
collections['checks'].update(
@@ -126,14 +126,43 @@ def update_database(cls, collections, prev_version):
else:
raise Exception(f'Неподдерживаемый переход с версии {prev_version}')
+class Version21(Version):
+ VERSION_NAME = '2.1'
+ CHANGES = '0/1 -> T/F; criteria.slides_number: [] -> {}'
+
+ @classmethod
+ def update_database(cls, collections, prev_version):
+ if prev_version in (Version10.VERSION_NAME, Version11.VERSION_NAME, Version20.VERSION_NAME):
+
+ #mv from 0/-1 -> T/F
+ for check in collections['checks'].find({}):
+ check_dt = Checks(check).get_checks().items()
+ upd_check = {k: False if v == -1 else v for k, v in check_dt}
+ collections['checks'].update(
+ {'_id': check['_id']},
+ {'$set': upd_check}
+ )
+
+ for user in collections['users'].find():
+ criteria_dt = Checks(user['criteria']).get_checks()
+ upd_criteria = {k: False if v == -1 else True for k, v in criteria_dt.items()}
+ upd_criteria['slides_number'] = {"sld_num": criteria_dt['slides_number'], "detect_additional": True} if upd_criteria['slides_number'] else False
+ collections['users'].update(
+ {'_id': user['_id']},
+ {'$set': {'criteria': upd_criteria}}
+ )
+
+ else:
+ raise Exception(f'Неподдерживаемый переход с версии {prev_version}')
VERSIONS = {
'1.0': Version10,
'1.1': Version11,
'2.0': Version20,
+ '2.1': Version21,
}
-LAST_VERSION = '2.0'
+LAST_VERSION = '2.1'
for _, ver in VERSIONS.items():
- print(ver.to_dict())
\ No newline at end of file
+ print(ver.to_dict())
diff --git a/package.json b/package.json
index b6a5b62a..6b52e59a 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,8 @@
"crypto-js": "^3.1.2",
"bootstrap-datepicker": "^1.9.0",
"bootstrap-table": "^1.18.3",
- "bootstrap-icons": "1.5.0"
+ "bootstrap-icons": "1.5.0",
+ "pdfjs-dist": "^2.2.228"
+
}
}
diff --git a/templates/results.html b/templates/results.html
index e0374079..ad093254 100644
--- a/templates/results.html
+++ b/templates/results.html
@@ -68,7 +68,7 @@ Результат проверки:
{{ "Не проведена" }}
{% else %}
{% for item in results.slides_enum.get('verdict', ["Пройдена!"] if results.slides_enum.pass else ["Не пройдена"]) %}
- {{ item }}
+ {{ item|safe }}
{% endfor %}
{% endif %}
@@ -85,7 +85,7 @@ Результат проверки:
{{ "Не проведена" }}
{% else %}
{% for item in results.slides_headers.get('verdict', ["Пройдена!"] if results.slides_headers.pass else ["Не пройдена"]) %}
- {{ item }}
+ {{ item|safe }}
{% endfor %}
{% endif %}
@@ -102,7 +102,7 @@ Результат проверки:
{{ "Не проведена" }}
{% else %}
{% for item in results.goals_slide.get('verdict', ["Найден"] if results.goals_slide.pass else ["Не найден!"]) %}
- {{ item }}
+ {{ item|safe }}
{% endfor %}
{% endif %}
@@ -119,7 +119,7 @@ Результат проверки:
{{ "Не проведена" }}
{% else %}
{% for item in results.probe_slide.get('verdict', ["Найден"] if results.probe_slide.pass else ["Не найден!"]) %}
- {{ item }}
+ {{ item|safe }}
{% endfor %}
{% endif %}
@@ -136,7 +136,7 @@ Результат проверки:
{{ "Не проведена" }}
{% else %}
{% for item in results.actual_slide.get('verdict', ["Найден"] if results.actual_slide.pass else ["Не найден!"]) %}
- {{ item }}
+ {{ item|safe }}
{% endfor %}
{% endif %}
@@ -153,7 +153,7 @@ Результат проверки:
{{ "Не проведена" }}
{% else %}
{% for item in results.conclusion_slide.get('verdict', ["Найден"] if results.conclusion_slide.pass else ["Не найден!"]) %}
- {{ item }}
+ {{ item|safe }}
{% endfor %}
{% endif %}
@@ -207,12 +207,31 @@ Результат проверки:
{{ item }}
{% endfor %}
{% endif %}
+ {% if results.conv_pdf_fs_id and results.conclusion_along.pass %}
+ {{ "Найдено на странице: " }}
+ {% for item in results.conclusion_slide.get('value') %}
+ {{ item|safe }}
+ {{ ", " if not loop.last else "" }}
+ {% endfor %}
+ {% endif %}
+ {% if results.conv_pdf_fs_id %}
+
+
+
+
+
+ Страница из
+
+
+
+
+ {% endif %}
Скачать презентацию
{% if results.conv_pdf_fs_id %}
- PDF
+ PDF
{% endif %}