Skip to content

Commit 9457436

Browse files
Merge pull request #379 from moevm/check_pipeline_fixes
Check pipeline / tables / export fixes
2 parents 7b6207a + f2c323e commit 9457436

File tree

10 files changed

+205
-181
lines changed

10 files changed

+205
-181
lines changed

app/db/db_methods.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
from bson import ObjectId
66
from gridfs import GridFSBucket, NoFile
77
from pymongo import MongoClient
8-
98
from utils import convert_to
9+
1010
from .db_types import User, Presentation, Check, Consumers, Logs
1111

1212
client = MongoClient("mongodb://mongodb:27017")
@@ -133,11 +133,6 @@ def delete_presentation(user, presentation_id):
133133
return user, get_presentation(presentation_id)
134134

135135

136-
# Creates checks from given user check-list (not created in DB)
137-
def create_check(user, file_type='pres'):
138-
return Check({'enabled_checks': user.criteria, 'file_type': file_type})
139-
140-
141136
# Adds checks to given presentations, updates presentations, returns presentations and checks id
142137
def add_check(file_id, check):
143138
checks_id = checks_collection.insert_one(check.pack()).inserted_id
@@ -215,7 +210,7 @@ def set_passbacked_flag(checks_id, flag):
215210
upd_check['$set']['is_passbacked'] = flag
216211
if not (flag is None):
217212
# None - if user without passback
218-
upd_check['$set']['lms_passback_time'] = datetime.now()
213+
upd_check['$set']['lms_passback_time'] = None
219214
check = checks_collection.update_one({'_id': checks_id}, upd_check)
220215
return check if check else None
221216

app/db/db_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ def __init__(self, dictionary=None):
9696
self.score = dictionary.get('score', -1)
9797
self.file_type = dictionary.get('file_type', DEFAULT_TYPE_INFO)
9898
self.enabled_checks = dictionary.get('enabled_checks', BASE_PACKS.get(self.file_type['type']).name)
99+
self.criteria = dictionary.get('criteria', BASE_PACKS.get(self.file_type['type']).name)
100+
self.params_for_passback = dictionary.get('params_for_passback', None)
99101
self.is_failed = dictionary.get('is_failed', None)
100102
self.is_ended = dictionary.get('is_ended', True)
101103
self.is_passed = dictionary.get('is_passed', int(self.score) == 1)

app/main/checker.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
from db.db_methods import get_criteria_pack
2+
23
from .check_packs import BaseCriterionPack
34

45

5-
def check(parsed_file, check_obj, filename, user):
6+
def check(parsed_file, check_obj):
7+
filename = check_obj.filename
68
file_info = {
79
'file': parsed_file,
810
'filename': filename,
911
'pdf_id': check_obj.conv_pdf_fs_id
1012
}
11-
pack = BaseCriterionPack(**get_criteria_pack(user.criteria))
13+
pack = BaseCriterionPack(**get_criteria_pack(check_obj.criteria))
1214
pack.init(file_info)
1315
result, score, is_passed = pack.check()
1416

1517
check_obj.enabled_checks = result
1618
check_obj.score = score
1719
check_obj.is_passed = is_passed
18-
check_obj.filename = filename
19-
check_obj.user = user.username
20-
check_obj.lms_user_id = user.lms_user_id
21-
if user.params_for_passback:
20+
if check_obj.params_for_passback:
2221
check_obj.is_passbacked = False
2322

2423
return check_obj

app/passback_grades.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,56 @@
11
import configparser
22

3+
import urllib3
34

4-
from db.db_methods import ConsumersDBManager, get_unpassed_checks, set_passbacked_flag, get_user
5+
from db.db_methods import ConsumersDBManager, get_unpassed_checks, set_passbacked_flag
6+
from lti_session_passback.lti_provider import LTIProvider
57
from root_logger import get_root_logger
68
from utils import RepeatedTimer
7-
from lti_session_passback.lti_provider import LTIProvider
89

10+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
911
config = configparser.ConfigParser()
1012
config.read('app/config.ini')
1113

1214
logger = get_root_logger('passback_grades')
1315

1416

17+
def check_success_response(response):
18+
return response.code_major == 'success' and response.severity == 'status'
19+
20+
1521
class ChecksPassBack:
1622
def __init__(self, timeout_seconds=10):
1723
self._timeout_seconds = timeout_seconds
1824

1925
def grade_passback(self, check):
20-
user = check.get('user')
21-
passback_params = get_user(user).params_for_passback
26+
passback_params = check.get('params_for_passback', None)
2227
if not passback_params or passback_params["lis_outcome_service_url"] == "lis_outcome_service_url":
2328
set_passbacked_flag(check.get('_id'), None)
2429
return
2530

2631
consumer_secret = ConsumersDBManager.get_secret(passback_params['oauth_consumer_key'])
27-
response = LTIProvider.from_unpacked_request(secret=consumer_secret, params=passback_params, headers=None,
28-
url=None).post_replace_result(score=check.get('score'))
32+
provider = LTIProvider.from_unpacked_request(secret=consumer_secret, params=passback_params, headers=None,
33+
url=None)
2934

30-
if response.code_major == 'success' and response.severity == 'status':
31-
logger.info('Score was successfully passed back: score = {}, check_id = {}'.format(check.get('score'),
32-
check.get('_id')))
33-
set_passbacked_flag(check.get('_id'), True)
35+
current_lms_result = provider.post_read_result()
36+
current_lms_score = float(current_lms_result.score) if check_success_response(current_lms_result) else 0.0
37+
system_score = check.get('score')
38+
39+
if round(system_score, 2) > current_lms_score:
40+
# if our score > lms_score -> send, else - ???
41+
response = provider.post_replace_result(score=check.get('score'))
42+
43+
if check_success_response(response):
44+
logger.info('Score was successfully passed back: score = {}, check_id = {}'.format(check.get('score'),
45+
check.get('_id')))
46+
set_passbacked_flag(check.get('_id'), True)
47+
else:
48+
logger.error('Passback failed for check_id = {}'.format(check.get('_id')))
3449
else:
35-
logger.error('Passback failed for check_id = {}'.format(check.get('_id')))
50+
logger.info(
51+
'LMS score is more then current (not passbacked): LMS_score = {}, system_score = {} check_id = {}'.format(
52+
current_lms_score, check.get('score'), check.get('_id')))
53+
set_passbacked_flag(check.get('_id'), None)
3654

3755
def _run(self):
3856
logger.info('Start passback')

app/server.py

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from flask_recaptcha import ReCaptcha
1818

1919
import servants.user as user
20+
from app.utils import format_check_for_table
2021
from db import db_methods
2122
from db.db_types import Check
2223
from lti_session_passback.lti import utils
@@ -26,7 +27,7 @@
2627
from root_logger import get_logging_stdout_handler, get_root_logger
2728
from servants import pre_luncher
2829
from tasks import create_task
29-
from utils import checklist_filter, decorator_assertion, get_file_len, timezone_offset, format_check
30+
from utils import checklist_filter, decorator_assertion, get_file_len, format_check
3031

3132
logger = get_root_logger('web')
3233
UPLOAD_FOLDER = '/usr/src/project/files'
@@ -35,7 +36,7 @@
3536
'report': {'doc', 'odt', 'docx'}
3637
}
3738
DOCUMENT_TYPES = {'Лабораторная работа', 'Курсовая работа', 'ВКР'}
38-
TABLE_COLUMNS = ['Solution', 'User', 'File', 'Check added', 'LMS date', 'Score']
39+
TABLE_COLUMNS = ['Solution', 'User', 'File', 'Criteria', 'Check added', 'LMS date', 'Score']
3940

4041
app = Flask(__name__, static_folder="./../src/", template_folder="./templates/")
4142
app.config.from_pyfile('settings.py')
@@ -188,11 +189,13 @@ def run_task():
188189
'user': current_user.username,
189190
'lms_user_id': current_user.lms_user_id,
190191
'enabled_checks': current_user.criteria,
192+
'criteria': current_user.criteria,
191193
'file_type': current_user.file_type,
192194
'filename': file.filename,
193195
'score': -1, # score=-1 -> checking in progress
194196
'is_ended': False,
195-
'is_failed': False
197+
'is_failed': False,
198+
'params_for_passback': current_user.params_for_passback
196199
})
197200
db_methods.add_check(file_id, check) # add check for parsed_file to db
198201
task = create_task.delay(check.pack(to_str=True)) # add check to queue
@@ -243,7 +246,7 @@ def results(_id):
243246
if check is not None:
244247
# show processing time for user
245248
avg_process_time = None if check.is_ended else db_methods.get_average_processing_time()
246-
return render_template("./results.html", navi_upload=True, name=current_user.name, results=check, id=_id,
249+
return render_template("./results.html", navi_upload=True, results=check,
247250
columns=TABLE_COLUMNS, avg_process_time=avg_process_time,
248251
stats=format_check(check.pack()))
249252
else:
@@ -336,7 +339,8 @@ def api_criteria_pack():
336339
# testing pack initialization
337340
file_type_info = {'type': file_type}
338341
if file_type == DEFAULT_REPORT_TYPE_INFO['type']:
339-
file_type_info['report_type'] = report_type if report_type in REPORT_TYPES else DEFAULT_REPORT_TYPE_INFO['report_type']
342+
file_type_info['report_type'] = report_type if report_type in REPORT_TYPES else DEFAULT_REPORT_TYPE_INFO[
343+
'report_type']
340344
inited, err = init_criterions(raw_criterions, file_type=file_type_info)
341345
if len(raw_criterions) != len(inited) or err:
342346
msg = f"При инициализации набора {pack_name} возникли ошибки. JSON-конфигурация: '{raw_criterions}'. Успешно инициализированные: {inited}. Возникшие ошибки: {err}."
@@ -416,16 +420,7 @@ def check_list_data():
416420
# construct response
417421
response = {
418422
"total": count,
419-
"rows": [{
420-
"_id": str(item["_id"]),
421-
"filename": item["filename"],
422-
"user": item["user"],
423-
"lms-user-id": item["lms_user_id"] if item.get("lms_user_id") else '-',
424-
"upload-date": (item["_id"].generation_time + timezone_offset).strftime("%d.%m.%Y %H:%M:%S"),
425-
"moodle-date": item['lms_passback_time'].strftime("%d.%m.%Y %H:%M:%S") if item.get(
426-
'lms_passback_time') else '-',
427-
"score": item["score"]
428-
} for item in rows]
423+
"rows": [format_check_for_table(item) for item in rows]
429424
}
430425

431426
# return json data
@@ -448,17 +443,7 @@ def get_query(req):
448443

449444
def get_stats():
450445
rows, count = db_methods.get_checks(**get_query(request))
451-
return [{
452-
"_id": str(item["_id"]),
453-
"filename": item["filename"],
454-
"user": item["user"],
455-
"lms-username": item["user"].rsplit('_', 1)[0],
456-
"lms-user-id": item["lms_user_id"] if item.get("lms_user_id") else '-',
457-
"upload-date": (item["_id"].generation_time + timezone_offset).strftime("%d.%m.%Y %H:%M:%S"),
458-
"moodle-date": item['lms_passback_time'].strftime("%d.%m.%Y %H:%M:%S") if item.get(
459-
'lms_passback_time') else '-',
460-
"score": item["score"]
461-
} for item in rows]
446+
return [format_check_for_table(item) for item in rows]
462447

463448

464449
@app.route("/get_csv")

app/tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def create_task(self, check_info):
2929
pdf_filepath = join(FILES_FOLDER, f"{check_id}.pdf")
3030
try:
3131
user = get_user(check_obj.user)
32-
updated_check = check(parse(original_filepath), check_obj, check_obj.filename, user)
32+
updated_check = check(parse(original_filepath), check_obj)
3333
updated_check.is_ended = True
3434
db_methods.update_check(updated_check) # save to db
3535
db_methods.mark_celery_task_as_finished(self.request.id)

app/templates/check_list.html

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@
88

99
{% block main %}
1010
<style>
11-
.fht-cell { margin: 0 0.2rem 0.2rem; }
11+
.fht-cell {
12+
margin: 0 0.2rem 0.2rem;
13+
}
14+
1215
/* .check-list-table th td { border: #54585d; } */
1316

1417
#check-list-table {
1518
table-layout: fixed;
16-
word-wrap:break-word;
19+
word-wrap: break-word;
1720
}
1821

1922
#check-list-table.table-bordered,
@@ -26,41 +29,48 @@
2629
<div class="holder row">
2730
<div class="container-fluid table-responsive-xl">
2831
<table id="check-list-table" class="table bg-white"
29-
data-filter-control="true"
30-
data-pagination="true"
31-
data-page-list="[5, 10, 25, 50, All]"
32-
data-ajax="ajaxRequest"
33-
data-query-params="queryParams"
34-
data-show-refresh="true"
35-
data-auto-refresh="true"
36-
data-auto-refresh-interval="10"
37-
data-side-pagination="server"
38-
data-icon-size="lg"
39-
data-buttons="buttons"
40-
data-show-filter-control-switch="true"
41-
data-show-button-icons="false"
42-
data-show-button-text="true"
32+
data-filter-control="true"
33+
data-pagination="true"
34+
data-page-list="[5, 10, 25, 50, All]"
35+
data-ajax="ajaxRequest"
36+
data-query-params="queryParams"
37+
data-show-refresh="true"
38+
data-auto-refresh="true"
39+
data-auto-refresh-interval="10"
40+
data-side-pagination="server"
41+
data-icon-size="lg"
42+
data-buttons="buttons"
43+
data-show-filter-control-switch="true"
44+
data-show-button-icons="false"
45+
data-show-button-text="true"
4346
>
4447
<thead>
45-
<tr>
46-
<th data-field="_id" data-width="160">Upload ID</th>
47-
<th data-field="filename" data-filter-control="input" data-sortable="true">File name</th>
48-
{% if current_user.is_admin %}
49-
<th data-field="user" data-filter-control="input" data-sortable="true">Username</th>
50-
<th data-field="lms-user-id" data-sortable="false">User ID</th>
51-
{% endif %}
52-
<th data-field="upload-date" data-filter-control="datepicker" data-filter-datepicker-options='{"autoclose":true, "clearBtn": true, "multidate":2, "multidateSeparator":"-", "format":"dd.mm.yyyy"}' data-sortable="true">Upload date</th>
53-
<th data-field="moodle-date" data-filter-control="datepicker" data-filter-datepicker-options='{"autoclose":true, "clearBtn": true, "multidate":2, "multidateSeparator":"-", "format":"dd.mm.yyyy"}' data-sortable="true">Moodle upload date</th>
54-
<th data-field="score" data-filter-control="input" data-sortable="true">Result</th>
55-
</tr>
48+
<tr>
49+
<th data-field="_id" data-width="160">Upload ID</th>
50+
<th data-field="filename" data-filter-control="input" data-sortable="true">File name</th>
51+
<th data-field="criteria" data-sortable="true">Criteria pack</th>
52+
{% if current_user.is_admin %}
53+
<th data-field="user" data-filter-control="input" data-sortable="true">Username</th>
54+
<th data-field="lms-user-id" data-sortable="false">User ID</th>
55+
{% endif %}
56+
<th data-field="upload-date" data-filter-control="datepicker"
57+
data-filter-datepicker-options='{"autoclose":true, "clearBtn": true, "multidate":2, "multidateSeparator":"-", "format":"dd.mm.yyyy"}'
58+
data-sortable="true">Upload date
59+
</th>
60+
<th data-field="moodle-date" data-filter-control="datepicker"
61+
data-filter-datepicker-options='{"autoclose":true, "clearBtn": true, "multidate":2, "multidateSeparator":"-", "format":"dd.mm.yyyy"}'
62+
data-sortable="true">Moodle upload date
63+
</th>
64+
<th data-field="score" data-filter-control="input" data-sortable="true">Result</th>
65+
</tr>
5666
</thead>
5767
</table>
5868
</div>
5969
</div>
6070
{% endblock main %}
6171

6272
{% block script %}
63-
<script>
64-
var is_admin = "{{current_user.is_admin}}" == "True"
65-
</script>
73+
<script>
74+
var is_admin = "{{current_user.is_admin}}" == "True"
75+
</script>
6676
{% endblock %}

0 commit comments

Comments
 (0)