From a797f0cf10d09985110bf1eae079ea6b3ed6a796 Mon Sep 17 00:00:00 2001 From: Yuriy Chebyshev Date: Wed, 13 Sep 2023 23:28:18 +0300 Subject: [PATCH] fixed dialog manager usage from out of dialog router --- shvatka/tgbot/dialogs/__init__.py | 9 ++-- shvatka/tgbot/dialogs/starters/__init__.py | 3 +- shvatka/tgbot/dialogs/starters/organizer.py | 56 ++++++++++++++++++++ shvatka/tgbot/handlers/__init__.py | 9 ++-- shvatka/tgbot/handlers/game/add_organizer.py | 6 +-- shvatka/tgbot/handlers/game/organizer.py | 47 +--------------- shvatka/tgbot/handlers/merge.py | 14 ++--- shvatka/tgbot/handlers/player.py | 6 +-- shvatka/tgbot/main_factory.py | 3 +- shvatka/tgbot/middlewares/__init__.py | 3 ++ shvatka/tgbot/middlewares/init_middleware.py | 4 ++ shvatka/tgbot/utils/data.py | 2 + tests/integration/conftest.py | 3 +- 13 files changed, 98 insertions(+), 67 deletions(-) create mode 100644 shvatka/tgbot/dialogs/starters/organizer.py diff --git a/shvatka/tgbot/dialogs/__init__.py b/shvatka/tgbot/dialogs/__init__.py index 07217ddb..9e517dbe 100644 --- a/shvatka/tgbot/dialogs/__init__.py +++ b/shvatka/tgbot/dialogs/__init__.py @@ -1,7 +1,7 @@ from aiogram import Router, F from aiogram.enums import ChatType from aiogram_dialog import setup_dialogs -from aiogram_dialog.api.protocols import MessageManagerProtocol +from aiogram_dialog.api.protocols import MessageManagerProtocol, BgManagerFactory from shvatka.tgbot.dialogs import ( game_orgs, @@ -22,7 +22,7 @@ from shvatka.tgbot.filters import GameStatusFilter -def setup(message_manager: MessageManagerProtocol) -> Router: +def setup(router: Router, message_manager: MessageManagerProtocol) -> BgManagerFactory: dialogs_router = Router(name=__name__) dialogs_router.message.filter(F.chat.type == ChatType.PRIVATE) @@ -30,8 +30,9 @@ def setup(message_manager: MessageManagerProtocol) -> Router: dialogs_router.include_router(setup_all_dialogs()) dialogs_router.include_router(setup_active_game_dialogs()) - setup_dialogs(dialogs_router, message_manager=message_manager) - return dialogs_router + bg_manager = setup_dialogs(dialogs_router, message_manager=message_manager) + router.include_router(dialogs_router) + return bg_manager def setup_all_dialogs() -> Router: diff --git a/shvatka/tgbot/dialogs/starters/__init__.py b/shvatka/tgbot/dialogs/starters/__init__.py index 74d06faa..0ff1c419 100644 --- a/shvatka/tgbot/dialogs/starters/__init__.py +++ b/shvatka/tgbot/dialogs/starters/__init__.py @@ -1,7 +1,7 @@ from aiogram import Router, F from aiogram.enums import ChatType -from . import editor, game_spy, info, manage_team, player, stat, base +from . import editor, game_spy, info, manage_team, player, stat, base, organizer from shvatka.tgbot.filters import GameStatusFilter from shvatka.tgbot.utils.router import disable_router_on_game @@ -19,6 +19,7 @@ def setup() -> Router: common_router.include_router(manage_team.setup()) common_router.include_router(player.setup()) common_router.include_router(stat.setup()) + common_router.include_router(organizer.setup()) game_router = router.include_router(Router(name=__name__ + ".game")) game_router.message.filter(GameStatusFilter(running=True)) diff --git a/shvatka/tgbot/dialogs/starters/organizer.py b/shvatka/tgbot/dialogs/starters/organizer.py new file mode 100644 index 00000000..92c9c2b2 --- /dev/null +++ b/shvatka/tgbot/dialogs/starters/organizer.py @@ -0,0 +1,56 @@ +from aiogram import Router, Bot +from aiogram.types import CallbackQuery +from aiogram_dialog import DialogManager + +from shvatka.core.interfaces.clients.file_storage import FileStorage +from shvatka.core.interfaces.scheduler import LevelTestScheduler +from shvatka.core.models import dto +from shvatka.core.services.level import get_level_by_id_for_org +from shvatka.core.services.level_testing import start_level_test +from shvatka.core.services.organizers import get_org_by_id +from shvatka.core.utils.exceptions import PermissionsError +from shvatka.infrastructure.db.dao.holder import HolderDao +from shvatka.tgbot import keyboards as kb +from shvatka.tgbot import states +from shvatka.tgbot.utils.router import disable_router_on_game +from shvatka.tgbot.views.level_testing import create_level_test_view + + +async def start_test_level( + c: CallbackQuery, + player: dto.Player, + callback_data: kb.LevelTestInviteCD, + dao: HolderDao, + dialog_manager: DialogManager, + scheduler: LevelTestScheduler, + bot: Bot, + file_storage: FileStorage, +): + await c.answer() + org = await get_org_by_id(callback_data.org_id, dao.organizer) + if org.player.id != player.id: + raise PermissionsError( + notify_user="Игрок пытается начать тестирование уровня " + "предназначенное для другого игрока", + player=player, + game=org.game, + alarm=True, + ) + level = await get_level_by_id_for_org(callback_data.level_id, org, dao.level) + suite = dto.LevelTestSuite(tester=org, level=level) + view = create_level_test_view(bot=bot, dao=dao, storage=file_storage) + await dialog_manager.start( + states.LevelTestSG.wait_key, + data={"level_id": callback_data.level_id, "org_id": org.id}, + ) + await start_level_test( + suite=suite, scheduler=scheduler, view=view, dao=dao.level_testing_complex + ) + + +def setup() -> Router: + router = Router(name=__name__) + disable_router_on_game(router) + + router.callback_query.register(start_test_level, kb.LevelTestInviteCD.filter()) + return router diff --git a/shvatka/tgbot/handlers/__init__.py b/shvatka/tgbot/handlers/__init__.py index ae553f3a..3323bed0 100644 --- a/shvatka/tgbot/handlers/__init__.py +++ b/shvatka/tgbot/handlers/__init__.py @@ -1,7 +1,7 @@ import logging from aiogram import Dispatcher -from aiogram_dialog.api.protocols import MessageManagerProtocol +from aiogram_dialog.api.protocols import MessageManagerProtocol, BgManagerFactory from shvatka.tgbot import dialogs from shvatka.tgbot.config.models.bot import BotConfig @@ -14,7 +14,9 @@ logger = logging.getLogger(__name__) -def setup_handlers(dp: Dispatcher, bot_config: BotConfig, message_manager: MessageManagerProtocol): +def setup_handlers( + dp: Dispatcher, bot_config: BotConfig, message_manager: MessageManagerProtocol +) -> BgManagerFactory: errors.setup(dp, bot_config.log_chat) dp.include_router(base.setup()) dp.include_router(superuser.setup(bot_config)) @@ -24,8 +26,9 @@ def setup_handlers(dp: Dispatcher, bot_config: BotConfig, message_manager: Messa dp.include_router(game.setup()) dp.include_router(waivers.setup()) - dp.include_router(dialogs.setup(message_manager)) + bg_manager_factory = dialogs.setup(dp, message_manager) # always must be last registered dp.include_router(last.setup()) logger.debug("handlers configured successfully") + return bg_manager_factory diff --git a/shvatka/tgbot/handlers/game/add_organizer.py b/shvatka/tgbot/handlers/game/add_organizer.py index 65421c4b..320cdd48 100644 --- a/shvatka/tgbot/handlers/game/add_organizer.py +++ b/shvatka/tgbot/handlers/game/add_organizer.py @@ -8,7 +8,7 @@ CallbackQuery, ) from aiogram.utils.text_decorations import html_decoration as hd -from aiogram_dialog import DialogManager +from aiogram_dialog.api.protocols import BgManagerFactory from shvatka.core.models import dto from shvatka.core.services.game import get_game @@ -74,7 +74,7 @@ async def agree_to_be_org_handler( player: dto.Player, dao: HolderDao, bot: Bot, - dialog_manager: DialogManager, + bg_manager_factory: BgManagerFactory, ): await c.answer() await agree_to_be_org( @@ -89,7 +89,7 @@ async def agree_to_be_org_handler( inline_message_id=c.inline_message_id, ) primary_chat_id = player.get_chat_id() - bg = dialog_manager.bg(user_id=primary_chat_id, chat_id=primary_chat_id) + bg = bg_manager_factory.bg(bot=bot, user_id=primary_chat_id, chat_id=primary_chat_id) await bg.update({}) diff --git a/shvatka/tgbot/handlers/game/organizer.py b/shvatka/tgbot/handlers/game/organizer.py index 704f87bc..6f867906 100644 --- a/shvatka/tgbot/handlers/game/organizer.py +++ b/shvatka/tgbot/handlers/game/organizer.py @@ -1,57 +1,15 @@ import asyncio -from aiogram import Router, Bot +from aiogram import Router from aiogram.filters import CommandObject, Command -from aiogram.types import CallbackQuery, Message -from aiogram_dialog import DialogManager +from aiogram.types import Message -from shvatka.core.interfaces.clients.file_storage import FileStorage -from shvatka.core.interfaces.scheduler import LevelTestScheduler from shvatka.core.models import dto from shvatka.core.services.game import get_full_game -from shvatka.core.services.level import get_level_by_id_for_org -from shvatka.core.services.level_testing import start_level_test -from shvatka.core.services.organizers import get_org_by_id -from shvatka.core.utils.exceptions import PermissionsError from shvatka.infrastructure.db.dao.holder import HolderDao -from shvatka.tgbot import keyboards as kb -from shvatka.tgbot import states from shvatka.tgbot.dialogs.game_manage.handlers import upload_wrapper from shvatka.tgbot.utils.router import disable_router_on_game from shvatka.tgbot.views.commands import PUBLISH_COMMAND -from shvatka.tgbot.views.level_testing import create_level_test_view - - -async def start_test_level( - c: CallbackQuery, - player: dto.Player, - callback_data: kb.LevelTestInviteCD, - dao: HolderDao, - dialog_manager: DialogManager, - scheduler: LevelTestScheduler, - bot: Bot, - file_storage: FileStorage, -): - await c.answer() - org = await get_org_by_id(callback_data.org_id, dao.organizer) - if org.player.id != player.id: - raise PermissionsError( - notify_user="Игрок пытается начать тестирование уровня " - "предназначенное для другого игрока", - player=player, - game=org.game, - alarm=True, - ) - level = await get_level_by_id_for_org(callback_data.level_id, org, dao.level) - suite = dto.LevelTestSuite(tester=org, level=level) - view = create_level_test_view(bot=bot, dao=dao, storage=file_storage) - await dialog_manager.start( - states.LevelTestSG.wait_key, - data={"level_id": callback_data.level_id, "org_id": org.id}, - ) - await start_level_test( - suite=suite, scheduler=scheduler, view=view, dao=dao.level_testing_complex - ) async def publish_game_forum( @@ -68,6 +26,5 @@ def setup() -> Router: router = Router(name=__name__) disable_router_on_game(router) - router.callback_query.register(start_test_level, kb.LevelTestInviteCD.filter()) router.message.register(publish_game_forum, Command(PUBLISH_COMMAND)) return router diff --git a/shvatka/tgbot/handlers/merge.py b/shvatka/tgbot/handlers/merge.py index b80278d1..ae977aa2 100644 --- a/shvatka/tgbot/handlers/merge.py +++ b/shvatka/tgbot/handlers/merge.py @@ -1,8 +1,8 @@ from functools import partial -from aiogram import Router +from aiogram import Router, Bot from aiogram.types import CallbackQuery -from aiogram_dialog import DialogManager +from aiogram_dialog.api.protocols import BgManagerFactory from shvatka.core.services.player import get_player_by_id, merge_players from shvatka.core.services.team import get_team_by_id, merge_teams @@ -23,7 +23,8 @@ async def confirm_merge_team( callback_data: kb.TeamMergeCD, dao: HolderDao, game_log: GameLogWriter, - dialog_manager: DialogManager, + bg_manager_factory: BgManagerFactory, + bot: Bot, ): primary = await get_team_by_id(callback_data.primary_team_id, dao.team) assert primary.captain @@ -33,7 +34,7 @@ async def confirm_merge_team( assert callback_query.message await callback_query.message.edit_reply_markup(reply_markup=None) captain_chat_id = primary.captain.get_chat_id() - bg = dialog_manager.bg(user_id=captain_chat_id, chat_id=captain_chat_id) + bg = bg_manager_factory.bg(bot=bot, user_id=captain_chat_id, chat_id=captain_chat_id) await bg.update({}) @@ -42,7 +43,8 @@ async def confirm_merge_players( callback_data: kb.PlayerMergeCD, dao: HolderDao, game_log: GameLogWriter, - dialog_manager: DialogManager, + bg_manager_factory: BgManagerFactory, + bot: Bot, ): primary = await get_player_by_id(callback_data.primary_player_id, dao.player) secondary = await get_player_by_id(callback_data.secondary_player_id, dao.player) @@ -51,7 +53,7 @@ async def confirm_merge_players( assert callback_query.message await callback_query.message.edit_reply_markup(reply_markup=None) primary_chat_id = primary.get_chat_id() - bg = dialog_manager.bg(user_id=primary_chat_id, chat_id=primary_chat_id) + bg = bg_manager_factory.bg(bot=bot, user_id=primary_chat_id, chat_id=primary_chat_id) await bg.update({}) diff --git a/shvatka/tgbot/handlers/player.py b/shvatka/tgbot/handlers/player.py index 174de5aa..341b8d50 100644 --- a/shvatka/tgbot/handlers/player.py +++ b/shvatka/tgbot/handlers/player.py @@ -11,7 +11,7 @@ CallbackQuery, ) from aiogram.utils.text_decorations import html_decoration as hd -from aiogram_dialog import DialogManager +from aiogram_dialog.api.protocols import BgManagerFactory from shvatka.core.models import dto from shvatka.core.services.player import ( @@ -84,7 +84,7 @@ async def agree_promotion_handler( player: dto.Player, dao: HolderDao, bot: Bot, - dialog_manager: DialogManager, + bg_manager_factory: BgManagerFactory, ): await c.answer() try: @@ -108,7 +108,7 @@ async def agree_promotion_handler( inline_message_id=c.inline_message_id, ) primary_chat_id = player.get_chat_id() - bg = dialog_manager.bg(user_id=primary_chat_id, chat_id=primary_chat_id) + bg = bg_manager_factory.bg(bot=bot, user_id=primary_chat_id, chat_id=primary_chat_id) await bg.update({}) diff --git a/shvatka/tgbot/main_factory.py b/shvatka/tgbot/main_factory.py index 9b364fb2..17e79c76 100644 --- a/shvatka/tgbot/main_factory.py +++ b/shvatka/tgbot/main_factory.py @@ -49,6 +49,7 @@ def create_dispatcher( message_manager: MessageManager, ) -> Dispatcher: dp = create_only_dispatcher(config, redis) + bg_manager_factory = setup_handlers(dp, config.bot, message_manager) setup_middlewares( dp=dp, pool=pool, @@ -61,8 +62,8 @@ def create_dispatcher( file_storage=file_storage, level_test_dao=level_test_dao, telegraph=telegraph, + bg_manager_factory=bg_manager_factory, ) - setup_handlers(dp, config.bot, message_manager) return dp diff --git a/shvatka/tgbot/middlewares/__init__.py b/shvatka/tgbot/middlewares/__init__.py index 9c131c97..2e7c5fec 100644 --- a/shvatka/tgbot/middlewares/__init__.py +++ b/shvatka/tgbot/middlewares/__init__.py @@ -1,4 +1,5 @@ from aiogram import Dispatcher +from aiogram_dialog.api.protocols import BgManagerFactory from dataclass_factory import Factory from redis.asyncio.client import Redis from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession @@ -29,6 +30,7 @@ def setup_middlewares( file_storage: FileStorage, level_test_dao: LevelTestingData, telegraph: Telegraph, + bg_manager_factory: BgManagerFactory, ): dp.update.middleware(ConfigMiddleware(bot_config)) dp.update.middleware( @@ -42,6 +44,7 @@ def setup_middlewares( file_storage=file_storage, level_test_dao=level_test_dao, telegraph=telegraph, + bg_manager_factory=bg_manager_factory, ) ) dp.update.middleware(LoadDataMiddleware()) diff --git a/shvatka/tgbot/middlewares/init_middleware.py b/shvatka/tgbot/middlewares/init_middleware.py index 55cad96d..7c4341da 100644 --- a/shvatka/tgbot/middlewares/init_middleware.py +++ b/shvatka/tgbot/middlewares/init_middleware.py @@ -2,6 +2,7 @@ from aiogram import BaseMiddleware from aiogram.types import TelegramObject +from aiogram_dialog.api.protocols import BgManagerFactory from dataclass_factory import Factory from redis.asyncio.client import Redis from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession @@ -32,6 +33,7 @@ def __init__( file_storage: FileStorage, level_test_dao: LevelTestingData, telegraph: Telegraph, + bg_manager_factory: BgManagerFactory, ) -> None: self.pool = pool self.user_getter = user_getter @@ -42,6 +44,7 @@ def __init__( self.file_storage = file_storage self.level_test_dao = level_test_dao self.telegraph = telegraph + self.bg_manager_factory = bg_manager_factory async def __call__( # type: ignore[override] self, @@ -55,6 +58,7 @@ async def __call__( # type: ignore[override] data["locker"] = self.locker data["file_storage"] = self.file_storage data["telegraph"] = self.telegraph + data["bg_manager_factory"] = self.bg_manager_factory data["game_log"] = GameBotLog(bot=data["bot"], log_chat_id=data["config"].game_log_chat) async with self.pool() as session: holder_dao = HolderDao(session, self.redis, self.level_test_dao) diff --git a/shvatka/tgbot/utils/data.py b/shvatka/tgbot/utils/data.py index 73ca898f..42129683 100644 --- a/shvatka/tgbot/utils/data.py +++ b/shvatka/tgbot/utils/data.py @@ -6,6 +6,7 @@ from aiogram.fsm.storage.base import BaseStorage from aiogram_dialog import DialogManager from aiogram_dialog.api.entities import Stack, Context +from aiogram_dialog.api.protocols import BgManagerFactory from aiogram_dialog.context.storage import StorageProxy from dataclass_factory import Factory from telegraph.aio import Telegraph @@ -60,3 +61,4 @@ class MiddlewareData(DialogMiddlewareData, total=False): team_player: dto.FullTeamPlayer | None results_painter: ResultsPainter game_log: GameLogWriter + bg_manager_factory: BgManagerFactory diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index fb13cf08..55f7c967 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -181,6 +181,7 @@ def dp( message_manager: MockMessageManager, ) -> Dispatcher: dp = create_only_dispatcher(bot_config, redis) + bg_factory = setup_handlers(dp, bot_config.bot, message_manager=message_manager) setup_middlewares( dp=dp, pool=pool, @@ -193,8 +194,8 @@ def dp( file_storage=file_storage, level_test_dao=level_test_dao, telegraph=telegraph, + bg_manager_factory=bg_factory, ) - setup_handlers(dp, bot_config.bot, message_manager=message_manager) return dp