UI bugfixes with boss

This commit is contained in:
Константин Лебединский
2026-04-30 19:53:49 +05:00
parent df6e770f90
commit b72b485fce
17 changed files with 469 additions and 250 deletions
+60 -6
View File
@@ -1,12 +1,26 @@
"""Кто видит тест: автор + назначенные пользователи."""
from __future__ import annotations
import os
from dataclasses import dataclass
from sqlalchemy import exists, select
from sqlalchemy import exists, func
from ..db import get_session
from ..models import Test, TestAssignment, TestAssignmentTarget, TestAttempt, TestVersion, User
from ..models import Question, Test, TestAssignment, TestAssignmentTarget, TestAttempt, TestVersion, User
def _truthy_env(val: str | None) -> bool:
return (val or '').strip().lower() in ('1', 'true', 'yes', 'on')
def is_test_edit_open() -> bool:
"""Пока без RBAC: любой залогиненный пользователь может править любой тест.
Задайте ``CLINIC_TESTS_RESTRICT_EDIT_TO_AUTHOR=1``, чтобы снова требовать роль автора
для редактирования, подсказок, списка попыток и разбора чужих попыток.
"""
return not _truthy_env(os.environ.get('CLINIC_TESTS_RESTRICT_EDIT_TO_AUTHOR'))
def is_test_author(created_by, user_id) -> bool:
@@ -64,10 +78,20 @@ def list_visible_tests(user_id: str) -> list[dict]:
except (ValueError, AttributeError):
uid = None
qcount_sq = (
session.query(
Question.test_version_id.label('tv_id'),
func.count(Question.id).label('qc'),
)
.group_by(Question.test_version_id)
.subquery()
)
rows = (
session.query(Test, TestVersion, User)
session.query(Test, TestVersion, User, qcount_sq.c.qc)
.join(TestVersion, (TestVersion.test_id == Test.id) & TestVersion.is_active.is_(True))
.outerjoin(User, User.id == Test.created_by)
.outerjoin(qcount_sq, qcount_sq.c.tv_id == TestVersion.id)
.filter(Test.is_active.is_(True))
.order_by(Test.updated_at.desc().nullslast(), Test.created_at.desc())
.all()
@@ -85,6 +109,11 @@ def list_visible_tests(user_id: str) -> list[dict]:
'version': tv.version,
'created_by': str(t.created_by) if t.created_by else None,
'author_full_name': u.full_name if u else '',
'passing_threshold': int(t.passing_threshold or 0),
'time_limit': t.time_limit,
'result_mode': (t.result_mode or 'end'),
'hints_enabled': bool(t.hints_enabled),
'questions_count': int(qc or 0),
'has_in_progress_attempt': bool(
uid and session.query(
exists().where(
@@ -96,7 +125,7 @@ def list_visible_tests(user_id: str) -> list[dict]:
).scalar()
),
}
for t, tv, u in rows
for t, tv, u, qc in rows
]
@@ -108,10 +137,20 @@ def list_hidden_by_author(user_id: str) -> list[dict]:
except (ValueError, AttributeError):
return []
qcount_sq = (
session.query(
Question.test_version_id.label('tv_id'),
func.count(Question.id).label('qc'),
)
.group_by(Question.test_version_id)
.subquery()
)
rows = (
session.query(Test, TestVersion, User)
session.query(Test, TestVersion, User, qcount_sq.c.qc)
.join(TestVersion, (TestVersion.test_id == Test.id) & TestVersion.is_active.is_(True))
.join(User, User.id == Test.created_by)
.outerjoin(qcount_sq, qcount_sq.c.tv_id == TestVersion.id)
.filter(Test.is_active.is_(False), Test.created_by == uid)
.order_by(Test.updated_at.desc().nullslast(), Test.created_at.desc())
.all()
@@ -129,6 +168,21 @@ def list_hidden_by_author(user_id: str) -> list[dict]:
'version': tv.version,
'created_by': str(t.created_by),
'author_full_name': u.full_name,
'passing_threshold': int(t.passing_threshold or 0),
'time_limit': t.time_limit,
'result_mode': (t.result_mode or 'end'),
'hints_enabled': bool(t.hints_enabled),
'questions_count': int(qc or 0),
'has_in_progress_attempt': bool(
session.query(
exists().where(
TestAttempt.user_id == uid,
TestAttempt.status == 'in_progress',
TestAttempt.test_version_id == TestVersion.id,
TestVersion.test_id == t.id,
)
).scalar()
),
}
for t, tv, u in rows
for t, tv, u, qc in rows
]