diff --git a/src/trudex/application/bot/admin_dialogs/tests.py b/src/trudex/application/bot/admin_dialogs/tests.py index 0bf85e0..043e3c9 100644 --- a/src/trudex/application/bot/admin_dialogs/tests.py +++ b/src/trudex/application/bot/admin_dialogs/tests.py @@ -14,6 +14,7 @@ from dishka.integrations.aiogram_dialog import inject from trudex.application.bot.admin_dialogs.states import (AdminMenuSG, AdminTestsSG) +from trudex.application.bot.creator_dialogs.states import CreateTestSG from trudex.infrastructure.database.dao.group import GroupDAO from trudex.infrastructure.database.dao.test import TestDAO from trudex.infrastructure.database.repo.test import TestRepository @@ -393,8 +394,8 @@ async def on_remove_expires(_callback: CallbackQuery, _button: Button, manager: await manager.switch_to(AdminTestsSG.test_detail) -async def on_add_test_clicked(_callback: CallbackQuery, _button: Button, _manager: DialogManager): - await _callback.answer("Добавление теста") +async def on_add_test_clicked(_callback: CallbackQuery, _button: Button, manager: DialogManager): + await manager.start(CreateTestSG.input_title, mode=StartMode.RESET_STACK) async def on_back_clicked(_callback: CallbackQuery, _button: Button, manager: DialogManager): diff --git a/src/trudex/application/bot/user_dialogs/main_menu.py b/src/trudex/application/bot/user_dialogs/main_menu.py index b5b09bc..f37af0b 100644 --- a/src/trudex/application/bot/user_dialogs/main_menu.py +++ b/src/trudex/application/bot/user_dialogs/main_menu.py @@ -1,6 +1,9 @@ +import asyncio +import functools from datetime import datetime, timedelta, timezone -from aiogram.types import CallbackQuery, Message +from aiogram import Bot +from aiogram.types import BufferedInputFile, CallbackQuery, Message from aiogram_dialog import Dialog, DialogManager, Window from aiogram_dialog.widgets.input import MessageInput from aiogram_dialog.widgets.kbd import Button, Column, Row, ScrollingGroup, Select @@ -14,6 +17,9 @@ from trudex.infrastructure.database.dao.group import GroupDAO from trudex.infrastructure.database.dao.user import UserDAO from trudex.infrastructure.database.repo.test import TestRepository from trudex.infrastructure.database.repo.test_attempt import TestAttemptRepository +from trudex.infrastructure.utils.config import Config +from trudex.infrastructure.utils.qr_generator import generate_qr_bytes +from trudex.infrastructure.utils.test_id_to_hash import encode_id @inject @@ -189,6 +195,44 @@ async def on_back_to_tests(_callback: CallbackQuery, _button: Button, manager: D await manager.switch_to(UserMenuSG.available_tests) +@inject +async def on_share_test( + _callback: CallbackQuery, + _button: Button, + manager: DialogManager, + config: FromDishka[Config], + bot_inst: FromDishka[Bot], +): + test_id = manager.dialog_data.get("selected_test_id") + + if not test_id: + await _callback.answer("Ошибка: тест не найден") + return + + test_hash = encode_id( + test_id, + config.security.encode_key, + config.security.encoded_string_length, + ) + + bot_info = await bot_inst.get_me() + bot_username = bot_info.username or "your_bot" + share_link = f"https://t.me/{bot_username}?start={test_hash}" + + loop = asyncio.get_running_loop() + qr_bytes = await loop.run_in_executor( + None, + functools.partial(generate_qr_bytes, share_link), + ) + + assert _callback.message is not None + + await _callback.message.answer_photo( + photo=BufferedInputFile(qr_bytes, filename="qr.png"), + caption=f"🔗 Поделиться тестом\n\n📎 Ссылка на тест:\n{share_link}\n\n💡 Отправьте эту ссылку или QR-код пользователям для прохождения теста", + ) + + @inject async def get_test_detail( dialog_manager: DialogManager, @@ -349,6 +393,7 @@ user_menu_dialog = Dialog( Format("{test_info}"), Column( Button(Const("▶️ Пройти тест"), id="start_test", on_click=on_start_test), + Button(Const("🔗 Поделиться"), id="share", on_click=on_share_test), Button(Const("◀️ Назад"), id="back", on_click=on_back_to_tests), ), state=UserMenuSG.test_detail,