Compare commits
25 Commits
2420e4232e
...
6f86d15de4
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f86d15de4 | |||
| 7ea24fe2af | |||
| 39fb0c5823 | |||
| af84301e4f | |||
| ec432fe8ce | |||
| 1bfd93f2ea | |||
| 7925087ac7 | |||
| 7ed540683c | |||
| 30350c8521 | |||
| 54683256ce | |||
| be7f98976e | |||
| 54c073ab76 | |||
| 29b319768b | |||
| 5e98e540ea | |||
| 1df293f44d | |||
| c667b82a6c | |||
| 62523c1eb2 | |||
| b0b7040206 | |||
| 29d3d7c042 | |||
| fd048e8544 | |||
| 32c0ca7647 | |||
| 02b4e2d39a | |||
| 354c296fed | |||
| 8f93cf36e4 | |||
| e1064761e4 |
@@ -13,7 +13,13 @@ from maxapi.types import (
|
|||||||
MessageEdited,
|
MessageEdited,
|
||||||
MessageRemoved,
|
MessageRemoved,
|
||||||
UserAdded,
|
UserAdded,
|
||||||
UserRemoved
|
UserRemoved,
|
||||||
|
BotStopped,
|
||||||
|
DialogCleared,
|
||||||
|
DialogMuted,
|
||||||
|
DialogUnmuted,
|
||||||
|
ChatButton,
|
||||||
|
MessageChatCreated
|
||||||
)
|
)
|
||||||
from maxapi.utils.inline_keyboard import InlineKeyboardBuilder
|
from maxapi.utils.inline_keyboard import InlineKeyboardBuilder
|
||||||
|
|
||||||
@@ -38,9 +44,9 @@ async def hello(event: MessageCreated):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
builder.add(
|
builder.add(
|
||||||
CallbackButton(
|
ChatButton(
|
||||||
text='Кнопка 3',
|
text='Создать чат',
|
||||||
payload='btn_3',
|
chat_title='Тест чат'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -80,7 +86,7 @@ async def bot_started(event: BotStarted):
|
|||||||
async def chat_title_changed(event: ChatTitleChanged):
|
async def chat_title_changed(event: ChatTitleChanged):
|
||||||
await event.bot.send_message(
|
await event.bot.send_message(
|
||||||
chat_id=event.chat_id,
|
chat_id=event.chat_id,
|
||||||
text=f'Крутое новое название "{event.chat.title}!"'
|
text=f'Крутое новое название "{event.chat.title}"!'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -114,6 +120,34 @@ async def user_added(event: UserAdded):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.bot_stopped()
|
||||||
|
async def bot_stopped(event: BotStopped):
|
||||||
|
print(event.from_user.full_name, 'остановил бота') # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
@dp.dialog_cleared()
|
||||||
|
async def dialog_cleared(event: DialogCleared):
|
||||||
|
print(event.from_user.full_name, 'очистил историю чата с ботом') # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
@dp.dialog_muted()
|
||||||
|
async def dialog_muted(event: DialogMuted):
|
||||||
|
print(event.from_user.full_name, 'отключил оповещения от чата бота до ', event.muted_until_datetime) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
@dp.dialog_unmuted()
|
||||||
|
async def dialog_unmuted(event: DialogUnmuted):
|
||||||
|
print(event.from_user.full_name, 'включил оповещения от чата бота') # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_chat_created()
|
||||||
|
async def message_chat_created(event: MessageChatCreated):
|
||||||
|
await event.bot.send_message(
|
||||||
|
chat_id=event.chat.chat_id,
|
||||||
|
text=f'Чат создан! Ссылка: {event.chat.link}'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
await dp.start_polling(bot)
|
await dp.start_polling(bot)
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ async def echo(event: MessageCreated):
|
|||||||
|
|
||||||
|
|
||||||
@dp.message_created(Command('builder'))
|
@dp.message_created(Command('builder'))
|
||||||
async def echo(event: MessageCreated):
|
async def builder(event: MessageCreated):
|
||||||
builder = InlineKeyboardBuilder()
|
builder = InlineKeyboardBuilder()
|
||||||
|
|
||||||
builder.row(
|
builder.row(
|
||||||
@@ -88,7 +88,7 @@ async def echo(event: MessageCreated):
|
|||||||
|
|
||||||
|
|
||||||
@dp.message_created(Command('payload'))
|
@dp.message_created(Command('payload'))
|
||||||
async def echo(event: MessageCreated):
|
async def payload(event: MessageCreated):
|
||||||
buttons = [
|
buttons = [
|
||||||
[
|
[
|
||||||
# кнопку типа "chat" убрали из документации,
|
# кнопку типа "chat" убрали из документации,
|
||||||
@@ -133,7 +133,7 @@ async def echo(event: MessageCreated):
|
|||||||
|
|
||||||
|
|
||||||
@dp.message_chat_created()
|
@dp.message_chat_created()
|
||||||
async def callback(obj: MessageChatCreated):
|
async def message_chat_created(obj: MessageChatCreated):
|
||||||
await obj.bot.send_message(
|
await obj.bot.send_message(
|
||||||
chat_id=obj.chat.chat_id,
|
chat_id=obj.chat.chat_id,
|
||||||
text=f'Чат создан! Ссылка: {obj.chat.link}'
|
text=f'Чат создан! Ссылка: {obj.chat.link}'
|
||||||
@@ -141,7 +141,7 @@ async def callback(obj: MessageChatCreated):
|
|||||||
|
|
||||||
|
|
||||||
@dp.message_callback()
|
@dp.message_callback()
|
||||||
async def callback(callback: MessageCallback):
|
async def message_callback(callback: MessageCallback):
|
||||||
await callback.message.answer('Вы нажали на Callback!')
|
await callback.message.answer('Вы нажали на Callback!')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ async def handle_message(event: MessageCreated):
|
|||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
await dp.handle_webhook(bot)
|
await dp.handle_webhook(bot, log_level='critical')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from fastapi import Request
|
try:
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi import Request
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError(
|
||||||
|
'\n\t Не установлен fastapi!'
|
||||||
|
'\n\t Выполните команду для установки fastapi: '
|
||||||
|
'\n\t pip install fastapi>=0.68.0'
|
||||||
|
'\n\t Или сразу все зависимости для работы вебхука:'
|
||||||
|
'\n\t pip install maxapi[webhook]'
|
||||||
|
)
|
||||||
|
|
||||||
from maxapi import Bot, Dispatcher
|
from maxapi import Bot, Dispatcher
|
||||||
from maxapi.methods.types.getted_updates import process_update_webhook
|
from maxapi.methods.types.getted_updates import process_update_webhook
|
||||||
from maxapi.types import MessageCreated
|
from maxapi.types import MessageCreated
|
||||||
from maxapi.dispatcher import webhook_app
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
@@ -21,7 +29,7 @@ async def handle_message(event: MessageCreated):
|
|||||||
|
|
||||||
# Регистрация обработчика
|
# Регистрация обработчика
|
||||||
# для вебхука
|
# для вебхука
|
||||||
@webhook_app.post('/')
|
@dp.webhook_post('/')
|
||||||
async def _(request: Request):
|
async def _(request: Request):
|
||||||
|
|
||||||
# Сериализация полученного запроса
|
# Сериализация полученного запроса
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ from .dispatcher import Dispatcher, Router
|
|||||||
from .filters import F
|
from .filters import F
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
Bot,
|
'Bot',
|
||||||
Dispatcher,
|
'Dispatcher',
|
||||||
F,
|
'F',
|
||||||
Router
|
'Router'
|
||||||
]
|
]
|
||||||
@@ -49,7 +49,6 @@ if TYPE_CHECKING:
|
|||||||
from .types.chats import Chat, ChatMember, Chats
|
from .types.chats import Chat, ChatMember, Chats
|
||||||
from .types.command import BotCommand
|
from .types.command import BotCommand
|
||||||
from .types.message import Message, Messages, NewMessageLink
|
from .types.message import Message, Messages, NewMessageLink
|
||||||
from .types.updates import UpdateUnion
|
|
||||||
from .types.users import ChatAdmin, User
|
from .types.users import ChatAdmin, User
|
||||||
|
|
||||||
from .methods.types.added_admin_chat import AddedListAdminChat
|
from .methods.types.added_admin_chat import AddedListAdminChat
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import os
|
|||||||
import mimetypes
|
import mimetypes
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
from uuid import uuid4
|
|
||||||
|
|
||||||
import aiofiles
|
import aiofiles
|
||||||
import puremagic
|
import puremagic
|
||||||
@@ -70,7 +69,8 @@ class BaseConnection:
|
|||||||
- dict (если is_return_raw=True)
|
- dict (если is_return_raw=True)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
if not self.bot.session:
|
if not self.bot.session:
|
||||||
self.bot.session = ClientSession(
|
self.bot.session = ClientSession(
|
||||||
@@ -100,7 +100,8 @@ class BaseConnection:
|
|||||||
|
|
||||||
raw = await r.json()
|
raw = await r.json()
|
||||||
|
|
||||||
if is_return_raw: return raw
|
if is_return_raw:
|
||||||
|
return raw
|
||||||
|
|
||||||
model = model(**raw) # type: ignore
|
model = model(**raw) # type: ignore
|
||||||
|
|
||||||
@@ -154,6 +155,7 @@ class BaseConnection:
|
|||||||
|
|
||||||
async def upload_file_buffer(
|
async def upload_file_buffer(
|
||||||
self,
|
self,
|
||||||
|
filename: str,
|
||||||
url: str,
|
url: str,
|
||||||
buffer: bytes,
|
buffer: bytes,
|
||||||
type: UploadType
|
type: UploadType
|
||||||
@@ -180,7 +182,7 @@ class BaseConnection:
|
|||||||
mime_type = f"{type.value}/*"
|
mime_type = f"{type.value}/*"
|
||||||
ext = ''
|
ext = ''
|
||||||
|
|
||||||
basename = f'{uuid4()}{ext}'
|
basename = f'{filename}{ext}'
|
||||||
|
|
||||||
form = FormData()
|
form = FormData()
|
||||||
form.add_field(
|
form.add_field(
|
||||||
|
|||||||
@@ -1,93 +1,9 @@
|
|||||||
import asyncio
|
|
||||||
|
|
||||||
from typing import Any, Dict, Optional, Union
|
|
||||||
|
|
||||||
from ..context.state_machine import State, StatesGroup
|
from ..context.state_machine import State, StatesGroup
|
||||||
|
from .context import MemoryContext
|
||||||
|
|
||||||
|
|
||||||
class MemoryContext:
|
__all__ = [
|
||||||
|
'State',
|
||||||
"""
|
'StatesGroup',
|
||||||
Контекст хранения данных пользователя с блокировками.
|
'MemoryContext'
|
||||||
|
]
|
||||||
Args:
|
|
||||||
chat_id (int): Идентификатор чата
|
|
||||||
user_id (int): Идентификатор пользователя
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, chat_id: int, user_id: int):
|
|
||||||
self.chat_id = chat_id
|
|
||||||
self.user_id = user_id
|
|
||||||
self._context: Dict[str, Any] = {}
|
|
||||||
self._state: State | str | None = None
|
|
||||||
self._lock = asyncio.Lock()
|
|
||||||
|
|
||||||
async def get_data(self) -> dict[str, Any]:
|
|
||||||
|
|
||||||
"""
|
|
||||||
Возвращает текущий контекст данных.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Словарь с данными контекста
|
|
||||||
"""
|
|
||||||
|
|
||||||
async with self._lock:
|
|
||||||
return self._context
|
|
||||||
|
|
||||||
async def set_data(self, data: dict[str, Any]):
|
|
||||||
|
|
||||||
"""
|
|
||||||
Полностью заменяет контекст данных.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
data: Новый словарь контекста
|
|
||||||
"""
|
|
||||||
|
|
||||||
async with self._lock:
|
|
||||||
self._context = data
|
|
||||||
|
|
||||||
async def update_data(self, **kwargs):
|
|
||||||
|
|
||||||
"""
|
|
||||||
Обновляет контекст данных новыми значениями.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
**kwargs: Пары ключ-значение для обновления
|
|
||||||
"""
|
|
||||||
|
|
||||||
async with self._lock:
|
|
||||||
self._context.update(kwargs)
|
|
||||||
|
|
||||||
async def set_state(self, state: Optional[Union[State, str]] = None):
|
|
||||||
|
|
||||||
"""
|
|
||||||
Устанавливает новое состояние.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
state: Новое состояние или None для сброса
|
|
||||||
"""
|
|
||||||
|
|
||||||
async with self._lock:
|
|
||||||
self._state = state
|
|
||||||
|
|
||||||
async def get_state(self):
|
|
||||||
|
|
||||||
"""
|
|
||||||
Возвращает текущее состояние.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Текущее состояние или None
|
|
||||||
"""
|
|
||||||
|
|
||||||
async with self._lock:
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
async def clear(self):
|
|
||||||
|
|
||||||
"""
|
|
||||||
Очищает контекст и сбрасывает состояние.
|
|
||||||
"""
|
|
||||||
|
|
||||||
async with self._lock:
|
|
||||||
self._state = None
|
|
||||||
self._context = {}
|
|
||||||
93
maxapi/context/context.py
Normal file
93
maxapi/context/context.py
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
|
from typing import Any, Dict, Optional, Union
|
||||||
|
|
||||||
|
from ..context.state_machine import State
|
||||||
|
|
||||||
|
|
||||||
|
class MemoryContext:
|
||||||
|
|
||||||
|
"""
|
||||||
|
Контекст хранения данных пользователя с блокировками.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (int): Идентификатор чата
|
||||||
|
user_id (int): Идентификатор пользователя
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, chat_id: int, user_id: int):
|
||||||
|
self.chat_id = chat_id
|
||||||
|
self.user_id = user_id
|
||||||
|
self._context: Dict[str, Any] = {}
|
||||||
|
self._state: State | str | None = None
|
||||||
|
self._lock = asyncio.Lock()
|
||||||
|
|
||||||
|
async def get_data(self) -> dict[str, Any]:
|
||||||
|
|
||||||
|
"""
|
||||||
|
Возвращает текущий контекст данных.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Словарь с данными контекста
|
||||||
|
"""
|
||||||
|
|
||||||
|
async with self._lock:
|
||||||
|
return self._context
|
||||||
|
|
||||||
|
async def set_data(self, data: dict[str, Any]):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Полностью заменяет контекст данных.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data: Новый словарь контекста
|
||||||
|
"""
|
||||||
|
|
||||||
|
async with self._lock:
|
||||||
|
self._context = data
|
||||||
|
|
||||||
|
async def update_data(self, **kwargs):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Обновляет контекст данных новыми значениями.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
**kwargs: Пары ключ-значение для обновления
|
||||||
|
"""
|
||||||
|
|
||||||
|
async with self._lock:
|
||||||
|
self._context.update(kwargs)
|
||||||
|
|
||||||
|
async def set_state(self, state: Optional[Union[State, str]] = None):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Устанавливает новое состояние.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
state: Новое состояние или None для сброса
|
||||||
|
"""
|
||||||
|
|
||||||
|
async with self._lock:
|
||||||
|
self._state = state
|
||||||
|
|
||||||
|
async def get_state(self):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Возвращает текущее состояние.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Текущее состояние или None
|
||||||
|
"""
|
||||||
|
|
||||||
|
async with self._lock:
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
async def clear(self):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Очищает контекст и сбрасывает состояние.
|
||||||
|
"""
|
||||||
|
|
||||||
|
async with self._lock:
|
||||||
|
self._state = None
|
||||||
|
self._context = {}
|
||||||
@@ -5,9 +5,6 @@ import asyncio
|
|||||||
from typing import Any, Callable, Dict, List, TYPE_CHECKING, Optional
|
from typing import Any, Callable, Dict, List, TYPE_CHECKING, Optional
|
||||||
from asyncio.exceptions import TimeoutError as AsyncioTimeoutError
|
from asyncio.exceptions import TimeoutError as AsyncioTimeoutError
|
||||||
|
|
||||||
from fastapi import FastAPI, Request
|
|
||||||
from fastapi.responses import JSONResponse
|
|
||||||
from uvicorn import Config, Server
|
|
||||||
from aiohttp import ClientConnectorError
|
from aiohttp import ClientConnectorError
|
||||||
|
|
||||||
from .filters.middleware import BaseMiddleware
|
from .filters.middleware import BaseMiddleware
|
||||||
@@ -17,7 +14,7 @@ from .context import MemoryContext
|
|||||||
from .types.updates import UpdateUnion
|
from .types.updates import UpdateUnion
|
||||||
from .types.errors import Error
|
from .types.errors import Error
|
||||||
|
|
||||||
from .methods.types.getted_updates import process_update_webhook, process_update_request
|
from .methods.types.getted_updates import process_update_request, process_update_webhook
|
||||||
|
|
||||||
from .filters import filter_attrs
|
from .filters import filter_attrs
|
||||||
|
|
||||||
@@ -25,12 +22,25 @@ from .bot import Bot
|
|||||||
from .enums.update import UpdateType
|
from .enums.update import UpdateType
|
||||||
from .loggers import logger_dp
|
from .loggers import logger_dp
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from fastapi import FastAPI, Request # type: ignore
|
||||||
|
from fastapi.responses import JSONResponse # type: ignore
|
||||||
|
FASTAPI_INSTALLED = True
|
||||||
|
except ImportError:
|
||||||
|
FASTAPI_INSTALLED = False
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from uvicorn import Config, Server # type: ignore
|
||||||
|
UVICORN_INSTALLED = True
|
||||||
|
except ImportError:
|
||||||
|
UVICORN_INSTALLED = False
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from magic_filter import MagicFilter
|
from magic_filter import MagicFilter
|
||||||
|
|
||||||
|
|
||||||
webhook_app = FastAPI()
|
|
||||||
|
|
||||||
CONNECTION_RETRY_DELAY = 30
|
CONNECTION_RETRY_DELAY = 30
|
||||||
GET_UPDATES_RETRY_DELAY = 5
|
GET_UPDATES_RETRY_DELAY = 5
|
||||||
|
|
||||||
@@ -44,12 +54,14 @@ class Dispatcher:
|
|||||||
применение middleware, фильтров и вызов соответствующих обработчиков.
|
применение middleware, фильтров и вызов соответствующих обработчиков.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self, router_id: str | None = None) -> None:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Инициализация диспетчера.
|
Инициализация диспетчера.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self.router_id = router_id
|
||||||
|
|
||||||
self.event_handlers: List[Handler] = []
|
self.event_handlers: List[Handler] = []
|
||||||
self.contexts: List[MemoryContext] = []
|
self.contexts: List[MemoryContext] = []
|
||||||
self.routers: List[Router | Dispatcher] = []
|
self.routers: List[Router | Dispatcher] = []
|
||||||
@@ -57,12 +69,17 @@ class Dispatcher:
|
|||||||
self.middlewares: List[BaseMiddleware] = []
|
self.middlewares: List[BaseMiddleware] = []
|
||||||
|
|
||||||
self.bot: Optional[Bot] = None
|
self.bot: Optional[Bot] = None
|
||||||
|
self.webhook_app: Optional[FastAPI] = None
|
||||||
self.on_started_func: Optional[Callable] = None
|
self.on_started_func: Optional[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)
|
||||||
self.bot_removed = Event(update_type=UpdateType.BOT_REMOVED, router=self)
|
self.bot_removed = Event(update_type=UpdateType.BOT_REMOVED, router=self)
|
||||||
self.bot_started = Event(update_type=UpdateType.BOT_STARTED, router=self)
|
self.bot_started = Event(update_type=UpdateType.BOT_STARTED, router=self)
|
||||||
|
self.bot_stopped = Event(update_type=UpdateType.BOT_STOPPED, router=self)
|
||||||
|
self.dialog_cleared = Event(update_type=UpdateType.DIALOG_CLEARED, router=self)
|
||||||
|
self.dialog_muted = Event(update_type=UpdateType.DIALOG_MUTED, router=self)
|
||||||
|
self.dialog_unmuted = Event(update_type=UpdateType.DIALOG_UNMUTED, router=self)
|
||||||
self.chat_title_changed = Event(update_type=UpdateType.CHAT_TITLE_CHANGED, router=self)
|
self.chat_title_changed = Event(update_type=UpdateType.CHAT_TITLE_CHANGED, router=self)
|
||||||
self.message_callback = Event(update_type=UpdateType.MESSAGE_CALLBACK, router=self)
|
self.message_callback = Event(update_type=UpdateType.MESSAGE_CALLBACK, router=self)
|
||||||
self.message_chat_created = Event(update_type=UpdateType.MESSAGE_CHAT_CREATED, router=self)
|
self.message_chat_created = Event(update_type=UpdateType.MESSAGE_CHAT_CREATED, router=self)
|
||||||
@@ -72,6 +89,23 @@ class Dispatcher:
|
|||||||
self.user_removed = Event(update_type=UpdateType.USER_REMOVED, router=self)
|
self.user_removed = Event(update_type=UpdateType.USER_REMOVED, router=self)
|
||||||
self.on_started = Event(update_type=UpdateType.ON_STARTED, router=self)
|
self.on_started = Event(update_type=UpdateType.ON_STARTED, router=self)
|
||||||
|
|
||||||
|
def webhook_post(self, path: str):
|
||||||
|
def decorator(func):
|
||||||
|
if self.webhook_app is None:
|
||||||
|
try:
|
||||||
|
from fastapi import FastAPI # type: ignore
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError(
|
||||||
|
'\n\t Не установлен fastapi!'
|
||||||
|
'\n\t Выполните команду для установки fastapi: '
|
||||||
|
'\n\t pip install fastapi>=0.68.0'
|
||||||
|
'\n\t Или сразу все зависимости для работы вебхука:'
|
||||||
|
'\n\t pip install maxapi[webhook]'
|
||||||
|
)
|
||||||
|
self.webhook_app = FastAPI()
|
||||||
|
return self.webhook_app.post(path)(func)
|
||||||
|
return decorator
|
||||||
|
|
||||||
async def check_me(self):
|
async def check_me(self):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -178,14 +212,19 @@ class Dispatcher:
|
|||||||
memory_context = self.__get_memory_context(*ids)
|
memory_context = self.__get_memory_context(*ids)
|
||||||
current_state = await memory_context.get_state()
|
current_state = await memory_context.get_state()
|
||||||
kwargs = {'context': memory_context}
|
kwargs = {'context': memory_context}
|
||||||
|
router_id = None
|
||||||
|
|
||||||
|
process_info = f'{event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]}'
|
||||||
|
|
||||||
is_handled = False
|
is_handled = False
|
||||||
|
|
||||||
for router in self.routers:
|
for index, router in enumerate(self.routers):
|
||||||
|
|
||||||
if is_handled:
|
if is_handled:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
router_id = router.router_id or index
|
||||||
|
|
||||||
if router.filters:
|
if router.filters:
|
||||||
if not filter_attrs(event_object, *router.filters):
|
if not filter_attrs(event_object, *router.filters):
|
||||||
continue
|
continue
|
||||||
@@ -220,21 +259,21 @@ class Dispatcher:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
for key in kwargs.copy().keys():
|
for key in kwargs.copy().keys():
|
||||||
if not key in func_args:
|
if key not in func_args:
|
||||||
del kwargs[key]
|
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'Обработано: {router_id} | {process_info}')
|
||||||
|
|
||||||
is_handled = True
|
is_handled = True
|
||||||
break
|
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'Проигнорировано: {router_id} | {process_info}')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger_dp.error(f"Ошибка при обработке события: {event_object.update_type} | chat_id: {ids[0]}, user_id: {ids[1]} | {e} ")
|
logger_dp.error(f"Ошибка при обработке события: {router_id} | {process_info} | {e} ")
|
||||||
|
|
||||||
async def start_polling(self, bot: Bot):
|
async def start_polling(self, bot: Bot):
|
||||||
|
|
||||||
@@ -248,8 +287,11 @@ class Dispatcher:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
events: Dict = await self.bot.get_updates() # type: ignore
|
events: Dict = await self.bot.get_updates()
|
||||||
except AsyncioTimeoutError:
|
except AsyncioTimeoutError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -260,11 +302,11 @@ class Dispatcher:
|
|||||||
await asyncio.sleep(GET_UPDATES_RETRY_DELAY)
|
await asyncio.sleep(GET_UPDATES_RETRY_DELAY)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.bot.marker_updates = events.get('marker') # type: ignore
|
self.bot.marker_updates = events.get('marker')
|
||||||
|
|
||||||
processed_events = await process_update_request(
|
processed_events = await process_update_request(
|
||||||
events=events,
|
events=events,
|
||||||
bot=self.bot # type: ignore
|
bot=self.bot
|
||||||
)
|
)
|
||||||
|
|
||||||
for event in processed_events:
|
for event in processed_events:
|
||||||
@@ -276,7 +318,7 @@ class Dispatcher:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger_dp.error(f'Общая ошибка при обработке событий: {e.__class__} - {e}')
|
logger_dp.error(f'Общая ошибка при обработке событий: {e.__class__} - {e}')
|
||||||
|
|
||||||
async def handle_webhook(self, bot: Bot, host: str = '0.0.0.0', port: int = 8080):
|
async def handle_webhook(self, bot: Bot, host: str = 'localhost', port: int = 8080, **kwargs):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Запускает FastAPI-приложение для приёма обновлений через вебхук.
|
Запускает FastAPI-приложение для приёма обновлений через вебхук.
|
||||||
@@ -286,29 +328,57 @@ class Dispatcher:
|
|||||||
:param port: Порт сервера.
|
:param port: Порт сервера.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@webhook_app.post('/')
|
if not FASTAPI_INSTALLED:
|
||||||
|
raise ImportError(
|
||||||
|
'\n\t Не установлен fastapi!'
|
||||||
|
'\n\t Выполните команду для установки fastapi: '
|
||||||
|
'\n\t pip install fastapi>=0.68.0'
|
||||||
|
'\n\t Или сразу все зависимости для работы вебхука:'
|
||||||
|
'\n\t pip install maxapi[webhook]'
|
||||||
|
)
|
||||||
|
|
||||||
|
elif not UVICORN_INSTALLED:
|
||||||
|
raise ImportError(
|
||||||
|
'\n\t Не установлен uvicorn!'
|
||||||
|
'\n\t Выполните команду для установки uvicorn: '
|
||||||
|
'\n\t pip install uvicorn>=0.15.0'
|
||||||
|
'\n\t Или сразу все зависимости для работы вебхука:'
|
||||||
|
'\n\t pip install maxapi[webhook]'
|
||||||
|
)
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# from fastapi import Request
|
||||||
|
# from fastapi.responses import JSONResponse
|
||||||
|
# except ImportError:
|
||||||
|
# raise ImportError(
|
||||||
|
# '\n\t Не установлен fastapi!'
|
||||||
|
# '\n\t Выполните команду для установки fastapi: '
|
||||||
|
# '\n\t pip install fastapi>=0.68.0'
|
||||||
|
# '\n\t Или сразу все зависимости для работы вебхука:'
|
||||||
|
# '\n\t pip install maxapi[webhook]'
|
||||||
|
# )
|
||||||
|
|
||||||
|
|
||||||
|
@self.webhook_post('/')
|
||||||
async def _(request: Request):
|
async def _(request: Request):
|
||||||
try:
|
event_json = await request.json()
|
||||||
event_json = await request.json()
|
event_object = await process_update_webhook(
|
||||||
|
event_json=event_json,
|
||||||
|
bot=bot
|
||||||
|
)
|
||||||
|
|
||||||
event_object = await process_update_webhook(
|
await self.handle(event_object)
|
||||||
event_json=event_json,
|
return JSONResponse(content={'ok': True}, status_code=200)
|
||||||
bot=self.bot # type: ignore
|
|
||||||
)
|
|
||||||
|
|
||||||
await self.handle(event_object)
|
|
||||||
|
|
||||||
return JSONResponse(content={'ok': True}, status_code=200)
|
|
||||||
except Exception as e:
|
|
||||||
logger_dp.error(f"Ошибка при обработке события: {event_json['update_type']}: {e}")
|
|
||||||
|
|
||||||
await self.init_serve(
|
await self.init_serve(
|
||||||
bot=bot,
|
bot=bot,
|
||||||
host=host,
|
host=host,
|
||||||
port=port
|
port=port,
|
||||||
|
**kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
async def init_serve(self, bot: Bot, host: str = '0.0.0.0', port: int = 8080, **kwargs):
|
async def init_serve(self, bot: Bot, host: str = 'localhost', port: int = 8080, **kwargs):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Запускает сервер для обработки входящих вебхуков.
|
Запускает сервер для обработки входящих вебхуков.
|
||||||
@@ -318,7 +388,30 @@ class Dispatcher:
|
|||||||
:param port: Порт сервера.
|
:param port: Порт сервера.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
config = Config(app=webhook_app, host=host, port=port, **kwargs)
|
# try:
|
||||||
|
# from uvicorn import Config, Server
|
||||||
|
# except ImportError:
|
||||||
|
# raise ImportError(
|
||||||
|
# '\n\t Не установлен uvicorn!'
|
||||||
|
# '\n\t Выполните команду для установки uvicorn: '
|
||||||
|
# '\n\t pip install uvicorn>=0.15.0'
|
||||||
|
# '\n\t Или сразу все зависимости для работы вебхука:'
|
||||||
|
# '\n\t pip install maxapi[webhook]'
|
||||||
|
# )
|
||||||
|
|
||||||
|
if not UVICORN_INSTALLED:
|
||||||
|
raise ImportError(
|
||||||
|
'\n\t Не установлен uvicorn!'
|
||||||
|
'\n\t Выполните команду для установки uvicorn: '
|
||||||
|
'\n\t pip install uvicorn>=0.15.0'
|
||||||
|
'\n\t Или сразу все зависимости для работы вебхука:'
|
||||||
|
'\n\t pip install maxapi[webhook]'
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.webhook_app is None:
|
||||||
|
raise RuntimeError('webhook_app не инициализирован')
|
||||||
|
|
||||||
|
config = Config(app=self.webhook_app, host=host, port=port, **kwargs)
|
||||||
server = Server(config)
|
server = Server(config)
|
||||||
|
|
||||||
await self.__ready(bot)
|
await self.__ready(bot)
|
||||||
@@ -332,8 +425,8 @@ class Router(Dispatcher):
|
|||||||
Роутер для группировки обработчиков событий.
|
Роутер для группировки обработчиков событий.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, router_id: str | None = None):
|
||||||
super().__init__()
|
super().__init__(router_id)
|
||||||
|
|
||||||
|
|
||||||
class Event:
|
class Event:
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ class UpdateType(str, Enum):
|
|||||||
MESSAGE_REMOVED = 'message_removed'
|
MESSAGE_REMOVED = 'message_removed'
|
||||||
USER_ADDED = 'user_added'
|
USER_ADDED = 'user_added'
|
||||||
USER_REMOVED = 'user_removed'
|
USER_REMOVED = 'user_removed'
|
||||||
|
BOT_STOPPED = 'bot_stopped'
|
||||||
|
DIALOG_CLEARED = 'dialog_cleared'
|
||||||
|
DIALOG_MUTED = 'dialog_muted'
|
||||||
|
DIALOG_UNMUTED = 'dialog_unmuted'
|
||||||
|
|
||||||
# Для начинки диспатчера
|
# Для начинки диспатчера
|
||||||
ON_STARTED = 'on_started'
|
ON_STARTED = 'on_started'
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import Callable, List
|
from typing import Callable, List, Optional
|
||||||
|
|
||||||
from magic_filter import F, MagicFilter
|
from magic_filter import F, MagicFilter
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ class Handler:
|
|||||||
self.func_event: Callable = func_event
|
self.func_event: Callable = func_event
|
||||||
self.update_type: UpdateType = update_type
|
self.update_type: UpdateType = update_type
|
||||||
self.filters = []
|
self.filters = []
|
||||||
self.state: State = None
|
self.state: Optional[State] = None
|
||||||
self.middlewares: List[BaseMiddleware] = []
|
self.middlewares: List[BaseMiddleware] = []
|
||||||
|
|
||||||
for arg in args:
|
for arg in args:
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ class BaseMiddleware:
|
|||||||
kwargs_temp = {'data': result_data_kwargs.copy()}
|
kwargs_temp = {'data': result_data_kwargs.copy()}
|
||||||
|
|
||||||
for key in kwargs_temp.copy().keys():
|
for key in kwargs_temp.copy().keys():
|
||||||
if not key in self.__call__.__annotations__.keys():
|
if key not in self.__call__.__annotations__.keys(): # type: ignore
|
||||||
del kwargs_temp[key]
|
del kwargs_temp[key]
|
||||||
|
|
||||||
result: Dict[str, Any] = await self(event_object, **kwargs_temp)
|
result: Dict[str, Any] = await self(event_object, **kwargs_temp) # type: ignore
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -48,7 +48,8 @@ class AddAdminChat(BaseConnection):
|
|||||||
AddedListAdminChat: Результат операции с информацией об успешности.
|
AddedListAdminChat: Результат операции с информацией об успешности.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
json: Dict[str, Any] = {}
|
json: Dict[str, Any] = {}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ class AddMembersChat(BaseConnection):
|
|||||||
AddedMembersChat: Результат операции с информацией об успешности добавления.
|
AddedMembersChat: Результат операции с информацией об успешности добавления.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
json: Dict[str, Any] = {}
|
json: Dict[str, Any] = {}
|
||||||
|
|
||||||
|
|||||||
@@ -48,14 +48,19 @@ class ChangeInfo(BaseConnection):
|
|||||||
User: Объект с обновленными данными бота
|
User: Объект с обновленными данными бота
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
json: Dict[str, Any] = {}
|
json: Dict[str, Any] = {}
|
||||||
|
|
||||||
if self.name: json['name'] = self.name
|
if self.name:
|
||||||
if self.description: json['description'] = self.description
|
json['name'] = self.name
|
||||||
if self.commands: json['commands'] = [command.model_dump() for command in self.commands]
|
if self.description:
|
||||||
if self.photo: json['photo'] = self.photo
|
json['description'] = self.description
|
||||||
|
if self.commands:
|
||||||
|
json['commands'] = [command.model_dump() for command in self.commands]
|
||||||
|
if self.photo:
|
||||||
|
json['photo'] = self.photo
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.PATCH,
|
method=HTTPMethod.PATCH,
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ class DeleteMeFromMessage(BaseConnection):
|
|||||||
DeletedBotFromChat: Результат операции удаления.
|
DeletedBotFromChat: Результат операции удаления.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.DELETE,
|
method=HTTPMethod.DELETE,
|
||||||
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ME,
|
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ME,
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ class DeleteChat(BaseConnection):
|
|||||||
DeletedChat: Результат операции удаления чата.
|
DeletedChat: Результат операции удаления чата.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.DELETE,
|
method=HTTPMethod.DELETE,
|
||||||
path=ApiPath.CHATS.value + '/' + str(self.chat_id),
|
path=ApiPath.CHATS.value + '/' + str(self.chat_id),
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ class DeleteMessage(BaseConnection):
|
|||||||
DeletedMessage: Результат операции удаления сообщения.
|
DeletedMessage: Результат операции удаления сообщения.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
params = self.bot.params.copy()
|
params = self.bot.params.copy()
|
||||||
|
|
||||||
params['message_id'] = self.message_id
|
params['message_id'] = self.message_id
|
||||||
|
|||||||
@@ -38,7 +38,10 @@ class DeletePinMessage(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
DeletedPinMessage: Результат операции удаления закреплённого сообщения.
|
DeletedPinMessage: Результат операции удаления закреплённого сообщения.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.DELETE,
|
method=HTTPMethod.DELETE,
|
||||||
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.PIN,
|
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.PIN,
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
from typing import TYPE_CHECKING
|
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
|
from ..connection.base import BaseConnection
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -64,14 +64,16 @@ class EditChat(BaseConnection):
|
|||||||
Chat: Обновлённый объект чата.
|
Chat: Обновлённый объект чата.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
json: Dict[str, Any] = {}
|
json: Dict[str, Any] = {}
|
||||||
|
|
||||||
if self.icon:
|
if self.icon:
|
||||||
dump = self.icon.model_dump()
|
dump = self.icon.model_dump()
|
||||||
counter = Counter(dump.values())
|
counter = Counter(dump.values())
|
||||||
|
|
||||||
if not None in counter or \
|
if None not in counter or \
|
||||||
not counter[None] == 2:
|
not counter[None] == 2:
|
||||||
|
|
||||||
raise MaxIconParamsException(
|
raise MaxIconParamsException(
|
||||||
@@ -81,9 +83,12 @@ class EditChat(BaseConnection):
|
|||||||
|
|
||||||
json['icon'] = dump
|
json['icon'] = dump
|
||||||
|
|
||||||
if self.title: json['title'] = self.title
|
if self.title:
|
||||||
if self.pin: json['pin'] = self.pin
|
json['title'] = self.title
|
||||||
if self.notify: json['notify'] = self.notify
|
if self.pin:
|
||||||
|
json['pin'] = self.pin
|
||||||
|
if self.notify:
|
||||||
|
json['notify'] = self.notify
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.PATCH,
|
method=HTTPMethod.PATCH,
|
||||||
|
|||||||
@@ -66,14 +66,17 @@ class EditMessage(BaseConnection):
|
|||||||
EditedMessage: Обновлённое сообщение.
|
EditedMessage: Обновлённое сообщение.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
params = self.bot.params.copy()
|
params = self.bot.params.copy()
|
||||||
|
|
||||||
json: Dict[str, Any] = {'attachments': []}
|
json: Dict[str, Any] = {'attachments': []}
|
||||||
|
|
||||||
params['message_id'] = self.message_id
|
params['message_id'] = self.message_id
|
||||||
|
|
||||||
if not self.text is None: json['text'] = self.text
|
if self.text is not None:
|
||||||
|
json['text'] = self.text
|
||||||
|
|
||||||
if self.attachments:
|
if self.attachments:
|
||||||
|
|
||||||
@@ -91,9 +94,12 @@ class EditMessage(BaseConnection):
|
|||||||
else:
|
else:
|
||||||
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 self.link is not None:
|
||||||
if not self.notify is None: json['notify'] = self.notify
|
json['link'] = self.link.model_dump()
|
||||||
if not self.parse_mode is None: json['format'] = self.parse_mode.value
|
if self.notify is not None:
|
||||||
|
json['notify'] = self.notify
|
||||||
|
if self.parse_mode is not None:
|
||||||
|
json['format'] = self.parse_mode.value
|
||||||
|
|
||||||
await asyncio.sleep(self.bot.after_input_media_delay)
|
await asyncio.sleep(self.bot.after_input_media_delay)
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ class GetChatById(BaseConnection):
|
|||||||
Chat: Объект чата с полной информацией.
|
Chat: Объект чата с полной информацией.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.GET,
|
method=HTTPMethod.GET,
|
||||||
path=ApiPath.CHATS.value + '/' + str(self.id),
|
path=ApiPath.CHATS.value + '/' + str(self.id),
|
||||||
|
|||||||
@@ -49,7 +49,9 @@ class GetChatByLink(BaseConnection):
|
|||||||
Chat: Объект с информацией о чате.
|
Chat: Объект с информацией о чате.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.GET,
|
method=HTTPMethod.GET,
|
||||||
path=ApiPath.CHATS.value + '/' + self.link[-1],
|
path=ApiPath.CHATS.value + '/' + self.link[-1],
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ class GetChats(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
Chats: Объект с данными по списку чатов.
|
Chats: Объект с данными по списку чатов.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
params = self.bot.params.copy()
|
params = self.bot.params.copy()
|
||||||
|
|
||||||
params['count'] = self.count
|
params['count'] = self.count
|
||||||
|
|||||||
@@ -42,7 +42,10 @@ class GetListAdminChat(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
GettedListAdminChat: Объект с информацией о администраторах чата.
|
GettedListAdminChat: Объект с информацией о администраторах чата.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.GET,
|
method=HTTPMethod.GET,
|
||||||
path=ApiPath.CHATS.value + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ADMINS,
|
path=ApiPath.CHATS.value + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ADMINS,
|
||||||
|
|||||||
@@ -32,7 +32,10 @@ class GetMe(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
User: Объект пользователя с полной информацией.
|
User: Объект пользователя с полной информацией.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.GET,
|
method=HTTPMethod.GET,
|
||||||
path=ApiPath.ME,
|
path=ApiPath.ME,
|
||||||
|
|||||||
@@ -42,7 +42,10 @@ class GetMeFromChat(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
ChatMember: Информация о боте как участнике чата.
|
ChatMember: Информация о боте как участнике чата.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.GET,
|
method=HTTPMethod.GET,
|
||||||
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ME,
|
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ME,
|
||||||
|
|||||||
@@ -57,14 +57,19 @@ class GetMembersChat(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
GettedMembersChat: Объект с данными по участникам чата.
|
GettedMembersChat: Объект с данными по участникам чата.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
params = self.bot.params.copy()
|
params = self.bot.params.copy()
|
||||||
|
|
||||||
if self.user_ids:
|
if self.user_ids:
|
||||||
params['user_ids'] = ','.join([str(user_id) for user_id in self.user_ids])
|
params['user_ids'] = ','.join([str(user_id) for user_id in self.user_ids])
|
||||||
|
|
||||||
if self.marker: params['marker'] = self.marker
|
if self.marker:
|
||||||
if self.count: params['marker'] = self.count
|
params['marker'] = self.marker
|
||||||
|
if self.count:
|
||||||
|
params['marker'] = self.count
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.GET,
|
method=HTTPMethod.GET,
|
||||||
|
|||||||
@@ -59,10 +59,14 @@ class GetMessages(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
Messages: Объект с полученными сообщениями.
|
Messages: Объект с полученными сообщениями.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
params = self.bot.params.copy()
|
params = self.bot.params.copy()
|
||||||
|
|
||||||
if self.chat_id: params['chat_id'] = self.chat_id
|
if self.chat_id:
|
||||||
|
params['chat_id'] = self.chat_id
|
||||||
|
|
||||||
if self.message_ids:
|
if self.message_ids:
|
||||||
params['message_ids'] = ','.join(self.message_ids)
|
params['message_ids'] = ','.join(self.message_ids)
|
||||||
|
|||||||
@@ -37,7 +37,10 @@ class GetPinnedMessage(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
GettedPin: Объект с информацией о закреплённом сообщении.
|
GettedPin: Объект с информацией о закреплённом сообщении.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.GET,
|
method=HTTPMethod.GET,
|
||||||
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.PIN,
|
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.PIN,
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import TYPE_CHECKING, Dict
|
from typing import TYPE_CHECKING, Dict
|
||||||
|
|
||||||
from ..types.updates import UpdateUnion
|
|
||||||
|
|
||||||
from ..enums.http_method import HTTPMethod
|
from ..enums.http_method import HTTPMethod
|
||||||
from ..enums.api_path import ApiPath
|
from ..enums.api_path import ApiPath
|
||||||
|
|
||||||
@@ -45,7 +43,10 @@ class GetUpdates(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
UpdateUnion: Объединённый тип данных обновлений.
|
UpdateUnion: Объединённый тип данных обновлений.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
params = self.bot.params.copy()
|
params = self.bot.params.copy()
|
||||||
|
|
||||||
params['limit'] = self.limit
|
params['limit'] = self.limit
|
||||||
|
|||||||
@@ -43,7 +43,10 @@ class GetUploadURL(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
GettedUploadUrl: Результат с URL для загрузки.
|
GettedUploadUrl: Результат с URL для загрузки.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
params = self.bot.params.copy()
|
params = self.bot.params.copy()
|
||||||
|
|
||||||
params['type'] = self.type.value
|
params['type'] = self.type.value
|
||||||
|
|||||||
@@ -38,7 +38,10 @@ class GetVideo(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
Video: Объект с информацией о видео.
|
Video: Объект с информацией о видео.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.GET,
|
method=HTTPMethod.GET,
|
||||||
path=ApiPath.VIDEOS.value + '/' + self.video_token,
|
path=ApiPath.VIDEOS.value + '/' + self.video_token,
|
||||||
|
|||||||
@@ -52,7 +52,10 @@ class PinMessage(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
PinnedMessage: Объект с информацией о закреплённом сообщении.
|
PinnedMessage: Объект с информацией о закреплённом сообщении.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
json: Dict[str, Any] = {}
|
json: Dict[str, Any] = {}
|
||||||
|
|
||||||
json['message_id'] = self.message_id
|
json['message_id'] = self.message_id
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ class RemoveAdmin(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
RemovedAdmin: Объект с результатом отмены прав администратора.
|
RemovedAdmin: Объект с результатом отмены прав администратора.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.DELETE,
|
method=HTTPMethod.DELETE,
|
||||||
path=ApiPath.CHATS + '/' + str(self.chat_id) + \
|
path=ApiPath.CHATS + '/' + str(self.chat_id) + \
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ class RemoveMemberChat(BaseConnection):
|
|||||||
RemovedMemberChat: Результат удаления участника.
|
RemovedMemberChat: Результат удаления участника.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
params = self.bot.params.copy()
|
params = self.bot.params.copy()
|
||||||
|
|
||||||
params['chat_id'] = self.chat_id
|
params['chat_id'] = self.chat_id
|
||||||
|
|||||||
@@ -49,7 +49,9 @@ class SendAction(BaseConnection):
|
|||||||
Returns:
|
Returns:
|
||||||
SendedAction: Результат выполнения запроса.
|
SendedAction: Результат выполнения запроса.
|
||||||
"""
|
"""
|
||||||
assert self.bot is not None
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
json: Dict[str, Any] = {}
|
json: Dict[str, Any] = {}
|
||||||
|
|
||||||
|
|||||||
@@ -55,15 +55,19 @@ class SendCallback(BaseConnection):
|
|||||||
SendedCallback: Объект с результатом отправки callback.
|
SendedCallback: Объект с результатом отправки callback.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
params = self.bot.params.copy()
|
params = self.bot.params.copy()
|
||||||
|
|
||||||
params['callback_id'] = self.callback_id
|
params['callback_id'] = self.callback_id
|
||||||
|
|
||||||
json: Dict[str, Any] = {}
|
json: Dict[str, Any] = {}
|
||||||
|
|
||||||
if self.message: json['message'] = self.message.model_dump()
|
if self.message:
|
||||||
if self.notification: json['notification'] = self.notification
|
json['message'] = self.message.model_dump()
|
||||||
|
if self.notification:
|
||||||
|
json['notification'] = self.notification
|
||||||
|
|
||||||
return await super().request(
|
return await super().request(
|
||||||
method=HTTPMethod.POST,
|
method=HTTPMethod.POST,
|
||||||
|
|||||||
@@ -70,21 +70,29 @@ class SendMessage(BaseConnection):
|
|||||||
SendedMessage или Error
|
SendedMessage или Error
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
params = self.bot.params.copy()
|
params = self.bot.params.copy()
|
||||||
|
|
||||||
json: Dict[str, Any] = {'attachments': []}
|
json: Dict[str, Any] = {'attachments': []}
|
||||||
|
|
||||||
if self.chat_id: params['chat_id'] = self.chat_id
|
if self.chat_id:
|
||||||
elif self.user_id: params['user_id'] = self.user_id
|
params['chat_id'] = self.chat_id
|
||||||
|
elif self.user_id:
|
||||||
|
params['user_id'] = self.user_id
|
||||||
|
|
||||||
json['text'] = self.text
|
json['text'] = self.text
|
||||||
|
|
||||||
|
HAS_INPUT_MEDIA = False
|
||||||
|
|
||||||
if self.attachments:
|
if self.attachments:
|
||||||
|
|
||||||
for att in self.attachments:
|
for att in self.attachments:
|
||||||
|
|
||||||
if isinstance(att, InputMedia) or isinstance(att, InputMediaBuffer):
|
if isinstance(att, (InputMedia, InputMediaBuffer)):
|
||||||
|
HAS_INPUT_MEDIA = True
|
||||||
|
|
||||||
input_media = await process_input_media(
|
input_media = await process_input_media(
|
||||||
base_connection=self,
|
base_connection=self,
|
||||||
bot=self.bot,
|
bot=self.bot,
|
||||||
@@ -96,11 +104,16 @@ class SendMessage(BaseConnection):
|
|||||||
else:
|
else:
|
||||||
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 self.link is not None:
|
||||||
json['notify'] = self.notify
|
json['link'] = self.link.model_dump()
|
||||||
if not self.parse_mode is None: json['format'] = self.parse_mode.value
|
|
||||||
|
|
||||||
await asyncio.sleep(self.bot.after_input_media_delay)
|
json['notify'] = self.notify
|
||||||
|
|
||||||
|
if self.parse_mode is not None:
|
||||||
|
json['format'] = self.parse_mode.value
|
||||||
|
|
||||||
|
if HAS_INPUT_MEDIA:
|
||||||
|
await asyncio.sleep(self.bot.after_input_media_delay)
|
||||||
|
|
||||||
response = None
|
response = None
|
||||||
for attempt in range(self.ATTEMPTS_COUNT):
|
for attempt in range(self.ATTEMPTS_COUNT):
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from ...utils.updates import enrich_event
|
||||||
|
|
||||||
from ...enums.update import UpdateType
|
from ...enums.update import UpdateType
|
||||||
from ...types.updates.bot_added import BotAdded
|
from ...types.updates.bot_added import BotAdded
|
||||||
from ...types.updates.bot_removed import BotRemoved
|
from ...types.updates.bot_removed import BotRemoved
|
||||||
from ...types.updates.bot_started import BotStarted
|
from ...types.updates.bot_started import BotStarted
|
||||||
|
from ...types.updates.bot_stopped import BotStopped
|
||||||
from ...types.updates.chat_title_changed import ChatTitleChanged
|
from ...types.updates.chat_title_changed import ChatTitleChanged
|
||||||
from ...types.updates.message_callback import MessageCallback
|
from ...types.updates.message_callback import MessageCallback
|
||||||
from ...types.updates.message_chat_created import MessageChatCreated
|
from ...types.updates.message_chat_created import MessageChatCreated
|
||||||
@@ -12,125 +15,54 @@ 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.dialog_cleared import DialogCleared
|
||||||
|
from ...types.updates.dialog_muted import DialogMuted
|
||||||
|
from ...types.updates.dialog_unmuted import DialogUnmuted
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ...bot import Bot
|
from ...bot import Bot
|
||||||
|
|
||||||
|
|
||||||
|
UPDATE_MODEL_MAPPING = {
|
||||||
|
UpdateType.BOT_ADDED: BotAdded,
|
||||||
|
UpdateType.BOT_REMOVED: BotRemoved,
|
||||||
|
UpdateType.BOT_STARTED: BotStarted,
|
||||||
|
UpdateType.CHAT_TITLE_CHANGED: ChatTitleChanged,
|
||||||
|
UpdateType.MESSAGE_CALLBACK: MessageCallback,
|
||||||
|
UpdateType.MESSAGE_CHAT_CREATED: MessageChatCreated,
|
||||||
|
UpdateType.MESSAGE_CREATED: MessageCreated,
|
||||||
|
UpdateType.MESSAGE_EDITED: MessageEdited,
|
||||||
|
UpdateType.MESSAGE_REMOVED: MessageRemoved,
|
||||||
|
UpdateType.USER_ADDED: UserAdded,
|
||||||
|
UpdateType.USER_REMOVED: UserRemoved,
|
||||||
|
UpdateType.BOT_STOPPED: BotStopped,
|
||||||
|
UpdateType.DIALOG_CLEARED: DialogCleared,
|
||||||
|
UpdateType.DIALOG_MUTED: DialogMuted,
|
||||||
|
UpdateType.DIALOG_UNMUTED: DialogUnmuted
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def get_update_model(event: dict, bot: 'Bot'):
|
async def get_update_model(event: dict, bot: 'Bot'):
|
||||||
event_object = None
|
update_type = event['update_type']
|
||||||
|
model_cls = UPDATE_MODEL_MAPPING.get(update_type)
|
||||||
|
|
||||||
match event['update_type']:
|
if not model_cls:
|
||||||
|
raise ValueError(f'Unknown update type: {update_type}')
|
||||||
|
|
||||||
case UpdateType.BOT_ADDED:
|
event_object = await enrich_event(
|
||||||
event_object = BotAdded(**event)
|
event_object=model_cls(**event),
|
||||||
|
bot=bot
|
||||||
case UpdateType.BOT_REMOVED:
|
)
|
||||||
event_object = BotRemoved(**event)
|
|
||||||
|
|
||||||
case UpdateType.BOT_STARTED:
|
|
||||||
event_object = BotStarted(**event)
|
|
||||||
|
|
||||||
case UpdateType.CHAT_TITLE_CHANGED:
|
|
||||||
event_object = ChatTitleChanged(**event)
|
|
||||||
|
|
||||||
case UpdateType.MESSAGE_CALLBACK:
|
|
||||||
event_object = MessageCallback(**event)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
case UpdateType.MESSAGE_CHAT_CREATED:
|
|
||||||
event_object = MessageChatCreated(**event)
|
|
||||||
event_object.chat = event_object.chat
|
|
||||||
|
|
||||||
case UpdateType.MESSAGE_CREATED:
|
|
||||||
event_object = MessageCreated(**event)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
case UpdateType.MESSAGE_EDITED:
|
|
||||||
event_object = MessageEdited(**event)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
case UpdateType.MESSAGE_REMOVED:
|
|
||||||
event_object = MessageRemoved(**event)
|
|
||||||
|
|
||||||
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(
|
|
||||||
chat_id=event_object.chat_id,
|
|
||||||
user_id=event_object.user_id
|
|
||||||
) if bot.auto_requests else None
|
|
||||||
|
|
||||||
case UpdateType.USER_ADDED:
|
|
||||||
event_object = UserAdded(**event)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
case UpdateType.USER_REMOVED:
|
|
||||||
event_object = UserRemoved(**event)
|
|
||||||
|
|
||||||
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(
|
|
||||||
chat_id=event_object.chat_id,
|
|
||||||
user_id=event_object.admin_id
|
|
||||||
) if event_object.admin_id and \
|
|
||||||
bot.auto_requests 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) \
|
|
||||||
if bot.auto_requests else None
|
|
||||||
|
|
||||||
event_object.from_user = event_object.user
|
|
||||||
|
|
||||||
if hasattr(event_object, 'bot'):
|
|
||||||
event_object.bot = bot
|
|
||||||
|
|
||||||
if hasattr(event_object, 'message'):
|
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def process_update_request(events: dict, bot: 'Bot'):
|
async def process_update_request(events: dict, bot: 'Bot'):
|
||||||
events = [event for event in events['updates']]
|
return [
|
||||||
|
await get_update_model(event, bot)
|
||||||
objects = []
|
for event in events['updates']
|
||||||
|
]
|
||||||
for event in events:
|
|
||||||
|
|
||||||
objects.append(
|
|
||||||
await get_update_model(
|
|
||||||
bot=bot,
|
|
||||||
event=event
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return objects
|
|
||||||
|
|
||||||
|
|
||||||
async def process_update_webhook(event_json: dict, bot: 'Bot'):
|
async def process_update_webhook(event_json: dict, bot: 'Bot'):
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ class SendedCallback(BaseModel):
|
|||||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
bot: Optional[Bot]
|
bot: Optional[Bot] # type: ignore
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ 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.bot_stopped import BotStopped
|
||||||
|
from ..types.updates.dialog_cleared import DialogCleared
|
||||||
|
from ..types.updates.dialog_muted import DialogMuted
|
||||||
|
from ..types.updates.dialog_unmuted import DialogUnmuted
|
||||||
from ..types.updates import UpdateUnion
|
from ..types.updates import UpdateUnion
|
||||||
|
|
||||||
from ..types.attachments.attachment import Attachment
|
from ..types.attachments.attachment import Attachment
|
||||||
@@ -32,6 +36,10 @@ from .input_media import InputMedia
|
|||||||
from .input_media import InputMediaBuffer
|
from .input_media import InputMediaBuffer
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
'DialogUnmuted',
|
||||||
|
'DialogMuted',
|
||||||
|
'DialogCleared',
|
||||||
|
'BotStopped',
|
||||||
'CommandStart',
|
'CommandStart',
|
||||||
'OpenAppButton',
|
'OpenAppButton',
|
||||||
'Message',
|
'Message',
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
from typing import TYPE_CHECKING, Any, List, Optional, Union
|
from typing import TYPE_CHECKING, Any, List, Optional, Union
|
||||||
from pydantic import BaseModel, Field
|
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
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ class ChatButton(Button):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
type: ButtonType = ButtonType.CHAT
|
type: ButtonType = ButtonType.CHAT
|
||||||
chat_title: Optional[str] = None
|
chat_title: str
|
||||||
chat_description: Optional[str] = None
|
chat_description: Optional[str] = None
|
||||||
start_payload: Optional[str] = None
|
start_payload: Optional[str] = None
|
||||||
chat_title: Optional[str] = None
|
|
||||||
uuid: Optional[int] = None
|
uuid: Optional[int] = None
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
from ....enums.button_type import ButtonType
|
from ....enums.button_type import ButtonType
|
||||||
|
|
||||||
from .button import Button
|
from .button import Button
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from ....enums.button_type import ButtonType
|
from ....enums.button_type import ButtonType
|
||||||
|
|
||||||
from .button import Button
|
from .button import Button
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Literal, Optional
|
from typing import TYPE_CHECKING, Any, Optional
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from ...enums.attachment import AttachmentType
|
from ...enums.attachment import AttachmentType
|
||||||
|
|||||||
@@ -1,16 +1,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
import puremagic
|
import puremagic
|
||||||
|
|
||||||
from ..enums.upload_type import UploadType
|
from ..enums.upload_type import UploadType
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from io import BytesIO
|
|
||||||
|
|
||||||
|
|
||||||
class InputMedia:
|
class InputMedia:
|
||||||
"""
|
"""
|
||||||
Класс для представления медиафайла.
|
Класс для представления медиафайла.
|
||||||
@@ -74,13 +68,15 @@ class InputMediaBuffer:
|
|||||||
type (UploadType): Тип файла, определенный по содержимому.
|
type (UploadType): Тип файла, определенный по содержимому.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, buffer: bytes):
|
def __init__(self, buffer: bytes, filename: str | None = None):
|
||||||
"""
|
"""
|
||||||
Инициализирует объект медиафайла из буфера.
|
Инициализирует объект медиафайла из буфера.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
buffer (IO): Буфер с содержимым файла.
|
buffer (IO): Буфер с содержимым файла.
|
||||||
|
filename (str): Название файла (по умолчанию присваивается uuid4).
|
||||||
"""
|
"""
|
||||||
|
self.filename = filename
|
||||||
self.buffer = buffer
|
self.buffer = buffer
|
||||||
self.type = self.__detect_file_type(buffer)
|
self.type = self.__detect_file_type(buffer)
|
||||||
|
|
||||||
|
|||||||
@@ -195,7 +195,9 @@ class Message(BaseModel):
|
|||||||
Any: Результат выполнения метода send_message бота.
|
Any: Результат выполнения метода send_message бота.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await self.bot.send_message(
|
return await self.bot.send_message(
|
||||||
chat_id=self.recipient.chat_id,
|
chat_id=self.recipient.chat_id,
|
||||||
user_id=self.recipient.user_id,
|
user_id=self.recipient.user_id,
|
||||||
@@ -227,7 +229,9 @@ class Message(BaseModel):
|
|||||||
Any: Результат выполнения метода send_message бота.
|
Any: Результат выполнения метода send_message бота.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await self.bot.send_message(
|
return await self.bot.send_message(
|
||||||
chat_id=self.recipient.chat_id,
|
chat_id=self.recipient.chat_id,
|
||||||
user_id=self.recipient.user_id,
|
user_id=self.recipient.user_id,
|
||||||
@@ -264,7 +268,9 @@ class Message(BaseModel):
|
|||||||
Any: Результат выполнения метода send_message бота.
|
Any: Результат выполнения метода send_message бота.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await self.bot.send_message(
|
return await self.bot.send_message(
|
||||||
chat_id=chat_id,
|
chat_id=chat_id,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
@@ -300,7 +306,9 @@ class Message(BaseModel):
|
|||||||
Any: Результат выполнения метода edit_message бота.
|
Any: Результат выполнения метода edit_message бота.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await self.bot.edit_message(
|
return await self.bot.edit_message(
|
||||||
message_id=self.body.mid,
|
message_id=self.body.mid,
|
||||||
text=text,
|
text=text,
|
||||||
@@ -335,7 +343,9 @@ class Message(BaseModel):
|
|||||||
Any: Результат выполнения метода pin_message бота.
|
Any: Результат выполнения метода pin_message бота.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert self.bot is not None
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
return await self.bot.pin_message(
|
return await self.bot.pin_message(
|
||||||
chat_id=self.recipient.chat_id,
|
chat_id=self.recipient.chat_id,
|
||||||
message_id=self.body.mid,
|
message_id=self.body.mid,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
@@ -14,12 +14,14 @@ class BotAdded(Update):
|
|||||||
Обновление, сигнализирующее о добавлении бота в чат.
|
Обновление, сигнализирующее о добавлении бота в чат.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
chat_id (Optional[int]): Идентификатор чата, куда добавлен бот.
|
chat_id (int): Идентификатор чата, куда добавлен бот.
|
||||||
user (User): Объект пользователя-бота.
|
user (User): Объект пользователя-бота.
|
||||||
|
is_channel (bool): Указывает, был ли бот добавлен в канал или нет
|
||||||
"""
|
"""
|
||||||
|
|
||||||
chat_id: Optional[int] = None
|
chat_id: int
|
||||||
user: User
|
user: User
|
||||||
|
is_channel: bool
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
bot: Optional[Bot]
|
bot: Optional[Bot]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
@@ -14,12 +14,14 @@ class BotRemoved(Update):
|
|||||||
Обновление, сигнализирующее об удалении бота из чата.
|
Обновление, сигнализирующее об удалении бота из чата.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
chat_id (Optional[int]): Идентификатор чата, из которого удалён бот.
|
chat_id (int): Идентификатор чата, из которого удалён бот.
|
||||||
user (User): Объект пользователя-бота.
|
user (User): Объект пользователя-бота.
|
||||||
|
is_channel (bool): Указывает, был ли пользователь добавлен в канал или нет
|
||||||
"""
|
"""
|
||||||
|
|
||||||
chat_id: Optional[int] = None
|
chat_id: int
|
||||||
user: User
|
user: User
|
||||||
|
is_channel: bool
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
bot: Optional[Bot]
|
bot: Optional[Bot]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
@@ -14,13 +14,13 @@ class BotStarted(Update):
|
|||||||
Обновление, сигнализирующее о первом старте бота.
|
Обновление, сигнализирующее о первом старте бота.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
chat_id (Optional[int]): Идентификатор чата.
|
chat_id (int): Идентификатор чата.
|
||||||
user (User): Пользователь (бот).
|
user (User): Пользователь (бот).
|
||||||
user_locale (Optional[str]): Локаль пользователя.
|
user_locale (Optional[str]): Локаль пользователя.
|
||||||
payload (Optional[str]): Дополнительные данные.
|
payload (Optional[str]): Дополнительные данные.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
chat_id: Optional[int] = None
|
chat_id: int
|
||||||
user: User
|
user: User
|
||||||
user_locale: Optional[str] = None
|
user_locale: Optional[str] = None
|
||||||
payload: Optional[str] = None
|
payload: Optional[str] = None
|
||||||
|
|||||||
32
maxapi/types/updates/bot_stopped.py
Normal file
32
maxapi/types/updates/bot_stopped.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
from .update import Update
|
||||||
|
|
||||||
|
from ...types.users import User
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ...bot import Bot
|
||||||
|
|
||||||
|
|
||||||
|
class BotStopped(Update):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Обновление, сигнализирующее об остановке бота.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
chat_id (int): Идентификатор чата.
|
||||||
|
user (User): Пользователь (бот).
|
||||||
|
user_locale (Optional[str]): Локаль пользователя.
|
||||||
|
payload (Optional[str]): Дополнительные данные.
|
||||||
|
"""
|
||||||
|
|
||||||
|
chat_id: int
|
||||||
|
user: User
|
||||||
|
user_locale: Optional[str] = None
|
||||||
|
payload: Optional[str] = None
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
bot: Optional[Bot]
|
||||||
|
|
||||||
|
def get_ids(self):
|
||||||
|
return (self.chat_id, self.user.user_id)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import TYPE_CHECKING, Any, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
@@ -16,12 +16,12 @@ class ChatTitleChanged(Update):
|
|||||||
Attributes:
|
Attributes:
|
||||||
chat_id (Optional[int]): Идентификатор чата.
|
chat_id (Optional[int]): Идентификатор чата.
|
||||||
user (User): Пользователь, совершивший изменение.
|
user (User): Пользователь, совершивший изменение.
|
||||||
title (Optional[str]): Новое название чата.
|
title (str): Новое название чата.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
chat_id: Optional[int] = None
|
chat_id: int
|
||||||
user: User
|
user: User
|
||||||
title: Optional[str] = None
|
title: str
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
bot: Optional[Bot]
|
bot: Optional[Bot]
|
||||||
|
|||||||
30
maxapi/types/updates/dialog_cleared.py
Normal file
30
maxapi/types/updates/dialog_cleared.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
from .update import Update
|
||||||
|
|
||||||
|
from ...types.users import User
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ...bot import Bot
|
||||||
|
|
||||||
|
|
||||||
|
class DialogCleared(Update):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Обновление, сигнализирующее об очистке диалога с ботом.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
chat_id (int): Идентификатор чата.
|
||||||
|
user (User): Пользователь (бот).
|
||||||
|
user_locale (Optional[str]): Локаль пользователя.
|
||||||
|
"""
|
||||||
|
|
||||||
|
chat_id: int
|
||||||
|
user: User
|
||||||
|
user_locale: Optional[str] = None
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
bot: Optional[Bot]
|
||||||
|
|
||||||
|
def get_ids(self):
|
||||||
|
return (self.chat_id, self.user.user_id)
|
||||||
40
maxapi/types/updates/dialog_muted.py
Normal file
40
maxapi/types/updates/dialog_muted.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from .update import Update
|
||||||
|
|
||||||
|
from ...types.users import User
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ...bot import Bot
|
||||||
|
|
||||||
|
|
||||||
|
class DialogMuted(Update):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Обновление, сигнализирующее об отключении оповещений от бота.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
chat_id (int): Идентификатор чата.
|
||||||
|
muted_until (int): Время до включения оповещений от бота.
|
||||||
|
user (User): Пользователь (бот).
|
||||||
|
user_locale (Optional[str]): Локаль пользователя.
|
||||||
|
"""
|
||||||
|
|
||||||
|
chat_id: int
|
||||||
|
muted_until: int
|
||||||
|
user: User
|
||||||
|
user_locale: Optional[str] = None
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
bot: Optional[Bot]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def muted_until_datetime(self):
|
||||||
|
try:
|
||||||
|
return datetime.fromtimestamp(self.muted_until // 1000)
|
||||||
|
except (OverflowError, OSError):
|
||||||
|
return datetime.max
|
||||||
|
|
||||||
|
def get_ids(self):
|
||||||
|
return (self.chat_id, self.user.user_id)
|
||||||
30
maxapi/types/updates/dialog_unmuted.py
Normal file
30
maxapi/types/updates/dialog_unmuted.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
from .update import Update
|
||||||
|
|
||||||
|
from ...types.users import User
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ...bot import Bot
|
||||||
|
|
||||||
|
|
||||||
|
class DialogUnmuted(Update):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Обновление, сигнализирующее о включении оповещений от бота.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
chat_id (int): Идентификатор чата.
|
||||||
|
user (User): Пользователь (бот).
|
||||||
|
user_locale (Optional[str]): Локаль пользователя.
|
||||||
|
"""
|
||||||
|
|
||||||
|
chat_id: int
|
||||||
|
user: User
|
||||||
|
user_locale: Optional[str] = None
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
bot: Optional[Bot]
|
||||||
|
|
||||||
|
def get_ids(self):
|
||||||
|
return (self.chat_id, self.user.user_id)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import List, Optional, TYPE_CHECKING, Union
|
from typing import List, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
@@ -21,12 +21,6 @@ from ..attachments.video import Video
|
|||||||
from ..attachments.audio import Audio
|
from ..attachments.audio import Audio
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from ...bot import Bot
|
|
||||||
from ...types.chats import Chat
|
|
||||||
from ...types.users import User
|
|
||||||
|
|
||||||
|
|
||||||
class MessageForCallback(BaseModel):
|
class MessageForCallback(BaseModel):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -110,6 +104,9 @@ class MessageCallback(Update):
|
|||||||
Результат вызова send_callback бота.
|
Результат вызова send_callback бота.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self.bot is None:
|
||||||
|
raise RuntimeError('Bot не инициализирован')
|
||||||
|
|
||||||
message = MessageForCallback()
|
message = MessageForCallback()
|
||||||
|
|
||||||
message.text = new_text
|
message.text = new_text
|
||||||
@@ -118,7 +115,6 @@ class MessageCallback(Update):
|
|||||||
message.notify = notify
|
message.notify = notify
|
||||||
message.format = format
|
message.format = format
|
||||||
|
|
||||||
assert self.bot is not None
|
|
||||||
return await self.bot.send_callback(
|
return await self.bot.send_callback(
|
||||||
callback_id=self.callback.callback_id,
|
callback_id=self.callback.callback_id,
|
||||||
message=message,
|
message=message,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Optional, TYPE_CHECKING
|
from typing import Optional
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
from .update import Update
|
from .update import Update
|
||||||
|
|
||||||
|
|
||||||
@@ -9,14 +7,14 @@ class MessageRemoved(Update):
|
|||||||
Класс для обработки события удаления сообщения в чате.
|
Класс для обработки события удаления сообщения в чате.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
message_id (Optional[str]): Идентификатор удаленного сообщения. Может быть None.
|
message_id (str): Идентификатор удаленного сообщения. Может быть None.
|
||||||
chat_id (Optional[int]): Идентификатор чата. Может быть None.
|
chat_id (int): Идентификатор чата. Может быть None.
|
||||||
user_id (Optional[int]): Идентификатор пользователя. Может быть None.
|
user_id (int): Идентификатор пользователя. Может быть None.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
message_id: Optional[str] = None
|
message_id: str
|
||||||
chat_id: Optional[int] = None
|
chat_id: int
|
||||||
user_id: Optional[int] = None
|
user_id: int
|
||||||
|
|
||||||
def get_ids(self):
|
def get_ids(self):
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ class Update(BaseModel):
|
|||||||
chat: Optional[Any] = Field(default=None, exclude=True)
|
chat: Optional[Any] = Field(default=None, exclude=True)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
bot: Optional[Bot]
|
bot: Optional[Bot] # type: ignore
|
||||||
from_user: Optional[User]
|
from_user: Optional[User] # type: ignore
|
||||||
chat: Optional[Chat]
|
chat: Optional[Chat] # type: ignore
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
arbitrary_types_allowed=True
|
arbitrary_types_allowed=True
|
||||||
@@ -11,14 +11,16 @@ class UserAdded(Update):
|
|||||||
Класс для обработки события добавления пользователя в чат.
|
Класс для обработки события добавления пользователя в чат.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
inviter_id (Optional[int]): Идентификатор пользователя, добавившего нового участника. Может быть None.
|
inviter_id (int): Идентификатор пользователя, добавившего нового участника. Может быть None.
|
||||||
chat_id (Optional[int]): Идентификатор чата. Может быть None.
|
chat_id (int): Идентификатор чата. Может быть None.
|
||||||
user (User): Объект пользователя, добавленного в чат.
|
user (User): Объект пользователя, добавленного в чат.
|
||||||
|
is_channel (bool): Указывает, был ли пользователь добавлен в канал или нет
|
||||||
"""
|
"""
|
||||||
|
|
||||||
inviter_id: Optional[int] = None
|
inviter_id: Optional[int] = None
|
||||||
chat_id: Optional[int] = None
|
chat_id: int
|
||||||
user: User
|
user: User
|
||||||
|
is_channel: bool
|
||||||
|
|
||||||
def get_ids(self):
|
def get_ids(self):
|
||||||
|
|
||||||
|
|||||||
@@ -12,13 +12,15 @@ class UserRemoved(Update):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
admin_id (Optional[int]): Идентификатор администратора, удалившего пользователя. Может быть None.
|
admin_id (Optional[int]): Идентификатор администратора, удалившего пользователя. Может быть None.
|
||||||
chat_id (Optional[int]): Идентификатор чата. Может быть None.
|
chat_id (int): Идентификатор чата. Может быть None.
|
||||||
user (User): Объект пользователя, удаленного из чата.
|
user (User): Объект пользователя, удаленного из чата.
|
||||||
|
is_channel (bool): Указывает, был ли пользователь удален из канала или нет
|
||||||
"""
|
"""
|
||||||
|
|
||||||
admin_id: Optional[int] = None
|
admin_id: Optional[int] = None
|
||||||
chat_id: Optional[int] = None
|
chat_id: int
|
||||||
user: User
|
user: User
|
||||||
|
is_channel: bool
|
||||||
|
|
||||||
def get_ids(self):
|
def get_ids(self):
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,13 @@ class User(BaseModel):
|
|||||||
full_avatar_url: Optional[str] = None
|
full_avatar_url: Optional[str] = None
|
||||||
commands: Optional[List[BotCommand]] = None
|
commands: Optional[List[BotCommand]] = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def full_name(self):
|
||||||
|
if self.last_name is None:
|
||||||
|
return self.first_name
|
||||||
|
|
||||||
|
return f'{self.first_name} {self.last_name}'
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
json_encoders = {
|
json_encoders = {
|
||||||
datetime: lambda v: int(v.timestamp() * 1000)
|
datetime: lambda v: int(v.timestamp() * 1000)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from json import loads
|
from json import loads
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
from ..types.input_media import InputMedia, InputMediaBuffer
|
from ..types.input_media import InputMedia, InputMediaBuffer
|
||||||
from ..enums.upload_type import UploadType
|
from ..enums.upload_type import UploadType
|
||||||
@@ -46,6 +47,7 @@ async def process_input_media(
|
|||||||
)
|
)
|
||||||
elif isinstance(att, InputMediaBuffer):
|
elif isinstance(att, InputMediaBuffer):
|
||||||
upload_file_response = await base_connection.upload_file_buffer(
|
upload_file_response = await base_connection.upload_file_buffer(
|
||||||
|
filename=att.filename or str(uuid4()),
|
||||||
url=upload.url,
|
url=upload.url,
|
||||||
buffer=att.buffer,
|
buffer=att.buffer,
|
||||||
type=att.type,
|
type=att.type,
|
||||||
@@ -53,8 +55,10 @@ async def process_input_media(
|
|||||||
|
|
||||||
if att.type in (UploadType.VIDEO, UploadType.AUDIO):
|
if att.type in (UploadType.VIDEO, UploadType.AUDIO):
|
||||||
if upload.token is None:
|
if upload.token is None:
|
||||||
assert bot.session is not None
|
|
||||||
await bot.session.close()
|
if bot.session is not None:
|
||||||
|
await bot.session.close()
|
||||||
|
|
||||||
raise MaxUploadFileFailed('По неизвестной причине token не был получен')
|
raise MaxUploadFileFailed('По неизвестной причине token не был получен')
|
||||||
|
|
||||||
token = upload.token
|
token = upload.token
|
||||||
|
|||||||
77
maxapi/utils/updates.py
Normal file
77
maxapi/utils/updates.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
|
from ..types.updates.bot_added import BotAdded
|
||||||
|
from ..types.updates.bot_removed import BotRemoved
|
||||||
|
from ..types.updates.bot_started import BotStarted
|
||||||
|
from ..types.updates.bot_stopped import BotStopped
|
||||||
|
from ..types.updates.chat_title_changed import ChatTitleChanged
|
||||||
|
from ..types.updates.message_callback import MessageCallback
|
||||||
|
from ..types.updates.message_created import MessageCreated
|
||||||
|
from ..types.updates.message_edited import MessageEdited
|
||||||
|
from ..types.updates.message_removed import MessageRemoved
|
||||||
|
from ..types.updates.user_added import UserAdded
|
||||||
|
from ..types.updates.user_removed import UserRemoved
|
||||||
|
from ..types.updates.dialog_cleared import DialogCleared
|
||||||
|
from ..types.updates.dialog_muted import DialogMuted
|
||||||
|
from ..types.updates.dialog_unmuted import DialogUnmuted
|
||||||
|
|
||||||
|
from ..enums.chat_type import ChatType
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from ..bot import Bot
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def enrich_event(event_object: Any, bot: Bot) -> Any:
|
||||||
|
if not bot.auto_requests:
|
||||||
|
return event_object
|
||||||
|
|
||||||
|
if hasattr(event_object, 'chat_id'):
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.chat_id)
|
||||||
|
|
||||||
|
if isinstance(event_object, (MessageCreated, MessageEdited, MessageCallback)):
|
||||||
|
|
||||||
|
if event_object.message.recipient.chat_id is not None:
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.message.recipient.chat_id)
|
||||||
|
|
||||||
|
event_object.from_user = getattr(event_object.message, 'sender', None)
|
||||||
|
|
||||||
|
elif isinstance(event_object, MessageRemoved):
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.chat_id)
|
||||||
|
|
||||||
|
if event_object.chat.type == ChatType.CHAT:
|
||||||
|
event_object.from_user = await bot.get_chat_member(
|
||||||
|
chat_id=event_object.chat_id,
|
||||||
|
user_id=event_object.user_id
|
||||||
|
)
|
||||||
|
|
||||||
|
elif event_object.chat.type == ChatType.DIALOG:
|
||||||
|
event_object.from_user = event_object.chat
|
||||||
|
|
||||||
|
elif isinstance(event_object, UserRemoved):
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.chat_id)
|
||||||
|
if event_object.admin_id:
|
||||||
|
event_object.from_user = await bot.get_chat_member(
|
||||||
|
chat_id=event_object.chat_id,
|
||||||
|
user_id=event_object.admin_id
|
||||||
|
)
|
||||||
|
|
||||||
|
elif isinstance(event_object, UserAdded):
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.chat_id)
|
||||||
|
event_object.from_user = event_object.user
|
||||||
|
|
||||||
|
elif isinstance(event_object, (BotAdded, BotRemoved, BotStarted, ChatTitleChanged, BotStopped, DialogCleared, DialogMuted, DialogUnmuted)):
|
||||||
|
event_object.chat = await bot.get_chat_by_id(event_object.chat_id)
|
||||||
|
event_object.from_user = event_object.user
|
||||||
|
|
||||||
|
if hasattr(event_object, 'message'):
|
||||||
|
event_object.message.bot = bot
|
||||||
|
for att in event_object.message.body.attachments:
|
||||||
|
if hasattr(att, 'bot'):
|
||||||
|
att.bot = bot
|
||||||
|
|
||||||
|
if hasattr(event_object, 'bot'):
|
||||||
|
event_object.bot = bot
|
||||||
|
|
||||||
|
return event_object
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
| `bot_added` | Бот добавлен в чат |
|
| `bot_added` | Бот добавлен в чат |
|
||||||
| `bot_removed` | Бот удалён из чата |
|
| `bot_removed` | Бот удалён из чата |
|
||||||
| `bot_started` | Пользователь запустил бота |
|
| `bot_started` | Пользователь запустил бота |
|
||||||
|
| `bot_stopped` | Пользователь остановил бота |
|
||||||
|
| `dialog_cleared` | Пользователь очистил историю диалога с ботом |
|
||||||
|
| `dialog_muted` | Пользователь отключил оповещения от чата бота |
|
||||||
|
| `dialog_unmuted` | Пользователь включил оповещения от чата бота |
|
||||||
| `chat_title_changed` | Изменено название чата |
|
| `chat_title_changed` | Изменено название чата |
|
||||||
| `message_callback` | Пользователь нажал на callback-кнопку (inline button) |
|
| `message_callback` | Пользователь нажал на callback-кнопку (inline button) |
|
||||||
| `message_chat_created`| Срабатывает когда пользователь нажал на кнопку с действием "Создать чат" (работает некорректно со стороны API MAX, ждем исправлений) |
|
| `message_chat_created`| Срабатывает когда пользователь нажал на кнопку с действием "Создать чат" (работает некорректно со стороны API MAX, ждем исправлений) |
|
||||||
|
|||||||
@@ -81,13 +81,21 @@ async def init_serve(self, bot: Bot, host: str = '0.0.0.0', port: int = 8080, **
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from fastapi import Request
|
try:
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi import Request
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError(
|
||||||
|
'\n\t Не установлен fastapi!'
|
||||||
|
'\n\t Выполните команду для установки fastapi: '
|
||||||
|
'\n\t pip install fastapi>=0.68.0'
|
||||||
|
'\n\t Или сразу все зависимости для работы вебхука:'
|
||||||
|
'\n\t pip install maxapi[webhook]'
|
||||||
|
)
|
||||||
|
|
||||||
from maxapi import Bot, Dispatcher
|
from maxapi import Bot, Dispatcher
|
||||||
from maxapi.methods.types.getted_updates import process_update_webhook
|
from maxapi.methods.types.getted_updates import process_update_webhook
|
||||||
from maxapi.types import MessageCreated
|
from maxapi.types import MessageCreated
|
||||||
from maxapi.dispatcher import webhook_app
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
@@ -101,7 +109,7 @@ async def handle_message(event: MessageCreated):
|
|||||||
|
|
||||||
# Регистрация обработчика
|
# Регистрация обработчика
|
||||||
# для вебхука
|
# для вебхука
|
||||||
@webhook_app.post('/')
|
@dp.webhook_post('/')
|
||||||
async def _(request: Request):
|
async def _(request: Request):
|
||||||
|
|
||||||
# Сериализация полученного запроса
|
# Сериализация полученного запроса
|
||||||
@@ -133,7 +141,6 @@ async def main():
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
|
|
||||||
```
|
```
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user