integrate dialog management with initial "main menu" state and update SRS schema

This commit is contained in:
ruslangilfanov 2025-08-17 00:24:16 +03:00
parent 54155a99c5
commit 40ed52777e
No known key found for this signature in database
8 changed files with 128 additions and 50 deletions

View File

@ -5,6 +5,7 @@ Revises: 747797032526
Create Date: 2025-08-16 19:40:06.376743 Create Date: 2025-08-16 19:40:06.376743
""" """
from typing import Sequence, Union from typing import Sequence, Union
from alembic import op from alembic import op
@ -12,8 +13,8 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision: str = '9a2898513cf2' revision: str = "9a2898513cf2"
down_revision: Union[str, None] = '747797032526' down_revision: Union[str, None] = "747797032526"
branch_labels: Union[str, Sequence[str], None] = None branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None
@ -21,51 +22,91 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
"""Upgrade schema.""" """Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('srs_progress', op.create_table(
sa.Column('id', sa.BigInteger(), nullable=False), "srs_progress",
sa.Column('user_id', sa.BigInteger(), nullable=False), sa.Column("id", sa.BigInteger(), nullable=False),
sa.Column('word_id', sa.BigInteger(), nullable=False), sa.Column("user_id", sa.BigInteger(), nullable=False),
sa.Column('due_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.Column("word_id", sa.BigInteger(), nullable=False),
sa.Column('interval_days', sa.Integer(), nullable=False), sa.Column(
sa.Column('ease', sa.Float(), nullable=False), "due_at",
sa.Column('reps', sa.Integer(), nullable=False), sa.DateTime(timezone=True),
sa.Column('lrn_step', sa.Integer(), nullable=False), server_default=sa.text("now()"),
sa.Column('state', sa.Enum('learning', 'review', 'lapsed', name='reviewstate', native_enum=False), nullable=False), nullable=False,
sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_srs_progress_user_id_users')), ),
sa.ForeignKeyConstraint(['word_id'], ['glossary_word.id'], name=op.f('fk_srs_progress_word_id_glossary_word')), sa.Column("interval_days", sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('id', name=op.f('pk_srs_progress')), sa.Column("ease", sa.Float(), nullable=False),
sa.UniqueConstraint('user_id', 'word_id', name='uq_srs_user_word') sa.Column("reps", sa.Integer(), nullable=False),
sa.Column("lrn_step", sa.Integer(), nullable=False),
sa.Column(
"state",
sa.Enum(
"learning", "review", "lapsed", name="reviewstate", native_enum=False
),
nullable=False,
),
sa.ForeignKeyConstraint(
["user_id"], ["users.id"], name=op.f("fk_srs_progress_user_id_users")
),
sa.ForeignKeyConstraint(
["word_id"],
["glossary_word.id"],
name=op.f("fk_srs_progress_word_id_glossary_word"),
),
sa.PrimaryKeyConstraint("id", name=op.f("pk_srs_progress")),
sa.UniqueConstraint("user_id", "word_id", name="uq_srs_user_word"),
) )
op.create_index(op.f('ix_srs_progress_due_at'), 'srs_progress', ['due_at'], unique=False) op.create_index(
op.create_index(op.f('ix_srs_progress_user_id'), 'srs_progress', ['user_id'], unique=False) op.f("ix_srs_progress_due_at"), "srs_progress", ["due_at"], unique=False
op.create_index(op.f('ix_srs_progress_word_id'), 'srs_progress', ['word_id'], unique=False) )
op.create_table('srs_review_log', op.create_index(
sa.Column('id', sa.BigInteger(), nullable=False), op.f("ix_srs_progress_user_id"), "srs_progress", ["user_id"], unique=False
sa.Column('user_id', sa.BigInteger(), nullable=False), )
sa.Column('word_id', sa.BigInteger(), nullable=False), op.create_index(
sa.Column('ts', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), op.f("ix_srs_progress_word_id"), "srs_progress", ["word_id"], unique=False
sa.Column('grade', sa.Integer(), nullable=False), )
sa.Column('prev_interval', sa.Integer(), nullable=False), op.create_table(
sa.Column('new_interval', sa.Integer(), nullable=False), "srs_review_log",
sa.Column('prev_ease', sa.Float(), nullable=False), sa.Column("id", sa.BigInteger(), nullable=False),
sa.Column('new_ease', sa.Float(), nullable=False), sa.Column("user_id", sa.BigInteger(), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_srs_review_log_user_id_users')), sa.Column("word_id", sa.BigInteger(), nullable=False),
sa.ForeignKeyConstraint(['word_id'], ['glossary_word.id'], name=op.f('fk_srs_review_log_word_id_glossary_word')), sa.Column(
sa.PrimaryKeyConstraint('id', name=op.f('pk_srs_review_log')) "ts",
sa.DateTime(timezone=True),
server_default=sa.text("now()"),
nullable=False,
),
sa.Column("grade", sa.Integer(), nullable=False),
sa.Column("prev_interval", sa.Integer(), nullable=False),
sa.Column("new_interval", sa.Integer(), nullable=False),
sa.Column("prev_ease", sa.Float(), nullable=False),
sa.Column("new_ease", sa.Float(), nullable=False),
sa.ForeignKeyConstraint(
["user_id"], ["users.id"], name=op.f("fk_srs_review_log_user_id_users")
),
sa.ForeignKeyConstraint(
["word_id"],
["glossary_word.id"],
name=op.f("fk_srs_review_log_word_id_glossary_word"),
),
sa.PrimaryKeyConstraint("id", name=op.f("pk_srs_review_log")),
)
op.create_index(
op.f("ix_srs_review_log_user_id"), "srs_review_log", ["user_id"], unique=False
)
op.create_index(
op.f("ix_srs_review_log_word_id"), "srs_review_log", ["word_id"], unique=False
) )
op.create_index(op.f('ix_srs_review_log_user_id'), 'srs_review_log', ['user_id'], unique=False)
op.create_index(op.f('ix_srs_review_log_word_id'), 'srs_review_log', ['word_id'], unique=False)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
"""Downgrade schema.""" """Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_srs_review_log_word_id'), table_name='srs_review_log') op.drop_index(op.f("ix_srs_review_log_word_id"), table_name="srs_review_log")
op.drop_index(op.f('ix_srs_review_log_user_id'), table_name='srs_review_log') op.drop_index(op.f("ix_srs_review_log_user_id"), table_name="srs_review_log")
op.drop_table('srs_review_log') op.drop_table("srs_review_log")
op.drop_index(op.f('ix_srs_progress_word_id'), table_name='srs_progress') op.drop_index(op.f("ix_srs_progress_word_id"), table_name="srs_progress")
op.drop_index(op.f('ix_srs_progress_user_id'), table_name='srs_progress') op.drop_index(op.f("ix_srs_progress_user_id"), table_name="srs_progress")
op.drop_index(op.f('ix_srs_progress_due_at'), table_name='srs_progress') op.drop_index(op.f("ix_srs_progress_due_at"), table_name="srs_progress")
op.drop_table('srs_progress') op.drop_table("srs_progress")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -3,6 +3,7 @@ from aiogram import Bot, Dispatcher, BaseMiddleware
from aiogram.fsm.storage.base import BaseStorage, DefaultKeyBuilder from aiogram.fsm.storage.base import BaseStorage, DefaultKeyBuilder
from aiogram.fsm.storage.redis import RedisStorage from aiogram.fsm.storage.redis import RedisStorage
from aiogram.types import BotCommandScopeAllPrivateChats from aiogram.types import BotCommandScopeAllPrivateChats
from aiogram_dialog import setup_dialogs
from dependency_injector.wiring import Provide, inject from dependency_injector.wiring import Provide, inject
from ..configs.container import ConfigContainer from ..configs.container import ConfigContainer
@ -24,6 +25,7 @@ def create_bot(
async def create_dispatcher() -> Dispatcher: async def create_dispatcher() -> Dispatcher:
from .router import router as root_router from .router import router as root_router
from .dialogs import dialog
fsm_storage = await create_fsm_storage() fsm_storage = await create_fsm_storage()
@ -35,7 +37,10 @@ async def create_dispatcher() -> Dispatcher:
for middleware in middlewares: for middleware in middlewares:
dp.update.middleware(middleware) dp.update.middleware(middleware)
dp.include_routers(root_router) dp.include_routers(dialog, root_router)
setup_dialogs(dp)
return dp return dp

View File

@ -1,10 +1,9 @@
from gettext import gettext
from aiogram import Router from aiogram import Router
from aiogram.enums import ParseMode
from aiogram.filters import CommandStart from aiogram.filters import CommandStart
from aiogram.types import Message from aiogram.types import Message
from aiogram_dialog import DialogManager, StartMode
from greek_lang.tg_bot.dialogs.states import States
from greek_lang.users.manager import get_or_create_telegram_user from greek_lang.users.manager import get_or_create_telegram_user
@ -12,12 +11,9 @@ router = Router()
@router.message(CommandStart()) @router.message(CommandStart())
async def start(message: Message) -> None: async def start(message: Message, dialog_manager: DialogManager) -> None:
user = message.from_user user = message.from_user
if user is None: if user is None:
return return
await get_or_create_telegram_user(user) await get_or_create_telegram_user(user)
await message.answer( await dialog_manager.start(States.main_menu, mode=StartMode.RESET_STACK)
text=gettext("Регистрация прошла.").format(user=user.full_name),
parse_mode=ParseMode.HTML,
)

View File

@ -0,0 +1,8 @@
from aiogram_dialog import Dialog
from .main_menu import windows as main_windows
dialog = Dialog(
main_windows.main_window,
)

View File

@ -0,0 +1,23 @@
from typing import Any
from aiogram.enums import ParseMode
from aiogram_dialog import DialogManager, Window
from aiogram_dialog.widgets.text import Format
from ..states import States
async def main_getter(dialog_manager: DialogManager, **kwargs: Any) -> dict[str, Any]:
return {}
main_window = Window(
Format(
"Выбери действие:",
when=lambda data, widget, dialog_manager: data["dialog_data"].get("action")
is None,
),
state=States.main_menu,
getter=main_getter,
parse_mode=ParseMode.HTML,
)

View File

@ -0,0 +1,5 @@
from aiogram.fsm.state import State, StatesGroup
class States(StatesGroup):
main_menu = State()