This commit is contained in:
2026-01-06 18:06:51 +03:00
parent 326ced233b
commit efe3f4ab43
71 changed files with 245 additions and 245 deletions
+2 -2
View File
@@ -5,8 +5,8 @@ from sqlalchemy import Connection
from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.ext.asyncio import create_async_engine
from alembic import context from alembic import context
from trudex.infrastructure.database.models import Base from quizzi.infrastructure.database.models import Base
from trudex.infrastructure.utils.config import Config from quizzi.infrastructure.utils.config import Config
# this is the Alembic Config object, which provides # this is the Alembic Config object, which provides
# access to the values within the .ini file in use. # access to the values within the .ini file in use.
+1 -1
View File
@@ -1,5 +1,5 @@
[project] [project]
name = "trudex" name = "quizzi"
version = "0.1.0" version = "0.1.0"
description = "Occupational health and safety testing platform" description = "Occupational health and safety testing platform"
authors = [{ name = "kolo", email = "kolo.is.main@gmail.com" }] authors = [{ name = "kolo", email = "kolo.is.main@gmail.com" }]
@@ -9,26 +9,26 @@ from apscheduler.schedulers.asyncio import AsyncIOScheduler
from dishka import make_async_container from dishka import make_async_container
from dishka.integrations.aiogram import setup_dishka from dishka.integrations.aiogram import setup_dishka
from trudex.application.bot.admin_dialogs.main_menu import admin_menu_dialog from quizzi.application.bot.admin_dialogs.main_menu import admin_menu_dialog
from trudex.application.bot.admin_dialogs.users import admin_users_dialog from quizzi.application.bot.admin_dialogs.users import admin_users_dialog
from trudex.application.bot.creator_dialogs.main_menu import creator_menu_dialog from quizzi.application.bot.creator_dialogs.main_menu import creator_menu_dialog
from trudex.application.bot.creator_dialogs.users import creator_users_dialog from quizzi.application.bot.creator_dialogs.users import creator_users_dialog
from trudex.application.bot.handlers import router from quizzi.application.bot.handlers import router
from trudex.application.bot.middlewares.reject_not_admin import RejectNotAdminMiddleware from quizzi.application.bot.middlewares.reject_not_admin import RejectNotAdminMiddleware
from trudex.application.bot.middlewares.reject_not_creator import RejectNotCreatorMiddleware from quizzi.application.bot.middlewares.reject_not_creator import RejectNotCreatorMiddleware
from trudex.application.bot.shared_dialogs.broadcast import shared_broadcast_dialog from quizzi.application.bot.shared_dialogs.broadcast import shared_broadcast_dialog
from trudex.application.bot.shared_dialogs.create_test import shared_create_test_dialog from quizzi.application.bot.shared_dialogs.create_test import shared_create_test_dialog
from trudex.application.bot.shared_dialogs.groups import shared_groups_dialog from quizzi.application.bot.shared_dialogs.groups import shared_groups_dialog
from trudex.application.bot.shared_dialogs.templates import shared_templates_dialog from quizzi.application.bot.shared_dialogs.templates import shared_templates_dialog
from trudex.application.bot.shared_dialogs.tests import shared_tests_dialog from quizzi.application.bot.shared_dialogs.tests import shared_tests_dialog
from trudex.application.bot.user_dialogs.deeplink import deeplink_dialog from quizzi.application.bot.user_dialogs.deeplink import deeplink_dialog
from trudex.application.bot.user_dialogs.main_menu import user_menu_dialog from quizzi.application.bot.user_dialogs.main_menu import user_menu_dialog
from trudex.application.bot.user_dialogs.registration import registration_dialog from quizzi.application.bot.user_dialogs.registration import registration_dialog
from trudex.application.bot.user_dialogs.take_test import take_test_dialog from quizzi.application.bot.user_dialogs.take_test import take_test_dialog
from trudex.infrastructure.database.repo.user import UserRepository from quizzi.infrastructure.database.repo.user import UserRepository
from trudex.infrastructure.di import DatabaseProvider, SchedulerProvider from quizzi.infrastructure.di import DatabaseProvider, SchedulerProvider
from trudex.infrastructure.utils.bot_commands import setup_bot_commands from quizzi.infrastructure.utils.bot_commands import setup_bot_commands
from trudex.infrastructure.utils.config import Config from quizzi.infrastructure.utils.config import Config
async def main() -> None: async def main() -> None:
@@ -3,8 +3,8 @@ from aiogram_dialog import Dialog, DialogManager, Window
from aiogram_dialog.widgets.kbd import Button, Column from aiogram_dialog.widgets.kbd import Button, Column
from aiogram_dialog.widgets.text import Const from aiogram_dialog.widgets.text import Const
from trudex.application.bot.admin_dialogs.states import AdminMenuSG, AdminUsersSG from quizzi.application.bot.admin_dialogs.states import AdminMenuSG, AdminUsersSG
from trudex.application.bot.shared_dialogs.states import ( from quizzi.application.bot.shared_dialogs.states import (
SharedBroadcastSG, SharedBroadcastSG,
SharedGroupsSG, SharedGroupsSG,
SharedTemplatesSG, SharedTemplatesSG,
@@ -6,11 +6,11 @@ from aiogram_dialog.widgets.text import Const, Format
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject from dishka.integrations.aiogram_dialog import inject
from trudex.application.bot.admin_dialogs.states import AdminUsersSG from quizzi.application.bot.admin_dialogs.states import AdminUsersSG
from trudex.infrastructure.database.dao.user import UserDAO from quizzi.infrastructure.database.dao.user import UserDAO
from trudex.infrastructure.database.repo.test import TestRepository from quizzi.infrastructure.database.repo.test import TestRepository
from trudex.infrastructure.database.repo.test_attempt import TestAttemptRepository from quizzi.infrastructure.database.repo.test_attempt import TestAttemptRepository
from trudex.infrastructure.utils.timezone import to_msk from quizzi.infrastructure.utils.timezone import to_msk
@inject @inject
@@ -3,8 +3,8 @@ from aiogram_dialog import Dialog, DialogManager, Window
from aiogram_dialog.widgets.kbd import Button, Column from aiogram_dialog.widgets.kbd import Button, Column
from aiogram_dialog.widgets.text import Const from aiogram_dialog.widgets.text import Const
from trudex.application.bot.creator_dialogs.states import CreatorMenuSG, CreatorUsersSG from quizzi.application.bot.creator_dialogs.states import CreatorMenuSG, CreatorUsersSG
from trudex.application.bot.shared_dialogs.states import ( from quizzi.application.bot.shared_dialogs.states import (
SharedBroadcastSG, SharedBroadcastSG,
SharedGroupsSG, SharedGroupsSG,
SharedTemplatesSG, SharedTemplatesSG,
@@ -9,14 +9,14 @@ from aiogram_dialog.widgets.text import Const, Format
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject from dishka.integrations.aiogram_dialog import inject
from trudex.application.bot.creator_dialogs.states import CreatorUsersSG from quizzi.application.bot.creator_dialogs.states import CreatorUsersSG
from trudex.infrastructure.database.dao.user import UserDAO from quizzi.infrastructure.database.dao.user import UserDAO
from trudex.infrastructure.database.repo.test import TestRepository from quizzi.infrastructure.database.repo.test import TestRepository
from trudex.infrastructure.database.repo.test_attempt import TestAttemptRepository from quizzi.infrastructure.database.repo.test_attempt import TestAttemptRepository
from trudex.infrastructure.database.repo.user import UserRepository from quizzi.infrastructure.database.repo.user import UserRepository
from trudex.infrastructure.utils.bot_commands import setup_bot_commands from quizzi.infrastructure.utils.bot_commands import setup_bot_commands
from trudex.infrastructure.utils.config import Config from quizzi.infrastructure.utils.config import Config
from trudex.infrastructure.utils.timezone import to_msk from quizzi.infrastructure.utils.timezone import to_msk
@inject @inject
@@ -7,15 +7,15 @@ from aiogram_dialog import DialogManager, StartMode
from aiogram_dialog.api.exceptions import OutdatedIntent, UnknownIntent from aiogram_dialog.api.exceptions import OutdatedIntent, UnknownIntent
from dishka.integrations.aiogram import FromDishka from dishka.integrations.aiogram import FromDishka
from trudex.application.bot.admin_dialogs.states import AdminMenuSG from quizzi.application.bot.admin_dialogs.states import AdminMenuSG
from trudex.application.bot.creator_dialogs.states import CreatorMenuSG from quizzi.application.bot.creator_dialogs.states import CreatorMenuSG
from trudex.application.bot.user_dialogs.states import UserDeeplinkSG, UserMenuSG, UserRegistrationSG from quizzi.application.bot.user_dialogs.states import UserDeeplinkSG, UserMenuSG, UserRegistrationSG
from trudex.infrastructure.database.dao.group import GroupDAO from quizzi.infrastructure.database.dao.group import GroupDAO
from trudex.infrastructure.database.dao.test import TestDAO from quizzi.infrastructure.database.dao.test import TestDAO
from trudex.infrastructure.database.dao.user import UserDAO from quizzi.infrastructure.database.dao.user import UserDAO
from trudex.infrastructure.utils.config import Config from quizzi.infrastructure.utils.config import Config
from trudex.infrastructure.utils.test_id_to_hash import decode_id from quizzi.infrastructure.utils.test_id_to_hash import decode_id
from trudex.infrastructure.utils.timezone import now_msk_naive from quizzi.infrastructure.utils.timezone import now_msk_naive
router = Router() router = Router()
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -5,8 +5,8 @@ from aiogram import BaseMiddleware
from aiogram.types import Message, TelegramObject from aiogram.types import Message, TelegramObject
from dishka import AsyncContainer from dishka import AsyncContainer
from trudex.infrastructure.database.repo import UserRepository from quizzi.infrastructure.database.repo import UserRepository
from trudex.infrastructure.utils.config import Config from quizzi.infrastructure.utils.config import Config
class RejectNotAdminMiddleware(BaseMiddleware): class RejectNotAdminMiddleware(BaseMiddleware):
@@ -5,7 +5,7 @@ from aiogram import BaseMiddleware
from aiogram.types import Message, TelegramObject from aiogram.types import Message, TelegramObject
from dishka import AsyncContainer from dishka import AsyncContainer
from trudex.infrastructure.utils.config import Config from quizzi.infrastructure.utils.config import Config
class RejectNotCreatorMiddleware(BaseMiddleware): class RejectNotCreatorMiddleware(BaseMiddleware):
@@ -6,9 +6,9 @@ from aiogram_dialog.widgets.text import Const
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject from dishka.integrations.aiogram_dialog import inject
from trudex.application.bot.shared_dialogs.states import SharedBroadcastSG from quizzi.application.bot.shared_dialogs.states import SharedBroadcastSG
from trudex.infrastructure.database.dao.user import UserDAO from quizzi.infrastructure.database.dao.user import UserDAO
from trudex.infrastructure.utils.broadcast import broadcast_message from quizzi.infrastructure.utils.broadcast import broadcast_message
async def on_broadcast_input(message: Message, _widget: MessageInput, manager: DialogManager): async def on_broadcast_input(message: Message, _widget: MessageInput, manager: DialogManager):
@@ -8,13 +8,13 @@ from aiogram_dialog.widgets.text import Const, Format
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject from dishka.integrations.aiogram_dialog import inject
from trudex.application.bot.shared_dialogs.states import SharedCreateTestSG, SharedTestsSG from quizzi.application.bot.shared_dialogs.states import SharedCreateTestSG, SharedTestsSG
from trudex.infrastructure.database.dao.group import GroupDAO from quizzi.infrastructure.database.dao.group import GroupDAO
from trudex.infrastructure.database.dao.option import OptionDAO from quizzi.infrastructure.database.dao.option import OptionDAO
from trudex.infrastructure.database.dao.question import QuestionDAO from quizzi.infrastructure.database.dao.question import QuestionDAO
from trudex.infrastructure.database.dao.test import TestDAO from quizzi.infrastructure.database.dao.test import TestDAO
from trudex.infrastructure.database.repo.test import TestRepository from quizzi.infrastructure.database.repo.test import TestRepository
from trudex.infrastructure.utils.timezone import to_msk from quizzi.infrastructure.utils.timezone import to_msk
async def on_title_input(message: Message, _widget: MessageInput, manager: DialogManager): async def on_title_input(message: Message, _widget: MessageInput, manager: DialogManager):
@@ -6,8 +6,8 @@ from aiogram_dialog.widgets.text import Const, Format
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject from dishka.integrations.aiogram_dialog import inject
from trudex.application.bot.shared_dialogs.states import SharedGroupsSG from quizzi.application.bot.shared_dialogs.states import SharedGroupsSG
from trudex.infrastructure.database.dao.group import GroupDAO from quizzi.infrastructure.database.dao.group import GroupDAO
async def on_group_click(_callback: CallbackQuery, _widget, _manager: DialogManager, _item_id: str): async def on_group_click(_callback: CallbackQuery, _widget, _manager: DialogManager, _item_id: str):
@@ -10,14 +10,14 @@ from aiogram_dialog.widgets.text import Const, Format
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject from dishka.integrations.aiogram_dialog import inject
from trudex.application.bot.shared_dialogs.states import SharedTemplatesSG, SharedTestsSG from quizzi.application.bot.shared_dialogs.states import SharedTemplatesSG, SharedTestsSG
from trudex.domain.schemas import QuestionType from quizzi.domain.schemas import QuestionType
from trudex.domain.test_parser import ParsedTest, TestParser from quizzi.domain.test_parser import ParsedTest, TestParser
from trudex.infrastructure.database.dao.group import GroupDAO from quizzi.infrastructure.database.dao.group import GroupDAO
from trudex.infrastructure.database.dao.option import OptionDAO from quizzi.infrastructure.database.dao.option import OptionDAO
from trudex.infrastructure.database.dao.question import QuestionDAO from quizzi.infrastructure.database.dao.question import QuestionDAO
from trudex.infrastructure.database.dao.test import TestDAO from quizzi.infrastructure.database.dao.test import TestDAO
from trudex.infrastructure.database.repo.test import TestRepository from quizzi.infrastructure.database.repo.test import TestRepository
TEMPLATES_INFO = ( TEMPLATES_INFO = (
@@ -12,16 +12,16 @@ from aiogram_dialog.widgets.text import Const, Format
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject from dishka.integrations.aiogram_dialog import inject
from trudex.application.bot.shared_dialogs.states import SharedCreateTestSG, SharedTestsSG from quizzi.application.bot.shared_dialogs.states import SharedCreateTestSG, SharedTestsSG
from trudex.domain.schemas import QuestionType from quizzi.domain.schemas import QuestionType
from trudex.infrastructure.database.dao.group import GroupDAO from quizzi.infrastructure.database.dao.group import GroupDAO
from trudex.infrastructure.database.dao.test import TestDAO from quizzi.infrastructure.database.dao.test import TestDAO
from trudex.infrastructure.database.repo.test import TestRepository from quizzi.infrastructure.database.repo.test import TestRepository
from trudex.infrastructure.database.repo.test_attempt import TestAttemptRepository from quizzi.infrastructure.database.repo.test_attempt import TestAttemptRepository
from trudex.infrastructure.utils.config import Config from quizzi.infrastructure.utils.config import Config
from trudex.infrastructure.utils.qr_generator import generate_qr_bytes from quizzi.infrastructure.utils.qr_generator import generate_qr_bytes
from trudex.infrastructure.utils.test_id_to_hash import encode_id from quizzi.infrastructure.utils.test_id_to_hash import encode_id
from trudex.infrastructure.utils.timezone import to_msk from quizzi.infrastructure.utils.timezone import to_msk
@inject @inject
@@ -6,12 +6,12 @@ from aiogram_dialog.widgets.text import Const, Format
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject from dishka.integrations.aiogram_dialog import inject
from trudex.application.bot.user_dialogs.states import UserDeeplinkSG, UserMenuSG, UserTestSG from quizzi.application.bot.user_dialogs.states import UserDeeplinkSG, UserMenuSG, UserTestSG
from trudex.infrastructure.database.dao.test import TestDAO from quizzi.infrastructure.database.dao.test import TestDAO
from trudex.infrastructure.database.models import QuestionType from quizzi.infrastructure.database.models import QuestionType
from trudex.infrastructure.database.repo.test import TestRepository from quizzi.infrastructure.database.repo.test import TestRepository
from trudex.infrastructure.database.repo.test_attempt import TestAttemptRepository from quizzi.infrastructure.database.repo.test_attempt import TestAttemptRepository
from trudex.infrastructure.utils.rate_limiter import PasswordRateLimiter from quizzi.infrastructure.utils.rate_limiter import PasswordRateLimiter
@inject @inject
@@ -11,16 +11,16 @@ from aiogram_dialog.widgets.text import Const, Format
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject from dishka.integrations.aiogram_dialog import inject
from trudex.application.bot.user_dialogs.states import UserMenuSG from quizzi.application.bot.user_dialogs.states import UserMenuSG
from trudex.application.bot.user_dialogs.take_test import on_start_test from quizzi.application.bot.user_dialogs.take_test import on_start_test
from trudex.infrastructure.database.dao.group import GroupDAO from quizzi.infrastructure.database.dao.group import GroupDAO
from trudex.infrastructure.database.dao.user import UserDAO from quizzi.infrastructure.database.dao.user import UserDAO
from trudex.infrastructure.database.repo.test import TestRepository from quizzi.infrastructure.database.repo.test import TestRepository
from trudex.infrastructure.database.repo.test_attempt import TestAttemptRepository from quizzi.infrastructure.database.repo.test_attempt import TestAttemptRepository
from trudex.infrastructure.utils.config import Config from quizzi.infrastructure.utils.config import Config
from trudex.infrastructure.utils.qr_generator import generate_qr_bytes from quizzi.infrastructure.utils.qr_generator import generate_qr_bytes
from trudex.infrastructure.utils.test_id_to_hash import encode_id from quizzi.infrastructure.utils.test_id_to_hash import encode_id
from trudex.infrastructure.utils.timezone import now_msk, now_msk_naive, to_msk from quizzi.infrastructure.utils.timezone import now_msk, now_msk_naive, to_msk
def can_edit_field(updated_at: datetime | None) -> bool: def can_edit_field(updated_at: datetime | None) -> bool:
@@ -6,9 +6,9 @@ from aiogram_dialog.widgets.text import Const, Format
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject from dishka.integrations.aiogram_dialog import inject
from trudex.application.bot.user_dialogs.states import UserDeeplinkSG, UserMenuSG, UserRegistrationSG from quizzi.application.bot.user_dialogs.states import UserDeeplinkSG, UserMenuSG, UserRegistrationSG
from trudex.infrastructure.database.dao.group import GroupDAO from quizzi.infrastructure.database.dao.group import GroupDAO
from trudex.infrastructure.database.dao.user import UserDAO from quizzi.infrastructure.database.dao.user import UserDAO
@inject @inject
@@ -9,14 +9,14 @@ from aiogram_dialog.widgets.text import Const, Format
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject from dishka.integrations.aiogram_dialog import inject
from trudex.application.bot.user_dialogs.states import UserMenuSG, UserTestSG from quizzi.application.bot.user_dialogs.states import UserMenuSG, UserTestSG
from trudex.domain.schemas import QuestionType from quizzi.domain.schemas import QuestionType
from trudex.infrastructure.database.dao.test import TestDAO from quizzi.infrastructure.database.dao.test import TestDAO
from trudex.infrastructure.database.dao.user_answer import UserAnswerDAO from quizzi.infrastructure.database.dao.user_answer import UserAnswerDAO
from trudex.infrastructure.database.repo.test import TestRepository from quizzi.infrastructure.database.repo.test import TestRepository
from trudex.infrastructure.database.repo.test_attempt import TestAttemptRepository from quizzi.infrastructure.database.repo.test_attempt import TestAttemptRepository
from trudex.infrastructure.utils.rate_limiter import PasswordRateLimiter from quizzi.infrastructure.utils.rate_limiter import PasswordRateLimiter
from trudex.infrastructure.utils.timezone import now_msk_naive from quizzi.infrastructure.utils.timezone import now_msk_naive
async def get_state_for_question_type(question_type: str): async def get_state_for_question_type(question_type: str):
@@ -1,9 +1,9 @@
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from trudex.domain.schemas import Group as DomainGroup from quizzi.domain.schemas import Group as DomainGroup
from trudex.infrastructure.database.dto.group import GroupDTO from quizzi.infrastructure.database.dto.group import GroupDTO
from trudex.infrastructure.database.models import Group from quizzi.infrastructure.database.models import Group
class GroupDAO: class GroupDAO:
@@ -1,9 +1,9 @@
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from trudex.domain.schemas import Option as DomainOption from quizzi.domain.schemas import Option as DomainOption
from trudex.infrastructure.database.dto.option import OptionDTO from quizzi.infrastructure.database.dto.option import OptionDTO
from trudex.infrastructure.database.models import Option from quizzi.infrastructure.database.models import Option
class OptionDAO: class OptionDAO:
@@ -1,10 +1,10 @@
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from trudex.domain.schemas import Question as DomainQuestion from quizzi.domain.schemas import Question as DomainQuestion
from trudex.domain.schemas import QuestionType from quizzi.domain.schemas import QuestionType
from trudex.infrastructure.database.dto.question import QuestionDTO from quizzi.infrastructure.database.dto.question import QuestionDTO
from trudex.infrastructure.database.models import Question from quizzi.infrastructure.database.models import Question
class QuestionDAO: class QuestionDAO:
@@ -4,9 +4,9 @@ from typing import NotRequired, TypedDict, Unpack
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from trudex.domain.schemas import Test as DomainTest from quizzi.domain.schemas import Test as DomainTest
from trudex.infrastructure.database.dto.test import TestDTO from quizzi.infrastructure.database.dto.test import TestDTO
from trudex.infrastructure.database.models import Test from quizzi.infrastructure.database.models import Test
class _UNSET: class _UNSET:
@@ -3,9 +3,9 @@ from datetime import datetime
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from trudex.domain.schemas import TestAttempt as DomainTestAttempt from quizzi.domain.schemas import TestAttempt as DomainTestAttempt
from trudex.infrastructure.database.dto.test_attempt import TestAttemptDTO from quizzi.infrastructure.database.dto.test_attempt import TestAttemptDTO
from trudex.infrastructure.database.models import TestAttempt from quizzi.infrastructure.database.models import TestAttempt
class TestAttemptDAO: class TestAttemptDAO:
@@ -3,9 +3,9 @@ from datetime import datetime
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from trudex.domain.schemas import User as DomainUser from quizzi.domain.schemas import User as DomainUser
from trudex.infrastructure.database.dto.user import UserDTO from quizzi.infrastructure.database.dto.user import UserDTO
from trudex.infrastructure.database.models import User from quizzi.infrastructure.database.models import User
class _UNSET: class _UNSET:
@@ -1,9 +1,9 @@
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from trudex.domain.schemas import UserAnswer as DomainUserAnswer from quizzi.domain.schemas import UserAnswer as DomainUserAnswer
from trudex.infrastructure.database.dto.user_answer import UserAnswerDTO from quizzi.infrastructure.database.dto.user_answer import UserAnswerDTO
from trudex.infrastructure.database.models import UserAnswer from quizzi.infrastructure.database.models import UserAnswer
class UserAnswerDAO: class UserAnswerDAO:
@@ -1,5 +1,5 @@
from trudex.domain.schemas import Group as DomainGroup from quizzi.domain.schemas import Group as DomainGroup
from trudex.infrastructure.database.models import Group as GroupModel from quizzi.infrastructure.database.models import Group as GroupModel
class GroupDTO: class GroupDTO:
@@ -1,5 +1,5 @@
from trudex.domain.schemas import Option as DomainOption from quizzi.domain.schemas import Option as DomainOption
from trudex.infrastructure.database.models import Option as OptionModel from quizzi.infrastructure.database.models import Option as OptionModel
class OptionDTO: class OptionDTO:
@@ -1,5 +1,5 @@
from trudex.domain.schemas import Question as DomainQuestion from quizzi.domain.schemas import Question as DomainQuestion
from trudex.infrastructure.database.models import Question as QuestionModel from quizzi.infrastructure.database.models import Question as QuestionModel
class QuestionDTO: class QuestionDTO:
@@ -1,5 +1,5 @@
from trudex.domain.schemas import Test as DomainTest from quizzi.domain.schemas import Test as DomainTest
from trudex.infrastructure.database.models import Test as TestModel from quizzi.infrastructure.database.models import Test as TestModel
class TestDTO: class TestDTO:
@@ -1,5 +1,5 @@
from trudex.domain.schemas import TestAttempt as DomainTestAttempt from quizzi.domain.schemas import TestAttempt as DomainTestAttempt
from trudex.infrastructure.database.models import TestAttempt as TestAttemptModel from quizzi.infrastructure.database.models import TestAttempt as TestAttemptModel
class TestAttemptDTO: class TestAttemptDTO:
@@ -1,5 +1,5 @@
from trudex.domain.schemas import User as DomainUser from quizzi.domain.schemas import User as DomainUser
from trudex.infrastructure.database.models import User as UserModel from quizzi.infrastructure.database.models import User as UserModel
class UserDTO: class UserDTO:
@@ -1,5 +1,5 @@
from trudex.domain.schemas import UserAnswer as DomainUserAnswer from quizzi.domain.schemas import UserAnswer as DomainUserAnswer
from trudex.infrastructure.database.models import UserAnswer as UserAnswerModel from quizzi.infrastructure.database.models import UserAnswer as UserAnswerModel
class UserAnswerDTO: class UserAnswerDTO:
@@ -4,7 +4,7 @@ from typing import final
from sqlalchemy import BigInteger, CheckConstraint, ForeignKey, Integer, String, Text, func from sqlalchemy import BigInteger, CheckConstraint, ForeignKey, Integer, String, Text, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from trudex.domain.schemas import QuestionType from quizzi.domain.schemas import QuestionType
class Base(DeclarativeBase): class Base(DeclarativeBase):
@@ -0,0 +1,5 @@
from quizzi.infrastructure.database.repo.test import TestRepository
from quizzi.infrastructure.database.repo.test_attempt import TestAttemptRepository
from quizzi.infrastructure.database.repo.user import UserRepository
__all__ = ["TestRepository", "TestAttemptRepository", "UserRepository"]
@@ -4,16 +4,16 @@ from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
from trudex.domain.schemas import Option, Question, Test from quizzi.domain.schemas import Option, Question, Test
from trudex.infrastructure.database.dao.option import OptionDAO from quizzi.infrastructure.database.dao.option import OptionDAO
from trudex.infrastructure.database.dao.question import QuestionDAO from quizzi.infrastructure.database.dao.question import QuestionDAO
from trudex.infrastructure.database.dao.test import TestDAO from quizzi.infrastructure.database.dao.test import TestDAO
from trudex.infrastructure.database.dto.option import OptionDTO from quizzi.infrastructure.database.dto.option import OptionDTO
from trudex.infrastructure.database.dto.question import QuestionDTO from quizzi.infrastructure.database.dto.question import QuestionDTO
from trudex.infrastructure.database.dto.test import TestDTO from quizzi.infrastructure.database.dto.test import TestDTO
from trudex.infrastructure.database.models import Option as OptionModel from quizzi.infrastructure.database.models import Option as OptionModel
from trudex.infrastructure.database.models import Question as QuestionModel from quizzi.infrastructure.database.models import Question as QuestionModel
from trudex.infrastructure.database.models import Test as TestModel from quizzi.infrastructure.database.models import Test as TestModel
@final @final
@@ -176,7 +176,7 @@ class TestRepository:
return new_test return new_test
async def get_available_tests_for_user(self, user_id: int, user_group: int | None) -> list[Test]: async def get_available_tests_for_user(self, user_id: int, user_group: int | None) -> list[Test]:
from trudex.infrastructure.database.models import TestAttempt from quizzi.infrastructure.database.models import TestAttempt
subquery = ( subquery = (
select( select(
@@ -4,14 +4,14 @@ from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload from sqlalchemy.orm import selectinload
from trudex.domain.schemas import TestAttempt, UserAnswer from quizzi.domain.schemas import TestAttempt, UserAnswer
from trudex.infrastructure.database.dao.test_attempt import TestAttemptDAO from quizzi.infrastructure.database.dao.test_attempt import TestAttemptDAO
from trudex.infrastructure.database.dao.user_answer import UserAnswerDAO from quizzi.infrastructure.database.dao.user_answer import UserAnswerDAO
from trudex.infrastructure.database.dto.test_attempt import TestAttemptDTO from quizzi.infrastructure.database.dto.test_attempt import TestAttemptDTO
from trudex.infrastructure.database.dto.user_answer import UserAnswerDTO from quizzi.infrastructure.database.dto.user_answer import UserAnswerDTO
from trudex.infrastructure.database.models import TestAttempt as TestAttemptModel from quizzi.infrastructure.database.models import TestAttempt as TestAttemptModel
from trudex.infrastructure.database.models import UserAnswer as UserAnswerModel from quizzi.infrastructure.database.models import UserAnswer as UserAnswerModel
from trudex.infrastructure.utils.timezone import now_msk_naive from quizzi.infrastructure.utils.timezone import now_msk_naive
@final @final
@@ -173,7 +173,7 @@ class TestAttemptRepository:
} }
async def get_most_difficult_questions(self, test_id: int, limit: int = 10) -> list[tuple[int, float]]: async def get_most_difficult_questions(self, test_id: int, limit: int = 10) -> list[tuple[int, float]]:
from trudex.infrastructure.database.models import Question as QuestionModel from quizzi.infrastructure.database.models import Question as QuestionModel
result = await self.session.execute( result = await self.session.execute(
select( select(
@@ -209,7 +209,7 @@ class TestAttemptRepository:
} }
async def get_finished_attempts_with_tests(self, user_id: int) -> list[tuple[TestAttempt, str]]: async def get_finished_attempts_with_tests(self, user_id: int) -> list[tuple[TestAttempt, str]]:
from trudex.infrastructure.database.models import Test as TestModel from quizzi.infrastructure.database.models import Test as TestModel
result = await self.session.execute( result = await self.session.execute(
select(TestAttemptModel, TestModel.title) select(TestAttemptModel, TestModel.title)
@@ -222,7 +222,7 @@ class TestAttemptRepository:
return [(TestAttemptDTO(row[0]).to_domain(), row[1]) for row in rows] return [(TestAttemptDTO(row[0]).to_domain(), row[1]) for row in rows]
async def get_test_attempts_with_users(self, test_id: int) -> list[tuple[TestAttempt, str]]: async def get_test_attempts_with_users(self, test_id: int) -> list[tuple[TestAttempt, str]]:
from trudex.infrastructure.database.models import User as UserModel from quizzi.infrastructure.database.models import User as UserModel
result = await self.session.execute( result = await self.session.execute(
select(TestAttemptModel, UserModel.name, UserModel.first_name) select(TestAttemptModel, UserModel.name, UserModel.first_name)
@@ -3,10 +3,10 @@ from typing import final
from sqlalchemy import func, select from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from trudex.domain.schemas import User from quizzi.domain.schemas import User
from trudex.infrastructure.database.dao.user import UserDAO from quizzi.infrastructure.database.dao.user import UserDAO
from trudex.infrastructure.database.dto.user import UserDTO from quizzi.infrastructure.database.dto.user import UserDTO
from trudex.infrastructure.database.models import User as UserModel from quizzi.infrastructure.database.models import User as UserModel
@final @final
@@ -5,20 +5,20 @@ from apscheduler.schedulers.asyncio import AsyncIOScheduler
from dishka import AsyncContainer, Provider, Scope, provide from dishka import AsyncContainer, Provider, Scope, provide
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
from trudex.infrastructure.database.config import new_session_maker from quizzi.infrastructure.database.config import new_session_maker
from trudex.infrastructure.database.dao.group import GroupDAO from quizzi.infrastructure.database.dao.group import GroupDAO
from trudex.infrastructure.database.dao.option import OptionDAO from quizzi.infrastructure.database.dao.option import OptionDAO
from trudex.infrastructure.database.dao.question import QuestionDAO from quizzi.infrastructure.database.dao.question import QuestionDAO
from trudex.infrastructure.database.dao.test import TestDAO from quizzi.infrastructure.database.dao.test import TestDAO
from trudex.infrastructure.database.dao.test_attempt import TestAttemptDAO from quizzi.infrastructure.database.dao.test_attempt import TestAttemptDAO
from trudex.infrastructure.database.dao.user import UserDAO from quizzi.infrastructure.database.dao.user import UserDAO
from trudex.infrastructure.database.dao.user_answer import UserAnswerDAO from quizzi.infrastructure.database.dao.user_answer import UserAnswerDAO
from trudex.infrastructure.database.repo.test import TestRepository from quizzi.infrastructure.database.repo.test import TestRepository
from trudex.infrastructure.database.repo.test_attempt import TestAttemptRepository from quizzi.infrastructure.database.repo.test_attempt import TestAttemptRepository
from trudex.infrastructure.database.repo.user import UserRepository from quizzi.infrastructure.database.repo.user import UserRepository
from trudex.infrastructure.scheduling.tasks import deactivate_expired_tests from quizzi.infrastructure.scheduling.tasks import deactivate_expired_tests
from trudex.infrastructure.utils.config import Config from quizzi.infrastructure.utils.config import Config
from trudex.infrastructure.utils.rate_limiter import PasswordRateLimiter from quizzi.infrastructure.utils.rate_limiter import PasswordRateLimiter
class DatabaseProvider(Provider): class DatabaseProvider(Provider):
@@ -2,8 +2,8 @@ import logging
from dishka import AsyncContainer from dishka import AsyncContainer
from trudex.infrastructure.database.dao.test import TestDAO from quizzi.infrastructure.database.dao.test import TestDAO
from trudex.infrastructure.utils.timezone import now_msk_naive from quizzi.infrastructure.utils.timezone import now_msk_naive
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -1,8 +1,8 @@
from aiogram import Bot from aiogram import Bot
from aiogram.types import BotCommand, BotCommandScopeAllPrivateChats, BotCommandScopeChat from aiogram.types import BotCommand, BotCommandScopeAllPrivateChats, BotCommandScopeChat
from trudex.infrastructure.database.repo.user import UserRepository from quizzi.infrastructure.database.repo.user import UserRepository
from trudex.infrastructure.utils.config import Config from quizzi.infrastructure.utils.config import Config
async def setup_bot_commands(bot: Bot, config: Config, user_repo: UserRepository) -> None: async def setup_bot_commands(bot: Bot, config: Config, user_repo: UserRepository) -> None:
@@ -11,7 +11,7 @@ from aiogram.exceptions import (
TelegramRetryAfter, TelegramRetryAfter,
) )
from trudex.infrastructure.database.dao.user import UserDAO from quizzi.infrastructure.database.dao.user import UserDAO
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -1,5 +0,0 @@
from trudex.infrastructure.database.repo.test import TestRepository
from trudex.infrastructure.database.repo.test_attempt import TestAttemptRepository
from trudex.infrastructure.database.repo.user import UserRepository
__all__ = ["TestRepository", "TestAttemptRepository", "UserRepository"]
Generated
+49 -49
View File
@@ -717,6 +717,55 @@ pil = [
{ name = "pillow" }, { name = "pillow" },
] ]
[[package]]
name = "quizzi"
version = "0.1.0"
source = { editable = "." }
dependencies = [
{ name = "aiogram" },
{ name = "aiogram-dialog" },
{ name = "alembic" },
{ name = "apscheduler" },
{ name = "asyncpg" },
{ name = "dishka" },
{ name = "httpx" },
{ name = "json5" },
{ name = "pycryptodome" },
{ name = "pydantic" },
{ name = "qrcode", extra = ["pil"] },
{ name = "sqlalchemy" },
]
[package.dev-dependencies]
dev = [
{ name = "isort" },
{ name = "ruff" },
{ name = "watchfiles" },
]
[package.metadata]
requires-dist = [
{ name = "aiogram", specifier = ">=3.23.0" },
{ name = "aiogram-dialog", specifier = ">=2.4.0" },
{ name = "alembic", specifier = ">=1.17.2" },
{ name = "apscheduler", specifier = ">=3.10.4" },
{ name = "asyncpg", specifier = ">=0.31.0" },
{ name = "dishka", specifier = ">=1.7.2" },
{ name = "httpx", specifier = ">=0.28.1" },
{ name = "json5", specifier = ">=0.13.0" },
{ name = "pycryptodome", specifier = ">=3.23.0" },
{ name = "pydantic", specifier = ">=2.10.5" },
{ name = "qrcode", extras = ["pil"], specifier = ">=8.2" },
{ name = "sqlalchemy", specifier = ">=2.0.45" },
]
[package.metadata.requires-dev]
dev = [
{ name = "isort", specifier = ">=7.0.0" },
{ name = "ruff", specifier = ">=0.14.10" },
{ name = "watchfiles", specifier = ">=1.1.1" },
]
[[package]] [[package]]
name = "ruff" name = "ruff"
version = "0.14.10" version = "0.14.10"
@@ -770,55 +819,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/bf/e1/3ccb13c643399d22289c6a9786c1a91e3dcbb68bce4beb44926ac2c557bf/sqlalchemy-2.0.45-py3-none-any.whl", hash = "sha256:5225a288e4c8cc2308dbdd874edad6e7d0fd38eac1e9e5f23503425c8eee20d0", size = 1936672, upload-time = "2025-12-09T21:54:52.608Z" }, { url = "https://files.pythonhosted.org/packages/bf/e1/3ccb13c643399d22289c6a9786c1a91e3dcbb68bce4beb44926ac2c557bf/sqlalchemy-2.0.45-py3-none-any.whl", hash = "sha256:5225a288e4c8cc2308dbdd874edad6e7d0fd38eac1e9e5f23503425c8eee20d0", size = 1936672, upload-time = "2025-12-09T21:54:52.608Z" },
] ]
[[package]]
name = "trudex"
version = "0.1.0"
source = { editable = "." }
dependencies = [
{ name = "aiogram" },
{ name = "aiogram-dialog" },
{ name = "alembic" },
{ name = "apscheduler" },
{ name = "asyncpg" },
{ name = "dishka" },
{ name = "httpx" },
{ name = "json5" },
{ name = "pycryptodome" },
{ name = "pydantic" },
{ name = "qrcode", extra = ["pil"] },
{ name = "sqlalchemy" },
]
[package.dev-dependencies]
dev = [
{ name = "isort" },
{ name = "ruff" },
{ name = "watchfiles" },
]
[package.metadata]
requires-dist = [
{ name = "aiogram", specifier = ">=3.23.0" },
{ name = "aiogram-dialog", specifier = ">=2.4.0" },
{ name = "alembic", specifier = ">=1.17.2" },
{ name = "apscheduler", specifier = ">=3.10.4" },
{ name = "asyncpg", specifier = ">=0.31.0" },
{ name = "dishka", specifier = ">=1.7.2" },
{ name = "httpx", specifier = ">=0.28.1" },
{ name = "json5", specifier = ">=0.13.0" },
{ name = "pycryptodome", specifier = ">=3.23.0" },
{ name = "pydantic", specifier = ">=2.10.5" },
{ name = "qrcode", extras = ["pil"], specifier = ">=8.2" },
{ name = "sqlalchemy", specifier = ">=2.0.45" },
]
[package.metadata.requires-dev]
dev = [
{ name = "isort", specifier = ">=7.0.0" },
{ name = "ruff", specifier = ">=0.14.10" },
{ name = "watchfiles", specifier = ">=1.1.1" },
]
[[package]] [[package]]
name = "typing-extensions" name = "typing-extensions"
version = "4.15.0" version = "4.15.0"