You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

95 lines
3.1 KiB

"""Контент редактора: тест + активная версия + дерево вопросов с правильными вариантами.
Порт `getEditorContent` + `loadQuestionsForVersion` (только includeCorrect=true вариант)
из `services/testAttemptService.js`.
"""
from __future__ import annotations
from sqlalchemy import text
from ..db import get_engine
from ..messages import RU
from .test_access import is_test_author
class HttpError(Exception):
def __init__(self, status: int, message: str):
super().__init__(message)
self.status = status
self.message = message
def load_questions_for_version(conn, test_version_id, *, include_correct: bool) -> list[dict]:
qrows = conn.execute(
text(
'SELECT id, text, question_order, has_multiple_answers '
'FROM questions WHERE test_version_id = :v ORDER BY question_order'
),
{'v': test_version_id},
).mappings().all()
out = []
for r in qrows:
orows = conn.execute(
text(
'SELECT id, text, is_correct, option_order '
'FROM answer_options WHERE question_id = :q ORDER BY option_order'
),
{'q': r['id']},
).mappings().all()
options = []
for o in orows:
base = {
'id': str(o['id']),
'text': o['text'],
'optionOrder': o['option_order'],
}
if include_correct:
base['isCorrect'] = bool(o['is_correct'])
options.append(base)
out.append(
{
'id': str(r['id']),
'text': r['text'],
'questionOrder': r['question_order'],
'hasMultipleAnswers': bool(r['has_multiple_answers']),
'options': options,
}
)
return out
def get_editor_content(user_id: str, test_id: str) -> dict:
eng = get_engine()
with eng.connect() as conn:
tr = conn.execute(
text(
'SELECT id, title, description, passing_threshold, created_by '
'FROM tests WHERE id = :id'
),
{'id': test_id},
).mappings().first()
if not tr:
raise HttpError(404, 'Тест не найден.')
if not is_test_author(tr['created_by'], user_id):
raise HttpError(403, 'Доступ запрещён.')
tv = conn.execute(
text(
'SELECT id FROM test_versions WHERE test_id = :id AND is_active = true LIMIT 1'
),
{'id': test_id},
).mappings().first()
if not tv:
raise HttpError(400, 'Нет активной версии теста.')
version_id = tv['id']
questions = load_questions_for_version(conn, version_id, include_correct=True)
return {
'test': {
'id': str(tr['id']),
'title': tr['title'],
'description': tr['description'],
'passingThreshold': tr['passing_threshold'],
},
'activeVersionId': str(version_id),
'questions': questions,
}