Skip to content

Commit 30ba3e8

Browse files
committed
refactor: dialog_extensions and handles
1 parent d659d3f commit 30ba3e8

File tree

20 files changed

+254
-240
lines changed

20 files changed

+254
-240
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from src.bot.dialog_extension.extended_dialog_manager import ExtendedDialogManager, extend_dialog
2+
3+
__all__ = ["extend_dialog", "ExtendedDialogManager"]
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
from typing import Any
2+
3+
from aiogram.fsm.state import State
4+
from aiogram_dialog import DialogManager, ShowMode
5+
from aiogram_dialog.api.entities import AccessSettings, ChatEvent, Context, Stack, StartMode
6+
from aiogram_dialog.api.protocols.manager import BaseDialogManager, UnsetId
7+
8+
9+
class DialogManagerWrapper(DialogManager):
10+
original: DialogManager
11+
12+
def __init__(self, dialog_manager: DialogManager):
13+
self.original = dialog_manager
14+
15+
async def done(self, result: Any = None, show_mode: ShowMode | None = None) -> None:
16+
return await self.original.done(result, show_mode)
17+
18+
async def start(
19+
self,
20+
state: State,
21+
data: dict | list | int | str | float | None = None,
22+
mode: StartMode = StartMode.NORMAL,
23+
show_mode: ShowMode | None = None,
24+
access_settings: AccessSettings | None = None,
25+
) -> None:
26+
return await self.original.start(state, data, mode, show_mode, access_settings)
27+
28+
async def switch_to(self, state: State, show_mode: ShowMode | None = None) -> None:
29+
return await self.original.switch_to(state, show_mode)
30+
31+
async def update(self, data: dict, show_mode: ShowMode | None = None) -> None:
32+
return await self.original.update(data, show_mode)
33+
34+
def bg(
35+
self,
36+
user_id: int | None = None,
37+
chat_id: int | None = None,
38+
stack_id: str | None = None,
39+
thread_id: int | None | UnsetId = UnsetId.UNSET,
40+
business_connection_id: str | None | UnsetId = UnsetId.UNSET,
41+
load: bool = False,
42+
) -> BaseDialogManager:
43+
return self.original.bg(user_id, chat_id, stack_id, thread_id, business_connection_id, load)
44+
45+
@property
46+
def event(self) -> ChatEvent:
47+
return self.original.event
48+
49+
async def mark_closed(self) -> None:
50+
return await self.original.mark_closed()
51+
52+
@property
53+
def middleware_data(self) -> dict:
54+
return self.original.middleware_data
55+
56+
@property
57+
def dialog_data(self) -> dict:
58+
return self.original.dialog_data
59+
60+
@property
61+
def start_data(self) -> dict | list | int | str | float | None:
62+
return self.original.start_data
63+
64+
@property
65+
def show_mode(self) -> ShowMode:
66+
return self.original.show_mode
67+
68+
@show_mode.setter
69+
def show_mode(self, show_mode: ShowMode) -> None:
70+
self.original.show_mode = show_mode
71+
72+
def is_preview(self) -> bool:
73+
return self.original.is_preview()
74+
75+
async def show(self, show_mode: ShowMode | None = None) -> None:
76+
return await self.original.show(show_mode)
77+
78+
async def answer_callback(self) -> None:
79+
return await self.original.answer_callback()
80+
81+
def current_context(self) -> Context:
82+
return self.original.current_context()
83+
84+
def has_context(self) -> bool:
85+
return self.original.has_context()
86+
87+
def current_stack(self) -> Stack:
88+
return self.original.current_stack()
89+
90+
async def next(self, show_mode: ShowMode | None = None) -> None:
91+
return await self.original.next(show_mode)
92+
93+
async def back(self, show_mode: ShowMode | None = None) -> None:
94+
return await self.original.back(show_mode)
95+
96+
def find(self, widget_id) -> Any | None:
97+
return self.original.find(widget_id)
98+
99+
async def reset_stack(self, remove_keyboard: bool = True) -> None:
100+
return await self.original.reset_stack(remove_keyboard)
101+
102+
async def load_data(self) -> dict:
103+
return await self.original.load_data()
104+
105+
async def close_manager(self) -> None:
106+
return await self.original.close_manager()
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from aiogram import Bot
2+
from aiogram.types import Chat, Message
3+
from aiogram_dialog import DialogManager, ShowMode
4+
5+
from src.bot.dto import *
6+
7+
from .dialog_wrapper import DialogManagerWrapper
8+
from .extended_fsm_context import ExtendedFSMContext, extend_fsm_context
9+
10+
11+
class ExtendedDialogManager(DialogManagerWrapper):
12+
@property
13+
def state(self) -> ExtendedFSMContext:
14+
return extend_fsm_context(self.middleware_data["state"])
15+
16+
@property
17+
def bot(self) -> Bot:
18+
return self.middleware_data["bot"]
19+
20+
@property
21+
def chat(self) -> Chat:
22+
return self.middleware_data["event_chat"]
23+
24+
async def track_message(self, message: Message):
25+
"""Track messages to delete later ("to_delete_list" in state)"""
26+
await self.state.add_to_delete(message)
27+
28+
async def clear_messages(self):
29+
"""Delete tracked messages ("to_delete_id" in state)"""
30+
to_delete_list = await self.state.get_to_delete_list()
31+
print("TRYING TO CLEAR:", to_delete_list)
32+
try:
33+
await self.bot.delete_messages(self.chat.id, to_delete_list)
34+
except Exception as e:
35+
return print(f"clear_messages could not delete {len(to_delete_list)} messages, {e}")
36+
await self.state.set_to_delete_list([])
37+
38+
async def switch_to_current(self, show_mode: ShowMode):
39+
return await self.switch_to(self.current_context().state, show_mode=ShowMode.DELETE_AND_SEND)
40+
41+
async def answer_and_track(self, text: str, **kwargs):
42+
to_delete = await self.bot.send_message(chat_id=self.chat.id, text=text, **kwargs)
43+
await self.track_message(to_delete)
44+
45+
async def answer_and_retry(self, text: str, **kwargs):
46+
to_delete = await self.bot.send_message(chat_id=self.chat.id, text=text, **kwargs)
47+
await self.track_message(to_delete)
48+
await self.switch_to_current(ShowMode.DELETE_AND_SEND)
49+
50+
51+
def extend_dialog(dialog_manager: DialogManager) -> ExtendedDialogManager:
52+
if not isinstance(dialog_manager, ExtendedDialogManager):
53+
dialog_manager = ExtendedDialogManager(dialog_manager)
54+
return dialog_manager

src/bot/extended_fsm_context.py renamed to src/bot/dialog_extension/extended_fsm_context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ async def add_to_delete(self, message: Message):
5656
await self.set_to_delete_list(to_delete_list)
5757

5858

59-
def extend(fsm_context: FSMContext) -> ExtendedFSMContext:
59+
def extend_fsm_context(fsm_context: FSMContext) -> ExtendedFSMContext:
6060
if not isinstance(fsm_context, ExtendedFSMContext):
6161
fsm_context = ExtendedFSMContext.wrap(fsm_context)
6262
return fsm_context

src/bot/dialogs/attendance/handles.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
from aiogram_dialog import DialogManager, ShowMode
33
from aiogram_dialog.widgets.input import MessageInput
44

5+
from src.bot.dialog_extension import extend_dialog
56
from src.bot.dto import *
6-
from src.bot.extended_dialog_manager import extend
77
from src.bot.user_errors import *
88
from src.bot.utils import *
99
from src.db.repositories import meetings_repo
@@ -14,8 +14,8 @@
1414

1515

1616
async def get_attendance_file_close(message: Message, _: MessageInput, manager: DialogManager):
17-
manager = extend(manager)
18-
await clear_messages(manager)
17+
manager = extend_dialog(manager)
18+
await manager.clear_messages()
1919
await message.delete()
2020
try:
2121
contents = await get_document_contents(message, manager)
@@ -33,8 +33,8 @@ async def get_attendance_file_close(message: Message, _: MessageInput, manager:
3333

3434

3535
async def get_attendance_file_resend(message: Message, _: MessageInput, manager: DialogManager):
36-
manager = extend(manager)
37-
await clear_messages(manager)
36+
manager = extend_dialog(manager)
37+
await manager.clear_messages()
3838
await message.delete()
3939
try:
4040
contents = await get_document_contents(message, manager)
@@ -52,7 +52,7 @@ async def get_attendance_file_resend(message: Message, _: MessageInput, manager:
5252

5353

5454
async def on_download_attendance(query: CallbackQuery, button: Button, manager: DialogManager):
55-
manager = extend(manager)
55+
manager = extend_dialog(manager)
5656
try:
5757
input_file = await get_attendance_file_to_download(manager)
5858
await query.answer("Sending attendance file...")
@@ -65,15 +65,14 @@ async def on_download_attendance(query: CallbackQuery, button: Button, manager:
6565

6666

6767
async def get_email_to_add(message: Message, _: MessageInput, manager: DialogManager):
68-
manager = extend(manager)
69-
await clear_messages(manager)
68+
manager = extend_dialog(manager)
69+
await manager.clear_messages()
7070
await message.delete()
7171
try:
7272
email = await extract_email(message)
73+
await add_email_to_attendance(email, manager)
7374
except NoMessageText:
7475
return await manager.answer_and_retry("There's no text in your message, enter email of a person to add")
75-
try:
76-
await add_email_to_attendance(email, manager)
7776
except NoMeetingAttendance:
7877
return await manager.answer_and_retry("Somehow there is no attendance for this meeting, resend the file maybe")
7978
except EmailAlreadyPresent:

src/bot/dialogs/attendance/logic.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from aiogram.types import BufferedInputFile, InputFile
1+
from aiogram.types import BufferedInputFile, InputFile, Message
22
from aiogram_dialog import DialogManager
33

4-
from src.bot.extended_dialog_manager import extend
4+
from src.bot.dialog_extension import extend_dialog
55
from src.bot.scheduling import *
66
from src.bot.user_errors import *
77
from src.bot.utils import *
@@ -11,7 +11,7 @@
1111

1212

1313
async def get_document_contents(message: Message, manager: DialogManager) -> str:
14-
manager = extend(manager)
14+
manager = extend_dialog(manager)
1515
if not message.document:
1616
raise NoDocumentError()
1717
file = await manager.bot.get_file(message.document.file_id)
@@ -28,7 +28,7 @@ async def get_document_contents(message: Message, manager: DialogManager) -> str
2828

2929

3030
async def get_attendance_file_to_download(manager: DialogManager) -> InputFile:
31-
manager = extend(manager)
31+
manager = extend_dialog(manager)
3232
meeting = await manager.state.get_meeting()
3333
if not meeting.attendance:
3434
raise NoMeetingAttendance()
@@ -47,7 +47,7 @@ async def extract_email(message: Message) -> Email:
4747

4848

4949
async def add_email_to_attendance(email: Email, manager: DialogManager):
50-
manager = extend(manager)
50+
manager = extend_dialog(manager)
5151
async with manager.state.sync_meeting() as meeting:
5252
if not meeting.attendance:
5353
raise NoMeetingAttendance()

src/bot/dialogs/attendance/windows.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
resend_ww = Window(
3333
Format('Resend attendance file for "{title}"'),
3434
Row(
35-
SwitchTo(Const("Back"), state=AttendanceStates.init, id="to_attendance_init"),
35+
SwitchTo(Const("Back"), state=AttendanceStates.init, id="to_attendance_init", on_click=handle_clear),
3636
Button(Const(" "), id="blank", on_click=None),
3737
),
3838
MessageInput(get_attendance_file_resend),
@@ -42,7 +42,7 @@
4242

4343
close_ww = Window(
4444
Format('Send attendance file to close "{title}"'),
45-
Row(Cancel(Const("Back")), Button(Const(" "), id="blank", on_click=None)),
45+
Row(Cancel(Const("Back"), on_click=handle_clear), Button(Const(" "), id="blank", on_click=None)),
4646
MessageInput(get_attendance_file_close),
4747
getter=meeting_info_getter,
4848
state=AttendanceStates.close,
@@ -51,7 +51,7 @@
5151
add_email_ww = Window(
5252
Format("Enter email of a person to add 👤"),
5353
Row(
54-
SwitchTo(Const("Back"), state=AttendanceStates.init, id="to_attendance_init"),
54+
SwitchTo(Const("Back"), state=AttendanceStates.init, id="to_attendance_init", on_click=handle_clear),
5555
Button(Const(" "), id="blank", on_click=None),
5656
),
5757
MessageInput(get_email_to_add),

src/bot/dialogs/change_meeting/dialog_buttons.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
BTN_BLANK = Button(Const(" "), id="blank")
1010
BTN_ROW_BACK = Row(Back(), BTN_BLANK)
1111

12-
BTN_INIT = SwitchTo(Const("Back"), id="to_init", state=ChangeStates.init)
12+
BTN_INIT = SwitchTo(Const("Back"), id="to_init", state=ChangeStates.init, on_click=handle_clear)
1313

1414

1515
TUTORS_ASSIGN_SCROLLING_GROUP = ScrollingGroup(

src/bot/dialogs/change_meeting/getters.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from aiogram_dialog import DialogManager
22

3+
from src.bot.dialog_extension import extend_dialog
34
from src.bot.dialogs.meetings.getters import meeting_info_getter
45
from src.bot.dto import *
56
from src.bot.filters import *
@@ -8,14 +9,9 @@
89

910

1011
async def meeting_info_with_tutors_getter(dialog_manager: DialogManager, **kwargs):
11-
state = get_state(dialog_manager)
12-
meeting = dto_to_meeting(await state.get_value("meeting"))
13-
14-
if not meeting:
15-
raise ValueError("No Meeting in meeting_info_getter")
16-
12+
manager = extend_dialog(dialog_manager)
13+
meeting = await manager.state.get_meeting()
1714
tutors = await tutors_repo.list()
18-
1915
return {
2016
"title": meeting.title,
2117
"description": meeting.description,

0 commit comments

Comments
 (0)