Добавлены примеры и обновлена модель Update
This commit is contained in:
parent
ab52abc474
commit
ee58238261
84
README.md
84
README.md
@ -1,84 +0,0 @@
|
|||||||
# Асинхронный MAX API
|
|
||||||
|
|
||||||
[](https://pypi.org/project/maxapi/)
|
|
||||||
[](https://pypi.org/project/maxapi/)
|
|
||||||
[](https://love-apples/maxapi/blob/main/LICENSE)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📦 Установка
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install maxapi
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Быстрый старт
|
|
||||||
|
|
||||||
```python
|
|
||||||
import asyncio
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from maxapi import Bot, Dispatcher
|
|
||||||
from maxapi.types import BotStarted, Command, MessageCreated
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
|
||||||
|
|
||||||
bot = Bot('тут_ваш_токен')
|
|
||||||
dp = Dispatcher()
|
|
||||||
|
|
||||||
|
|
||||||
@dp.bot_started()
|
|
||||||
async def bot_started(event: BotStarted):
|
|
||||||
await event.bot.send_message(
|
|
||||||
chat_id=event.chat_id,
|
|
||||||
text='Привет! Отправь мне /start'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@dp.message_created(Command('start'))
|
|
||||||
async def hello(event: MessageCreated):
|
|
||||||
await event.message.answer(f"Пример чат-бота для MAX 💙")
|
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
await dp.start_polling(bot)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
asyncio.run(main())
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 Документация
|
|
||||||
|
|
||||||
В разработке...
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧩 Возможности
|
|
||||||
|
|
||||||
- ✅ Роутеры
|
|
||||||
- ✅ Билдер инлайн клавиатур
|
|
||||||
- ✅ Простая загрузка медиафайлов
|
|
||||||
- ✅ MagicFilter
|
|
||||||
- ✅ Внутренние функции моделей
|
|
||||||
- ✅ Контекстный менеджер
|
|
||||||
- ✅ Поллинг
|
|
||||||
- ✅ Вебхук
|
|
||||||
- ✅ Логгирование
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
## 💬 Обратная связь и поддержка
|
|
||||||
|
|
||||||
- MAX: [Чат](https://max.ru/join/IPAok63C3vFqbWTFdutMUtjmrAkGqO56YeAN7iyDfc8)
|
|
||||||
- Telegram: [@loveappless](https://t.me/loveappless)
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📄 Лицензия
|
|
||||||
|
|
||||||
Этот проект распространяется под лицензией MIT. См. файл [LICENSE](LICENSE) для подробностей.
|
|
@ -1,31 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from maxapi import Bot, Dispatcher
|
|
||||||
from maxapi.types import BotStarted, Command, MessageCreated
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
|
||||||
|
|
||||||
bot = Bot('тут_ваш_токен')
|
|
||||||
dp = Dispatcher()
|
|
||||||
|
|
||||||
|
|
||||||
@dp.bot_started()
|
|
||||||
async def bot_started(event: BotStarted):
|
|
||||||
await event.bot.send_message(
|
|
||||||
chat_id=event.chat_id,
|
|
||||||
text='Привет! Отправь мне /start'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@dp.message_created(Command('start'))
|
|
||||||
async def hello(event: MessageCreated):
|
|
||||||
await event.message.answer(f"Пример чат-бота для MAX 💙")
|
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
await dp.start_polling(bot)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
asyncio.run(main())
|
|
24
examples/echo/main.py
Normal file
24
examples/echo/main.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from maxapi import Bot, Dispatcher
|
||||||
|
from maxapi.filters import F
|
||||||
|
from maxapi.types import MessageCreated
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
bot = Bot('тут_ваш_токен')
|
||||||
|
dp = Dispatcher()
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(F.message.body.text)
|
||||||
|
async def echo(event: MessageCreated):
|
||||||
|
await event.message.answer(f"Повторяю за вами: {event.message.body.text}")
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await dp.start_polling(bot)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
122
examples/events/main.py
Normal file
122
examples/events/main.py
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from maxapi import Bot, Dispatcher
|
||||||
|
from maxapi.types import (
|
||||||
|
BotStarted,
|
||||||
|
Command,
|
||||||
|
MessageCreated,
|
||||||
|
CallbackButton,
|
||||||
|
MessageCallback,
|
||||||
|
BotAdded,
|
||||||
|
ChatTitleChanged,
|
||||||
|
MessageEdited,
|
||||||
|
MessageRemoved,
|
||||||
|
UserAdded,
|
||||||
|
UserRemoved
|
||||||
|
)
|
||||||
|
from maxapi.utils.inline_keyboard import InlineKeyboardBuilder
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
bot = Bot('тут_ваш_токен')
|
||||||
|
dp = Dispatcher()
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(Command('start'))
|
||||||
|
async def hello(event: MessageCreated):
|
||||||
|
builder = InlineKeyboardBuilder()
|
||||||
|
|
||||||
|
builder.row(
|
||||||
|
CallbackButton(
|
||||||
|
text='Кнопка 1',
|
||||||
|
payload='btn_1'
|
||||||
|
),
|
||||||
|
CallbackButton(
|
||||||
|
text='Кнопка 2',
|
||||||
|
payload='btn_2',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
builder.add(
|
||||||
|
CallbackButton(
|
||||||
|
text='Кнопка 3',
|
||||||
|
payload='btn_3',
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
await event.message.answer(
|
||||||
|
text='Привет!',
|
||||||
|
attachments=[
|
||||||
|
builder.as_markup(),
|
||||||
|
] # Для MAX клавиатура это вложение,
|
||||||
|
) # поэтому она в списке вложений
|
||||||
|
|
||||||
|
|
||||||
|
@dp.bot_added()
|
||||||
|
async def bot_added(event: BotAdded):
|
||||||
|
await event.bot.send_message(
|
||||||
|
chat_id=event.chat.id,
|
||||||
|
text=f'Привет чат {event.chat.title}!'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_removed()
|
||||||
|
async def message_removed(event: MessageRemoved):
|
||||||
|
await event.bot.send_message(
|
||||||
|
chat_id=event.chat_id,
|
||||||
|
text='Я всё видел!'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.bot_started()
|
||||||
|
async def bot_started(event: BotStarted):
|
||||||
|
await event.bot.send_message(
|
||||||
|
chat_id=event.chat_id,
|
||||||
|
text='Привет! Отправь мне /start'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.chat_title_changed()
|
||||||
|
async def chat_title_changed(event: ChatTitleChanged):
|
||||||
|
await event.bot.send_message(
|
||||||
|
chat_id=event.chat_id,
|
||||||
|
text=f'Крутое новое название "{event.chat.title}!"'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_callback()
|
||||||
|
async def message_callback(event: MessageCallback):
|
||||||
|
await event.answer(
|
||||||
|
new_text=f'Вы нажали на кнопку {event.callback.payload}!'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_edited()
|
||||||
|
async def message_edited(event: MessageEdited):
|
||||||
|
await event.message.answer(
|
||||||
|
text='Вы отредактировали сообщение!'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.user_removed()
|
||||||
|
async def user_removed(event: UserRemoved):
|
||||||
|
await event.bot.send_message(
|
||||||
|
chat_id=event.chat_id,
|
||||||
|
text=f'{event.from_user.first_name} кикнул {event.user.first_name} 😢'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.user_added()
|
||||||
|
async def user_added(event: UserAdded):
|
||||||
|
await event.bot.send_message(
|
||||||
|
chat_id=event.chat_id,
|
||||||
|
text=f'Чат "{event.chat.title}" приветствует вас, {event.user.first_name}!'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await dp.start_polling(bot)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
48
examples/magic_filters/magic_filters.py
Normal file
48
examples/magic_filters/magic_filters.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from maxapi import Bot, Dispatcher, F
|
||||||
|
from maxapi.types import MessageCreated
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
bot = Bot('тут_ваш_токен')
|
||||||
|
dp = Dispatcher()
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(F.message.body.text == 'привет')
|
||||||
|
async def on_hello(event: MessageCreated):
|
||||||
|
await event.message.answer('Привет!')
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(F.message.body.text.lower().contains('помощь'))
|
||||||
|
async def on_help(event: MessageCreated):
|
||||||
|
await event.message.answer('Чем могу помочь?')
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(F.message.body.text.regexp(r'^\d{4}$'))
|
||||||
|
async def on_code(event: MessageCreated):
|
||||||
|
await event.message.answer('Принят 4-значный код')
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(F.message.body.attachments)
|
||||||
|
async def on_attachment(event: MessageCreated):
|
||||||
|
await event.message.answer('Получено вложение')
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(F.message.body.text.len() > 20)
|
||||||
|
async def on_long_text(event: MessageCreated):
|
||||||
|
await event.message.answer('Слишком длинное сообщение')
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_created(F.message.body.text.len() > 0)
|
||||||
|
async def on_non_empty(event: MessageCreated):
|
||||||
|
await event.message.answer('Вы что-то написали.')
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await dp.start_polling(bot)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
@ -6,7 +6,7 @@ from maxapi.context import MemoryContext, State, StatesGroup
|
|||||||
from maxapi.types import BotStarted, Command, MessageCreated, CallbackButton, MessageCallback, BotCommand
|
from maxapi.types import BotStarted, Command, MessageCreated, CallbackButton, MessageCallback, BotCommand
|
||||||
from maxapi.utils.inline_keyboard import InlineKeyboardBuilder
|
from maxapi.utils.inline_keyboard import InlineKeyboardBuilder
|
||||||
|
|
||||||
from example.router_for_example import router
|
from router import router
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
@ -158,4 +158,5 @@ async def main():
|
|||||||
# )
|
# )
|
||||||
|
|
||||||
|
|
||||||
asyncio.run(main())
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
@ -1,6 +1,8 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, Dict, List, TYPE_CHECKING
|
from typing import Any, Dict, List, TYPE_CHECKING
|
||||||
|
|
||||||
|
from maxapi.methods.download_media import DownloadMedia
|
||||||
|
|
||||||
from .methods.get_upload_url import GetUploadURL
|
from .methods.get_upload_url import GetUploadURL
|
||||||
from .methods.get_updates import GetUpdates
|
from .methods.get_updates import GetUpdates
|
||||||
from .methods.remove_member_chat import RemoveMemberChat
|
from .methods.remove_member_chat import RemoveMemberChat
|
||||||
@ -570,7 +572,7 @@ class Bot(BaseConnection):
|
|||||||
"""Получает участников чата.
|
"""Получает участников чата.
|
||||||
|
|
||||||
:param chat_id: ID чата
|
:param chat_id: ID чата
|
||||||
:param user_ids: Фильтр по ID пользователей
|
:param user_ids: Список ID участников
|
||||||
:param marker: Маркер для пагинации
|
:param marker: Маркер для пагинации
|
||||||
:param count: Количество участников
|
:param count: Количество участников
|
||||||
|
|
||||||
@ -585,6 +587,28 @@ class Bot(BaseConnection):
|
|||||||
count=count,
|
count=count,
|
||||||
).request()
|
).request()
|
||||||
|
|
||||||
|
async def get_chat_member(
|
||||||
|
self,
|
||||||
|
chat_id: int,
|
||||||
|
user_id: int,
|
||||||
|
) -> GettedMembersChat:
|
||||||
|
|
||||||
|
"""Получает участника чата.
|
||||||
|
|
||||||
|
:param chat_id: ID чата
|
||||||
|
:param user_id: ID участника
|
||||||
|
|
||||||
|
:return: Участник
|
||||||
|
"""
|
||||||
|
|
||||||
|
members = await self.get_chat_members(
|
||||||
|
chat_id=chat_id,
|
||||||
|
user_ids=[user_id]
|
||||||
|
)
|
||||||
|
|
||||||
|
if members.members:
|
||||||
|
return members.members[0]
|
||||||
|
|
||||||
async def add_chat_members(
|
async def add_chat_members(
|
||||||
self,
|
self,
|
||||||
chat_id: int,
|
chat_id: int,
|
||||||
@ -674,3 +698,27 @@ class Bot(BaseConnection):
|
|||||||
bot=self,
|
bot=self,
|
||||||
commands=list(commands)
|
commands=list(commands)
|
||||||
).request()
|
).request()
|
||||||
|
|
||||||
|
async def download_file(
|
||||||
|
self,
|
||||||
|
path: str,
|
||||||
|
url: str,
|
||||||
|
token: str
|
||||||
|
):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Скачивает медиа с указанной ссылки по токену, сохраняя по определенному пути
|
||||||
|
|
||||||
|
:param path: Путь сохранения медиа
|
||||||
|
:param url: Ссылка на медиа
|
||||||
|
:param token: Токен медиа
|
||||||
|
|
||||||
|
:return: Числовой статус
|
||||||
|
"""
|
||||||
|
|
||||||
|
return await DownloadMedia(
|
||||||
|
bot=self,
|
||||||
|
path=path,
|
||||||
|
media_url=url,
|
||||||
|
media_token=token
|
||||||
|
).request()
|
@ -1,13 +1,19 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import aiofiles
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from ..exceptions.invalid_token import InvalidToken
|
||||||
|
|
||||||
from ..types.errors import Error
|
from ..types.errors import Error
|
||||||
from ..enums.http_method import HTTPMethod
|
from ..enums.http_method import HTTPMethod
|
||||||
from ..enums.api_path import ApiPath
|
from ..enums.api_path import ApiPath
|
||||||
from ..enums.upload_type import UploadType
|
from ..enums.upload_type import UploadType
|
||||||
|
|
||||||
from ..loggers import logger_bot, logger_connection
|
from ..loggers import logger_bot, logger_connection
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -66,6 +72,9 @@ class BaseConnection:
|
|||||||
except aiohttp.ClientConnectorDNSError as e:
|
except aiohttp.ClientConnectorDNSError as e:
|
||||||
return logger_connection.error(f'Ошибка при отправке запроса: {e}')
|
return logger_connection.error(f'Ошибка при отправке запроса: {e}')
|
||||||
|
|
||||||
|
if r.status == 401:
|
||||||
|
raise InvalidToken('Неверный токен!')
|
||||||
|
|
||||||
if not r.ok:
|
if not r.ok:
|
||||||
raw = await r.json()
|
raw = await r.json()
|
||||||
error = Error(code=r.status, raw=raw)
|
error = Error(code=r.status, raw=raw)
|
||||||
@ -125,3 +134,32 @@ class BaseConnection:
|
|||||||
)
|
)
|
||||||
|
|
||||||
return await response.text()
|
return await response.text()
|
||||||
|
|
||||||
|
async def download_file(
|
||||||
|
self,
|
||||||
|
path: str,
|
||||||
|
url: str,
|
||||||
|
token: str,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Скачивает медиа с указанной ссылки по токену, сохраняя по определенному пути
|
||||||
|
|
||||||
|
:param path: Путь сохранения медиа
|
||||||
|
:param url: Ссылка на медиа
|
||||||
|
:param token: Токен медиа
|
||||||
|
|
||||||
|
:return: Числовой статус
|
||||||
|
"""
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Authorization': f'Bearer {token}'
|
||||||
|
}
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.get(url, headers=headers) as response:
|
||||||
|
|
||||||
|
if response.status == 200:
|
||||||
|
async with aiofiles.open(path, 'wb') as f:
|
||||||
|
await f.write(await response.read())
|
||||||
|
|
||||||
|
return response.status
|
@ -2,6 +2,7 @@ from typing import Callable, List
|
|||||||
|
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
from magic_filter import MagicFilter
|
||||||
from uvicorn import Config, Server
|
from uvicorn import Config, Server
|
||||||
from aiohttp import ClientConnectorError
|
from aiohttp import ClientConnectorError
|
||||||
|
|
||||||
@ -33,6 +34,8 @@ class Dispatcher:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.event_handlers: List[Handler] = []
|
self.event_handlers: List[Handler] = []
|
||||||
self.contexts: List[MemoryContext] = []
|
self.contexts: List[MemoryContext] = []
|
||||||
|
self.routers: List[Router] = []
|
||||||
|
self.filters: List[MagicFilter] = []
|
||||||
self.bot = None
|
self.bot = None
|
||||||
self.on_started_func = None
|
self.on_started_func = None
|
||||||
|
|
||||||
@ -65,8 +68,23 @@ class Dispatcher:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
for router in routers:
|
for router in routers:
|
||||||
for event in router.event_handlers:
|
self.routers.append(router)
|
||||||
self.event_handlers.append(event)
|
|
||||||
|
async def __ready(self, bot: Bot):
|
||||||
|
self.bot = bot
|
||||||
|
await self.check_me()
|
||||||
|
|
||||||
|
self.routers += [self]
|
||||||
|
|
||||||
|
handlers_count = 0
|
||||||
|
for router in self.routers:
|
||||||
|
for handler in router.event_handlers:
|
||||||
|
handlers_count += 1
|
||||||
|
|
||||||
|
logger_dp.info(f'{handlers_count} событий на обработку')
|
||||||
|
|
||||||
|
if self.on_started_func:
|
||||||
|
await self.on_started_func()
|
||||||
|
|
||||||
def __get_memory_context(self, chat_id: int, user_id: int):
|
def __get_memory_context(self, chat_id: int, user_id: int):
|
||||||
|
|
||||||
@ -95,40 +113,51 @@ class Dispatcher:
|
|||||||
Args:
|
Args:
|
||||||
event_object: Объект события для обработки
|
event_object: Объект события для обработки
|
||||||
"""
|
"""
|
||||||
|
ids = event_object.get_ids()
|
||||||
|
|
||||||
is_handled = False
|
is_handled = False
|
||||||
|
|
||||||
for handler in self.event_handlers:
|
for router in self.routers:
|
||||||
|
|
||||||
if not handler.update_type == event_object.update_type:
|
if is_handled:
|
||||||
continue
|
break
|
||||||
|
|
||||||
if handler.filters:
|
if router.filters:
|
||||||
if not filter_attrs(event_object, *handler.filters):
|
if not filter_attrs(event_object, *router.filters):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ids = event_object.get_ids()
|
for handler in router.event_handlers:
|
||||||
|
|
||||||
memory_context = self.__get_memory_context(*ids)
|
if not handler.update_type == event_object.update_type:
|
||||||
|
continue
|
||||||
|
|
||||||
if not handler.state == await memory_context.get_state() \
|
if handler.filters:
|
||||||
and handler.state:
|
if not filter_attrs(event_object, *handler.filters):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
func_args = handler.func_event.__annotations__.keys()
|
memory_context = self.__get_memory_context(*ids)
|
||||||
|
|
||||||
kwargs = {'context': memory_context}
|
if not handler.state == await memory_context.get_state() \
|
||||||
|
and handler.state:
|
||||||
|
continue
|
||||||
|
|
||||||
for key in kwargs.copy().keys():
|
func_args = handler.func_event.__annotations__.keys()
|
||||||
if not key in func_args:
|
|
||||||
del kwargs[key]
|
|
||||||
|
|
||||||
await handler.func_event(event_object, **kwargs)
|
kwargs = {'context': memory_context}
|
||||||
|
|
||||||
logger_dp.info(f'Обработано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
|
for key in kwargs.copy().keys():
|
||||||
|
if not key in func_args:
|
||||||
|
del kwargs[key]
|
||||||
|
|
||||||
is_handled = True
|
if handler.middleware:
|
||||||
break
|
await handler.middleware()
|
||||||
|
|
||||||
|
await handler.func_event(event_object, **kwargs)
|
||||||
|
|
||||||
|
logger_dp.info(f'Обработано: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}')
|
||||||
|
|
||||||
|
is_handled = True
|
||||||
|
break
|
||||||
|
|
||||||
if not is_handled:
|
if not is_handled:
|
||||||
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]}')
|
||||||
@ -140,14 +169,7 @@ class Dispatcher:
|
|||||||
Args:
|
Args:
|
||||||
bot: Экземпляр бота
|
bot: Экземпляр бота
|
||||||
"""
|
"""
|
||||||
|
await self.__ready(bot)
|
||||||
self.bot = bot
|
|
||||||
await self.check_me()
|
|
||||||
|
|
||||||
logger_dp.info(f'{len(self.event_handlers)} событий на обработку')
|
|
||||||
|
|
||||||
if self.on_started_func:
|
|
||||||
await self.on_started_func()
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@ -184,11 +206,7 @@ class Dispatcher:
|
|||||||
port: Порт для сервера
|
port: Порт для сервера
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.bot = bot
|
await self.__ready(bot)
|
||||||
await self.check_me()
|
|
||||||
|
|
||||||
if self.on_started_func:
|
|
||||||
await self.on_started_func()
|
|
||||||
|
|
||||||
@app.post('/')
|
@app.post('/')
|
||||||
async def _(request: Request):
|
async def _(request: Request):
|
||||||
@ -206,7 +224,6 @@ 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}")
|
||||||
|
|
||||||
logger_dp.info(f'{len(self.event_handlers)} событий на обработку')
|
|
||||||
config = Config(app=app, host=host, port=port, log_level="critical")
|
config = Config(app=app, host=host, port=port, log_level="critical")
|
||||||
server = Server(config)
|
server = Server(config)
|
||||||
|
|
||||||
@ -231,8 +248,10 @@ class Event:
|
|||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
def decorator(func_event: Callable):
|
def decorator(func_event: Callable):
|
||||||
|
|
||||||
if self.update_type == UpdateType.ON_STARTED:
|
if self.update_type == UpdateType.ON_STARTED:
|
||||||
self.router.on_started_func = func_event
|
self.router.on_started_func = func_event
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.router.event_handlers.append(
|
self.router.event_handlers.append(
|
||||||
Handler(
|
Handler(
|
||||||
|
4
maxapi/exceptions/download_file.py
Normal file
4
maxapi/exceptions/download_file.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class NotAvailableForDownload(BaseException):
|
||||||
|
...
|
4
maxapi/exceptions/invalid_token.py
Normal file
4
maxapi/exceptions/invalid_token.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class InvalidToken(BaseException):
|
||||||
|
...
|
@ -6,48 +6,15 @@ from magic_filter.operations.comparator import ComparatorOperation as mf_compara
|
|||||||
F = MagicFilter()
|
F = MagicFilter()
|
||||||
|
|
||||||
|
|
||||||
def filter_attrs(obj, *magic_args):
|
def filter_attrs(obj: object, *filters: MagicFilter) -> bool:
|
||||||
|
"""
|
||||||
|
Применяет один или несколько фильтров MagicFilter к объекту.
|
||||||
|
|
||||||
|
:param obj: Любой объект с атрибутами (например, event/message)
|
||||||
|
:param filters: Один или несколько MagicFilter выражений
|
||||||
|
:return: True, если все фильтры возвращают True, иначе False
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
for arg in magic_args:
|
return all(f.resolve(obj) for f in filters)
|
||||||
|
except Exception:
|
||||||
attr_last = None
|
return False
|
||||||
method_found = False
|
|
||||||
|
|
||||||
operations = arg._operations
|
|
||||||
if isinstance(operations[-1], mf_call):
|
|
||||||
operations = operations[:len(operations)-2]
|
|
||||||
method_found = True
|
|
||||||
elif isinstance(operations[-1], mf_func):
|
|
||||||
operations = operations[:len(operations)-1]
|
|
||||||
method_found = True
|
|
||||||
elif isinstance(operations[-1], mf_comparator):
|
|
||||||
operations = operations[:len(operations)-1]
|
|
||||||
|
|
||||||
for element in operations:
|
|
||||||
if attr_last is None:
|
|
||||||
attr_last = getattr(obj, element.name)
|
|
||||||
else:
|
|
||||||
attr_last = getattr(attr_last, element.name)
|
|
||||||
|
|
||||||
if attr_last is None:
|
|
||||||
break
|
|
||||||
|
|
||||||
if isinstance(arg._operations[-1], mf_comparator):
|
|
||||||
return attr_last == arg._operations[-1].right
|
|
||||||
|
|
||||||
if not method_found:
|
|
||||||
return bool(attr_last)
|
|
||||||
|
|
||||||
if attr_last is None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if isinstance(arg._operations[-1], mf_func):
|
|
||||||
func_operation: mf_func = arg._operations[-1]
|
|
||||||
return func_operation.resolve(attr_last, attr_last)
|
|
||||||
else:
|
|
||||||
method = getattr(attr_last, arg._operations[-2].name)
|
|
||||||
args = arg._operations[-1].args
|
|
||||||
|
|
||||||
return method(*args)
|
|
||||||
except Exception as e:
|
|
||||||
...
|
|
@ -2,9 +2,14 @@ from typing import Callable
|
|||||||
|
|
||||||
from magic_filter import F, MagicFilter
|
from magic_filter import F, MagicFilter
|
||||||
|
|
||||||
|
from ..filters.middleware import BaseMiddleware
|
||||||
|
|
||||||
from ..types.command import Command
|
from ..types.command import Command
|
||||||
|
|
||||||
from ..context.state_machine import State
|
from ..context.state_machine import State
|
||||||
|
|
||||||
from ..enums.update import UpdateType
|
from ..enums.update import UpdateType
|
||||||
|
|
||||||
from ..loggers import logger_dp
|
from ..loggers import logger_dp
|
||||||
|
|
||||||
|
|
||||||
@ -36,10 +41,11 @@ class Handler:
|
|||||||
:param kwargs: Дополнительные параметры (не используются)
|
:param kwargs: Дополнительные параметры (не используются)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.func_event = func_event
|
self.func_event: Callable = func_event
|
||||||
self.update_type = update_type
|
self.update_type: UpdateType = update_type
|
||||||
self.filters = []
|
self.filters = []
|
||||||
self.state = None
|
self.state: State = None
|
||||||
|
self.middleware: BaseMiddleware = None
|
||||||
|
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if isinstance(arg, MagicFilter):
|
if isinstance(arg, MagicFilter):
|
||||||
@ -48,6 +54,8 @@ class Handler:
|
|||||||
self.state = arg
|
self.state = arg
|
||||||
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):
|
||||||
|
self.middleware = arg
|
||||||
else:
|
else:
|
||||||
logger_dp.info(f'Обнаружен неизвестный фильтр `{arg}` при '
|
logger_dp.info(f'Обнаружен неизвестный фильтр `{arg}` при '
|
||||||
f'регистрации функции `{func_event.__name__}`')
|
f'регистрации функции `{func_event.__name__}`')
|
6
maxapi/filters/middleware.py
Normal file
6
maxapi/filters/middleware.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from ..types.updates import UpdateUnion
|
||||||
|
|
||||||
|
|
||||||
|
class BaseMiddleware:
|
||||||
|
def __init__(self):
|
||||||
|
...
|
52
maxapi/methods/download_media.py
Normal file
52
maxapi/methods/download_media.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from ..methods.types.deleted_pin_message import DeletedPinMessage
|
||||||
|
|
||||||
|
from ..enums.http_method import HTTPMethod
|
||||||
|
from ..enums.api_path import ApiPath
|
||||||
|
from ..enums.upload_type import UploadType
|
||||||
|
|
||||||
|
from ..connection.base import BaseConnection
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ..bot import Bot
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadMedia(BaseConnection):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Класс для скачивания медиафайлов.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bot (Bot): Экземпляр бота для выполнения запроса.
|
||||||
|
media_url (str): Ссылка на медиа.
|
||||||
|
media_token (str): Токен медиа.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
bot: 'Bot',
|
||||||
|
path: str,
|
||||||
|
media_url: str,
|
||||||
|
media_token: str
|
||||||
|
):
|
||||||
|
self.bot = bot
|
||||||
|
self.path = path
|
||||||
|
self.media_url = media_url
|
||||||
|
self.media_token = media_token
|
||||||
|
|
||||||
|
async def request(self) -> int:
|
||||||
|
|
||||||
|
"""
|
||||||
|
Выполняет GET-запрос для скачивания медиафайла
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: Код операции.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return await super().download_file(
|
||||||
|
path=self.path,
|
||||||
|
url=self.media_url,
|
||||||
|
token=self.media_token
|
||||||
|
)
|
@ -60,7 +60,9 @@ class GetMembersChat(BaseConnection):
|
|||||||
|
|
||||||
params = self.bot.params.copy()
|
params = self.bot.params.copy()
|
||||||
|
|
||||||
if self.user_ids: params['user_ids'] = ','.join(self.user_ids)
|
if self.user_ids:
|
||||||
|
self.user_ids = [str(user_id) for user_id in self.user_ids]
|
||||||
|
params['user_ids'] = ','.join(self.user_ids)
|
||||||
if self.marker: params['marker'] = self.marker
|
if self.marker: params['marker'] = self.marker
|
||||||
if self.count: params['marker'] = self.count
|
if self.count: params['marker'] = self.count
|
||||||
|
|
||||||
|
@ -19,35 +19,78 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
async def get_update_model(event: dict, bot: 'Bot'):
|
async def get_update_model(event: dict, bot: 'Bot'):
|
||||||
event_object = None
|
event_object = None
|
||||||
|
|
||||||
match event['update_type']:
|
match event['update_type']:
|
||||||
|
|
||||||
case UpdateType.BOT_ADDED:
|
case UpdateType.BOT_ADDED:
|
||||||
event_object = BotAdded(**event)
|
event_object = BotAdded(**event)
|
||||||
|
|
||||||
case UpdateType.BOT_REMOVED:
|
case UpdateType.BOT_REMOVED:
|
||||||
event_object = BotRemoved(**event)
|
event_object = BotRemoved(**event)
|
||||||
|
|
||||||
case UpdateType.BOT_STARTED:
|
case UpdateType.BOT_STARTED:
|
||||||
event_object = BotStarted(**event)
|
event_object = BotStarted(**event)
|
||||||
|
|
||||||
case UpdateType.CHAT_TITLE_CHANGED:
|
case UpdateType.CHAT_TITLE_CHANGED:
|
||||||
event_object = ChatTitleChanged(**event)
|
event_object = ChatTitleChanged(**event)
|
||||||
|
|
||||||
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.from_user = event_object.callback.user
|
||||||
|
|
||||||
case UpdateType.MESSAGE_CHAT_CREATED:
|
case UpdateType.MESSAGE_CHAT_CREATED:
|
||||||
event_object = MessageChatCreated(**event)
|
event_object = MessageChatCreated(**event)
|
||||||
|
event_object.chat = event_object.chat
|
||||||
|
|
||||||
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.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.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.from_user = await bot.get_chat_member(
|
||||||
|
chat_id=event_object.chat_id,
|
||||||
|
user_id=event_object.user_id
|
||||||
|
)
|
||||||
|
|
||||||
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.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.from_user = await bot.get_chat_member(
|
||||||
|
chat_id=event_object.chat_id,
|
||||||
|
user_id=event_object.admin_id
|
||||||
|
) if event_object.admin_id else None
|
||||||
|
|
||||||
|
if event['update_type'] in (UpdateType.BOT_ADDED,
|
||||||
|
UpdateType.BOT_REMOVED,
|
||||||
|
UpdateType.BOT_STARTED,
|
||||||
|
UpdateType.CHAT_TITLE_CHANGED):
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.chat_id)
|
||||||
|
event_object.from_user = event_object.user
|
||||||
|
|
||||||
if hasattr(event_object, 'bot'):
|
if hasattr(event_object, 'bot'):
|
||||||
event_object.bot = bot
|
event_object.bot = bot
|
||||||
|
|
||||||
if hasattr(event_object, 'message'):
|
if hasattr(event_object, 'message'):
|
||||||
event_object.message.bot = bot
|
event_object.message.bot = bot
|
||||||
|
|
||||||
|
for attachment in event_object.message.body.attachments:
|
||||||
|
if hasattr(attachment, 'bot'):
|
||||||
|
attachment.bot = bot
|
||||||
|
|
||||||
return event_object
|
return event_object
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
from typing import List, Optional, Union
|
from typing import TYPE_CHECKING, Any, List, Optional, Union
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
from ...exceptions.download_file import NotAvailableForDownload
|
||||||
|
|
||||||
from ...types.attachments.upload import AttachmentUpload
|
from ...types.attachments.upload import AttachmentUpload
|
||||||
|
|
||||||
from ...types.attachments.buttons import InlineButtonUnion
|
from ...types.attachments.buttons import InlineButtonUnion
|
||||||
from ...types.users import User
|
from ...types.users import User
|
||||||
|
|
||||||
from ...enums.attachment import AttachmentType
|
from ...enums.attachment import AttachmentType
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ...bot import Bot
|
||||||
|
|
||||||
|
|
||||||
class StickerAttachmentPayload(BaseModel):
|
class StickerAttachmentPayload(BaseModel):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -98,6 +103,36 @@ class Attachment(BaseModel):
|
|||||||
ButtonsPayload,
|
ButtonsPayload,
|
||||||
StickerAttachmentPayload
|
StickerAttachmentPayload
|
||||||
]] = None
|
]] = None
|
||||||
|
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
bot: Optional[Bot]
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
use_enum_values = True
|
use_enum_values = True
|
||||||
|
|
||||||
|
async def download(
|
||||||
|
self,
|
||||||
|
path: str
|
||||||
|
):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Скачивает медиа, сохраняя по определенному пути
|
||||||
|
|
||||||
|
:param path: Путь сохранения медиа
|
||||||
|
|
||||||
|
:return: Числовой статус
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not hasattr(self.payload, 'token') or \
|
||||||
|
not hasattr(self.payload, 'url'):
|
||||||
|
raise NotAvailableForDownload()
|
||||||
|
|
||||||
|
elif not self.payload.token or not self.payload.url:
|
||||||
|
raise NotAvailableForDownload(f'Медиа типа `{self.type}` недоступно для скачивания')
|
||||||
|
|
||||||
|
return await self.bot.download_file(
|
||||||
|
path=path,
|
||||||
|
url=self.payload.url,
|
||||||
|
token=self.payload.token,
|
||||||
|
)
|
@ -1,7 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
|
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
from ...types.users import User
|
from ...types.users import User
|
||||||
@ -18,12 +16,10 @@ class BotAdded(Update):
|
|||||||
Attributes:
|
Attributes:
|
||||||
chat_id (Optional[int]): Идентификатор чата, куда добавлен бот.
|
chat_id (Optional[int]): Идентификатор чата, куда добавлен бот.
|
||||||
user (User): Объект пользователя-бота.
|
user (User): Объект пользователя-бота.
|
||||||
bot (Optional[Any]): Ссылка на экземпляр бота, не сериализуется.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
chat_id: Optional[int] = None
|
chat_id: Optional[int] = None
|
||||||
user: User
|
user: User
|
||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
bot: Optional[Bot]
|
bot: Optional[Bot]
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
|
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
from ...types.users import User
|
from ...types.users import User
|
||||||
@ -18,12 +16,10 @@ class BotRemoved(Update):
|
|||||||
Attributes:
|
Attributes:
|
||||||
chat_id (Optional[int]): Идентификатор чата, из которого удалён бот.
|
chat_id (Optional[int]): Идентификатор чата, из которого удалён бот.
|
||||||
user (User): Объект пользователя-бота.
|
user (User): Объект пользователя-бота.
|
||||||
bot (Optional[Any]): Ссылка на экземпляр бота, не сериализуется.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
chat_id: Optional[int] = None
|
chat_id: Optional[int] = None
|
||||||
user: User
|
user: User
|
||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
bot: Optional[Bot]
|
bot: Optional[Bot]
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
|
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
from ...types.users import User
|
from ...types.users import User
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -19,14 +18,12 @@ class BotStarted(Update):
|
|||||||
user (User): Пользователь (бот).
|
user (User): Пользователь (бот).
|
||||||
user_locale (Optional[str]): Локаль пользователя.
|
user_locale (Optional[str]): Локаль пользователя.
|
||||||
payload (Optional[str]): Дополнительные данные.
|
payload (Optional[str]): Дополнительные данные.
|
||||||
bot (Optional[Any]): Ссылка на экземпляр бота, не сериализуется.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
chat_id: Optional[int] = None
|
chat_id: Optional[int] = None
|
||||||
user: User
|
user: User
|
||||||
user_locale: Optional[str] = None
|
user_locale: Optional[str] = None
|
||||||
payload: Optional[str] = None
|
payload: Optional[str] = None
|
||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
bot: Optional[Bot]
|
bot: Optional[Bot]
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
|
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
from ...types.users import User
|
from ...types.users import User
|
||||||
@ -19,13 +17,11 @@ class ChatTitleChanged(Update):
|
|||||||
chat_id (Optional[int]): Идентификатор чата.
|
chat_id (Optional[int]): Идентификатор чата.
|
||||||
user (User): Пользователь, совершивший изменение.
|
user (User): Пользователь, совершивший изменение.
|
||||||
title (Optional[str]): Новое название чата.
|
title (Optional[str]): Новое название чата.
|
||||||
bot (Optional[Any]): Ссылка на экземпляр бота, не сериализуется.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
chat_id: Optional[int] = None
|
chat_id: Optional[int] = None
|
||||||
user: User
|
user: User
|
||||||
title: Optional[str] = None
|
title: Optional[str] = None
|
||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
bot: Optional[Bot]
|
bot: Optional[Bot]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from typing import Any, List, Optional, TYPE_CHECKING, Union
|
from typing import List, Optional, TYPE_CHECKING, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
@ -21,6 +21,8 @@ from ..attachments.audio import Audio
|
|||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ...bot import Bot
|
from ...bot import Bot
|
||||||
|
from ...types.chats import Chat
|
||||||
|
from ...types.users import User
|
||||||
|
|
||||||
|
|
||||||
class MessageForCallback(BaseModel):
|
class MessageForCallback(BaseModel):
|
||||||
@ -65,16 +67,11 @@ class MessageCallback(Update):
|
|||||||
message (Message): Сообщение, на которое пришёл callback.
|
message (Message): Сообщение, на которое пришёл callback.
|
||||||
user_locale (Optional[str]): Локаль пользователя.
|
user_locale (Optional[str]): Локаль пользователя.
|
||||||
callback (Callback): Объект callback.
|
callback (Callback): Объект callback.
|
||||||
bot (Optional[Any]): Экземпляр бота, не сериализуется.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
message: Message
|
message: Message
|
||||||
user_locale: Optional[str] = None
|
user_locale: Optional[str] = None
|
||||||
callback: Callback
|
callback: Callback
|
||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
bot: Optional[Bot]
|
|
||||||
|
|
||||||
def get_ids(self):
|
def get_ids(self):
|
||||||
|
|
||||||
@ -89,7 +86,7 @@ class MessageCallback(Update):
|
|||||||
|
|
||||||
async def answer(
|
async def answer(
|
||||||
self,
|
self,
|
||||||
notification: str,
|
notification: str = None,
|
||||||
new_text: str = None,
|
new_text: str = None,
|
||||||
link: NewMessageLink = None,
|
link: NewMessageLink = None,
|
||||||
notify: bool = True,
|
notify: bool = True,
|
||||||
|
@ -1,24 +1,15 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
from ...types.chats import Chat
|
from ...types.chats import Chat
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from ...bot import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class MessageChatCreated(Update):
|
class MessageChatCreated(Update):
|
||||||
chat: Chat
|
chat: Chat
|
||||||
title: Optional[str] = None
|
title: Optional[str] = None
|
||||||
message_id: Optional[str] = None
|
message_id: Optional[str] = None
|
||||||
start_payload: Optional[str] = None
|
start_payload: Optional[str] = None
|
||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
bot: Optional[Bot]
|
|
||||||
|
|
||||||
def get_ids(self):
|
def get_ids(self):
|
||||||
return (self.chat_id, 0)
|
return (self.chat.chat_id, self.chat.owner_id)
|
@ -1,15 +1,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Optional, TYPE_CHECKING
|
||||||
|
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
from ...types.message import Message
|
from ...types.message import Message
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from ...bot import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class MessageCreated(Update):
|
class MessageCreated(Update):
|
||||||
|
|
||||||
@ -19,15 +14,10 @@ class MessageCreated(Update):
|
|||||||
Attributes:
|
Attributes:
|
||||||
message (Message): Объект сообщения.
|
message (Message): Объект сообщения.
|
||||||
user_locale (Optional[str]): Локаль пользователя.
|
user_locale (Optional[str]): Локаль пользователя.
|
||||||
bot (Optional[Any]): Экземпляр бота, не сериализуется.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
message: Message
|
message: Message
|
||||||
user_locale: Optional[str] = None
|
user_locale: Optional[str] = None
|
||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
bot: Optional[Bot]
|
|
||||||
|
|
||||||
def get_ids(self):
|
def get_ids(self):
|
||||||
|
|
||||||
|
@ -1,14 +1,7 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
|
||||||
|
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
from ...types.message import Message
|
from ...types.message import Message
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from ...bot import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class MessageEdited(Update):
|
class MessageEdited(Update):
|
||||||
|
|
||||||
@ -17,14 +10,9 @@ class MessageEdited(Update):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
message (Message): Объект измененного сообщения.
|
message (Message): Объект измененного сообщения.
|
||||||
bot (Optional[Any]): Экземпляр бота, не сериализуется.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
message: Message
|
message: Message
|
||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
bot: Optional[Bot]
|
|
||||||
|
|
||||||
def get_ids(self):
|
def get_ids(self):
|
||||||
|
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from ...bot import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class MessageRemoved(Update):
|
class MessageRemoved(Update):
|
||||||
|
|
||||||
@ -17,16 +12,11 @@ class MessageRemoved(Update):
|
|||||||
message_id (Optional[str]): Идентификатор удаленного сообщения. Может быть None.
|
message_id (Optional[str]): Идентификатор удаленного сообщения. Может быть None.
|
||||||
chat_id (Optional[int]): Идентификатор чата. Может быть None.
|
chat_id (Optional[int]): Идентификатор чата. Может быть None.
|
||||||
user_id (Optional[int]): Идентификатор пользователя. Может быть None.
|
user_id (Optional[int]): Идентификатор пользователя. Может быть None.
|
||||||
bot (Optional[Bot]): Объект бота, исключается из сериализации.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
message_id: Optional[str] = None
|
message_id: Optional[str] = None
|
||||||
chat_id: Optional[int] = None
|
chat_id: Optional[int] = None
|
||||||
user_id: Optional[int] = None
|
user_id: Optional[int] = None
|
||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
bot: Optional[Bot]
|
|
||||||
|
|
||||||
def get_ids(self):
|
def get_ids(self):
|
||||||
|
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
from pydantic import BaseModel
|
from __future__ import annotations
|
||||||
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from ...enums.update import UpdateType
|
from ...enums.update import UpdateType
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ...bot import Bot
|
||||||
|
from ...types.chats import Chat
|
||||||
|
from ...types.users import User
|
||||||
|
|
||||||
|
|
||||||
class Update(BaseModel):
|
class Update(BaseModel):
|
||||||
|
|
||||||
@ -16,5 +23,14 @@ class Update(BaseModel):
|
|||||||
update_type: UpdateType
|
update_type: UpdateType
|
||||||
timestamp: int
|
timestamp: int
|
||||||
|
|
||||||
|
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||||
|
from_user: Optional[Any] = Field(default=None, exclude=True)
|
||||||
|
chat: Optional[Any] = Field(default=None, exclude=True)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
bot: Optional[Bot]
|
||||||
|
from_user: Optional[User]
|
||||||
|
chat: Optional[Chat]
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
arbitrary_types_allowed=True
|
arbitrary_types_allowed=True
|
@ -1,16 +1,10 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
from ...types.users import User
|
from ...types.users import User
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from ...bot import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class UserAdded(Update):
|
class UserAdded(Update):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -20,16 +14,11 @@ class UserAdded(Update):
|
|||||||
inviter_id (Optional[int]): Идентификатор пользователя, добавившего нового участника. Может быть None.
|
inviter_id (Optional[int]): Идентификатор пользователя, добавившего нового участника. Может быть None.
|
||||||
chat_id (Optional[int]): Идентификатор чата. Может быть None.
|
chat_id (Optional[int]): Идентификатор чата. Может быть None.
|
||||||
user (User): Объект пользователя, добавленного в чат.
|
user (User): Объект пользователя, добавленного в чат.
|
||||||
bot (Optional[Bot]): Объект бота, исключается из сериализации.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
inviter_id: Optional[int] = None
|
inviter_id: Optional[int] = None
|
||||||
chat_id: Optional[int] = None
|
chat_id: Optional[int] = None
|
||||||
user: User
|
user: User
|
||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
bot: Optional[Bot]
|
|
||||||
|
|
||||||
def get_ids(self):
|
def get_ids(self):
|
||||||
|
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import Field
|
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
from ...types.users import User
|
from ...types.users import User
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from ...bot import Bot
|
|
||||||
|
|
||||||
|
|
||||||
class UserRemoved(Update):
|
class UserRemoved(Update):
|
||||||
|
|
||||||
@ -19,16 +14,11 @@ class UserRemoved(Update):
|
|||||||
admin_id (Optional[int]): Идентификатор администратора, удалившего пользователя. Может быть None.
|
admin_id (Optional[int]): Идентификатор администратора, удалившего пользователя. Может быть None.
|
||||||
chat_id (Optional[int]): Идентификатор чата. Может быть None.
|
chat_id (Optional[int]): Идентификатор чата. Может быть None.
|
||||||
user (User): Объект пользователя, удаленного из чата.
|
user (User): Объект пользователя, удаленного из чата.
|
||||||
bot (Optional[Bot]): Объект бота, исключается из сериализации.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
admin_id: Optional[int] = None
|
admin_id: Optional[int] = None
|
||||||
chat_id: Optional[int] = None
|
chat_id: Optional[int] = None
|
||||||
user: User
|
user: User
|
||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
bot: Optional[Bot]
|
|
||||||
|
|
||||||
def get_ids(self):
|
def get_ids(self):
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user