telekit 0.0.1__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.
- telekit/__init__.py +14 -0
- telekit/callback_query_handler.py +58 -0
- telekit/chain.py +248 -0
- telekit/example/__init__.py +1 -0
- telekit/example/example_handlers/__init__.py +4 -0
- telekit/example/example_handlers/entry.py +125 -0
- telekit/example/example_handlers/help.py +42 -0
- telekit/example/example_handlers/start.py +49 -0
- telekit/example/example_server.py +9 -0
- telekit/handler.py +59 -0
- telekit/init.py +18 -0
- telekit/input_handler.py +79 -0
- telekit/senders.py +471 -0
- telekit/server.py +42 -0
- telekit/user.py +46 -0
- telekit-0.0.1.dist-info/METADATA +219 -0
- telekit-0.0.1.dist-info/RECORD +19 -0
- telekit-0.0.1.dist-info/WHEEL +5 -0
- telekit-0.0.1.dist-info/top_level.txt +1 -0
telekit/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Copyright (c) 2025 Ving Studio, Romashka
|
|
2
|
+
# Licensed under the MIT License. See LICENSE file for full terms.
|
|
3
|
+
|
|
4
|
+
# engine/__init__.py
|
|
5
|
+
from .handler import Handler
|
|
6
|
+
from .chain import Chain
|
|
7
|
+
from .callback_query_handler import CallbackQueryHandler
|
|
8
|
+
from .server import Server, example
|
|
9
|
+
from .snapvault.snapvault import Vault # type: ignore
|
|
10
|
+
from .chapters import chapters
|
|
11
|
+
from .user import User
|
|
12
|
+
from . import senders
|
|
13
|
+
|
|
14
|
+
__all__ = ["senders", "Chain", "Handler", "CallbackQueryHandler", "Server", "Vault", "User", "chapters", "example"]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import telebot # type: ignore
|
|
4
|
+
from telebot.types import ( # type: ignore
|
|
5
|
+
Message,
|
|
6
|
+
InaccessibleMessage,
|
|
7
|
+
CallbackQuery
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CallbackQueryHandler:
|
|
12
|
+
|
|
13
|
+
bot: telebot.TeleBot
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def init(cls, bot: telebot.TeleBot):
|
|
17
|
+
"""
|
|
18
|
+
Initializes the bot instance for the class.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
bot (TeleBot): The Telegram bot instance to be used for sending messages.
|
|
22
|
+
"""
|
|
23
|
+
cls.bot = bot
|
|
24
|
+
|
|
25
|
+
@bot.callback_query_handler(func=lambda call: True) # type: ignore
|
|
26
|
+
def handle_callback(call: telebot.types.CallbackQuery) -> None: # type: ignore
|
|
27
|
+
CallbackQueryHandler().handle(call)
|
|
28
|
+
|
|
29
|
+
def handle(self, call: CallbackQuery):
|
|
30
|
+
self._simulate(call.message, str(call.data), from_user=call.from_user)
|
|
31
|
+
|
|
32
|
+
def _simulate(self, message: Message | InaccessibleMessage, text: str, from_user: Any=None) -> None:
|
|
33
|
+
args = {}
|
|
34
|
+
|
|
35
|
+
is_bot: bool = getattr(getattr(message, "from_user", from_user), "is_bot", False)
|
|
36
|
+
|
|
37
|
+
args["message_id"] = getattr(message, "message_id", None)
|
|
38
|
+
args["from_user"] = from_user if from_user else getattr(message, "from_user", None)
|
|
39
|
+
args["date"] = getattr(message, "date", None)
|
|
40
|
+
args["chat"] = getattr(message, "chat", None)
|
|
41
|
+
args["json_string"] = getattr(message, "json", None)
|
|
42
|
+
|
|
43
|
+
args["content_type"] = "text"
|
|
44
|
+
args["options"] = {}
|
|
45
|
+
|
|
46
|
+
if any(value is None for value in args.values()): # type: ignore
|
|
47
|
+
return print("Error: Missing required fields in message simulation.")
|
|
48
|
+
|
|
49
|
+
original_message = message
|
|
50
|
+
|
|
51
|
+
message = Message(**args) # type: ignore
|
|
52
|
+
message.message_thread_id = getattr(original_message, "message_thread_id", None)
|
|
53
|
+
message.text = text
|
|
54
|
+
|
|
55
|
+
if message.from_user:
|
|
56
|
+
message.from_user.is_bot = is_bot
|
|
57
|
+
|
|
58
|
+
self.bot.process_new_messages([message]) # type: ignore
|
telekit/chain.py
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import random
|
|
2
|
+
from typing import Callable, Any
|
|
3
|
+
|
|
4
|
+
import telebot # type: ignore
|
|
5
|
+
from telebot.types import ( # type: ignore
|
|
6
|
+
Message,
|
|
7
|
+
InlineKeyboardButton,
|
|
8
|
+
InlineKeyboardMarkup
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from . import senders
|
|
12
|
+
from . import input_handler
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Chain:
|
|
16
|
+
|
|
17
|
+
bot: telebot.TeleBot
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def init(cls, bot: telebot.TeleBot):
|
|
21
|
+
"""
|
|
22
|
+
Initializes the bot instance for the class.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
bot (TeleBot): The Telegram bot instance to be used for sending messages.
|
|
26
|
+
"""
|
|
27
|
+
cls.bot = bot
|
|
28
|
+
|
|
29
|
+
def __init__(self, chat_id: int):
|
|
30
|
+
self.chat_id = chat_id
|
|
31
|
+
self.sender = senders.AlertSender(chat_id)
|
|
32
|
+
self.handler = input_handler.InputHandler(chat_id)
|
|
33
|
+
self.parent: Chain | None = None
|
|
34
|
+
self._previous_message: Message | None = None
|
|
35
|
+
self.always_edit_previous_message: bool = False
|
|
36
|
+
|
|
37
|
+
def set_inline_keyboard(self, keyboard: dict[str, 'Chain' | Callable[[Message], Any]], row_width: int = 1) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Sets an inline keyboard for the chain with buttons that call the corresponding functions.
|
|
40
|
+
Each button will call the function with the message as an argument.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
keyboard (dict[str, Callable[[Message], Any]]): A dictionary where keys are button captions
|
|
44
|
+
and values are functions to be called when the button is clicked.
|
|
45
|
+
"""
|
|
46
|
+
callback_functions: dict[str, Callable[[Message], Any]] = {}
|
|
47
|
+
buttons: list[InlineKeyboardButton] = []
|
|
48
|
+
|
|
49
|
+
for i, (caption, callback) in enumerate(keyboard.items()):
|
|
50
|
+
callback_data = f"button_{i}_{random.randint(1000, 9999)}"
|
|
51
|
+
callback_functions[callback_data] = callback
|
|
52
|
+
buttons.append(
|
|
53
|
+
InlineKeyboardButton(
|
|
54
|
+
text=caption,
|
|
55
|
+
callback_data=callback_data
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
rows = [buttons[i:i + row_width] for i in range(0, len(buttons), row_width)]
|
|
60
|
+
markup = InlineKeyboardMarkup()
|
|
61
|
+
markup.keyboard = rows
|
|
62
|
+
|
|
63
|
+
self.sender.set_reply_markup(markup) # type: ignore
|
|
64
|
+
self.handler.set_callback_functions(callback_functions)
|
|
65
|
+
|
|
66
|
+
def inline_keyboard[Caption: str, Value](self, keyboard: dict[Caption, Value], row_width: int = 1) -> Callable[[Callable[[Message, Value], None]], None]:
|
|
67
|
+
"""
|
|
68
|
+
Decorator to set an inline keyboard for the chain
|
|
69
|
+
with buttons that call the decorated function with the button value.
|
|
70
|
+
"""
|
|
71
|
+
def wrapper(func: Callable[[Message, Value], None]) -> None:
|
|
72
|
+
callback_functions: dict[str, Callable[[Message], Any]] = {}
|
|
73
|
+
buttons: list[InlineKeyboardButton] = []
|
|
74
|
+
|
|
75
|
+
def get_callback(value: Value) -> Callable[[Message], None]:
|
|
76
|
+
def callback(message: Message) -> None:
|
|
77
|
+
func(message, value)
|
|
78
|
+
return callback
|
|
79
|
+
|
|
80
|
+
for i, (caption, value) in enumerate(keyboard.items()):
|
|
81
|
+
callback_data = f"button_{i}_{random.randint(1000, 9999)}"
|
|
82
|
+
callback_functions[callback_data] = get_callback(value)
|
|
83
|
+
buttons.append(
|
|
84
|
+
InlineKeyboardButton(
|
|
85
|
+
text=caption,
|
|
86
|
+
callback_data=callback_data
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
rows = [buttons[i:i + row_width] for i in range(0, len(buttons), row_width)]
|
|
91
|
+
markup = InlineKeyboardMarkup()
|
|
92
|
+
markup.keyboard = rows
|
|
93
|
+
|
|
94
|
+
self.sender.set_reply_markup(markup) # type: ignore
|
|
95
|
+
self.handler.set_callback_functions(callback_functions)
|
|
96
|
+
|
|
97
|
+
return wrapper
|
|
98
|
+
|
|
99
|
+
def set_entry_suggestions(self, keyboard: dict[str, str] | list[str], row_width: int = 1) -> None:
|
|
100
|
+
"""
|
|
101
|
+
Sets reply suggestions as inline buttons below the message input field.
|
|
102
|
+
These buttons act as quick replies, and send the corresponding `callback_data` when clicked.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
keyboard (dict[Caption, Value]): A dictionary where each key is the button's visible text (caption),
|
|
106
|
+
and each value is the string to send as callback_data.
|
|
107
|
+
row_width (int, optional): Number of buttons per row. Defaults to 1.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
buttons: list[InlineKeyboardButton] = []
|
|
111
|
+
|
|
112
|
+
if isinstance(keyboard, list):
|
|
113
|
+
keyboard = {c: c for c in keyboard}
|
|
114
|
+
|
|
115
|
+
for caption, value in keyboard.items():
|
|
116
|
+
buttons.append(
|
|
117
|
+
InlineKeyboardButton(
|
|
118
|
+
text=caption,
|
|
119
|
+
callback_data=value
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
rows = [buttons[i:i + row_width] for i in range(0, len(buttons), row_width)]
|
|
124
|
+
markup = InlineKeyboardMarkup()
|
|
125
|
+
markup.keyboard = rows
|
|
126
|
+
|
|
127
|
+
self.sender.set_reply_markup(markup) # type: ignore
|
|
128
|
+
|
|
129
|
+
def entry(self,
|
|
130
|
+
filter_message: Callable[[Message], bool] | None=None,
|
|
131
|
+
delete_user_response: bool=False) -> Callable[[Callable[[Message], Any]], None]:
|
|
132
|
+
def wrapper(func: Callable[[Message], Any]) -> None:
|
|
133
|
+
def callback(message: Message) -> bool:
|
|
134
|
+
if delete_user_response:
|
|
135
|
+
self.sender.delete_message(message)
|
|
136
|
+
|
|
137
|
+
if filter_message and not filter_message(message):
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
func(message)
|
|
141
|
+
return True
|
|
142
|
+
|
|
143
|
+
self.handler.set_entry_callback(callback)
|
|
144
|
+
|
|
145
|
+
return wrapper
|
|
146
|
+
|
|
147
|
+
def entry_text(self,
|
|
148
|
+
filter_message: Callable[[Message, str], bool] | None=None,
|
|
149
|
+
delete_user_response: bool=False) -> Callable[[Callable[[Message, str], Any]], None]:
|
|
150
|
+
def wrapper(func: Callable[[Message, str], Any]) -> None:
|
|
151
|
+
def callback(message: Message) -> bool:
|
|
152
|
+
if delete_user_response:
|
|
153
|
+
self.sender.delete_message(message)
|
|
154
|
+
|
|
155
|
+
if not message.text:
|
|
156
|
+
return False # Only text messages
|
|
157
|
+
|
|
158
|
+
if filter_message and not filter_message(message, message.text):
|
|
159
|
+
return False
|
|
160
|
+
|
|
161
|
+
func(message, message.text)
|
|
162
|
+
return True
|
|
163
|
+
|
|
164
|
+
self.handler.set_entry_callback(callback)
|
|
165
|
+
|
|
166
|
+
return wrapper
|
|
167
|
+
|
|
168
|
+
def set_always_edit_previous_message(self, value: bool=True) -> None:
|
|
169
|
+
self.always_edit_previous_message = value
|
|
170
|
+
|
|
171
|
+
def send(self) -> Message | None:
|
|
172
|
+
self.handler.handle_next_message()
|
|
173
|
+
|
|
174
|
+
if self.always_edit_previous_message:
|
|
175
|
+
self.edit_previous_message()
|
|
176
|
+
|
|
177
|
+
message = self.sender.send_or_handle_error()
|
|
178
|
+
self._set_previous_message(message)
|
|
179
|
+
return message
|
|
180
|
+
|
|
181
|
+
def _set_previous_message(self, message: Message | None) -> None:
|
|
182
|
+
self._previous_message = message
|
|
183
|
+
|
|
184
|
+
if self.parent:
|
|
185
|
+
self.parent._set_previous_message(message)
|
|
186
|
+
|
|
187
|
+
def get_previous_message(self) -> Message | None:
|
|
188
|
+
"""
|
|
189
|
+
Returns the previous message sent by the chain.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
Message | None: The previous message or None if no message was sent
|
|
193
|
+
"""
|
|
194
|
+
if self._previous_message:
|
|
195
|
+
return self._previous_message
|
|
196
|
+
elif self.parent:
|
|
197
|
+
return self.parent.get_previous_message()
|
|
198
|
+
else:
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
def edit_previous_message(self) -> None:
|
|
202
|
+
"""
|
|
203
|
+
Edits the previous message sent by the chain with the current sender's message
|
|
204
|
+
"""
|
|
205
|
+
self.sender.set_edit_message(self.get_previous_message())
|
|
206
|
+
|
|
207
|
+
def set_parent(self, parent: 'Chain') -> None:
|
|
208
|
+
"""
|
|
209
|
+
Sets the parent chain for this chain.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
parent (Chain): The parent chain to be set.
|
|
213
|
+
"""
|
|
214
|
+
self.parent = parent
|
|
215
|
+
self.always_edit_previous_message = parent.always_edit_previous_message
|
|
216
|
+
|
|
217
|
+
def __call__(self, message: Message | None = None):
|
|
218
|
+
self.send()
|
|
219
|
+
|
|
220
|
+
def get_alert_sender(self) -> senders.AlertSender:
|
|
221
|
+
"""
|
|
222
|
+
Returns the sender for sending alert messages.
|
|
223
|
+
"""
|
|
224
|
+
return senders.AlertSender(self.chat_id)
|
|
225
|
+
|
|
226
|
+
def get_bot(self) -> telebot.TeleBot:
|
|
227
|
+
"""
|
|
228
|
+
Returns the bot instance associated with this chain.
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
telebot.TeleBot: The bot instance.
|
|
232
|
+
"""
|
|
233
|
+
return self.bot
|
|
234
|
+
|
|
235
|
+
@classmethod
|
|
236
|
+
def get_chain_factory(cls, chat_id: int) -> Callable[[], 'Chain']:
|
|
237
|
+
def message_factory() -> Chain:
|
|
238
|
+
return cls(chat_id)
|
|
239
|
+
return message_factory
|
|
240
|
+
|
|
241
|
+
@classmethod
|
|
242
|
+
def get_children_factory(cls, chat_id: int) -> Callable[[Any], 'Chain']:
|
|
243
|
+
def children_factory(parent: Chain | None=None) -> Chain:
|
|
244
|
+
chain = cls(chat_id)
|
|
245
|
+
if parent:
|
|
246
|
+
chain.set_parent(parent)
|
|
247
|
+
return chain
|
|
248
|
+
return children_factory
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from . import example_server
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import telebot.types # type: ignore
|
|
2
|
+
import telekit
|
|
3
|
+
import telekit.snapvault
|
|
4
|
+
import telekit.snapvault.snapvault
|
|
5
|
+
|
|
6
|
+
class User:
|
|
7
|
+
names: telekit.Vault = telekit.Vault(
|
|
8
|
+
path = "data_base",
|
|
9
|
+
table_name = "names",
|
|
10
|
+
key_field_name = "user_id",
|
|
11
|
+
value_field_name = "name"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
ages: telekit.Vault = telekit.Vault(
|
|
15
|
+
path = "data_base",
|
|
16
|
+
table_name = "ages",
|
|
17
|
+
key_field_name = "user_id",
|
|
18
|
+
value_field_name = "age"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def __init__(self, chat_id: int):
|
|
22
|
+
self.chat_id = chat_id
|
|
23
|
+
|
|
24
|
+
def get_name(self, default: str | None=None) -> str | None:
|
|
25
|
+
return self.names.get(self.chat_id, default)
|
|
26
|
+
|
|
27
|
+
def set_name(self, value: str):
|
|
28
|
+
self.names[self.chat_id] = value
|
|
29
|
+
|
|
30
|
+
def get_age(self, default: int | None=None) -> int | None:
|
|
31
|
+
return self.ages.get(self.chat_id, default)
|
|
32
|
+
|
|
33
|
+
def set_age(self, value: int):
|
|
34
|
+
self.ages[self.chat_id] = value
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class EntryHandler(telekit.Handler):
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def init_handler(cls, bot: telebot.TeleBot) -> None:
|
|
41
|
+
"""
|
|
42
|
+
Initializes the command handler.
|
|
43
|
+
"""
|
|
44
|
+
@bot.message_handler(commands=['entry']) # type: ignore
|
|
45
|
+
def handler(message: telebot.types.Message) -> None: # type: ignore
|
|
46
|
+
cls(message).handle()
|
|
47
|
+
|
|
48
|
+
# ------------------------------------------
|
|
49
|
+
# Handling Logic
|
|
50
|
+
# ------------------------------------------
|
|
51
|
+
|
|
52
|
+
def handle(self) -> None:
|
|
53
|
+
self._user = User(self.message.chat.id)
|
|
54
|
+
self.entry_name()
|
|
55
|
+
|
|
56
|
+
def entry_name(self, message: telebot.types.Message | None=None) -> None:
|
|
57
|
+
prompt: telekit.Chain = self.get_child()
|
|
58
|
+
prompt.set_always_edit_previous_message(True)
|
|
59
|
+
|
|
60
|
+
prompt.sender.set_title("⌨️ What`s your name?")
|
|
61
|
+
prompt.sender.set_message("Please, send a text message")
|
|
62
|
+
|
|
63
|
+
name = self._user.get_name(
|
|
64
|
+
self.user.get_username()
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if name:
|
|
68
|
+
prompt.set_entry_suggestions([name])
|
|
69
|
+
|
|
70
|
+
@prompt.entry_text(delete_user_response=True) # Text message only (User will not be abled to send photos, stickers, ...)
|
|
71
|
+
def _(message: telebot.types.Message, name: str) -> None:
|
|
72
|
+
received: telekit.Chain = self.get_child()
|
|
73
|
+
|
|
74
|
+
received.sender.set_title(f"👋 Bonjour, {name}!")
|
|
75
|
+
received.sender.set_message(f"Is that your name?")
|
|
76
|
+
|
|
77
|
+
self._user.set_name(name)
|
|
78
|
+
|
|
79
|
+
received.set_inline_keyboard(
|
|
80
|
+
{
|
|
81
|
+
"« Change": prompt,
|
|
82
|
+
"Yes »": self.entry_age,
|
|
83
|
+
}, row_width=2
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
received.send()
|
|
87
|
+
|
|
88
|
+
prompt.send()
|
|
89
|
+
|
|
90
|
+
def entry_age(self, message: telebot.types.Message) -> None:
|
|
91
|
+
prompt: telekit.Chain = self.get_child() # Child of `entry_name.<locals>.received` (previous chain)
|
|
92
|
+
|
|
93
|
+
prompt.sender.set_title("⏳ How old are you?")
|
|
94
|
+
prompt.sender.set_message("Please, send a numeric message")
|
|
95
|
+
|
|
96
|
+
@prompt.entry_text( # Text message only (User will not be abled to send photos, stickers, ...)
|
|
97
|
+
filter_message=lambda message, text: text.isdigit() and 0 < int(text) < 130, # Numeric message only
|
|
98
|
+
delete_user_response=True)
|
|
99
|
+
def _(message: telebot.types.Message, text: str) -> None:
|
|
100
|
+
received: telekit.Chain = self.get_child()
|
|
101
|
+
|
|
102
|
+
received.sender.set_title(f"😏 {text} years old?")
|
|
103
|
+
received.sender.set_message(f"Noted. Now I know which memes are safe to show you")
|
|
104
|
+
self._user.set_age(int(text))
|
|
105
|
+
|
|
106
|
+
received.set_inline_keyboard(
|
|
107
|
+
{
|
|
108
|
+
"« Change": prompt,
|
|
109
|
+
"Ok »": self.result,
|
|
110
|
+
}, row_width=2
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
received.send()
|
|
114
|
+
|
|
115
|
+
prompt.send()
|
|
116
|
+
|
|
117
|
+
def result(self, message: telebot.types.Message) -> None:
|
|
118
|
+
result: telekit.Chain = self.get_child() # Child of `entry_age.<locals>.received` (previous chain)
|
|
119
|
+
|
|
120
|
+
result.sender.set_title("😏 Well well well")
|
|
121
|
+
result.sender.set_message(f"So your name is {self._user.get_name()} and you're {self._user.get_age()}? Fancy!")
|
|
122
|
+
|
|
123
|
+
result.set_inline_keyboard({"« Change": self.entry_name})
|
|
124
|
+
|
|
125
|
+
result.send()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import telebot.types # type: ignore
|
|
2
|
+
import telekit
|
|
3
|
+
|
|
4
|
+
pages: dict[str, tuple[str, str]] = {}
|
|
5
|
+
|
|
6
|
+
for title, text in telekit.chapters.read("help.txt").items():
|
|
7
|
+
pages[title] = (title, text)
|
|
8
|
+
|
|
9
|
+
class HelpHandler(telekit.Handler):
|
|
10
|
+
|
|
11
|
+
@classmethod
|
|
12
|
+
def init_handler(cls, bot: telebot.TeleBot) -> None:
|
|
13
|
+
"""
|
|
14
|
+
Initializes the command handler.
|
|
15
|
+
"""
|
|
16
|
+
@bot.message_handler(commands=['help']) # type: ignore
|
|
17
|
+
def handler(message: telebot.types.Message) -> None: # type: ignore
|
|
18
|
+
cls(message).handle()
|
|
19
|
+
|
|
20
|
+
# ------------------------------------------
|
|
21
|
+
# Handling Logic
|
|
22
|
+
# ------------------------------------------
|
|
23
|
+
|
|
24
|
+
def handle(self) -> None:
|
|
25
|
+
main: telekit.Chain = self.get_chain()
|
|
26
|
+
main.set_always_edit_previous_message(True)
|
|
27
|
+
|
|
28
|
+
main.sender.set_title("FAQ - Frequently Asked Questions")
|
|
29
|
+
main.sender.set_message("Here are some common questions and answers to help you get started:")
|
|
30
|
+
|
|
31
|
+
@main.inline_keyboard(pages)
|
|
32
|
+
def _(message: telebot.types.Message, value: tuple[str, str]) -> None:
|
|
33
|
+
page: telekit.Chain = self.get_child()
|
|
34
|
+
|
|
35
|
+
page.sender.set_title(value[0])
|
|
36
|
+
page.sender.set_message(value[1])
|
|
37
|
+
|
|
38
|
+
page.set_inline_keyboard({"« Back": main})
|
|
39
|
+
|
|
40
|
+
page.send()
|
|
41
|
+
|
|
42
|
+
main.send()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import telebot.types # type: ignore
|
|
2
|
+
import telekit
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class StartHandler(telekit.Handler):
|
|
7
|
+
|
|
8
|
+
# ------------------------------------------
|
|
9
|
+
# Initialization
|
|
10
|
+
# ------------------------------------------
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def init_handler(cls, bot: telebot.TeleBot) -> None:
|
|
14
|
+
"""
|
|
15
|
+
Initializes the message handler for the '/start' command.
|
|
16
|
+
"""
|
|
17
|
+
@bot.message_handler(commands=['start']) # type: ignore
|
|
18
|
+
def handler(message: telebot.types.Message) -> None: # type: ignore
|
|
19
|
+
cls(message).handle()
|
|
20
|
+
|
|
21
|
+
# ------------------------------------------
|
|
22
|
+
# Handling Logic
|
|
23
|
+
# ------------------------------------------
|
|
24
|
+
|
|
25
|
+
def handle(self) -> None:
|
|
26
|
+
chain: telekit.Chain = self.get_chain()
|
|
27
|
+
|
|
28
|
+
chain.sender.set_title("Hello")
|
|
29
|
+
chain.sender.set_message("Welcome to the bot! Click the button below to start interacting.")
|
|
30
|
+
chain.sender.set_photo("https://static.wikia.nocookie.net/ssb-tourney/images/d/db/Bot_CG_Art.jpg/revision/latest?cb=20151224123450")
|
|
31
|
+
chain.sender.set_effect(chain.sender.Effect.PARTY)
|
|
32
|
+
|
|
33
|
+
def counter_factory() -> typing.Callable[[int], int]:
|
|
34
|
+
count = 0
|
|
35
|
+
def counter(value: int=1) -> int:
|
|
36
|
+
nonlocal count
|
|
37
|
+
count += value
|
|
38
|
+
return count
|
|
39
|
+
return counter
|
|
40
|
+
|
|
41
|
+
click_counter = counter_factory()
|
|
42
|
+
|
|
43
|
+
@chain.inline_keyboard({"⊕": 1, "⊖": -1}, row_width=2)
|
|
44
|
+
def _(message: telebot.types.Message, value: int) -> None:
|
|
45
|
+
chain.sender.set_message(f"You clicked {click_counter(value)} times")
|
|
46
|
+
chain.edit_previous_message()
|
|
47
|
+
chain.send()
|
|
48
|
+
|
|
49
|
+
chain.send()
|
telekit/handler.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
from telebot.types import Message # type: ignore
|
|
4
|
+
import telebot # type: ignore
|
|
5
|
+
|
|
6
|
+
from .chain import Chain
|
|
7
|
+
from .user import User
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Handler:
|
|
11
|
+
|
|
12
|
+
bot: telebot.TeleBot
|
|
13
|
+
|
|
14
|
+
# def __init__(self, message: telebot.types.Message):
|
|
15
|
+
# super().__init__(message)
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def init(cls, bot: telebot.TeleBot):
|
|
19
|
+
"""
|
|
20
|
+
Initializes the bot instance for the class.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
bot (TeleBot): The Telegram bot instance to be used for sending messages.
|
|
24
|
+
"""
|
|
25
|
+
cls.bot = bot
|
|
26
|
+
|
|
27
|
+
for handler in cls.handlers:
|
|
28
|
+
handler.init_handler(bot)
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def init_handler(cls, bot: telebot.TeleBot) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Initializes the message handler
|
|
34
|
+
"""
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
def __init__(self, message: Message):
|
|
38
|
+
self.message: Message = message
|
|
39
|
+
self.chain: Chain | None = None
|
|
40
|
+
self.user = User(self.message.chat.id, self.message.from_user)
|
|
41
|
+
self._chain_factory: Callable[[], Chain] = Chain.get_chain_factory(self.message.chat.id)
|
|
42
|
+
self._children_factory: Callable[[Chain | None], Chain] = Chain.get_children_factory(self.message.chat.id)
|
|
43
|
+
|
|
44
|
+
def get_chain(self) -> Chain:
|
|
45
|
+
self.chain = self._chain_factory()
|
|
46
|
+
return self.chain
|
|
47
|
+
|
|
48
|
+
def get_child(self, parent: Chain | None = None) -> Chain:
|
|
49
|
+
if parent is None:
|
|
50
|
+
parent = self.chain
|
|
51
|
+
|
|
52
|
+
self.chain = self._children_factory(self.chain)
|
|
53
|
+
return self.chain
|
|
54
|
+
|
|
55
|
+
handlers: list[type['Handler']] = []
|
|
56
|
+
|
|
57
|
+
def __init_subclass__(cls, **kwargs): # type: ignore
|
|
58
|
+
super().__init_subclass__(**kwargs)
|
|
59
|
+
Handler.handlers.append(cls)
|
telekit/init.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from .handler import Handler
|
|
2
|
+
from .chain import Chain
|
|
3
|
+
from .input_handler import InputHandler
|
|
4
|
+
from .callback_query_handler import CallbackQueryHandler
|
|
5
|
+
from .user import User
|
|
6
|
+
from . import senders
|
|
7
|
+
|
|
8
|
+
import telebot # type: ignore
|
|
9
|
+
|
|
10
|
+
__all__ = ["init"]
|
|
11
|
+
|
|
12
|
+
def init(bot: telebot.TeleBot) -> None:
|
|
13
|
+
senders.BaseSender.init(bot)
|
|
14
|
+
Handler.init(bot)
|
|
15
|
+
Chain.init(bot)
|
|
16
|
+
InputHandler.init(bot)
|
|
17
|
+
CallbackQueryHandler.init(bot)
|
|
18
|
+
User.init(bot)
|