bot-framework 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bot_framework/__init__.py +57 -0
- bot_framework/base_protocols/__init__.py +21 -0
- bot_framework/base_protocols/create.py +9 -0
- bot_framework/base_protocols/delete.py +9 -0
- bot_framework/base_protocols/get_all.py +9 -0
- bot_framework/base_protocols/get_by_key.py +9 -0
- bot_framework/base_protocols/get_by_name.py +9 -0
- bot_framework/base_protocols/read.py +11 -0
- bot_framework/base_protocols/read_sequence_by_user_id.py +11 -0
- bot_framework/base_protocols/update.py +9 -0
- bot_framework/entities/__init__.py +24 -0
- bot_framework/entities/bot_callback.py +21 -0
- bot_framework/entities/bot_message.py +27 -0
- bot_framework/entities/bot_user.py +22 -0
- bot_framework/entities/button.py +8 -0
- bot_framework/entities/keyboard.py +9 -0
- bot_framework/entities/language_code.py +8 -0
- bot_framework/entities/parse_mode.py +6 -0
- bot_framework/entities/role.py +16 -0
- bot_framework/entities/role_name.py +7 -0
- bot_framework/entities/user.py +23 -0
- bot_framework/flow_management/__init__.py +31 -0
- bot_framework/flow_management/entities/__init__.py +5 -0
- bot_framework/flow_management/entities/flow_stack_entry.py +10 -0
- bot_framework/flow_management/flow_registry.py +14 -0
- bot_framework/flow_management/protocols/__init__.py +11 -0
- bot_framework/flow_management/protocols/i_flow_message_deleter.py +8 -0
- bot_framework/flow_management/protocols/i_flow_message_storage.py +12 -0
- bot_framework/flow_management/protocols/i_flow_stack_storage.py +14 -0
- bot_framework/flow_management/protocols/i_flow_stack_validator.py +6 -0
- bot_framework/flow_management/repos/__init__.py +8 -0
- bot_framework/flow_management/repos/redis_flow_message_storage.py +35 -0
- bot_framework/flow_management/repos/redis_flow_stack_storage.py +53 -0
- bot_framework/flow_management/services/__init__.py +15 -0
- bot_framework/flow_management/services/flow_message_deleter.py +33 -0
- bot_framework/flow_management/services/flow_stack_navigator.py +104 -0
- bot_framework/flow_management/services/flow_stack_validator.py +46 -0
- bot_framework/flows/__init__.py +11 -0
- bot_framework/flows/request_role_flow/__init__.py +11 -0
- bot_framework/flows/request_role_flow/actions/__init__.py +13 -0
- bot_framework/flows/request_role_flow/actions/role_assigner.py +30 -0
- bot_framework/flows/request_role_flow/actions/role_rejection_notifier.py +24 -0
- bot_framework/flows/request_role_flow/actions/role_request_sender.py +74 -0
- bot_framework/flows/request_role_flow/entities/__init__.py +7 -0
- bot_framework/flows/request_role_flow/entities/request_role_flow_state.py +6 -0
- bot_framework/flows/request_role_flow/exceptions.py +6 -0
- bot_framework/flows/request_role_flow/factory.py +146 -0
- bot_framework/flows/request_role_flow/handlers/__init__.py +23 -0
- bot_framework/flows/request_role_flow/handlers/approve_role_handler.py +48 -0
- bot_framework/flows/request_role_flow/handlers/reject_role_handler.py +46 -0
- bot_framework/flows/request_role_flow/handlers/request_role_command_handler.py +24 -0
- bot_framework/flows/request_role_flow/handlers/role_selection_handler.py +76 -0
- bot_framework/flows/request_role_flow/handlers/show_roles_handler.py +30 -0
- bot_framework/flows/request_role_flow/presenters/__init__.py +7 -0
- bot_framework/flows/request_role_flow/presenters/role_list_presenter.py +53 -0
- bot_framework/flows/request_role_flow/protocols/__init__.py +27 -0
- bot_framework/flows/request_role_flow/protocols/i_request_role_flow_router.py +7 -0
- bot_framework/flows/request_role_flow/protocols/i_request_role_flow_state_storage.py +11 -0
- bot_framework/flows/request_role_flow/protocols/i_role_assigner.py +10 -0
- bot_framework/flows/request_role_flow/protocols/i_role_list_presenter.py +5 -0
- bot_framework/flows/request_role_flow/protocols/i_role_rejection_notifier.py +9 -0
- bot_framework/flows/request_role_flow/protocols/i_role_request_sender.py +12 -0
- bot_framework/flows/request_role_flow/repos/__init__.py +7 -0
- bot_framework/flows/request_role_flow/repos/redis_request_role_flow_state_storage.py +33 -0
- bot_framework/flows/request_role_flow/request_role_flow_router.py +18 -0
- bot_framework/language_management/__init__.py +13 -0
- bot_framework/language_management/entities/__init__.py +10 -0
- bot_framework/language_management/entities/language.py +15 -0
- bot_framework/language_management/entities/phrase.py +16 -0
- bot_framework/language_management/repos/__init__.py +7 -0
- bot_framework/language_management/repos/language_repo.py +67 -0
- bot_framework/language_management/repos/phrase_repo.py +31 -0
- bot_framework/language_management/repos/protocols/__init__.py +7 -0
- bot_framework/language_management/repos/protocols/i_language_repo.py +10 -0
- bot_framework/language_management/repos/protocols/i_phrase_repo.py +9 -0
- bot_framework/protocols/__init__.py +37 -0
- bot_framework/protocols/i_callback_answerer.py +10 -0
- bot_framework/protocols/i_callback_handler.py +16 -0
- bot_framework/protocols/i_callback_handler_registry.py +9 -0
- bot_framework/protocols/i_card_field_formatter.py +7 -0
- bot_framework/protocols/i_display_width_calculator.py +5 -0
- bot_framework/protocols/i_ensure_user_exists.py +7 -0
- bot_framework/protocols/i_flow_router.py +19 -0
- bot_framework/protocols/i_markdown_to_html_converter.py +5 -0
- bot_framework/protocols/i_message_deleter.py +5 -0
- bot_framework/protocols/i_message_handler.py +16 -0
- bot_framework/protocols/i_message_handler_registry.py +14 -0
- bot_framework/protocols/i_message_replacer.py +17 -0
- bot_framework/protocols/i_message_sender.py +31 -0
- bot_framework/protocols/i_message_service.py +16 -0
- bot_framework/protocols/i_next_step_handler_registrar.py +12 -0
- bot_framework/protocols/i_notify_replacer.py +17 -0
- bot_framework/protocols/i_remaining_time_formatter.py +6 -0
- bot_framework/role_management/__init__.py +13 -0
- bot_framework/role_management/entities/__init__.py +10 -0
- bot_framework/role_management/entities/user_role.py +13 -0
- bot_framework/role_management/repos/__init__.py +5 -0
- bot_framework/role_management/repos/protocols/__init__.py +7 -0
- bot_framework/role_management/repos/protocols/i_role_repo.py +30 -0
- bot_framework/role_management/repos/protocols/i_user_repo.py +24 -0
- bot_framework/role_management/repos/role_repo.py +103 -0
- bot_framework/role_management/services/__init__.py +1 -0
- bot_framework/role_management/services/protocols/__init__.py +1 -0
- bot_framework/services/__init__.py +9 -0
- bot_framework/services/card_field_formatter.py +43 -0
- bot_framework/services/display_width_calculator.py +45 -0
- bot_framework/services/remaining_time_formatter.py +31 -0
- bot_framework/telegram/__init__.py +56 -0
- bot_framework/telegram/middleware/__init__.py +4 -0
- bot_framework/telegram/middleware/ensure_user_middleware.py +46 -0
- bot_framework/telegram/middleware/i_middleware.py +7 -0
- bot_framework/telegram/protocols/__init__.py +36 -0
- bot_framework/telegram/protocols/i_markdown_escaper.py +5 -0
- bot_framework/telegram/services/__init__.py +29 -0
- bot_framework/telegram/services/callback_answerer.py +16 -0
- bot_framework/telegram/services/callback_handler_registry.py +43 -0
- bot_framework/telegram/services/close_callback_handler.py +25 -0
- bot_framework/telegram/services/ensure_user_exists.py +37 -0
- bot_framework/telegram/services/markdown_escaper.py +8 -0
- bot_framework/telegram/services/markdown_to_html_converter.py +16 -0
- bot_framework/telegram/services/message_handler_registry.py +49 -0
- bot_framework/telegram/services/next_step_handler_registrar.py +43 -0
- bot_framework/telegram/services/telegram_message_core.py +62 -0
- bot_framework/telegram/services/telegram_message_deleter.py +19 -0
- bot_framework/telegram/services/telegram_message_replacer.py +47 -0
- bot_framework/telegram/services/telegram_message_sender.py +73 -0
- bot_framework/telegram/services/telegram_notify_replacer.py +30 -0
- bot_framework-0.1.3.dist-info/METADATA +71 -0
- bot_framework-0.1.3.dist-info/RECORD +130 -0
- bot_framework-0.1.3.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Bot Framework - A reusable Python library for building Telegram bots.
|
|
3
|
+
|
|
4
|
+
This package provides core components for building Telegram bots with
|
|
5
|
+
Clean Architecture principles.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from bot_framework.entities.bot_callback import BotCallback
|
|
9
|
+
from bot_framework.entities.bot_message import BotMessage, BotMessageUser
|
|
10
|
+
from bot_framework.entities.bot_user import BotUser
|
|
11
|
+
from bot_framework.entities.button import Button
|
|
12
|
+
from bot_framework.entities.keyboard import Keyboard
|
|
13
|
+
from bot_framework.entities.language_code import LanguageCode
|
|
14
|
+
from bot_framework.entities.parse_mode import ParseMode
|
|
15
|
+
from bot_framework.entities.role import Role
|
|
16
|
+
from bot_framework.entities.role_name import RoleName
|
|
17
|
+
from bot_framework.entities.user import User
|
|
18
|
+
from bot_framework.protocols.i_callback_answerer import ICallbackAnswerer
|
|
19
|
+
from bot_framework.protocols.i_callback_handler import ICallbackHandler
|
|
20
|
+
from bot_framework.protocols.i_callback_handler_registry import (
|
|
21
|
+
ICallbackHandlerRegistry,
|
|
22
|
+
)
|
|
23
|
+
from bot_framework.protocols.i_flow_router import IFlowRouter
|
|
24
|
+
from bot_framework.protocols.i_message_deleter import IMessageDeleter
|
|
25
|
+
from bot_framework.protocols.i_message_handler import IMessageHandler
|
|
26
|
+
from bot_framework.protocols.i_message_handler_registry import IMessageHandlerRegistry
|
|
27
|
+
from bot_framework.protocols.i_message_replacer import IMessageReplacer
|
|
28
|
+
from bot_framework.protocols.i_message_sender import IMessageSender
|
|
29
|
+
from bot_framework.protocols.i_notify_replacer import INotifyReplacer
|
|
30
|
+
|
|
31
|
+
__version__ = "0.1.0"
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
# Entities
|
|
35
|
+
"BotCallback",
|
|
36
|
+
"BotMessage",
|
|
37
|
+
"BotMessageUser",
|
|
38
|
+
"BotUser",
|
|
39
|
+
"Button",
|
|
40
|
+
"Keyboard",
|
|
41
|
+
"LanguageCode",
|
|
42
|
+
"ParseMode",
|
|
43
|
+
"Role",
|
|
44
|
+
"RoleName",
|
|
45
|
+
"User",
|
|
46
|
+
# Protocols
|
|
47
|
+
"ICallbackAnswerer",
|
|
48
|
+
"ICallbackHandler",
|
|
49
|
+
"ICallbackHandlerRegistry",
|
|
50
|
+
"IFlowRouter",
|
|
51
|
+
"IMessageDeleter",
|
|
52
|
+
"IMessageHandler",
|
|
53
|
+
"IMessageHandlerRegistry",
|
|
54
|
+
"IMessageReplacer",
|
|
55
|
+
"IMessageSender",
|
|
56
|
+
"INotifyReplacer",
|
|
57
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .create import CreateProtocol
|
|
2
|
+
from .delete import DeleteProtocol
|
|
3
|
+
from .get_all import GetAllProtocol
|
|
4
|
+
from .get_by_key import GetByKeyProtocol
|
|
5
|
+
from .get_by_name import GetByNameProtocol
|
|
6
|
+
from .read import ReadProtocol
|
|
7
|
+
from .read_sequence_by_user_id import (
|
|
8
|
+
ReadSequenceByUserIdProtocol,
|
|
9
|
+
)
|
|
10
|
+
from .update import UpdateProtocol
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"CreateProtocol",
|
|
14
|
+
"ReadProtocol",
|
|
15
|
+
"UpdateProtocol",
|
|
16
|
+
"DeleteProtocol",
|
|
17
|
+
"GetAllProtocol",
|
|
18
|
+
"GetByKeyProtocol",
|
|
19
|
+
"GetByNameProtocol",
|
|
20
|
+
"ReadSequenceByUserIdProtocol",
|
|
21
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from .bot_callback import BotCallback
|
|
2
|
+
from .bot_message import BotMessage, BotMessageUser
|
|
3
|
+
from .bot_user import BotUser
|
|
4
|
+
from .button import Button
|
|
5
|
+
from .keyboard import Keyboard
|
|
6
|
+
from .language_code import LanguageCode
|
|
7
|
+
from .parse_mode import ParseMode
|
|
8
|
+
from .role import Role
|
|
9
|
+
from .role_name import RoleName
|
|
10
|
+
from .user import User
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"BotCallback",
|
|
14
|
+
"BotMessage",
|
|
15
|
+
"BotMessageUser",
|
|
16
|
+
"BotUser",
|
|
17
|
+
"Button",
|
|
18
|
+
"Keyboard",
|
|
19
|
+
"LanguageCode",
|
|
20
|
+
"ParseMode",
|
|
21
|
+
"Role",
|
|
22
|
+
"RoleName",
|
|
23
|
+
"User",
|
|
24
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, PrivateAttr
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BotCallback(BaseModel):
|
|
7
|
+
model_config = ConfigDict(from_attributes=True)
|
|
8
|
+
|
|
9
|
+
id: str
|
|
10
|
+
user_id: int
|
|
11
|
+
data: str | None
|
|
12
|
+
message_id: int | None
|
|
13
|
+
message_chat_id: int | None
|
|
14
|
+
user_language_code: str | None = None
|
|
15
|
+
_original: Any = PrivateAttr(default=None)
|
|
16
|
+
|
|
17
|
+
def get_original(self) -> Any:
|
|
18
|
+
return self._original
|
|
19
|
+
|
|
20
|
+
def set_original(self, original: Any) -> None:
|
|
21
|
+
self._original = original
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, PrivateAttr
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BotMessageUser(BaseModel):
|
|
7
|
+
model_config = ConfigDict(from_attributes=True)
|
|
8
|
+
|
|
9
|
+
id: int
|
|
10
|
+
language_code: str | None = None
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BotMessage(BaseModel):
|
|
14
|
+
model_config = ConfigDict(from_attributes=True)
|
|
15
|
+
|
|
16
|
+
chat_id: int
|
|
17
|
+
message_id: int
|
|
18
|
+
user_id: int | None = None
|
|
19
|
+
text: str | None = None
|
|
20
|
+
from_user: BotMessageUser | None = None
|
|
21
|
+
_original: Any = PrivateAttr(default=None)
|
|
22
|
+
|
|
23
|
+
def get_original(self) -> Any:
|
|
24
|
+
return self._original
|
|
25
|
+
|
|
26
|
+
def set_original(self, original: Any) -> None:
|
|
27
|
+
self._original = original
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, PrivateAttr
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BotUser(BaseModel):
|
|
7
|
+
model_config = ConfigDict(from_attributes=True)
|
|
8
|
+
|
|
9
|
+
id: int
|
|
10
|
+
username: str | None
|
|
11
|
+
first_name: str | None
|
|
12
|
+
last_name: str | None
|
|
13
|
+
language_code: str
|
|
14
|
+
is_bot: bool
|
|
15
|
+
is_premium: bool
|
|
16
|
+
_original: Any = PrivateAttr(default=None)
|
|
17
|
+
|
|
18
|
+
def get_original(self) -> Any:
|
|
19
|
+
return self._original
|
|
20
|
+
|
|
21
|
+
def set_original(self, original: Any) -> None:
|
|
22
|
+
self._original = original
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
from pydantic import (
|
|
4
|
+
BaseModel, ConfigDict, Field,
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Role(BaseModel):
|
|
9
|
+
id: int = 0
|
|
10
|
+
name: str
|
|
11
|
+
description: str | None = None
|
|
12
|
+
is_active: bool = True
|
|
13
|
+
created_at: datetime = Field(default_factory=datetime.now)
|
|
14
|
+
updated_at: datetime = Field(default_factory=datetime.now)
|
|
15
|
+
|
|
16
|
+
model_config = ConfigDict(from_attributes=True)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
from pydantic import (
|
|
4
|
+
BaseModel,
|
|
5
|
+
ConfigDict,
|
|
6
|
+
Field,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from bot_framework.entities.language_code import LanguageCode
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class User(BaseModel):
|
|
13
|
+
id: int
|
|
14
|
+
username: str | None = None
|
|
15
|
+
first_name: str | None = None
|
|
16
|
+
last_name: str | None = None
|
|
17
|
+
language_code: str = LanguageCode.EN
|
|
18
|
+
is_bot: bool = False
|
|
19
|
+
is_premium: bool = False
|
|
20
|
+
created_at: datetime = Field(default_factory=datetime.now)
|
|
21
|
+
updated_at: datetime = Field(default_factory=datetime.now)
|
|
22
|
+
|
|
23
|
+
model_config = ConfigDict(from_attributes=True)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from bot_framework.flow_management.entities import FlowStackEntry
|
|
2
|
+
from bot_framework.flow_management.flow_registry import FlowRegistry
|
|
3
|
+
from bot_framework.flow_management.protocols import (
|
|
4
|
+
IFlowMessageDeleter,
|
|
5
|
+
IFlowMessageStorage,
|
|
6
|
+
IFlowStackStorage,
|
|
7
|
+
IFlowStackValidator,
|
|
8
|
+
)
|
|
9
|
+
from bot_framework.flow_management.repos import (
|
|
10
|
+
RedisFlowMessageStorage,
|
|
11
|
+
RedisFlowStackStorage,
|
|
12
|
+
)
|
|
13
|
+
from bot_framework.flow_management.services import (
|
|
14
|
+
FlowMessageDeleter,
|
|
15
|
+
FlowStackNavigator,
|
|
16
|
+
FlowStackValidator,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"FlowStackEntry",
|
|
21
|
+
"FlowRegistry",
|
|
22
|
+
"RedisFlowMessageStorage",
|
|
23
|
+
"RedisFlowStackStorage",
|
|
24
|
+
"IFlowMessageStorage",
|
|
25
|
+
"IFlowStackStorage",
|
|
26
|
+
"FlowMessageDeleter",
|
|
27
|
+
"FlowStackNavigator",
|
|
28
|
+
"FlowStackValidator",
|
|
29
|
+
"IFlowMessageDeleter",
|
|
30
|
+
"IFlowStackValidator",
|
|
31
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from bot_framework.protocols.i_flow_router import IFlowRouter
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FlowRegistry:
|
|
7
|
+
def __init__(self):
|
|
8
|
+
self._flows: dict[str, IFlowRouter] = {}
|
|
9
|
+
|
|
10
|
+
def register(self, name: str, router: IFlowRouter) -> None:
|
|
11
|
+
self._flows[name] = router
|
|
12
|
+
|
|
13
|
+
def get(self, name: str) -> IFlowRouter | None:
|
|
14
|
+
return self._flows.get(name)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from bot_framework.flow_management.protocols.i_flow_message_deleter import IFlowMessageDeleter
|
|
2
|
+
from bot_framework.flow_management.protocols.i_flow_message_storage import IFlowMessageStorage
|
|
3
|
+
from bot_framework.flow_management.protocols.i_flow_stack_storage import IFlowStackStorage
|
|
4
|
+
from bot_framework.flow_management.protocols.i_flow_stack_validator import IFlowStackValidator
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"IFlowMessageDeleter",
|
|
8
|
+
"IFlowMessageStorage",
|
|
9
|
+
"IFlowStackStorage",
|
|
10
|
+
"IFlowStackValidator",
|
|
11
|
+
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing import Protocol, runtime_checkable
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@runtime_checkable
|
|
5
|
+
class IFlowMessageStorage(Protocol):
|
|
6
|
+
def add_message(self, telegram_id: int, flow_name: str, message_id: int) -> None: ...
|
|
7
|
+
|
|
8
|
+
def get_messages(self, telegram_id: int, flow_name: str) -> list[int]: ...
|
|
9
|
+
|
|
10
|
+
def clear_messages(self, telegram_id: int, flow_name: str) -> None: ...
|
|
11
|
+
|
|
12
|
+
def clear_all_messages(self, telegram_id: int) -> None: ...
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing import Protocol, runtime_checkable
|
|
2
|
+
|
|
3
|
+
from bot_framework.flow_management.entities import FlowStackEntry
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@runtime_checkable
|
|
7
|
+
class IFlowStackStorage(Protocol):
|
|
8
|
+
def push(self, telegram_id: int, entry: FlowStackEntry) -> None: ...
|
|
9
|
+
|
|
10
|
+
def pop(self, telegram_id: int) -> FlowStackEntry | None: ...
|
|
11
|
+
|
|
12
|
+
def get_stack(self, telegram_id: int) -> list[FlowStackEntry]: ...
|
|
13
|
+
|
|
14
|
+
def clear(self, telegram_id: int) -> None: ...
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from bot_framework.flow_management.repos.redis_flow_message_storage import (
|
|
4
|
+
RedisFlowMessageStorage,
|
|
5
|
+
)
|
|
6
|
+
from bot_framework.flow_management.repos.redis_flow_stack_storage import RedisFlowStackStorage
|
|
7
|
+
|
|
8
|
+
__all__ = ["RedisFlowMessageStorage", "RedisFlowStackStorage"]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import redis
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class RedisFlowMessageStorage:
|
|
7
|
+
def __init__(self, redis_url: str):
|
|
8
|
+
self.redis_client = redis.from_url(redis_url) # pyright: ignore[reportUnknownMemberType]
|
|
9
|
+
self.ttl = 600
|
|
10
|
+
|
|
11
|
+
def _get_key(self, telegram_id: int, flow_name: str) -> str:
|
|
12
|
+
return f"flow_messages:{telegram_id}:{flow_name}"
|
|
13
|
+
|
|
14
|
+
def _get_pattern(self, telegram_id: int) -> str:
|
|
15
|
+
return f"flow_messages:{telegram_id}:*"
|
|
16
|
+
|
|
17
|
+
def add_message(self, telegram_id: int, flow_name: str, message_id: int) -> None:
|
|
18
|
+
key = self._get_key(telegram_id, flow_name)
|
|
19
|
+
self.redis_client.rpush(key, message_id)
|
|
20
|
+
self.redis_client.expire(key, self.ttl)
|
|
21
|
+
|
|
22
|
+
def get_messages(self, telegram_id: int, flow_name: str) -> list[int]:
|
|
23
|
+
key = self._get_key(telegram_id, flow_name)
|
|
24
|
+
messages = self.redis_client.lrange(key, 0, -1)
|
|
25
|
+
return [int(m) for m in messages] # pyright: ignore[reportGeneralTypeIssues]
|
|
26
|
+
|
|
27
|
+
def clear_messages(self, telegram_id: int, flow_name: str) -> None:
|
|
28
|
+
key = self._get_key(telegram_id, flow_name)
|
|
29
|
+
self.redis_client.delete(key)
|
|
30
|
+
|
|
31
|
+
def clear_all_messages(self, telegram_id: int) -> None:
|
|
32
|
+
pattern = self._get_pattern(telegram_id)
|
|
33
|
+
keys = self.redis_client.keys(pattern)
|
|
34
|
+
if keys:
|
|
35
|
+
self.redis_client.delete(*keys) # pyright: ignore[reportGeneralTypeIssues]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
import redis
|
|
6
|
+
|
|
7
|
+
from bot_framework.flow_management.entities import FlowStackEntry
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RedisFlowStackStorage:
|
|
11
|
+
def __init__(self, redis_url: str):
|
|
12
|
+
self.redis_client = redis.from_url(redis_url)
|
|
13
|
+
self.ttl = 600
|
|
14
|
+
|
|
15
|
+
def _get_key(self, telegram_id: int) -> str:
|
|
16
|
+
return f"flow_stack:{telegram_id}"
|
|
17
|
+
|
|
18
|
+
def _get_raw_stack(self, telegram_id: int) -> list[dict]:
|
|
19
|
+
value = self.redis_client.get(self._get_key(telegram_id))
|
|
20
|
+
if value is None:
|
|
21
|
+
return []
|
|
22
|
+
if isinstance(value, bytes):
|
|
23
|
+
return json.loads(value.decode())
|
|
24
|
+
if isinstance(value, str):
|
|
25
|
+
return json.loads(value)
|
|
26
|
+
return []
|
|
27
|
+
|
|
28
|
+
def _save_raw_stack(self, telegram_id: int, stack: list[dict]) -> None:
|
|
29
|
+
self.redis_client.setex(
|
|
30
|
+
name=self._get_key(telegram_id),
|
|
31
|
+
time=self.ttl,
|
|
32
|
+
value=json.dumps(stack),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def push(self, telegram_id: int, entry: FlowStackEntry) -> None:
|
|
36
|
+
stack = self._get_raw_stack(telegram_id)
|
|
37
|
+
stack.append(entry.model_dump(mode="json"))
|
|
38
|
+
self._save_raw_stack(telegram_id, stack)
|
|
39
|
+
|
|
40
|
+
def pop(self, telegram_id: int) -> FlowStackEntry | None:
|
|
41
|
+
stack = self._get_raw_stack(telegram_id)
|
|
42
|
+
if not stack:
|
|
43
|
+
return None
|
|
44
|
+
entry_dict = stack.pop()
|
|
45
|
+
self._save_raw_stack(telegram_id, stack)
|
|
46
|
+
return FlowStackEntry.model_validate(entry_dict)
|
|
47
|
+
|
|
48
|
+
def get_stack(self, telegram_id: int) -> list[FlowStackEntry]:
|
|
49
|
+
raw_stack = self._get_raw_stack(telegram_id)
|
|
50
|
+
return [FlowStackEntry.model_validate(entry) for entry in raw_stack]
|
|
51
|
+
|
|
52
|
+
def clear(self, telegram_id: int) -> None:
|
|
53
|
+
self.redis_client.delete(self._get_key(telegram_id))
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from bot_framework.flow_management.protocols import (
|
|
2
|
+
IFlowMessageDeleter,
|
|
3
|
+
IFlowStackValidator,
|
|
4
|
+
)
|
|
5
|
+
from bot_framework.flow_management.services.flow_message_deleter import FlowMessageDeleter
|
|
6
|
+
from bot_framework.flow_management.services.flow_stack_navigator import FlowStackNavigator
|
|
7
|
+
from bot_framework.flow_management.services.flow_stack_validator import FlowStackValidator
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"FlowMessageDeleter",
|
|
11
|
+
"FlowStackNavigator",
|
|
12
|
+
"FlowStackValidator",
|
|
13
|
+
"IFlowMessageDeleter",
|
|
14
|
+
"IFlowStackValidator",
|
|
15
|
+
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from bot_framework.flow_management.protocols import IFlowMessageStorage
|
|
6
|
+
from bot_framework.protocols import IMessageDeleter
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FlowMessageDeleter:
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
message_deleter: IMessageDeleter,
|
|
15
|
+
message_storage: IFlowMessageStorage,
|
|
16
|
+
):
|
|
17
|
+
self._message_deleter = message_deleter
|
|
18
|
+
self._message_storage = message_storage
|
|
19
|
+
|
|
20
|
+
def delete_flow_messages(self, chat_id: int, flow_name: str) -> None:
|
|
21
|
+
message_ids = self._message_storage.get_messages(chat_id, flow_name)
|
|
22
|
+
if not message_ids:
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
self._delete_messages_batch(chat_id, message_ids)
|
|
26
|
+
self._message_storage.clear_messages(chat_id, flow_name)
|
|
27
|
+
|
|
28
|
+
def delete_all_flow_messages(self, chat_id: int) -> None:
|
|
29
|
+
self._message_storage.clear_all_messages(chat_id)
|
|
30
|
+
|
|
31
|
+
def _delete_messages_batch(self, chat_id: int, message_ids: list[int]) -> None:
|
|
32
|
+
for message_id in message_ids:
|
|
33
|
+
self._message_deleter.delete(chat_id, message_id)
|