mirror of
https://github.com/koloideal/Quizzi.git
synced 2026-06-10 10:25:28 +03:00
@@ -32,8 +32,9 @@ async def ensure_user_registered(
|
|||||||
|
|
||||||
existing_user = await user_dao.get_by_id(message.from_user.id)
|
existing_user = await user_dao.get_by_id(message.from_user.id)
|
||||||
groups = await group_dao.get_all()
|
groups = await group_dao.get_all()
|
||||||
|
has_groups = len(groups) > 0
|
||||||
|
|
||||||
start_data = {"user_id": message.from_user.id}
|
start_data = {"user_id": message.from_user.id, "has_groups": has_groups}
|
||||||
if pending_test_id:
|
if pending_test_id:
|
||||||
start_data["pending_test_id"] = pending_test_id
|
start_data["pending_test_id"] = pending_test_id
|
||||||
|
|
||||||
@@ -44,28 +45,30 @@ async def ensure_user_registered(
|
|||||||
username=message.from_user.username,
|
username=message.from_user.username,
|
||||||
last_name=message.from_user.last_name,
|
last_name=message.from_user.last_name,
|
||||||
)
|
)
|
||||||
if len(groups) > 0:
|
await dialog_manager.start(
|
||||||
await dialog_manager.start(
|
UserRegistrationSG.input_name,
|
||||||
UserRegistrationSG.input_name,
|
mode=StartMode.RESET_STACK,
|
||||||
mode=StartMode.RESET_STACK,
|
data=start_data
|
||||||
data=start_data
|
)
|
||||||
)
|
return False
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
if len(groups) > 0 and (existing_user.name is None or existing_user.group is None):
|
needs_name = existing_user.name is None
|
||||||
if existing_user.name is None:
|
needs_group = has_groups and existing_user.group is None
|
||||||
await dialog_manager.start(
|
|
||||||
UserRegistrationSG.input_name,
|
if needs_name:
|
||||||
mode=StartMode.RESET_STACK,
|
await dialog_manager.start(
|
||||||
data=start_data
|
UserRegistrationSG.input_name,
|
||||||
)
|
mode=StartMode.RESET_STACK,
|
||||||
else:
|
data=start_data
|
||||||
await dialog_manager.start(
|
)
|
||||||
UserRegistrationSG.select_group,
|
return False
|
||||||
mode=StartMode.RESET_STACK,
|
|
||||||
data=start_data
|
if needs_group:
|
||||||
)
|
await dialog_manager.start(
|
||||||
|
UserRegistrationSG.select_group,
|
||||||
|
mode=StartMode.RESET_STACK,
|
||||||
|
data=start_data
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
await user_dao.upsert(
|
await user_dao.upsert(
|
||||||
|
|||||||
@@ -22,13 +22,18 @@ from quizzi.infrastructure.database.repo.test import TestRepository
|
|||||||
|
|
||||||
TEMPLATES_INFO = (
|
TEMPLATES_INFO = (
|
||||||
"<b>📦 Шаблоны тестов</b>\n\n"
|
"<b>📦 Шаблоны тестов</b>\n\n"
|
||||||
"Шаблоны позволяют экспортировать и импортировать тесты в формате JSON.\n\n"
|
"Экспорт и импорт тестов в формате JSON\n\n"
|
||||||
"🔹 <b>Экспорт</b> — сохраните тест как файл для резервной копии или передачи\n"
|
"<blockquote>"
|
||||||
"🔹 <b>Импорт</b> — загрузите тест из файла\n"
|
"📤 <b>Экспорт</b>\n"
|
||||||
"🔹 <b>Спецификация</b> — описание формата JSON для создания тестов вручную"
|
"Сохранение теста в файл для резервной копии или передачи\n\n"
|
||||||
|
"📥 <b>Импорт</b>\n"
|
||||||
|
"Загрузка теста из JSON файла\n\n"
|
||||||
|
"📋 <b>Спецификация</b>\n"
|
||||||
|
"Описание формата теста для ручного создания"
|
||||||
|
"</blockquote>"
|
||||||
)
|
)
|
||||||
|
|
||||||
SPEC_INFO = """<b>📋 Спецификация формата JSON</b>
|
SPEC_INFO = """<b>📋 Спецификация формата теста в JSON</b>
|
||||||
|
|
||||||
<b>Структура файла:</b>
|
<b>Структура файла:</b>
|
||||||
<code>{
|
<code>{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from quizzi.infrastructure.database.models import QuestionType
|
|||||||
from quizzi.infrastructure.database.repo.test import TestRepository
|
from quizzi.infrastructure.database.repo.test import TestRepository
|
||||||
from quizzi.infrastructure.database.repo.test_attempt import TestAttemptRepository
|
from quizzi.infrastructure.database.repo.test_attempt import TestAttemptRepository
|
||||||
from quizzi.infrastructure.utils.rate_limiter import PasswordRateLimiter
|
from quizzi.infrastructure.utils.rate_limiter import PasswordRateLimiter
|
||||||
from quizzi.infrastructure.utils.timezone import now_msk_naive
|
from quizzi.infrastructure.utils.timezone import now_msk_naive, to_msk
|
||||||
|
|
||||||
|
|
||||||
@inject
|
@inject
|
||||||
@@ -20,12 +20,15 @@ async def get_deeplink_test_data(
|
|||||||
dialog_manager: DialogManager,
|
dialog_manager: DialogManager,
|
||||||
test_dao: FromDishka[TestDAO],
|
test_dao: FromDishka[TestDAO],
|
||||||
test_repo: FromDishka[TestRepository],
|
test_repo: FromDishka[TestRepository],
|
||||||
|
attempt_repo: FromDishka[TestAttemptRepository],
|
||||||
**_kwargs,
|
**_kwargs,
|
||||||
):
|
):
|
||||||
|
assert dialog_manager.event.from_user is not None
|
||||||
start_data = dialog_manager.start_data or {}
|
start_data = dialog_manager.start_data or {}
|
||||||
assert isinstance(start_data, dict)
|
assert isinstance(start_data, dict)
|
||||||
test_id = start_data.get("test_id")
|
test_id = start_data.get("test_id")
|
||||||
error = start_data.get("error")
|
error = start_data.get("error")
|
||||||
|
user_id = dialog_manager.event.from_user.id
|
||||||
|
|
||||||
if error:
|
if error:
|
||||||
return {"test_info": error, "can_start": False}
|
return {"test_info": error, "can_start": False}
|
||||||
@@ -40,17 +43,26 @@ async def get_deeplink_test_data(
|
|||||||
|
|
||||||
questions_count = await test_repo.count_questions_in_test(test_id)
|
questions_count = await test_repo.count_questions_in_test(test_id)
|
||||||
|
|
||||||
|
attempts = await attempt_repo.get_user_test_attempts(user_id, test_id)
|
||||||
|
finished_attempts = [a for a in attempts if a.finished_at]
|
||||||
|
|
||||||
password_str = "🔒 Требуется пароль" if test.password else "🔓 Без пароля"
|
password_str = "🔒 Требуется пароль" if test.password else "🔓 Без пароля"
|
||||||
attempts_str = f"🔄 Попыток: {test.attempts}" if test.attempts else "🔄 Попыток: ♾️"
|
attempts_str = f"🔄 Попыток: {len(finished_attempts)}/{test.attempts}" if test.attempts else f"🔄 Попыток: {len(finished_attempts)}/♾️"
|
||||||
time_limit_str = f"⏱️ Время: {test.time_limit // 60} мин" if test.time_limit else "⏱️ Без лимита"
|
time_limit_str = f"⏱️ Время: {test.time_limit // 60} мин" if test.time_limit else "⏱️ Без лимита"
|
||||||
|
|
||||||
|
expires_at_msk = to_msk(test.expires_at)
|
||||||
|
expires_str = f"📅 До {expires_at_msk.strftime('%d.%m.%Y %H:%M')}" if expires_at_msk else "📅 Без срока"
|
||||||
|
group_str = f"🎓 Для группы {test.for_group}" if test.for_group else "👥 Для всех"
|
||||||
|
|
||||||
test_info = (
|
test_info = (
|
||||||
f"<b>📝 {test.title}</b>\n\n"
|
f"<b>📝 {test.title}</b>\n\n"
|
||||||
f"<blockquote>{test.description or '—'}</blockquote>\n\n"
|
f"<blockquote>{test.description or '—'}</blockquote>\n\n"
|
||||||
f"<b>Вопросов:</b> {questions_count}\n"
|
f"<b>Вопросов:</b> {questions_count}\n"
|
||||||
f"{password_str}\n"
|
f"{password_str}\n"
|
||||||
f"{attempts_str}\n"
|
f"{attempts_str}\n"
|
||||||
f"{time_limit_str}"
|
f"{time_limit_str}\n"
|
||||||
|
f"{expires_str}\n"
|
||||||
|
f"{group_str}"
|
||||||
)
|
)
|
||||||
|
|
||||||
return {"test_info": test_info, "can_start": True, "has_password": bool(test.password)}
|
return {"test_info": test_info, "can_start": True, "has_password": bool(test.password)}
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ user_menu_dialog = Dialog(
|
|||||||
getter=get_test_detail,
|
getter=get_test_detail,
|
||||||
),
|
),
|
||||||
Window(
|
Window(
|
||||||
Const("<b>✏️ Изменение имени</b>\n\nВведите новое имя:"),
|
Const("<b>✏️ Изменение имени</b>\n\nВведите имя и фамилию:"),
|
||||||
MessageInput(on_name_input),
|
MessageInput(on_name_input),
|
||||||
Button(Const("◀️ Назад"), id="back", on_click=on_back_to_main),
|
Button(Const("◀️ Назад"), id="back", on_click=on_back_to_main),
|
||||||
state=UserMenuSG.edit_name,
|
state=UserMenuSG.edit_name,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from dishka.integrations.aiogram_dialog import inject
|
|||||||
from quizzi.application.bot.user_dialogs.states import UserDeeplinkSG, UserMenuSG, UserRegistrationSG
|
from quizzi.application.bot.user_dialogs.states import UserDeeplinkSG, UserMenuSG, UserRegistrationSG
|
||||||
from quizzi.infrastructure.database.dao.group import GroupDAO
|
from quizzi.infrastructure.database.dao.group import GroupDAO
|
||||||
from quizzi.infrastructure.database.dao.user import UserDAO
|
from quizzi.infrastructure.database.dao.user import UserDAO
|
||||||
|
from quizzi.infrastructure.utils.timezone import now_msk_naive
|
||||||
|
|
||||||
|
|
||||||
@inject
|
@inject
|
||||||
@@ -35,11 +36,24 @@ async def on_name_input(
|
|||||||
start_data = manager.start_data or {}
|
start_data = manager.start_data or {}
|
||||||
assert isinstance(start_data, dict)
|
assert isinstance(start_data, dict)
|
||||||
user_id = start_data.get("user_id")
|
user_id = start_data.get("user_id")
|
||||||
|
has_groups = start_data.get("has_groups", True)
|
||||||
|
pending_test_id = start_data.get("pending_test_id")
|
||||||
|
|
||||||
if user_id:
|
if user_id:
|
||||||
await user_dao.update(user_id=user_id, name=name)
|
await user_dao.update(user_id=user_id, name=name, name_updated_at=now_msk_naive())
|
||||||
|
|
||||||
manager.dialog_data["name"] = name
|
manager.dialog_data["name"] = name
|
||||||
await manager.switch_to(UserRegistrationSG.select_group)
|
|
||||||
|
if has_groups:
|
||||||
|
await manager.switch_to(UserRegistrationSG.select_group)
|
||||||
|
elif pending_test_id:
|
||||||
|
await manager.start(
|
||||||
|
UserDeeplinkSG.test_preview,
|
||||||
|
mode=StartMode.RESET_STACK,
|
||||||
|
data={"test_id": pending_test_id}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await manager.start(UserMenuSG.main, mode=StartMode.RESET_STACK)
|
||||||
|
|
||||||
|
|
||||||
@inject
|
@inject
|
||||||
@@ -66,7 +80,7 @@ async def on_group_selected(
|
|||||||
pending_test_id = start_data.get("pending_test_id")
|
pending_test_id = start_data.get("pending_test_id")
|
||||||
|
|
||||||
if user_id:
|
if user_id:
|
||||||
await user_dao.update(user_id=user_id, group=int(item_id))
|
await user_dao.update(user_id=user_id, group=int(item_id), group_updated_at=now_msk_naive())
|
||||||
|
|
||||||
if pending_test_id:
|
if pending_test_id:
|
||||||
await manager.start(
|
await manager.start(
|
||||||
|
|||||||
Reference in New Issue
Block a user