diff --git a/src/quizzi/application/bot/shared_dialogs/states.py b/src/quizzi/application/bot/shared_dialogs/states.py
index bfc7ac5..50041a2 100644
--- a/src/quizzi/application/bot/shared_dialogs/states.py
+++ b/src/quizzi/application/bot/shared_dialogs/states.py
@@ -21,6 +21,7 @@ class SharedTestsSG(StatesGroup):
statistics = State()
attempt_detail = State()
export_select_group = State()
+ delete_confirm = State()
class SharedBroadcastSG(StatesGroup):
diff --git a/src/quizzi/application/bot/shared_dialogs/tests.py b/src/quizzi/application/bot/shared_dialogs/tests.py
index a949384..12d2c97 100644
--- a/src/quizzi/application/bot/shared_dialogs/tests.py
+++ b/src/quizzi/application/bot/shared_dialogs/tests.py
@@ -299,6 +299,35 @@ async def on_edit_expires(_callback: CallbackQuery, _button: Button, manager: Di
await manager.switch_to(SharedTestsSG.edit_expires)
+async def on_delete_test(_callback: CallbackQuery, _button: Button, manager: DialogManager):
+ await manager.switch_to(SharedTestsSG.delete_confirm)
+
+
+@inject
+async def get_delete_confirm_data(dialog_manager: DialogManager, test_dao: FromDishka[TestDAO], **_kwargs):
+ test_id = dialog_manager.dialog_data.get("selected_test_id")
+ if not test_id:
+ return {"test_title": "Неизвестный тест"}
+
+ test = await test_dao.get_by_id(test_id)
+ return {"test_title": test.title if test else "Неизвестный тест"}
+
+
+@inject
+async def on_confirm_delete(_callback: CallbackQuery, _button: Button, manager: DialogManager, test_dao: FromDishka[TestDAO]):
+ test_id = manager.dialog_data.get("selected_test_id")
+ if not test_id:
+ await _callback.answer("❌ Тест не найден")
+ return
+
+ deleted = await test_dao.delete(test_id)
+ if deleted:
+ await _callback.answer("✅ Тест удалён")
+ await manager.switch_to(SharedTestsSG.tests_list)
+ else:
+ await _callback.answer("❌ Не удалось удалить тест")
+
+
@inject
async def on_password_input(message: Message, _widget: MessageInput, manager: DialogManager, test_dao: FromDishka[TestDAO]):
test_id = manager.dialog_data.get("selected_test_id")
@@ -689,6 +718,7 @@ shared_tests_dialog = Dialog(
Button(Const("⏱️ Лимит времени"), id="edit_time_limit", on_click=on_edit_time_limit),
Button(Const("👥 Группа"), id="edit_group", on_click=on_edit_group),
Button(Const("📅 Срок действия"), id="edit_expires", on_click=on_edit_expires),
+ Button(Const("🗑 Удалить тест"), id="delete_test", on_click=on_delete_test),
Button(Const("◀️ Назад"), id="back", on_click=on_back_to_detail),
),
state=SharedTestsSG.edit_menu,
@@ -795,4 +825,13 @@ shared_tests_dialog = Dialog(
state=SharedTestsSG.export_select_group,
getter=get_groups_for_export,
),
+ Window(
+ Format("🗑 Удаление теста\n\n⚠️ Вы уверены, что хотите удалить тест {test_title}?\n\nБудут удалены все вопросы, варианты ответов и результаты прохождений."),
+ Row(
+ Button(Const("✅ Да, удалить"), id="confirm_delete", on_click=on_confirm_delete),
+ Button(Const("❌ Отмена"), id="cancel_delete", on_click=on_back_to_edit_menu),
+ ),
+ state=SharedTestsSG.delete_confirm,
+ getter=get_delete_confirm_data,
+ ),
)
diff --git a/src/quizzi/infrastructure/database/dao/test.py b/src/quizzi/infrastructure/database/dao/test.py
index 1fbccf5..44a4069 100644
--- a/src/quizzi/infrastructure/database/dao/test.py
+++ b/src/quizzi/infrastructure/database/dao/test.py
@@ -41,7 +41,7 @@ class TestDAO:
async def get_all(self) -> list[DomainTest]:
result = await self.session.execute(
- select(Test).order_by(Test.created_at.desc())
+ select(Test).order_by(Test.is_active.desc(), Test.created_at.desc())
)
models = list(result.scalars().all())
return [TestDTO(model).to_domain() for model in models]
diff --git a/src/quizzi/infrastructure/database/models.py b/src/quizzi/infrastructure/database/models.py
index 897905f..68da7c3 100644
--- a/src/quizzi/infrastructure/database/models.py
+++ b/src/quizzi/infrastructure/database/models.py
@@ -63,6 +63,11 @@ class Test(Base):
cascade="all, delete-orphan",
order_by="Question.position"
)
+
+ test_attempts: Mapped[list["TestAttempt"]] = relationship(
+ back_populates="test",
+ cascade="all, delete-orphan",
+ )
@final
@@ -110,7 +115,7 @@ class TestAttempt(Base):
is_passed: Mapped[bool] = mapped_column(default=False)
user: Mapped["User"] = relationship()
- test: Mapped["Test"] = relationship()
+ test: Mapped["Test"] = relationship(back_populates="test_attempts")
answers: Mapped[list["UserAnswer"]] = relationship(
back_populates="attempt",
cascade="all, delete-orphan"