Compare commits
10 Commits
294c05ef91
...
c1df0c5338
Author | SHA1 | Date | |
---|---|---|---|
c1df0c5338 | |||
b5947e5f47 | |||
c481e3e931 | |||
63af421777 | |||
512eb9a4af | |||
8aa9c65fcc | |||
8f5fc9f398 | |||
de684aa200 | |||
7b8aa3d092 | |||
d35e15941f |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
|
test.py
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
|
@ -66,12 +66,16 @@ if __name__ == '__main__':
|
|||||||
- [Обработчик доступных событий](https://github.com/love-apples/maxapi/blob/main/examples/events/main.py)
|
- [Обработчик доступных событий](https://github.com/love-apples/maxapi/blob/main/examples/events/main.py)
|
||||||
- [Обработчики с MagicFilter](https://github.com/love-apples/maxapi/blob/main/examples/magic_filters/main.py)
|
- [Обработчики с MagicFilter](https://github.com/love-apples/maxapi/blob/main/examples/magic_filters/main.py)
|
||||||
- [Демонстрация роутинга, InputMedia и механика контекста](https://github.com/love-apples/maxapi/tree/main/examples/router_with_input_media) (audio.mp3 для команды /media)
|
- [Демонстрация роутинга, InputMedia и механика контекста](https://github.com/love-apples/maxapi/tree/main/examples/router_with_input_media) (audio.mp3 для команды /media)
|
||||||
|
- [Получение ID](https://github.com/love-apples/maxapi/tree/main/examples/get_ids/main.py)
|
||||||
|
- [Миддлварь в хендлерах](https://github.com/love-apples/maxapi/tree/main/examples/middleware_in_handlers/main.py)
|
||||||
|
- [Миддлварь в роутерах](https://github.com/love-apples/maxapi/tree/main/examples/middleware_for_router/main.py)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
## 🧩 Возможности
|
## 🧩 Возможности
|
||||||
|
|
||||||
|
- ✅ Middleware
|
||||||
- ✅ Роутеры
|
- ✅ Роутеры
|
||||||
- ✅ Билдер инлайн клавиатур
|
- ✅ Билдер инлайн клавиатур
|
||||||
- ✅ Простая загрузка медиафайлов
|
- ✅ Простая загрузка медиафайлов
|
||||||
|
39
examples/get_ids/main.py
Normal file
39
examples/get_ids/main.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from maxapi import Bot, Dispatcher, F
|
||||||
|
from maxapi.enums.parse_mode import ParseMode
|
||||||
|
from maxapi.types import MessageCreated
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
bot = Bot('тут_ваш_токен')
|
||||||
|
dp = Dispatcher()
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(F.message.link.type == 'forward')
|
||||||
|
async def get_ids_from_forward(event: MessageCreated):
|
||||||
|
text = (
|
||||||
|
'Информация о пересланном сообщении:\n\n'
|
||||||
|
|
||||||
|
f'Из чата: <b>{event.message.link.chat_id}</b>\n'
|
||||||
|
f'От пользователя: <b>{event.message.link.sender.user_id}</b>'
|
||||||
|
)
|
||||||
|
await event.message.reply(text)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created()
|
||||||
|
async def get_ids(event: MessageCreated):
|
||||||
|
text = (
|
||||||
|
f'Ваш ID: <b>{event.from_user.user_id}</b>\n'
|
||||||
|
f'ID этого чата: <b>{event.chat.chat_id}</b>'
|
||||||
|
)
|
||||||
|
await event.message.answer(text, parse_mode=ParseMode.HTML)
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await dp.start_polling(bot)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
41
examples/middleware_for_router/main.py
Normal file
41
examples/middleware_for_router/main.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
from maxapi import Bot, Dispatcher
|
||||||
|
from maxapi.types import MessageCreated, Command, UpdateUnion
|
||||||
|
from maxapi.filters.middleware import BaseMiddleware
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
bot = Bot(token='тут_ваш_токен')
|
||||||
|
dp = Dispatcher()
|
||||||
|
|
||||||
|
|
||||||
|
class CustomDataForRouterMiddleware(BaseMiddleware):
|
||||||
|
async def __call__(
|
||||||
|
self,
|
||||||
|
event: UpdateUnion,
|
||||||
|
data: Dict[str, Any]
|
||||||
|
):
|
||||||
|
|
||||||
|
data['custom_data'] = f'Это ID того кто вызвал команду: {event.from_user.user_id}'
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(Command('custom_data'))
|
||||||
|
async def custom_data(event: MessageCreated, custom_data: str):
|
||||||
|
await event.message.answer(custom_data)
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
dp.middlewares = [
|
||||||
|
CustomDataForRouterMiddleware()
|
||||||
|
]
|
||||||
|
await dp.start_polling(bot)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
59
examples/middleware_in_handlers/main.py
Normal file
59
examples/middleware_in_handlers/main.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
from maxapi import Bot, Dispatcher
|
||||||
|
from maxapi.filters.middleware import BaseMiddleware
|
||||||
|
from maxapi.types import MessageCreated, Command, UpdateUnion
|
||||||
|
from maxapi.types.command import Command
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
bot = Bot(token='тут_ваш_токен')
|
||||||
|
dp = Dispatcher()
|
||||||
|
|
||||||
|
|
||||||
|
class CheckChatTitleMiddleware(BaseMiddleware):
|
||||||
|
async def __call__(
|
||||||
|
self,
|
||||||
|
event: UpdateUnion,
|
||||||
|
):
|
||||||
|
|
||||||
|
return event.chat.title == 'MAXApi'
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(Command('start'), CheckChatTitleMiddleware())
|
||||||
|
async def start(event: MessageCreated):
|
||||||
|
await event.message.answer('Это сообщение было отправлено, так как ваш чат называется "MAXApi"!')
|
||||||
|
|
||||||
|
|
||||||
|
class CustomDataMiddleware(BaseMiddleware):
|
||||||
|
async def __call__(
|
||||||
|
self,
|
||||||
|
event: UpdateUnion,
|
||||||
|
data: Dict[str, Any]
|
||||||
|
):
|
||||||
|
|
||||||
|
data['custom_data'] = f'Это ID того кто вызвал команду: {event.from_user.user_id}'
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(Command('custom_data'), CustomDataMiddleware())
|
||||||
|
async def custom_data(event: MessageCreated, custom_data: str):
|
||||||
|
await event.message.answer(custom_data)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(Command('many_middlewares'), CheckChatTitleMiddleware(), CustomDataMiddleware())
|
||||||
|
async def many_middlewares(event: MessageCreated, custom_data: str):
|
||||||
|
await event.message.answer('Это сообщение было отправлено, так как ваш чат называется "MAXApi"!')
|
||||||
|
await event.message.answer(custom_data)
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await dp.start_polling(bot)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
175
maxapi/bot.py
175
maxapi/bot.py
@ -1,69 +1,69 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, Dict, List, TYPE_CHECKING
|
from typing import Any, Dict, List, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
from maxapi.methods.download_media import DownloadMedia
|
|
||||||
|
|
||||||
from .methods.get_upload_url import GetUploadURL
|
|
||||||
from .methods.get_updates import GetUpdates
|
|
||||||
from .methods.remove_member_chat import RemoveMemberChat
|
|
||||||
from .methods.add_admin_chat import AddAdminChat
|
|
||||||
from .methods.add_members_chat import AddMembersChat
|
|
||||||
from .methods.get_members_chat import GetMembersChat
|
|
||||||
from .methods.remove_admin import RemoveAdmin
|
|
||||||
from .methods.get_list_admin_chat import GetListAdminChat
|
|
||||||
from .methods.delete_bot_from_chat import DeleteMeFromMessage
|
|
||||||
from .methods.get_me_from_chat import GetMeFromChat
|
|
||||||
from .methods.delete_pin_message import DeletePinMessage
|
|
||||||
from .methods.get_pinned_message import GetPinnedMessage
|
|
||||||
from .methods.pin_message import PinMessage
|
|
||||||
from .methods.delete_chat import DeleteChat
|
|
||||||
from .methods.send_action import SendAction
|
|
||||||
from .methods.edit_chat import EditChat
|
|
||||||
from .methods.get_chat_by_id import GetChatById
|
|
||||||
from .methods.get_chat_by_link import GetChatByLink
|
|
||||||
from .methods.send_callback import SendCallback
|
|
||||||
from .methods.get_video import GetVideo
|
|
||||||
from .methods.delete_message import DeleteMessage
|
|
||||||
from .methods.edit_message import EditMessage
|
|
||||||
from .methods.change_info import ChangeInfo
|
|
||||||
from .methods.get_me import GetMe
|
|
||||||
from .methods.get_messages import GetMessages
|
|
||||||
from .methods.get_chats import GetChats
|
|
||||||
from .methods.send_message import SendMessage
|
|
||||||
|
|
||||||
|
from .connection.base import BaseConnection
|
||||||
from .enums.parse_mode import ParseMode
|
from .enums.parse_mode import ParseMode
|
||||||
from .enums.sender_action import SenderAction
|
from .enums.sender_action import SenderAction
|
||||||
from .enums.upload_type import UploadType
|
from .enums.upload_type import UploadType
|
||||||
|
|
||||||
from .types.message import Message
|
from .methods.add_admin_chat import AddAdminChat
|
||||||
from .types.attachments.attachment import Attachment
|
from .methods.add_members_chat import AddMembersChat
|
||||||
from .types.attachments.image import PhotoAttachmentRequestPayload
|
from .methods.change_info import ChangeInfo
|
||||||
from .types.message import Messages, NewMessageLink
|
from .methods.delete_bot_from_chat import DeleteMeFromMessage
|
||||||
from .types.users import ChatAdmin, User
|
from .methods.delete_chat import DeleteChat
|
||||||
from .types.command import BotCommand
|
from .methods.delete_message import DeleteMessage
|
||||||
|
from .methods.delete_pin_message import DeletePinMessage
|
||||||
|
from .methods.download_media import DownloadMedia
|
||||||
|
from .methods.edit_chat import EditChat
|
||||||
|
from .methods.edit_message import EditMessage
|
||||||
|
from .methods.get_chat_by_id import GetChatById
|
||||||
|
from .methods.get_chat_by_link import GetChatByLink
|
||||||
|
from .methods.get_chats import GetChats
|
||||||
|
from .methods.get_list_admin_chat import GetListAdminChat
|
||||||
|
from .methods.get_me import GetMe
|
||||||
|
from .methods.get_me_from_chat import GetMeFromChat
|
||||||
|
from .methods.get_members_chat import GetMembersChat
|
||||||
|
from .methods.get_messages import GetMessages
|
||||||
|
from .methods.get_pinned_message import GetPinnedMessage
|
||||||
|
from .methods.get_updates import GetUpdates
|
||||||
|
from .methods.get_upload_url import GetUploadURL
|
||||||
|
from .methods.get_video import GetVideo
|
||||||
|
from .methods.pin_message import PinMessage
|
||||||
|
from .methods.remove_admin import RemoveAdmin
|
||||||
|
from .methods.remove_member_chat import RemoveMemberChat
|
||||||
|
from .methods.send_action import SendAction
|
||||||
|
from .methods.send_callback import SendCallback
|
||||||
|
from .methods.send_message import SendMessage
|
||||||
|
|
||||||
from .connection.base import BaseConnection
|
if TYPE_CHECKING:
|
||||||
|
from .types.attachments.attachment import Attachment
|
||||||
|
from .types.attachments.image import PhotoAttachmentRequestPayload
|
||||||
|
from .types.attachments.video import Video
|
||||||
|
from .types.chats import Chat, ChatMember, Chats
|
||||||
|
from .types.command import BotCommand
|
||||||
|
from .types.message import Message, Messages, NewMessageLink
|
||||||
|
from .types.updates import UpdateUnion
|
||||||
|
from .types.users import ChatAdmin, User
|
||||||
|
|
||||||
from .methods.types.added_admin_chat import AddedListAdminChat
|
from .methods.types.added_admin_chat import AddedListAdminChat
|
||||||
from .methods.types.added_members_chat import AddedMembersChat
|
from .methods.types.added_members_chat import AddedMembersChat
|
||||||
from .methods.types.deleted_bot_from_chat import DeletedBotFromChat
|
from .methods.types.deleted_bot_from_chat import DeletedBotFromChat
|
||||||
from .methods.types.deleted_chat import DeletedChat
|
from .methods.types.deleted_chat import DeletedChat
|
||||||
from .methods.types.deleted_message import DeletedMessage
|
from .methods.types.deleted_message import DeletedMessage
|
||||||
from .methods.types.deleted_pin_message import DeletedPinMessage
|
from .methods.types.deleted_pin_message import DeletedPinMessage
|
||||||
from .methods.types.edited_message import EditedMessage
|
from .methods.types.edited_message import EditedMessage
|
||||||
from .methods.types.getted_list_admin_chat import GettedListAdminChat
|
from .methods.types.getted_list_admin_chat import GettedListAdminChat
|
||||||
from .methods.types.getted_members_chat import GettedMembersChat
|
from .methods.types.getted_members_chat import GettedMembersChat
|
||||||
from .methods.types.getted_pineed_message import GettedPin
|
from .methods.types.getted_pineed_message import GettedPin
|
||||||
from .methods.types.getted_upload_url import GettedUploadUrl
|
from .methods.types.getted_upload_url import GettedUploadUrl
|
||||||
from .methods.types.pinned_message import PinnedMessage
|
from .methods.types.pinned_message import PinnedMessage
|
||||||
from .methods.types.removed_admin import RemovedAdmin
|
from .methods.types.removed_admin import RemovedAdmin
|
||||||
from .methods.types.removed_member_chat import RemovedMemberChat
|
from .methods.types.removed_member_chat import RemovedMemberChat
|
||||||
from .methods.types.sended_action import SendedAction
|
from .methods.types.sended_action import SendedAction
|
||||||
from .methods.types.sended_callback import SendedCallback
|
from .methods.types.sended_callback import SendedCallback
|
||||||
from .methods.types.sended_message import SendedMessage
|
from .methods.types.sended_message import SendedMessage
|
||||||
from .types.attachments.video import Video
|
|
||||||
from .types.chats import Chat, ChatMember, Chats
|
|
||||||
from .types.updates import UpdateUnion
|
|
||||||
|
|
||||||
|
|
||||||
class Bot(BaseConnection):
|
class Bot(BaseConnection):
|
||||||
@ -74,11 +74,21 @@ class Bot(BaseConnection):
|
|||||||
пользователями и другими функциями бота.
|
пользователями и другими функциями бота.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, token: str):
|
def __init__(
|
||||||
|
self,
|
||||||
|
token: str,
|
||||||
|
parse_mode: Optional[ParseMode] = None,
|
||||||
|
notify: Optional[bool] = None,
|
||||||
|
auto_requests: bool = True,
|
||||||
|
):
|
||||||
|
|
||||||
"""Инициализирует экземпляр бота с указанным токеном.
|
"""Инициализирует экземпляр бота с указанным токеном.
|
||||||
|
|
||||||
:param token: Токен доступа к API бота
|
:param token: Токен доступа к API бота
|
||||||
|
:param parse_mode: Форматирование по умолчанию
|
||||||
|
:param notify: Отключение уведомлений при отправке сообщений (по умолчанию игнорируется) (не работает на стороне MAX)
|
||||||
|
:param auto_requests: Автоматическое заполнение полей chat и from_user в Update
|
||||||
|
с помощью API запросов если они не заложены как полноценные объекты в Update (по умолчанию True, при False chat и from_user в некоторых событиях будут выдавать None)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -89,27 +99,35 @@ class Bot(BaseConnection):
|
|||||||
self.params = {'access_token': self.__token}
|
self.params = {'access_token': self.__token}
|
||||||
self.marker_updates = None
|
self.marker_updates = None
|
||||||
|
|
||||||
|
self.parse_mode = parse_mode
|
||||||
|
self.notify = notify
|
||||||
|
self.auto_requests = auto_requests
|
||||||
|
|
||||||
|
def _resolve_notify(self, notify: Optional[bool]) -> Optional[bool]:
|
||||||
|
return notify if notify is not None else self.notify
|
||||||
|
|
||||||
|
def _resolve_parse_mode(self, mode: Optional[ParseMode]) -> Optional[ParseMode]:
|
||||||
|
return mode if mode is not None else self.parse_mode
|
||||||
|
|
||||||
async def send_message(
|
async def send_message(
|
||||||
self,
|
self,
|
||||||
chat_id: int = None,
|
chat_id: int = None,
|
||||||
user_id: int = None,
|
user_id: int = None,
|
||||||
disable_link_preview: bool = False,
|
|
||||||
text: str = None,
|
text: str = None,
|
||||||
attachments: List[Attachment] = None,
|
attachments: List[Attachment] = None,
|
||||||
link: NewMessageLink = None,
|
link: NewMessageLink = None,
|
||||||
notify: bool = True,
|
notify: Optional[bool] = None,
|
||||||
parse_mode: ParseMode = None
|
parse_mode: Optional[ParseMode] = None
|
||||||
) -> SendedMessage:
|
) -> SendedMessage:
|
||||||
|
|
||||||
"""Отправляет сообщение в чат или пользователю.
|
"""Отправляет сообщение в чат или пользователю.
|
||||||
|
|
||||||
:param chat_id: ID чата для отправки (обязателен, если не указан user_id)
|
:param chat_id: ID чата для отправки (обязателен, если не указан user_id)
|
||||||
:param user_id: ID пользователя для отправки (обязателен, если не указан chat_id)
|
:param user_id: ID пользователя для отправки (обязателен, если не указан chat_id)
|
||||||
:param disable_link_preview: Отключить предпросмотр ссылок (по умолчанию False)
|
|
||||||
:param text: Текст сообщения
|
:param text: Текст сообщения
|
||||||
:param attachments: Список вложений к сообщению
|
:param attachments: Список вложений к сообщению
|
||||||
:param link: Данные ссылки сообщения
|
:param link: Данные ссылки сообщения
|
||||||
:param notify: Отправлять уведомление получателю (по умолчанию True)
|
:param notify: Отправлять уведомление получателю (по умолчанию берется значение из бота)
|
||||||
:param parse_mode: Режим форматирования текста
|
:param parse_mode: Режим форматирования текста
|
||||||
|
|
||||||
:return: Объект отправленного сообщения
|
:return: Объект отправленного сообщения
|
||||||
@ -119,12 +137,11 @@ class Bot(BaseConnection):
|
|||||||
bot=self,
|
bot=self,
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
disable_link_preview=disable_link_preview,
|
|
||||||
text=text,
|
text=text,
|
||||||
attachments=attachments,
|
attachments=attachments,
|
||||||
link=link,
|
link=link,
|
||||||
notify=notify,
|
notify=self._resolve_notify(notify),
|
||||||
parse_mode=parse_mode
|
parse_mode=self._resolve_parse_mode(notify)
|
||||||
).request()
|
).request()
|
||||||
|
|
||||||
async def send_action(
|
async def send_action(
|
||||||
@ -153,8 +170,8 @@ class Bot(BaseConnection):
|
|||||||
text: str = None,
|
text: str = None,
|
||||||
attachments: List[Attachment] = None,
|
attachments: List[Attachment] = None,
|
||||||
link: NewMessageLink = None,
|
link: NewMessageLink = None,
|
||||||
notify: bool = True,
|
notify: Optional[bool] = None,
|
||||||
parse_mode: ParseMode = None
|
parse_mode: Optional[ParseMode] = None
|
||||||
) -> EditedMessage:
|
) -> EditedMessage:
|
||||||
|
|
||||||
"""Редактирует существующее сообщение.
|
"""Редактирует существующее сообщение.
|
||||||
@ -163,7 +180,7 @@ class Bot(BaseConnection):
|
|||||||
:param text: Новый текст сообщения
|
:param text: Новый текст сообщения
|
||||||
:param attachments: Новые вложения
|
:param attachments: Новые вложения
|
||||||
:param link: Новая ссылка сообщения
|
:param link: Новая ссылка сообщения
|
||||||
:param notify: Уведомлять получателя об изменении (по умолчанию True)
|
:param notify: Отправлять уведомление получателю (по умолчанию берется значение из бота)
|
||||||
:param parse_mode: Режим форматирования текста
|
:param parse_mode: Режим форматирования текста
|
||||||
|
|
||||||
:return: Объект отредактированного сообщения
|
:return: Объект отредактированного сообщения
|
||||||
@ -175,8 +192,8 @@ class Bot(BaseConnection):
|
|||||||
text=text,
|
text=text,
|
||||||
attachments=attachments,
|
attachments=attachments,
|
||||||
link=link,
|
link=link,
|
||||||
notify=notify,
|
notify=self._resolve_notify(notify),
|
||||||
parse_mode=parse_mode
|
parse_mode=self._resolve_parse_mode(notify)
|
||||||
).request()
|
).request()
|
||||||
|
|
||||||
async def delete_message(
|
async def delete_message(
|
||||||
@ -364,7 +381,7 @@ class Bot(BaseConnection):
|
|||||||
icon: PhotoAttachmentRequestPayload = None,
|
icon: PhotoAttachmentRequestPayload = None,
|
||||||
title: str = None,
|
title: str = None,
|
||||||
pin: str = None,
|
pin: str = None,
|
||||||
notify: bool = True,
|
notify: Optional[bool] = None,
|
||||||
) -> Chat:
|
) -> Chat:
|
||||||
|
|
||||||
"""Редактирует параметры чата.
|
"""Редактирует параметры чата.
|
||||||
@ -373,7 +390,7 @@ class Bot(BaseConnection):
|
|||||||
:param icon: Данные иконки чата
|
:param icon: Данные иконки чата
|
||||||
:param title: Новый заголовок чата
|
:param title: Новый заголовок чата
|
||||||
:param pin: ID сообщения для закрепления
|
:param pin: ID сообщения для закрепления
|
||||||
:param notify: Уведомлять участников (по умолчанию True)
|
:param notify: Отправлять уведомление получателю (по умолчанию берется значение из бота)
|
||||||
|
|
||||||
:return: Обновленный объект чата
|
:return: Обновленный объект чата
|
||||||
"""
|
"""
|
||||||
@ -384,7 +401,7 @@ class Bot(BaseConnection):
|
|||||||
icon=icon,
|
icon=icon,
|
||||||
title=title,
|
title=title,
|
||||||
pin=pin,
|
pin=pin,
|
||||||
notify=notify
|
notify=self._resolve_notify(notify),
|
||||||
).request()
|
).request()
|
||||||
|
|
||||||
async def get_video(
|
async def get_video(
|
||||||
@ -407,7 +424,7 @@ class Bot(BaseConnection):
|
|||||||
async def send_callback(
|
async def send_callback(
|
||||||
self,
|
self,
|
||||||
callback_id: str,
|
callback_id: str,
|
||||||
message: 'Message' = None,
|
message: Message = None,
|
||||||
notification: str = None
|
notification: str = None
|
||||||
) -> SendedCallback:
|
) -> SendedCallback:
|
||||||
|
|
||||||
@ -431,14 +448,14 @@ class Bot(BaseConnection):
|
|||||||
self,
|
self,
|
||||||
chat_id: int,
|
chat_id: int,
|
||||||
message_id: str,
|
message_id: str,
|
||||||
notify: bool = True
|
notify: Optional[bool] = None
|
||||||
) -> PinnedMessage:
|
) -> PinnedMessage:
|
||||||
|
|
||||||
"""Закрепляет сообщение в чате.
|
"""Закрепляет сообщение в чате.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
:param message_id: ID сообщения
|
:param message_id: ID сообщения
|
||||||
:param notify: Уведомлять участников (по умолчанию True)
|
:param notify: Отправлять уведомление получателю (по умолчанию берется значение из бота)
|
||||||
|
|
||||||
:return: Закрепленное сообщение
|
:return: Закрепленное сообщение
|
||||||
"""
|
"""
|
||||||
@ -447,7 +464,7 @@ class Bot(BaseConnection):
|
|||||||
bot=self,
|
bot=self,
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
notify=notify
|
notify=self._resolve_notify(notify),
|
||||||
).request()
|
).request()
|
||||||
|
|
||||||
async def delete_pin_message(
|
async def delete_pin_message(
|
||||||
|
@ -113,8 +113,8 @@ class BaseConnection:
|
|||||||
:return: Сырой .text() ответ от сервера после загрузки файла
|
:return: Сырой .text() ответ от сервера после загрузки файла
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with open(path, 'rb') as f:
|
async with aiofiles.open(path, 'rb') as f:
|
||||||
file_data = f.read()
|
file_data = await f.read()
|
||||||
|
|
||||||
basename = os.path.basename(path)
|
basename = os.path.basename(path)
|
||||||
_, ext = os.path.splitext(basename)
|
_, ext = os.path.splitext(basename)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
from typing import Callable, List
|
import asyncio
|
||||||
|
|
||||||
|
from typing import Any, Callable, Dict, List
|
||||||
|
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
@ -6,6 +8,7 @@ from magic_filter import MagicFilter
|
|||||||
from uvicorn import Config, Server
|
from uvicorn import Config, Server
|
||||||
from aiohttp import ClientConnectorError
|
from aiohttp import ClientConnectorError
|
||||||
|
|
||||||
|
from .filters.middleware import BaseMiddleware
|
||||||
from .filters.handler import Handler
|
from .filters.handler import Handler
|
||||||
|
|
||||||
from .context import MemoryContext
|
from .context import MemoryContext
|
||||||
@ -21,7 +24,8 @@ from .enums.update import UpdateType
|
|||||||
from .loggers import logger_dp
|
from .loggers import logger_dp
|
||||||
|
|
||||||
|
|
||||||
app = FastAPI()
|
webhook_app = FastAPI()
|
||||||
|
CONNECTION_RETRY_DELAY = 30
|
||||||
|
|
||||||
|
|
||||||
class Dispatcher:
|
class Dispatcher:
|
||||||
@ -36,8 +40,10 @@ class Dispatcher:
|
|||||||
self.contexts: List[MemoryContext] = []
|
self.contexts: List[MemoryContext] = []
|
||||||
self.routers: List[Router] = []
|
self.routers: List[Router] = []
|
||||||
self.filters: List[MagicFilter] = []
|
self.filters: List[MagicFilter] = []
|
||||||
self.bot = None
|
self.middlewares: List[BaseMiddleware] = []
|
||||||
self.on_started_func = None
|
|
||||||
|
self.bot: Bot = None
|
||||||
|
self.on_started_func: Callable = None
|
||||||
|
|
||||||
self.message_created = Event(update_type=UpdateType.MESSAGE_CREATED, router=self)
|
self.message_created = Event(update_type=UpdateType.MESSAGE_CREATED, router=self)
|
||||||
self.bot_added = Event(update_type=UpdateType.BOT_ADDED, router=self)
|
self.bot_added = Event(update_type=UpdateType.BOT_ADDED, router=self)
|
||||||
@ -78,7 +84,7 @@ class Dispatcher:
|
|||||||
|
|
||||||
handlers_count = 0
|
handlers_count = 0
|
||||||
for router in self.routers:
|
for router in self.routers:
|
||||||
for handler in router.event_handlers:
|
for _ in router.event_handlers:
|
||||||
handlers_count += 1
|
handlers_count += 1
|
||||||
|
|
||||||
logger_dp.info(f'{handlers_count} событий на обработку')
|
logger_dp.info(f'{handlers_count} событий на обработку')
|
||||||
@ -105,6 +111,30 @@ class Dispatcher:
|
|||||||
new_ctx = MemoryContext(chat_id, user_id)
|
new_ctx = MemoryContext(chat_id, user_id)
|
||||||
self.contexts.append(new_ctx)
|
self.contexts.append(new_ctx)
|
||||||
return new_ctx
|
return new_ctx
|
||||||
|
|
||||||
|
async def process_middlewares(
|
||||||
|
self,
|
||||||
|
middlewares: List[BaseMiddleware],
|
||||||
|
event_object: UpdateUnion,
|
||||||
|
result_data_kwargs: Dict[str, Any]
|
||||||
|
):
|
||||||
|
|
||||||
|
for middleware in middlewares:
|
||||||
|
result = await middleware.process_middleware(
|
||||||
|
event_object=event_object,
|
||||||
|
result_data_kwargs=result_data_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
if result == None or result == False:
|
||||||
|
return
|
||||||
|
|
||||||
|
elif result == True:
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
for key, value in result.items():
|
||||||
|
result_data_kwargs[key] = value
|
||||||
|
|
||||||
|
return result_data_kwargs
|
||||||
|
|
||||||
async def handle(self, event_object: UpdateUnion):
|
async def handle(self, event_object: UpdateUnion):
|
||||||
|
|
||||||
@ -113,54 +143,68 @@ class Dispatcher:
|
|||||||
Args:
|
Args:
|
||||||
event_object: Объект события для обработки
|
event_object: Объект события для обработки
|
||||||
"""
|
"""
|
||||||
ids = event_object.get_ids()
|
try:
|
||||||
|
ids = event_object.get_ids()
|
||||||
is_handled = False
|
memory_context = self.__get_memory_context(*ids)
|
||||||
|
kwargs = {'context': memory_context}
|
||||||
for router in self.routers:
|
|
||||||
|
|
||||||
if is_handled:
|
is_handled = False
|
||||||
break
|
|
||||||
|
|
||||||
if router.filters:
|
for router in self.routers:
|
||||||
if not filter_attrs(event_object, *router.filters):
|
|
||||||
continue
|
if is_handled:
|
||||||
|
break
|
||||||
for handler in router.event_handlers:
|
|
||||||
|
if router.filters:
|
||||||
|
if not filter_attrs(event_object, *router.filters):
|
||||||
|
continue
|
||||||
|
|
||||||
|
kwargs = await self.process_middlewares(
|
||||||
|
middlewares=router.middlewares,
|
||||||
|
event_object=event_object,
|
||||||
|
result_data_kwargs=kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
for handler in router.event_handlers:
|
||||||
|
|
||||||
if not handler.update_type == event_object.update_type:
|
if not handler.update_type == event_object.update_type:
|
||||||
continue
|
|
||||||
|
|
||||||
if handler.filters:
|
|
||||||
if not filter_attrs(event_object, *handler.filters):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
memory_context = self.__get_memory_context(*ids)
|
if handler.filters:
|
||||||
|
if not filter_attrs(event_object, *handler.filters):
|
||||||
if not handler.state == await memory_context.get_state() \
|
continue
|
||||||
and handler.state:
|
|
||||||
continue
|
|
||||||
|
|
||||||
func_args = handler.func_event.__annotations__.keys()
|
|
||||||
|
|
||||||
kwargs = {'context': memory_context}
|
if not handler.state == await memory_context.get_state() \
|
||||||
|
and handler.state:
|
||||||
for key in kwargs.copy().keys():
|
continue
|
||||||
if not key in func_args:
|
|
||||||
del kwargs[key]
|
func_args = handler.func_event.__annotations__.keys()
|
||||||
|
|
||||||
|
kwargs = await self.process_middlewares(
|
||||||
|
middlewares=handler.middlewares,
|
||||||
|
event_object=event_object,
|
||||||
|
result_data_kwargs=kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
if not kwargs:
|
||||||
|
continue
|
||||||
|
|
||||||
if handler.middleware:
|
for key in kwargs.copy().keys():
|
||||||
await handler.middleware()
|
if not key in func_args:
|
||||||
|
del kwargs[key]
|
||||||
|
|
||||||
|
await handler.func_event(event_object, **kwargs)
|
||||||
|
|
||||||
await handler.func_event(event_object, **kwargs)
|
logger_dp.info(f'Обработано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
|
||||||
|
|
||||||
logger_dp.info(f'Обработано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
|
is_handled = True
|
||||||
|
break
|
||||||
|
|
||||||
is_handled = True
|
if not is_handled:
|
||||||
break
|
logger_dp.info(f'Проигнорировано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
|
||||||
|
|
||||||
if not is_handled:
|
except Exception as e:
|
||||||
logger_dp.info(f'Проигнорировано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
|
logger_dp.error(f"Ошибка при обработке события: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]} | {e} ")
|
||||||
|
|
||||||
async def start_polling(self, bot: Bot):
|
async def start_polling(self, bot: Bot):
|
||||||
|
|
||||||
@ -187,12 +231,10 @@ class Dispatcher:
|
|||||||
)
|
)
|
||||||
|
|
||||||
for event in processed_events:
|
for event in processed_events:
|
||||||
try:
|
await self.handle(event)
|
||||||
await self.handle(event)
|
|
||||||
except Exception as e:
|
|
||||||
logger_dp.error(f"Ошибка при обработке события: {event.update_type}: {e}")
|
|
||||||
except ClientConnectorError:
|
except ClientConnectorError:
|
||||||
logger_dp.error(f'Ошибка подключения: {e}')
|
logger_dp.error(f'Ошибка подключения, жду {CONNECTION_RETRY_DELAY} секунд')
|
||||||
|
await asyncio.sleep(CONNECTION_RETRY_DELAY)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger_dp.error(f'Общая ошибка при обработке событий: {e}')
|
logger_dp.error(f'Общая ошибка при обработке событий: {e}')
|
||||||
|
|
||||||
@ -208,7 +250,7 @@ class Dispatcher:
|
|||||||
|
|
||||||
await self.__ready(bot)
|
await self.__ready(bot)
|
||||||
|
|
||||||
@app.post('/')
|
@webhook_app.post('/')
|
||||||
async def _(request: Request):
|
async def _(request: Request):
|
||||||
try:
|
try:
|
||||||
event_json = await request.json()
|
event_json = await request.json()
|
||||||
@ -224,7 +266,7 @@ class Dispatcher:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger_dp.error(f"Ошибка при обработке события: {event_json['update_type']}: {e}")
|
logger_dp.error(f"Ошибка при обработке события: {event_json['update_type']}: {e}")
|
||||||
|
|
||||||
config = Config(app=app, host=host, port=port, log_level="critical")
|
config = Config(app=webhook_app, host=host, port=port, log_level="critical")
|
||||||
server = Server(config)
|
server = Server(config)
|
||||||
|
|
||||||
await server.serve()
|
await server.serve()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import Callable
|
from typing import Callable, List
|
||||||
|
|
||||||
from magic_filter import F, MagicFilter
|
from magic_filter import F, MagicFilter
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ class Handler:
|
|||||||
self.update_type: UpdateType = update_type
|
self.update_type: UpdateType = update_type
|
||||||
self.filters = []
|
self.filters = []
|
||||||
self.state: State = None
|
self.state: State = None
|
||||||
self.middleware: BaseMiddleware = None
|
self.middlewares: List[BaseMiddleware] = []
|
||||||
|
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if isinstance(arg, MagicFilter):
|
if isinstance(arg, MagicFilter):
|
||||||
@ -55,7 +55,7 @@ class Handler:
|
|||||||
elif isinstance(arg, Command):
|
elif isinstance(arg, Command):
|
||||||
self.filters.insert(0, F.message.body.text.startswith(arg.command))
|
self.filters.insert(0, F.message.body.text.startswith(arg.command))
|
||||||
elif isinstance(arg, BaseMiddleware):
|
elif isinstance(arg, BaseMiddleware):
|
||||||
self.middleware = arg
|
self.middlewares.append(arg)
|
||||||
else:
|
else:
|
||||||
logger_dp.info(f'Обнаружен неизвестный фильтр `{arg}` при '
|
logger_dp.info(f'Обнаружен неизвестный фильтр `{arg}` при '
|
||||||
f'регистрации функции `{func_event.__name__}`')
|
f'регистрации функции `{func_event.__name__}`')
|
@ -1,6 +1,23 @@
|
|||||||
|
from typing import Any, Dict
|
||||||
from ..types.updates import UpdateUnion
|
from ..types.updates import UpdateUnion
|
||||||
|
|
||||||
|
|
||||||
class BaseMiddleware:
|
class BaseMiddleware:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
async def process_middleware(
|
||||||
|
self,
|
||||||
|
result_data_kwargs: Dict[str, Any],
|
||||||
|
event_object: UpdateUnion
|
||||||
|
):
|
||||||
|
|
||||||
|
kwargs_temp = {'data': result_data_kwargs.copy()}
|
||||||
|
|
||||||
|
for key in kwargs_temp.copy().keys():
|
||||||
|
if not key in self.__call__.__annotations__.keys():
|
||||||
|
del kwargs_temp[key]
|
||||||
|
|
||||||
|
result: Dict[str, Any] = await self(event_object, **kwargs_temp)
|
||||||
|
|
||||||
|
return result
|
@ -1,4 +1,4 @@
|
|||||||
from typing import List, TYPE_CHECKING
|
from typing import List, TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from .types.edited_message import EditedMessage
|
from .types.edited_message import EditedMessage
|
||||||
from ..types.message import NewMessageLink
|
from ..types.message import NewMessageLink
|
||||||
@ -38,7 +38,7 @@ class EditMessage(BaseConnection):
|
|||||||
attachments: List['Attachment'] = None,
|
attachments: List['Attachment'] = None,
|
||||||
link: 'NewMessageLink' = None,
|
link: 'NewMessageLink' = None,
|
||||||
notify: bool = True,
|
notify: bool = True,
|
||||||
parse_mode: ParseMode = None
|
parse_mode: Optional[ParseMode] = None
|
||||||
):
|
):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.message_id = message_id
|
self.message_id = message_id
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from ..methods.types.sended_callback import SendedCallback
|
from ..methods.types.sended_callback import SendedCallback
|
||||||
@ -37,7 +36,7 @@ class SendCallback(BaseConnection):
|
|||||||
self,
|
self,
|
||||||
bot: 'Bot',
|
bot: 'Bot',
|
||||||
callback_id: str,
|
callback_id: str,
|
||||||
message: 'Message' = None,
|
message: Message = None,
|
||||||
notification: str = None
|
notification: str = None
|
||||||
):
|
):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from typing import List, TYPE_CHECKING
|
from typing import List, TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from json import loads as json_loads
|
from json import loads as json_loads
|
||||||
|
|
||||||
@ -23,10 +23,10 @@ from ..loggers import logger_bot
|
|||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..bot import Bot
|
from ..bot import Bot
|
||||||
|
|
||||||
|
|
||||||
|
RETRY_DELAY = 2
|
||||||
class UploadResponse:
|
ATTEMPTS_COUNT = 5
|
||||||
token: str = None
|
|
||||||
|
|
||||||
|
|
||||||
class SendMessage(BaseConnection):
|
class SendMessage(BaseConnection):
|
||||||
@ -38,7 +38,6 @@ class SendMessage(BaseConnection):
|
|||||||
bot (Bot): Экземпляр бота для выполнения запроса.
|
bot (Bot): Экземпляр бота для выполнения запроса.
|
||||||
chat_id (int, optional): Идентификатор чата, куда отправлять сообщение.
|
chat_id (int, optional): Идентификатор чата, куда отправлять сообщение.
|
||||||
user_id (int, optional): Идентификатор пользователя, если нужно отправить личное сообщение.
|
user_id (int, optional): Идентификатор пользователя, если нужно отправить личное сообщение.
|
||||||
disable_link_preview (bool, optional): Отключить предпросмотр ссылок. По умолчанию False.
|
|
||||||
text (str, optional): Текст сообщения.
|
text (str, optional): Текст сообщения.
|
||||||
attachments (List[Attachment | InputMedia], optional): Список вложений к сообщению.
|
attachments (List[Attachment | InputMedia], optional): Список вложений к сообщению.
|
||||||
link (NewMessageLink, optional): Связь с другим сообщением (например, ответ или пересылка).
|
link (NewMessageLink, optional): Связь с другим сообщением (например, ответ или пересылка).
|
||||||
@ -51,17 +50,15 @@ class SendMessage(BaseConnection):
|
|||||||
bot: 'Bot',
|
bot: 'Bot',
|
||||||
chat_id: int = None,
|
chat_id: int = None,
|
||||||
user_id: int = None,
|
user_id: int = None,
|
||||||
disable_link_preview: bool = False,
|
|
||||||
text: str = None,
|
text: str = None,
|
||||||
attachments: List[Attachment | InputMedia] = None,
|
attachments: List[Attachment | InputMedia] = None,
|
||||||
link: NewMessageLink = None,
|
link: NewMessageLink = None,
|
||||||
notify: bool = True,
|
notify: bool = True,
|
||||||
parse_mode: ParseMode = None
|
parse_mode: Optional[ParseMode] = None
|
||||||
):
|
):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.chat_id = chat_id
|
self.chat_id = chat_id
|
||||||
self.user_id = user_id
|
self.user_id = user_id
|
||||||
self.disable_link_preview = disable_link_preview
|
|
||||||
self.text = text
|
self.text = text
|
||||||
self.attachments = attachments
|
self.attachments = attachments
|
||||||
self.link = link
|
self.link = link
|
||||||
@ -73,6 +70,9 @@ class SendMessage(BaseConnection):
|
|||||||
att: InputMedia
|
att: InputMedia
|
||||||
):
|
):
|
||||||
|
|
||||||
|
# очень нестабильный метод независящий от модуля
|
||||||
|
# ждем обновлений MAX API
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Загружает файл вложения и формирует объект AttachmentUpload.
|
Загружает файл вложения и формирует объект AttachmentUpload.
|
||||||
|
|
||||||
@ -129,7 +129,6 @@ class SendMessage(BaseConnection):
|
|||||||
elif self.user_id: params['user_id'] = self.user_id
|
elif self.user_id: params['user_id'] = self.user_id
|
||||||
|
|
||||||
json['text'] = self.text
|
json['text'] = self.text
|
||||||
json['disable_link_preview'] = str(self.disable_link_preview).lower()
|
|
||||||
|
|
||||||
if self.attachments:
|
if self.attachments:
|
||||||
|
|
||||||
@ -144,11 +143,11 @@ class SendMessage(BaseConnection):
|
|||||||
json['attachments'].append(att.model_dump())
|
json['attachments'].append(att.model_dump())
|
||||||
|
|
||||||
if not self.link is None: json['link'] = self.link.model_dump()
|
if not self.link is None: json['link'] = self.link.model_dump()
|
||||||
if not self.notify is None: json['notify'] = self.notify
|
json['notify'] = self.notify
|
||||||
if not self.parse_mode is None: json['format'] = self.parse_mode.value
|
if not self.parse_mode is None: json['format'] = self.parse_mode.value
|
||||||
|
|
||||||
response = None
|
response = None
|
||||||
for attempt in range(5):
|
for attempt in range(ATTEMPTS_COUNT):
|
||||||
response = await super().request(
|
response = await super().request(
|
||||||
method=HTTPMethod.POST,
|
method=HTTPMethod.POST,
|
||||||
path=ApiPath.MESSAGES,
|
path=ApiPath.MESSAGES,
|
||||||
@ -159,8 +158,8 @@ class SendMessage(BaseConnection):
|
|||||||
|
|
||||||
if isinstance(response, Error):
|
if isinstance(response, Error):
|
||||||
if response.raw.get('code') == 'attachment.not.ready':
|
if response.raw.get('code') == 'attachment.not.ready':
|
||||||
logger_bot.info(f'Ошибка при отправке загруженного медиа, попытка {attempt+1}, жду 2 секунды')
|
logger_bot.info(f'Ошибка при отправке загруженного медиа, попытка {attempt+1}, жду {RETRY_DELAY} секунды')
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(RETRY_DELAY)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
@ -36,7 +36,10 @@ async def get_update_model(event: dict, bot: 'Bot'):
|
|||||||
|
|
||||||
case UpdateType.MESSAGE_CALLBACK:
|
case UpdateType.MESSAGE_CALLBACK:
|
||||||
event_object = MessageCallback(**event)
|
event_object = MessageCallback(**event)
|
||||||
event_object.chat = await bot.get_chat_by_id(event_object.message.recipient.chat_id)
|
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.message.recipient.chat_id) \
|
||||||
|
if bot.auto_requests else None
|
||||||
|
|
||||||
event_object.from_user = event_object.callback.user
|
event_object.from_user = event_object.callback.user
|
||||||
|
|
||||||
case UpdateType.MESSAGE_CHAT_CREATED:
|
case UpdateType.MESSAGE_CHAT_CREATED:
|
||||||
@ -45,40 +48,59 @@ async def get_update_model(event: dict, bot: 'Bot'):
|
|||||||
|
|
||||||
case UpdateType.MESSAGE_CREATED:
|
case UpdateType.MESSAGE_CREATED:
|
||||||
event_object = MessageCreated(**event)
|
event_object = MessageCreated(**event)
|
||||||
event_object.chat = await bot.get_chat_by_id(event_object.message.recipient.chat_id)
|
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.message.recipient.chat_id) \
|
||||||
|
if bot.auto_requests else None
|
||||||
|
|
||||||
event_object.from_user = event_object.message.sender
|
event_object.from_user = event_object.message.sender
|
||||||
|
|
||||||
case UpdateType.MESSAGE_EDITED:
|
case UpdateType.MESSAGE_EDITED:
|
||||||
event_object = MessageEdited(**event)
|
event_object = MessageEdited(**event)
|
||||||
event_object.chat = await bot.get_chat_by_id(event_object.message.recipient.chat_id)
|
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.message.recipient.chat_id) \
|
||||||
|
if bot.auto_requests else None
|
||||||
|
|
||||||
event_object.from_user = event_object.message.sender
|
event_object.from_user = event_object.message.sender
|
||||||
|
|
||||||
case UpdateType.MESSAGE_REMOVED:
|
case UpdateType.MESSAGE_REMOVED:
|
||||||
event_object = MessageRemoved(**event)
|
event_object = MessageRemoved(**event)
|
||||||
event_object.chat = await bot.get_chat_by_id(event_object.chat_id)
|
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.chat_id) \
|
||||||
|
if bot.auto_requests else None
|
||||||
|
|
||||||
event_object.from_user = await bot.get_chat_member(
|
event_object.from_user = await bot.get_chat_member(
|
||||||
chat_id=event_object.chat_id,
|
chat_id=event_object.chat_id,
|
||||||
user_id=event_object.user_id
|
user_id=event_object.user_id
|
||||||
)
|
) if bot.auto_requests else None
|
||||||
|
|
||||||
case UpdateType.USER_ADDED:
|
case UpdateType.USER_ADDED:
|
||||||
event_object = UserAdded(**event)
|
event_object = UserAdded(**event)
|
||||||
event_object.chat = await bot.get_chat_by_id(event_object.chat_id)
|
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.chat_id) \
|
||||||
|
if bot.auto_requests else None
|
||||||
|
|
||||||
event_object.from_user = event_object.user
|
event_object.from_user = event_object.user
|
||||||
|
|
||||||
case UpdateType.USER_REMOVED:
|
case UpdateType.USER_REMOVED:
|
||||||
event_object = UserRemoved(**event)
|
event_object = UserRemoved(**event)
|
||||||
event_object.chat = await bot.get_chat_by_id(event_object.chat_id)
|
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.chat_id) \
|
||||||
|
if bot.auto_requests else None
|
||||||
|
|
||||||
event_object.from_user = await bot.get_chat_member(
|
event_object.from_user = await bot.get_chat_member(
|
||||||
chat_id=event_object.chat_id,
|
chat_id=event_object.chat_id,
|
||||||
user_id=event_object.admin_id
|
user_id=event_object.admin_id
|
||||||
) if event_object.admin_id else None
|
) if event_object.admin_id and \
|
||||||
|
bot.auto_requests else None
|
||||||
|
|
||||||
if event['update_type'] in (UpdateType.BOT_ADDED,
|
if event['update_type'] in (UpdateType.BOT_ADDED,
|
||||||
UpdateType.BOT_REMOVED,
|
UpdateType.BOT_REMOVED,
|
||||||
UpdateType.BOT_STARTED,
|
UpdateType.BOT_STARTED,
|
||||||
UpdateType.CHAT_TITLE_CHANGED):
|
UpdateType.CHAT_TITLE_CHANGED):
|
||||||
event_object.chat = await bot.get_chat_by_id(event_object.chat_id)
|
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.chat_id) \
|
||||||
|
if bot.auto_requests else None
|
||||||
|
|
||||||
event_object.from_user = event_object.user
|
event_object.from_user = event_object.user
|
||||||
|
|
||||||
if hasattr(event_object, 'bot'):
|
if hasattr(event_object, 'bot'):
|
||||||
|
@ -9,6 +9,7 @@ from ..types.updates.message_edited import MessageEdited
|
|||||||
from ..types.updates.message_removed import MessageRemoved
|
from ..types.updates.message_removed import MessageRemoved
|
||||||
from ..types.updates.user_added import UserAdded
|
from ..types.updates.user_added import UserAdded
|
||||||
from ..types.updates.user_removed import UserRemoved
|
from ..types.updates.user_removed import UserRemoved
|
||||||
|
from ..types.updates import UpdateUnion
|
||||||
|
|
||||||
from ..types.attachments.attachment import PhotoAttachmentPayload
|
from ..types.attachments.attachment import PhotoAttachmentPayload
|
||||||
from ..types.attachments.attachment import OtherAttachmentPayload
|
from ..types.attachments.attachment import OtherAttachmentPayload
|
||||||
@ -20,12 +21,14 @@ from ..types.attachments.buttons.chat_button import ChatButton
|
|||||||
from ..types.attachments.buttons.link_button import LinkButton
|
from ..types.attachments.buttons.link_button import LinkButton
|
||||||
from ..types.attachments.buttons.request_contact import RequestContact
|
from ..types.attachments.buttons.request_contact import RequestContact
|
||||||
from ..types.attachments.buttons.request_geo_location_button import RequestGeoLocationButton
|
from ..types.attachments.buttons.request_geo_location_button import RequestGeoLocationButton
|
||||||
|
from ..types.message import Message
|
||||||
|
|
||||||
from ..types.command import Command, BotCommand
|
from ..types.command import Command, BotCommand
|
||||||
|
|
||||||
from .input_media import InputMedia
|
from .input_media import InputMedia
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
UpdateUnion,
|
||||||
InputMedia,
|
InputMedia,
|
||||||
BotCommand,
|
BotCommand,
|
||||||
CallbackButton,
|
CallbackButton,
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from ....enums.button_type import ButtonType
|
||||||
|
|
||||||
from .button import Button
|
from .button import Button
|
||||||
|
|
||||||
|
|
||||||
@ -7,7 +9,6 @@ class ChatButton(Button):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
Attributes:
|
Attributes:
|
||||||
type: Тип кнопки (наследуется от Button)
|
|
||||||
text: Текст кнопки (наследуется от Button)
|
text: Текст кнопки (наследуется от Button)
|
||||||
chat_title: Название чата (до 128 символов)
|
chat_title: Название чата (до 128 символов)
|
||||||
chat_description: Описание чата (до 256 символов)
|
chat_description: Описание чата (до 256 символов)
|
||||||
@ -15,6 +16,7 @@ class ChatButton(Button):
|
|||||||
uuid: Уникальный идентификатор чата
|
uuid: Уникальный идентификатор чата
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
type: ButtonType = ButtonType.CHAT
|
||||||
chat_title: Optional[str] = None
|
chat_title: Optional[str] = None
|
||||||
chat_description: Optional[str] = None
|
chat_description: Optional[str] = None
|
||||||
start_payload: Optional[str] = None
|
start_payload: Optional[str] = None
|
||||||
|
@ -169,21 +169,20 @@ class Message(BaseModel):
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
bot: Optional[Bot]
|
bot: Optional[Bot]
|
||||||
|
|
||||||
async def answer(self,
|
async def answer(
|
||||||
|
self,
|
||||||
text: str = None,
|
text: str = None,
|
||||||
disable_link_preview: bool = False,
|
|
||||||
attachments: List[Attachment] = None,
|
attachments: List[Attachment] = None,
|
||||||
link: NewMessageLink = None,
|
link: NewMessageLink = None,
|
||||||
notify: bool = True,
|
notify: Optional[bool] = None,
|
||||||
parse_mode: ParseMode = None
|
parse_mode: Optional[ParseMode] = None
|
||||||
):
|
):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Отправляет ответное сообщение.
|
Отправляет сообщение (автозаполнение chat_id, user_id).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
text (str, optional): Текст ответа. Может быть None.
|
text (str, optional): Текст ответа. Может быть None.
|
||||||
disable_link_preview (bool): Отключить предпросмотр ссылок. По умолчанию False.
|
|
||||||
attachments (List[Attachment], optional): Список вложений. Может быть None.
|
attachments (List[Attachment], optional): Список вложений. Может быть None.
|
||||||
link (NewMessageLink, optional): Связь с другим сообщением. Может быть None.
|
link (NewMessageLink, optional): Связь с другим сообщением. Может быть None.
|
||||||
notify (bool): Флаг отправки уведомления. По умолчанию True.
|
notify (bool): Флаг отправки уведомления. По умолчанию True.
|
||||||
@ -197,12 +196,80 @@ class Message(BaseModel):
|
|||||||
chat_id=self.recipient.chat_id,
|
chat_id=self.recipient.chat_id,
|
||||||
user_id=self.recipient.user_id,
|
user_id=self.recipient.user_id,
|
||||||
text=text,
|
text=text,
|
||||||
disable_link_preview=disable_link_preview,
|
|
||||||
attachments=attachments,
|
attachments=attachments,
|
||||||
link=link,
|
link=link,
|
||||||
notify=notify,
|
notify=notify,
|
||||||
parse_mode=parse_mode
|
parse_mode=parse_mode
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def reply(
|
||||||
|
self,
|
||||||
|
text: str = None,
|
||||||
|
attachments: List[Attachment] = None,
|
||||||
|
notify: Optional[bool] = None,
|
||||||
|
parse_mode: Optional[ParseMode] = None
|
||||||
|
):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Отправляет ответное сообщение (автозаполнение chat_id, user_id, link).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str, optional): Текст ответа. Может быть None.
|
||||||
|
attachments (List[Attachment], optional): Список вложений. Может быть None.
|
||||||
|
notify (bool): Флаг отправки уведомления. По умолчанию True.
|
||||||
|
parse_mode (ParseMode, optional): Режим форматирования текста. Может быть None.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Any: Результат выполнения метода send_message бота.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return await self.bot.send_message(
|
||||||
|
chat_id=self.recipient.chat_id,
|
||||||
|
user_id=self.recipient.user_id,
|
||||||
|
text=text,
|
||||||
|
attachments=attachments,
|
||||||
|
link=NewMessageLink(
|
||||||
|
type=MessageLinkType.REPLY,
|
||||||
|
mid=self.body.mid
|
||||||
|
),
|
||||||
|
notify=notify,
|
||||||
|
parse_mode=parse_mode
|
||||||
|
)
|
||||||
|
|
||||||
|
async def forward(
|
||||||
|
self,
|
||||||
|
chat_id,
|
||||||
|
user_id: int = None,
|
||||||
|
attachments: List[Attachment] = None,
|
||||||
|
notify: Optional[bool] = None,
|
||||||
|
parse_mode: Optional[ParseMode] = None
|
||||||
|
):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Пересылает отправленное сообщение в указанный чат (автозаполнение link).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (int): ID чата для отправки (обязателен, если не указан user_id)
|
||||||
|
user_id (int): ID пользователя для отправки (обязателен, если не указан chat_id). По умолчанию None
|
||||||
|
attachments (List[Attachment], optional): Список вложений. Может быть None.
|
||||||
|
notify (bool): Флаг отправки уведомления. По умолчанию True.
|
||||||
|
parse_mode (ParseMode, optional): Режим форматирования текста. Может быть None.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Any: Результат выполнения метода send_message бота.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return await self.bot.send_message(
|
||||||
|
chat_id=chat_id,
|
||||||
|
user_id=user_id,
|
||||||
|
attachments=attachments,
|
||||||
|
link=NewMessageLink(
|
||||||
|
type=MessageLinkType.FORWARD,
|
||||||
|
mid=self.body.mid
|
||||||
|
),
|
||||||
|
notify=notify,
|
||||||
|
parse_mode=parse_mode
|
||||||
|
)
|
||||||
|
|
||||||
async def edit(
|
async def edit(
|
||||||
self,
|
self,
|
||||||
@ -210,7 +277,7 @@ class Message(BaseModel):
|
|||||||
attachments: List[Attachment] = None,
|
attachments: List[Attachment] = None,
|
||||||
link: NewMessageLink = None,
|
link: NewMessageLink = None,
|
||||||
notify: bool = True,
|
notify: bool = True,
|
||||||
parse_mode: ParseMode = None
|
parse_mode: Optional[ParseMode] = None
|
||||||
):
|
):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -90,7 +90,7 @@ class MessageCallback(Update):
|
|||||||
new_text: str = None,
|
new_text: str = None,
|
||||||
link: NewMessageLink = None,
|
link: NewMessageLink = None,
|
||||||
notify: bool = True,
|
notify: bool = True,
|
||||||
format: ParseMode = None,
|
format: Optional[ParseMode] = None,
|
||||||
):
|
):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from maxapi.types.attachments.buttons import InlineButtonUnion
|
from ..types.attachments.buttons import InlineButtonUnion
|
||||||
from ..enums.attachment import AttachmentType
|
from ..enums.attachment import AttachmentType
|
||||||
from ..types.attachments.attachment import Attachment, ButtonsPayload
|
from ..types.attachments.attachment import Attachment, ButtonsPayload
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "maxapi"
|
name = "maxapi"
|
||||||
version = "0.8.3"
|
version = "0.8.5"
|
||||||
description = "Библиотека для разработки чат-ботов с помощью API мессенджера MAX"
|
description = "Библиотека для разработки чат-ботов с помощью API мессенджера MAX"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
@ -18,6 +18,7 @@ dependencies = [
|
|||||||
"magic_filter>=1.0.0",
|
"magic_filter>=1.0.0",
|
||||||
"pydantic>=1.8.0",
|
"pydantic>=1.8.0",
|
||||||
"uvicorn>=0.15.0",
|
"uvicorn>=0.15.0",
|
||||||
|
"aiofiles==24.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user