Skip to content

Commit 49b32a5

Browse files
committed
merge with master
2 parents f8053a3 + 68339ef commit 49b32a5

File tree

8 files changed

+147
-58
lines changed

8 files changed

+147
-58
lines changed

app/api/sessions.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,26 @@
33
from flask import Blueprint, request, session
44

55
from app.config import Config
6-
from app.lti_session_passback.auth_checkers import check_auth
6+
from app.lti_session_passback.auth_checkers import check_auth, is_admin
77
from app.utils import DEFAULT_EXTENSION
88
from packaging import version as version_util
99
from ua_parser.user_agent_parser import Parse as user_agent_parse
1010

1111
api_sessions = Blueprint('api_sessions', __name__)
1212
logger = get_root_logger()
1313

14+
@api_sessions.route('/api/sessions/admin/', methods=['GET'])
15+
def get_session_admin():
16+
"""
17+
Endpoint to return session is admin.
18+
19+
:return: Dictionary with admin status (is corrent user admin or not), and 'OK' message, or
20+
or an empty dictionary with 404 HTTP code if access was denied.
21+
"""
1422

23+
if not check_auth():
24+
return {}, 404
25+
return {'admin': is_admin(), 'message': 'OK'}, 200
1526

1627
@api_sessions.route('/api/sessions/info/', methods=['GET'])
1728
def get_session_info():

app/api/trainings.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -207,40 +207,49 @@ def get_training_statistics(training_id: str) -> (dict, int):
207207
"""
208208
if not check_access({'_id': ObjectId(training_id)}):
209209
return {}, 404
210+
210211
training_db = TrainingsDBManager().get_training(training_id)
212+
213+
211214
presentation_file_id = training_db.presentation_file_id
212215
presentation_file_name = DBManager().get_file_name(presentation_file_id)
216+
213217
if presentation_file_name is None:
214218
return {'message': 'No presentation file with presentation_file_id = {}.'.format(presentation_file_id)}, 404
215-
presentation_record_file_id = training_db.presentation_record_file_id
216-
training_status = training_db.status
217-
audio_status = training_db.audio_status
218-
presentation_status = training_db.presentation_status
219+
220+
219221
slides_time = []
222+
audio_status = training_db.audio_status
223+
220224
if audio_status == AudioStatus.PROCESSED:
221225
# here we need to process audio_slides
222226
audio = Audio.from_json_file(DBManager().get_file(training_db.audio_id))
223227
slides_time = proccess_training_slides_info(audio)
224-
feedback = training_db.feedback
225-
criteria_pack_id = training_db.criteria_pack_id
226-
feedback_evaluator_id = training_db.feedback_evaluator_id
228+
229+
227230
remaining_processing_time_estimation, remaining_processing_time_estimation_code = \
228231
get_remaining_processing_time_by_training_id(training_id)
232+
229233
if remaining_processing_time_estimation['message'] != 'OK':
230234
return remaining_processing_time_estimation, remaining_processing_time_estimation_code
235+
236+
231237
return {
232238
'message': 'OK',
239+
'username': training_db.username,
240+
'full_name': training_db.full_name,
241+
'task_attempt_id': training_db.task_attempt_id,
233242
'presentation_file_id': str(presentation_file_id),
234243
'presentation_file_name': presentation_file_name,
235-
'presentation_record_file_id': str(presentation_record_file_id),
236-
'feedback': feedback,
237-
'training_status': training_status,
244+
'presentation_record_file_id': str(training_db.presentation_record_file_id),
245+
'feedback': training_db.feedback,
246+
'training_status': training_db.status,
238247
'audio_status': audio_status,
239-
'presentation_status': presentation_status,
248+
'presentation_status': training_db.presentation_status,
240249
'slides_time': slides_time,
241250
'remaining_processing_time_estimation': remaining_processing_time_estimation['processing_time_remaining'],
242-
'criteria_pack_id': criteria_pack_id,
243-
'feedback_evaluator_id': feedback_evaluator_id,
251+
'criteria_pack_id': training_db.criteria_pack_id,
252+
'feedback_evaluator_id': training_db.feedback_evaluator_id,
244253
}, 200
245254

246255

@@ -357,7 +366,7 @@ def get_training_information(current_training: Trainings) -> dict:
357366
'task_attempt_id': str(task_attempt_id),
358367
'task_id': str(task_attempt.task_id),
359368
'params_for_passback': task_attempt.params_for_passback,
360-
"training_start_timestamp": ObjectId(str(_id)).generation_time.astimezone(pytz.timezone("Europe/Moscow")).replace(tzinfo=None),
369+
"training_start_timestamp": ObjectId(str(_id)).generation_time.astimezone(pytz.timezone("Europe/Moscow")),
361370
'processing_start_timestamp': processing_start_timestamp,
362371
'processing_finish_timestamp': processing_finish_timestamp,
363372
'score': current_training.feedback.get('score', None),

app/routes/trainings.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,13 @@ def view_training_statistics(training_id: str):
6666
verdict_str = ''
6767
training_status = training_statistics['training_status']
6868
training_status_str = TrainingStatus.russian.get(training_status, '')
69-
if training_status_str:
70-
training_status_str = '{}: {}'.format(t("Статус"), t(training_status_str))
69+
7170
audio_status = training_statistics['audio_status']
7271
audio_status_str = AudioStatus.russian.get(audio_status, '')
73-
if audio_status_str:
74-
audio_status_str = '{}: {}'.format(t("Статус"), t(audio_status_str))
72+
7573
presentation_status = training_statistics['presentation_status']
7674
presentation_status_str = PresentationStatus.russian.get(presentation_status, '')
77-
if presentation_status_str:
78-
presentation_status_str = '{}: {}'.format(t("Статус"), t(presentation_status_str))
75+
7976
remaining_processing_time_estimation = training_statistics['remaining_processing_time_estimation']
8077
if remaining_processing_time_estimation and remaining_processing_time_estimation > 0:
8178
remaining_processing_time_estimation_str = '{}: {} с.'.format(t("Ожидаемое время обработки"),
@@ -88,6 +85,9 @@ def view_training_statistics(training_id: str):
8885
'training/statistics.html',
8986
title='{}: {}'.format(t("Статистика тренировки с ID"), training_id),
9087
training_id=training_id,
88+
username=training_statistics['username'],
89+
full_name=training_statistics['full_name'],
90+
task_attempt_id=training_statistics['task_attempt_id'],
9191
presentation_file_id=training_statistics['presentation_file_id'],
9292
presentation_file_name=training_statistics['presentation_file_name'],
9393
presentation_record_file_id=training_statistics['presentation_record_file_id'],

app/static/css/index.css

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
text-align: center;
88
}
99

10-
.table > tr > td,
11-
.table > tr > th {
10+
.table tr > td,
11+
.table tr > th {
1212
border: 1px solid black;
1313
padding-left: 5px;
1414
padding-right: 5px;
@@ -17,7 +17,7 @@
1717
.button_action{
1818
padding: 10px 15px;
1919
background-color: #2f5cff;
20-
border: 0;http://localhost:5000/show_all_trainings/?username=testing_session_id
20+
border: 0;
2121
border-radius: 3px;
2222
color: white;
2323
font-size: 16px;

app/static/js/show_all_trainings.js

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
function get_time_string(timestamp){
2-
options = { weekday: 'short', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: '2-digit', second: '2-digit', timeZoneName: 'short' }
2+
let options = {year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: '2-digit', second: '2-digit'}
33
if (!isNaN(timestamp)) {
4-
processing_time = new Date(timestamp);
4+
let processing_time = new Date(timestamp);
55
return processing_time.toLocaleString("ru-RU", options);
66
} else {
77
return "";
88
}
99
}
1010

11-
function buildCurrentTrainingRow(trainingId, trainingJson, is_Admin=false) {
11+
function buildCurrentTrainingRow(trainingId, trainingJson, isAdmin=false) {
1212

1313
const currentTrainingRowElement = document.createElement("tr");
1414

@@ -102,7 +102,7 @@ function buildCurrentTrainingRow(trainingId, trainingJson, is_Admin=false) {
102102
}
103103
currentTrainingRowElement.appendChild(recordingElement);
104104

105-
if (is_Admin) {
105+
if (isAdmin) {
106106
const recheckingElement = document.createElement("td");
107107
const button = document.createElement("input")
108108
button.type = "button"
@@ -112,22 +112,11 @@ function buildCurrentTrainingRow(trainingId, trainingJson, is_Admin=false) {
112112
recheckingElement.appendChild(button);
113113
currentTrainingRowElement.appendChild(recheckingElement);
114114
}
115-
return currentTrainingRowElement;
116-
}
117115

118-
function recheck(trainingId){
119-
console.log(`Start recheck for ${trainingId}`)
120-
fetch(`/api/trainings/${trainingId}/`, {method: "POST"})
121-
.then(response => response.json())
122-
.then(innerResponseJson => {
123-
if (innerResponseJson["message"] === "OK") {
124-
window.open(`/trainings/statistics/${trainingId}/`);
125-
//location.href = `/trainings/statistics/${trainingId}/`;
126-
}
127-
});
116+
return currentTrainingRowElement;
128117
}
129118

130-
function buildAllTrainingsTable(trainingsJson, is_Admin=false) {
119+
function buildAllTrainingsTable(trainingsJson) {
131120
if (trainingsJson["message"] !== "OK") return;
132121

133122
const allTrainingsTable = document.getElementById("all-trainings-table");
@@ -148,16 +137,31 @@ function buildAllTrainingsTable(trainingsJson, is_Admin=false) {
148137
"Презентация",
149138
"Аудиозапись"
150139
]
151-
if (is_Admin) {titles.push('Запустить перепроверку')}
152-
const titleRow = buildTitleRow(titles);
153-
allTrainingsTable.appendChild(titleRow);
154140

155-
const arrayTrainings = trainingsJson.trainings; // Array of train from FETCH
141+
fetch('/api/sessions/admin')
142+
.then(response => response.json())
143+
.then(responseJson => {
144+
const isAdmin = responseJson.admin;
145+
const arrayTrainings = trainingsJson.trainings; // Array of train from FETCH
146+
147+
if (isAdmin) {
148+
titles.push('Запустить перепроверку');
149+
}
156150

157-
Object.keys(arrayTrainings).forEach(trainingId => {
158-
const currentTrainingRowElement = buildCurrentTrainingRow(trainingId, arrayTrainings[trainingId], is_Admin);
159-
allTrainingsTable.appendChild(currentTrainingRowElement);
160-
});
151+
const titleRow = buildTitleRow(titles);
152+
allTrainingsTable.appendChild(titleRow);
153+
154+
Object.keys(arrayTrainings).forEach(trainingId => {
155+
const currentTrainingRowElement = buildCurrentTrainingRow(
156+
trainingId,
157+
arrayTrainings[trainingId],
158+
isAdmin
159+
);
160+
161+
allTrainingsTable.appendChild(currentTrainingRowElement);
162+
});
163+
})
164+
.catch(err => console.log(err));
161165
}
162166

163167
const REF_PAGE_COUNT = document.getElementById('ref-page-count');
@@ -262,7 +266,7 @@ async function updateCountPage() {
262266
REF_BUTTON_TO_END.innerText = pageTotal;
263267
}
264268

265-
function call_get_all_trainings({filters, admin=false, page = 0, count}) {
269+
function call_get_all_trainings({filters, page = 0, count}) {
266270
const query = new URLSearchParams({
267271
filters,
268272
count
@@ -272,5 +276,5 @@ function call_get_all_trainings({filters, admin=false, page = 0, count}) {
272276

273277
return fetch(`/api/trainings?${query.toString()}`)
274278
.then(response => response.json())
275-
.then(responseJson => buildAllTrainingsTable(responseJson, admin));
279+
.then(responseJson => buildAllTrainingsTable(responseJson));
276280
}

app/static/js/training_statistics.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,34 @@ function buildCurrentAttemptStatistics() {
33
fetch(`/api/task-attempts/?training_id=${trainingId}`)
44
.then(response => response.json())
55
.then(response => {
6+
fetch('/api/sessions/admin')
7+
.then(response_admin => response_admin.json())
8+
.then(responseJSON => {
9+
const isAdmin = responseJSON.admin;
10+
11+
if (isAdmin) {
12+
const recheckBtn = $("#recheck-btn")[0];
13+
14+
recheckBtn.addEventListener("click", () => {
15+
recheck(trainingId);
16+
})
17+
18+
recheckBtn.style.visibility = 'visible';
19+
}
20+
})
21+
622
let trainingNumber = response["training_number"];
723
let attemptCount = response["attempt_count"];
24+
825
if (jQuery.isEmptyObject(response) || trainingNumber === attemptCount) {
926
return;
1027
}
28+
1129
document.getElementById("training-number").textContent
1230
= "Номер тренировки: " + response["training_number"] + " / " + response["attempt_count"];
1331
document.getElementById("current-points").textContent
1432
= "Сумма баллов за предыдущие тренировки: " + response["current_points_sum"].toFixed(2);
33+
1534
let next_training = document.getElementById("next-training");
1635
next_training.style.visibility = "visible";
1736
next_training.style.fontSize = "14pt";

app/static/js/utils.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,23 @@ function buildTitleRow(columns) {
88
return titleRowElement;
99
}
1010

11+
function recheck(trainingId){
12+
fetch('/api/sessions/admin')
13+
.then(response => response.json())
14+
.then(res => {
15+
if (res.admin) {
16+
fetch(`/api/trainings/${trainingId}/`, {method: "POST"})
17+
.then(response => response.json())
18+
.then(innerResponseJson => {
19+
if (innerResponseJson["message"] === "OK") {
20+
window.open(`/trainings/statistics/${trainingId}/`);
21+
//location.href = `/trainings/statistics/${trainingId}/`;
22+
}
23+
});
24+
}
25+
});
26+
}
27+
1128
function strtobool(val, onError= false) {
1229
try {
1330
val = val.toLowerCase();

app/templates/training/statistics.html

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,43 @@
88
{% block content %}
99
<div class="base-container">
1010
<h3>{{ title }}</h3>
11+
<h3>Связанные попытки: <a href="/task_attempts/{{task_attempt_id}}">{{ task_attempt_id }}</a></h3>
12+
13+
<h3>Логин студента: {{ username }}</h3>
14+
<h3>{{ t("Дата создания тренировки") }}: {{ gen_time }}. </h3>
15+
16+
<h3>{{ remaining_processing_time_estimation }}</h3>
17+
18+
<table class="table">
19+
<tr>
20+
<th></th>
21+
<th>Id</th>
22+
<th>Статус</th>
23+
</tr>
24+
<tr>
25+
<td><b>Тренировка</b></td>
26+
<td>{{ training_id }}</td>
27+
<td>{{ training_status }}</td>
28+
</tr>
29+
<tr>
30+
<td><b>Презентация</b></td>
31+
<td>{{ presentation_file_id }}</td>
32+
<td>{{ presentation_status }}</td>
33+
</tr>
34+
<tr>
35+
<td><b>Аудиозапись</b></td>
36+
<td>{{ presentation_record_file_id }}</td>
37+
<td>{{ audio_status }}</td>
38+
</tr>
39+
</table>
40+
1141
<h3 id="feedback">{{ feedback }}</h3>
42+
<button id="recheck-btn" style="visibility: hidden;">Запустить перепроверку</button>
1243
<div id="criteria-results" style="margin-left: auto"></div>
1344
<div id="verdict"></div>
14-
<h3>{{ remaining_processing_time_estimation }}</h3>
15-
<h3>{{ t("id тренировки") }}: {{ training_id }}. {{ training_status }}. </h3>
16-
<h3>{{ t("Дата создания тренировки") }}: {{ gen_time }}. </h3>
17-
<h3>{{ t("id презентации") }}: {{ presentation_file_id }}. {{ presentation_status }}</h3>
18-
<h3>{{ t("Название презентации") }}: {{ presentation_file_name }}</h3>
19-
<h3>{{ t("id аудиозаписи") }}: {{ presentation_record_file_id }}. {{ audio_status }}</h3>
45+
46+
<h3>{{ t("Название презентации") }}: <a href="/api/files/presentations/{{ presentation_file_id }}">{{ presentation_file_name }}</a></h3>
47+
2048
<div id="next-training" style="visibility: hidden; font-size: 0">
2149
<h3 id="training-number"></h3>
2250
<h3 id="current-points"></h3>
@@ -32,8 +60,9 @@ <h3 id="current-points"></h3>
3260
<div>
3361
<canvas id="the-canvas" style="border: 1px solid #000000; direction: ltr;"></canvas>
3462
</div>
35-
63+
3664
<audio id="presentation-record" controls src="/api/files/presentation-records/{{ presentation_record_file_id }}/"></audio>
65+
3766
<table class="table transcription-table" id="per-slide-audio-transcription-table"></table>
3867
</div>
3968
<script src="{{ url_for('static', filename='js/libraries/jquery.min.js') }}"></script>

0 commit comments

Comments
 (0)