Compare commits
5 Commits
3f8c68cca4
...
4de32ca476
Author | SHA1 | Date | |
---|---|---|---|
4de32ca476 | |||
9a39dce1a6 | |||
ff19f99704 | |||
eff34b42c2 | |||
b2283ab538 |
30
README.md
30
README.md
@ -1,16 +1,28 @@
|
||||
# maxapi
|
||||
|
||||
#### Библиотека (like aiogram) для взаимодействия с социальной сетью MAX по Webhook (или подписке бота)
|
||||
#### Библиотека (like aiogram) для взаимодействия с мессенджером MAX
|
||||
|
||||
Информация на данный момент:
|
||||
* Проект не готов, ведется активная разработка
|
||||
* Планируется:
|
||||
+ Сокращение импортов в ваших хендлерах (громадные импорты в example.py)
|
||||
+ Сокращение "построения" клавиатур
|
||||
+ Разработка контекста бота
|
||||
+ Разработка Longpoll метода
|
||||
+ Доработка базовой составляющей проекта
|
||||
+ и так далее...
|
||||
* Проект тестируется и активно дорабатывается
|
||||
* На данный момент имеется:
|
||||
Роутеры
|
||||
Билдер инлайн клавиатур
|
||||
Этакая машина состояний и контекст к нему
|
||||
Поллинг и вебхук методы запуска
|
||||
Логгирование
|
||||
|
||||
|
||||
```bash
|
||||
Пример бота описан в example.py
|
||||
Перед запуском примера установите зависимости:
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
Запуск бота:
|
||||
|
||||
python example.py
|
||||
```
|
||||
|
||||
|
||||
### Контакты
|
||||
[Группа MAX](https://max.ru/join/IPAok63C3vFqbWTFdutMUtjmrAkGqO56YeAN7iyDfc8)
|
155
example.py
155
example.py
@ -1,50 +1,127 @@
|
||||
from maxapi.bot import Bot
|
||||
from maxapi.dispatcher import Dispatcher
|
||||
from maxapi.types.updates.message_created import MessageCreated
|
||||
from maxapi.types.updates.message_callback import MessageCallback
|
||||
from maxapi.types.attachments.attachment import ButtonsPayload
|
||||
from maxapi.types.attachments.buttons.callback_button import CallbackButton
|
||||
from maxapi.types.attachments.attachment import Attachment
|
||||
from maxapi.enums.attachment import AttachmentType
|
||||
from maxapi.enums.button_type import ButtonType
|
||||
from maxapi.enums.intent import Intent
|
||||
from maxapi.filters import F
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from maxapi import Bot, Dispatcher, F
|
||||
from maxapi.context import MemoryContext, State, StatesGroup
|
||||
from maxapi.types import Command, MessageCreated, CallbackButton, MessageCallback
|
||||
from maxapi.utils.inline_keyboard import InlineKeyboardBuilder
|
||||
|
||||
from for_example import router
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
bot = Bot('токен')
|
||||
dp = Dispatcher()
|
||||
dp.include_routers(router)
|
||||
|
||||
# Отвечает только на текст "Привет"
|
||||
@dp.message_created(F.message.body.text == 'Привет')
|
||||
|
||||
start_text = '''Мои команды:
|
||||
|
||||
/clear очищает ваш контекст
|
||||
/state или /context показывают ваше контекстное состояние
|
||||
/data показывает вашу контекстную память
|
||||
'''
|
||||
|
||||
|
||||
class Form(StatesGroup):
|
||||
name = State()
|
||||
age = State()
|
||||
|
||||
|
||||
@dp.on_started()
|
||||
async def _():
|
||||
logging.info('Бот стартовал!')
|
||||
|
||||
|
||||
@dp.message_created(Command('clear'))
|
||||
async def hello(obj: MessageCreated, context: MemoryContext):
|
||||
await context.clear()
|
||||
await obj.message.answer(f"Ваш контекст был очищен!")
|
||||
|
||||
|
||||
@dp.message_created(Command('data'))
|
||||
async def hello(obj: MessageCreated, context: MemoryContext):
|
||||
data = await context.get_data()
|
||||
await obj.message.answer(f"Ваша контекстная память: {str(data)}")
|
||||
|
||||
|
||||
@dp.message_created(Command('context'))
|
||||
@dp.message_created(Command('state'))
|
||||
async def hello(obj: MessageCreated, context: MemoryContext):
|
||||
data = await context.get_state()
|
||||
await obj.message.answer(f"Ваше контекстное состояние: {str(data)}")
|
||||
|
||||
|
||||
@dp.message_created(Command('start'))
|
||||
async def hello(obj: MessageCreated):
|
||||
await obj.message.answer('Привет 👋')
|
||||
builder = InlineKeyboardBuilder()
|
||||
|
||||
# Отвечает только на текст "Клавиатура"
|
||||
@dp.message_created(F.message.body.text == 'Клавиатура')
|
||||
async def hello(obj: MessageCreated):
|
||||
button_1 = CallbackButton(type=ButtonType.CALLBACK, text='Кнопка 1', payload='1', intent=Intent.DEFAULT)
|
||||
button_2 = CallbackButton(type=ButtonType.CALLBACK, text='Кнопка 2', payload='2', intent=Intent.DEFAULT)
|
||||
builder.row(
|
||||
CallbackButton(
|
||||
text='Ввести свое имя',
|
||||
payload='btn_1'
|
||||
),
|
||||
CallbackButton(
|
||||
text='Ввести свой возраст',
|
||||
payload='btn_2'
|
||||
)
|
||||
)
|
||||
builder.row(
|
||||
CallbackButton(
|
||||
text='Не хочу',
|
||||
payload='btn_3'
|
||||
)
|
||||
)
|
||||
|
||||
keyboard = ButtonsPayload(buttons=[[button_1], [button_2]])
|
||||
await obj.message.answer(
|
||||
text=start_text,
|
||||
attachments=[builder.as_markup()] # Для MAX клавиатура это вложение,
|
||||
) # поэтому она в списке вложений
|
||||
|
||||
|
||||
attachments = [Attachment(type=AttachmentType.INLINE_KEYBOARD, payload=keyboard)]
|
||||
|
||||
await obj.message.answer('Привет 👋', attachments=attachments)
|
||||
|
||||
# Ответчает на коллбек с начинкой "1"
|
||||
@dp.message_callback(F.callback.payload == '1')
|
||||
async def _(obj: MessageCallback):
|
||||
await obj.message.answer('Вы нажали на кнопку 1 🤩')
|
||||
|
||||
# Ответчает на коллбек с начинкой "2"
|
||||
@dp.message_callback(F.callback.payload == '2')
|
||||
async def _(obj: MessageCallback):
|
||||
await obj.message.answer('Вы нажали на кнопку 2 🥳')
|
||||
|
||||
# Отвечает на любое текстовое сообщение
|
||||
@dp.message_created(F.message.body.text)
|
||||
async def hello(obj: MessageCreated):
|
||||
await obj.message.answer(f'Повторяю за вами: {obj.message.body.text}')
|
||||
@dp.message_callback(F.callback.payload == 'btn_1')
|
||||
async def hello(obj: MessageCallback, context: MemoryContext):
|
||||
await context.set_state(Form.name)
|
||||
await obj.message.delete()
|
||||
await obj.message.answer(f'Отправьте свое имя:')
|
||||
|
||||
|
||||
dp.handle_webhook(bot)
|
||||
@dp.message_callback(F.callback.payload == 'btn_2')
|
||||
async def hello(obj: MessageCallback, context: MemoryContext):
|
||||
await context.set_state(Form.age)
|
||||
await obj.message.delete()
|
||||
await obj.message.answer(f'Отправьте ваш возраст:')
|
||||
|
||||
|
||||
@dp.message_callback(F.callback.payload == 'btn_3')
|
||||
async def hello(obj: MessageCallback, context: MemoryContext):
|
||||
await obj.message.delete()
|
||||
await obj.message.answer(f'Ну ладно 🥲')
|
||||
|
||||
|
||||
@dp.message_created(F.message.body.text, Form.name)
|
||||
async def hello(obj: MessageCreated, context: MemoryContext):
|
||||
await context.update_data(name=obj.message.body.text)
|
||||
|
||||
data = await context.get_data()
|
||||
|
||||
await obj.message.answer(f"Приятно познакомиться, {data['name'].title()}!")
|
||||
|
||||
|
||||
@dp.message_created(F.message.body.text, Form.age)
|
||||
async def hello(obj: MessageCreated, context: MemoryContext):
|
||||
await context.update_data(age=obj.message.body.text)
|
||||
|
||||
await obj.message.answer(f"Ого! А мне всего пару недель 😁")
|
||||
|
||||
|
||||
async def main():
|
||||
await dp.start_polling(bot)
|
||||
# await dp.handle_webhook(
|
||||
# bot=bot,
|
||||
# host='localhost',
|
||||
# port=8080
|
||||
# )
|
||||
|
||||
|
||||
asyncio.run(main())
|
10
for_example.py
Normal file
10
for_example.py
Normal file
@ -0,0 +1,10 @@
|
||||
from maxapi import F, Router
|
||||
from maxapi.types import Command, MessageCreated
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@router.message_created(Command('router'))
|
||||
async def hello(obj: MessageCreated):
|
||||
file = __file__.split('\\')[-1]
|
||||
await obj.message.answer(f"Пишу тебе из роута {file}")
|
10
maxapi/__init__.py
Normal file
10
maxapi/__init__.py
Normal file
@ -0,0 +1,10 @@
|
||||
from .bot import Bot
|
||||
from .dispatcher import Dispatcher, Router
|
||||
from .filters import F
|
||||
|
||||
__all__ = [
|
||||
Bot,
|
||||
Dispatcher,
|
||||
F,
|
||||
Router
|
||||
]
|
267
maxapi/bot.py
267
maxapi/bot.py
@ -1,25 +1,58 @@
|
||||
from typing import Any, Dict, List
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, TYPE_CHECKING
|
||||
|
||||
from .methods.get_updates import GetUpdates
|
||||
from .methods.remove_member_chat import RemoveMemberChat
|
||||
from .methods.add_admin_chat import AddAdminChat
|
||||
from .methods.add_members_chat import AddMembersChat
|
||||
from .methods.get_members_chat import GetMembersChat
|
||||
from .methods.remove_admin import RemoveAdmin
|
||||
from .methods.get_list_admin_chat import GetListAdminChat
|
||||
from .methods.delete_bot_from_chat import DeleteMeFromMessage
|
||||
from .methods.get_me_from_chat import GetMeFromChat
|
||||
from .methods.delete_pin_message import DeletePinMessage
|
||||
from .methods.get_pinned_message import GetPinnedMessage
|
||||
from .methods.pin_message import PinMessage
|
||||
from .methods.delete_chat import DeleteChat
|
||||
from .methods.send_action import SendAction
|
||||
from .methods.edit_chat import EditChat
|
||||
from .methods.get_chat_by_id import GetChatById
|
||||
from .methods.get_chat_by_link import GetChatByLink
|
||||
from .methods.send_callback import SendCallback
|
||||
from .methods.get_video import GetVideo
|
||||
from .methods.delete_message import DeleteMessage
|
||||
from .methods.edit_message import EditMessage
|
||||
from .enums.parse_mode import ParseMode
|
||||
from .types.attachments.attachment import Attachment
|
||||
from .types.message import NewMessageLink
|
||||
from .types.users import BotCommand
|
||||
from .methods.change_info import ChangeInfo
|
||||
from .methods.get_me import GetMe
|
||||
from .methods.get_messages import GetMessages
|
||||
from .methods.get_chats import GetChats
|
||||
from .methods.send_message import SendMessage
|
||||
|
||||
from .enums.parse_mode import ParseMode
|
||||
from .enums.sender_action import SenderAction
|
||||
|
||||
from .types.attachments.attachment import Attachment
|
||||
from .types.attachments.image import PhotoAttachmentRequestPayload
|
||||
from .types.message import NewMessageLink
|
||||
from .types.users import BotCommand, ChatAdmin
|
||||
|
||||
from .connection.base import BaseConnection
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .types.message import Message
|
||||
|
||||
|
||||
class Bot(BaseConnection):
|
||||
|
||||
def __init__(self, token: str):
|
||||
super().__init__()
|
||||
self.bot = self
|
||||
|
||||
self.__token = token
|
||||
self.params = {
|
||||
'access_token': self.__token
|
||||
}
|
||||
self.marker_updates = None
|
||||
|
||||
async def send_message(
|
||||
self,
|
||||
@ -44,6 +77,17 @@ class Bot(BaseConnection):
|
||||
parse_mode=parse_mode
|
||||
).request()
|
||||
|
||||
async def send_action(
|
||||
self,
|
||||
chat_id: int = None,
|
||||
action: SenderAction = SenderAction.TYPING_ON
|
||||
):
|
||||
return await SendAction(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
action=action
|
||||
).request()
|
||||
|
||||
async def edit_message(
|
||||
self,
|
||||
message_id: str,
|
||||
@ -62,13 +106,51 @@ class Bot(BaseConnection):
|
||||
notify=notify,
|
||||
parse_mode=parse_mode
|
||||
).request()
|
||||
|
||||
async def delete_message(
|
||||
self,
|
||||
message_id: str
|
||||
):
|
||||
return await DeleteMessage(
|
||||
bot=self,
|
||||
message_id=message_id,
|
||||
).request()
|
||||
|
||||
async def delete_chat(
|
||||
self,
|
||||
chat_id: int
|
||||
):
|
||||
return await DeleteChat(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
).request()
|
||||
|
||||
async def get_messages(self, chat_id: int = None):
|
||||
return await GetMessages(self, chat_id).request()
|
||||
async def get_messages(
|
||||
self,
|
||||
chat_id: int = None,
|
||||
message_ids: List[str] = None,
|
||||
from_time: datetime | int = None,
|
||||
to_time: datetime | int = None,
|
||||
count: int = 50,
|
||||
):
|
||||
return await GetMessages(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
message_ids=message_ids,
|
||||
from_time=from_time,
|
||||
to_time=to_time,
|
||||
count=count
|
||||
).request()
|
||||
|
||||
async def get_message(self, message_id: str):
|
||||
return await self.get_messages(message_ids=[message_id])
|
||||
|
||||
async def get_me(self):
|
||||
return await GetMe(self).request()
|
||||
|
||||
async def get_pin_message(self, chat_id: int):
|
||||
return await GetPinnedMessage(bot=self, chat_id=chat_id).request()
|
||||
|
||||
async def change_info(
|
||||
self,
|
||||
name: str = None,
|
||||
@ -85,5 +167,172 @@ class Bot(BaseConnection):
|
||||
photo=photo
|
||||
).request()
|
||||
|
||||
async def get_chats(self):
|
||||
return await GetChats(self).request()
|
||||
async def get_chats(
|
||||
self,
|
||||
count: int = 50,
|
||||
marker: int = None
|
||||
):
|
||||
return await GetChats(
|
||||
bot=self,
|
||||
count=count,
|
||||
marker=marker
|
||||
).request()
|
||||
|
||||
async def get_chat_by_link(self, link: str):
|
||||
"""под вопросом"""
|
||||
return await GetChatByLink(bot=self, link=link).request()
|
||||
|
||||
async def get_chat_by_id(self, id: int):
|
||||
return await GetChatById(bot=self, id=id).request()
|
||||
|
||||
async def edit_chat(
|
||||
self,
|
||||
chat_id: int,
|
||||
icon: PhotoAttachmentRequestPayload = None,
|
||||
title: str = None,
|
||||
pin: str = None,
|
||||
notify: bool = True,
|
||||
):
|
||||
return await EditChat(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
icon=icon,
|
||||
title=title,
|
||||
pin=pin,
|
||||
notify=notify
|
||||
).request()
|
||||
|
||||
async def get_video(self, video_token: str):
|
||||
return await GetVideo(bot=self, video_token=video_token).request()
|
||||
|
||||
async def send_callback(
|
||||
self,
|
||||
callback_id: str,
|
||||
message: 'Message' = None,
|
||||
notification: str = None
|
||||
):
|
||||
return await SendCallback(
|
||||
bot=self,
|
||||
callback_id=callback_id,
|
||||
message=message,
|
||||
notification=notification
|
||||
).request()
|
||||
|
||||
async def pin_message(
|
||||
self,
|
||||
chat_id: int,
|
||||
message_id: str,
|
||||
notify: bool = True
|
||||
):
|
||||
return await PinMessage(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
message_id=message_id,
|
||||
notify=notify
|
||||
).request()
|
||||
|
||||
async def delete_pin_message(
|
||||
self,
|
||||
chat_id: int,
|
||||
):
|
||||
return await DeletePinMessage(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
).request()
|
||||
|
||||
async def get_me_from_chat(
|
||||
self,
|
||||
chat_id: int,
|
||||
):
|
||||
return await GetMeFromChat(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
).request()
|
||||
|
||||
async def delete_me_from_chat(
|
||||
self,
|
||||
chat_id: int,
|
||||
):
|
||||
return await DeleteMeFromMessage(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
).request()
|
||||
|
||||
async def get_list_admin_chat(
|
||||
self,
|
||||
chat_id: int,
|
||||
):
|
||||
return await GetListAdminChat(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
).request()
|
||||
|
||||
async def add_list_admin_chat(
|
||||
self,
|
||||
chat_id: int,
|
||||
admins: List[ChatAdmin],
|
||||
marker: int = None
|
||||
):
|
||||
return await AddAdminChat(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
admins=admins,
|
||||
marker=marker,
|
||||
).request()
|
||||
|
||||
async def remove_admin(
|
||||
self,
|
||||
chat_id: int,
|
||||
user_id: int
|
||||
):
|
||||
return await RemoveAdmin(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
user_id=user_id,
|
||||
).request()
|
||||
|
||||
async def get_chat_members(
|
||||
self,
|
||||
chat_id: int,
|
||||
user_ids: List[int] = None,
|
||||
marker: int = None,
|
||||
count: int = None,
|
||||
):
|
||||
return await GetMembersChat(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
user_ids=user_ids,
|
||||
marker=marker,
|
||||
count=count,
|
||||
).request()
|
||||
|
||||
async def add_chat_members(
|
||||
self,
|
||||
chat_id: int,
|
||||
user_ids: List[str],
|
||||
):
|
||||
return await AddMembersChat(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
user_ids=user_ids,
|
||||
).request()
|
||||
|
||||
async def kick_chat_member(
|
||||
self,
|
||||
chat_id: int,
|
||||
user_id: int,
|
||||
block: bool = False,
|
||||
):
|
||||
return await RemoveMemberChat(
|
||||
bot=self,
|
||||
chat_id=chat_id,
|
||||
user_id=user_id,
|
||||
block=block,
|
||||
).request()
|
||||
|
||||
async def get_updates(
|
||||
self,
|
||||
):
|
||||
return await GetUpdates(
|
||||
bot=self,
|
||||
).request()
|
@ -4,12 +4,17 @@ from pydantic import BaseModel
|
||||
from ..types.errors import Error
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from ..loggers import logger_bot
|
||||
|
||||
|
||||
class BaseConnection:
|
||||
|
||||
API_URL = 'https://botapi.max.ru'
|
||||
|
||||
def __init__(self):
|
||||
self.bot = None
|
||||
self.session = None
|
||||
|
||||
async def request(
|
||||
self,
|
||||
method: HTTPMethod,
|
||||
@ -18,19 +23,34 @@ class BaseConnection:
|
||||
is_return_raw: bool = False,
|
||||
**kwargs
|
||||
):
|
||||
async with aiohttp.ClientSession(self.API_URL) as s:
|
||||
r = await s.request(
|
||||
method=method.value,
|
||||
url=path.value,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
if not self.bot.session:
|
||||
self.bot.session = aiohttp.ClientSession(self.bot.API_URL)
|
||||
|
||||
if not r.ok:
|
||||
raw = await r.text()
|
||||
return Error(code=r.status, text=raw)
|
||||
|
||||
raw = await r.json()
|
||||
r = await self.bot.session.request(
|
||||
method=method.value,
|
||||
url=path.value if isinstance(path, ApiPath) else path,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
if is_return_raw: return raw
|
||||
if not r.ok:
|
||||
raw = await r.text()
|
||||
error = Error(code=r.status, text=raw)
|
||||
logger_bot.error(error)
|
||||
return error
|
||||
|
||||
raw = await r.json()
|
||||
|
||||
return model(**raw)
|
||||
if is_return_raw: return raw
|
||||
|
||||
model = model(**raw)
|
||||
|
||||
if hasattr(model, 'message'):
|
||||
attr = getattr(model, 'message')
|
||||
if hasattr(attr, 'bot'):
|
||||
attr.bot = self.bot
|
||||
|
||||
if hasattr(model, 'bot'):
|
||||
model.bot = self.bot
|
||||
|
||||
return model
|
36
maxapi/context/__init__.py
Normal file
36
maxapi/context/__init__.py
Normal file
@ -0,0 +1,36 @@
|
||||
import asyncio
|
||||
|
||||
from typing import Any, Dict
|
||||
|
||||
from ..context.state_machine import State, StatesGroup
|
||||
|
||||
|
||||
class MemoryContext:
|
||||
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 | None = None
|
||||
self._lock = asyncio.Lock()
|
||||
|
||||
async def get_data(self) -> dict[str, Any]:
|
||||
async with self._lock:
|
||||
return self._context
|
||||
|
||||
async def set_data(self, data: dict[str, Any]):
|
||||
async with self._lock:
|
||||
self._context = data
|
||||
|
||||
async def update_data(self, **kwargs):
|
||||
async with self._lock:
|
||||
self._context.update(kwargs)
|
||||
|
||||
async def set_state(self, state: State | str = None):
|
||||
self._state = state
|
||||
|
||||
async def get_state(self):
|
||||
return self._state
|
||||
|
||||
async def clear(self):
|
||||
self._state = None
|
||||
self._context = {}
|
16
maxapi/context/state_machine.py
Normal file
16
maxapi/context/state_machine.py
Normal file
@ -0,0 +1,16 @@
|
||||
class State:
|
||||
def __init__(self):
|
||||
self.name = None
|
||||
|
||||
def __set_name__(self, owner, attr_name):
|
||||
self.name = f'{owner.__name__}:{attr_name}'
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class StatesGroup:
|
||||
@classmethod
|
||||
def states(cls) -> list[str]:
|
||||
return [str(getattr(cls, attr)) for attr in dir(cls)
|
||||
if isinstance(getattr(cls, attr), State)]
|
@ -1,54 +1,33 @@
|
||||
from typing import Callable, List
|
||||
|
||||
import uvicorn
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
from magic_filter import MagicFilter
|
||||
from fastapi.responses import JSONResponse
|
||||
from uvicorn import Config, Server
|
||||
|
||||
from .filters import filter_m
|
||||
from .types.updates import Update
|
||||
from .filters.handler import Handler
|
||||
|
||||
from .context import MemoryContext
|
||||
from .types.updates import UpdateUnion
|
||||
from .types.errors import Error
|
||||
|
||||
from .methods.types.getted_updates import process_update_webhook, process_update_request
|
||||
|
||||
from .filters import filter_attrs
|
||||
|
||||
from .bot import Bot
|
||||
from .enums.update import UpdateType
|
||||
from .types.updates.bot_added import BotAdded
|
||||
from .types.updates.bot_removed import BotRemoved
|
||||
from .types.updates.bot_started import BotStarted
|
||||
from .types.updates.chat_title_changed import ChatTitleChanged
|
||||
from .types.updates.message_callback import MessageCallback
|
||||
from .types.updates.message_chat_created import MessageChatCreated
|
||||
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 .loggers import logger
|
||||
from .loggers import logger_dp
|
||||
|
||||
|
||||
class Handler:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*args,
|
||||
func_event: Callable,
|
||||
update_type: UpdateType,
|
||||
**kwargs
|
||||
):
|
||||
|
||||
self.func_event = func_event
|
||||
self.update_type = update_type
|
||||
self.filters = []
|
||||
|
||||
for arg in args:
|
||||
if isinstance(arg, MagicFilter):
|
||||
arg: MagicFilter = arg
|
||||
|
||||
self.filters.append(arg)
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class Dispatcher:
|
||||
def __init__(self):
|
||||
self.event_handlers = []
|
||||
self.event_handlers: List[Handler] = []
|
||||
self.contexts: List[MemoryContext] = []
|
||||
self.bot = None
|
||||
self.on_started_func = None
|
||||
|
||||
self.message_created = Event(update_type=UpdateType.MESSAGE_CREATED, router=self)
|
||||
self.bot_added = Event(update_type=UpdateType.BOT_ADDED, router=self)
|
||||
@ -61,70 +40,114 @@ class Dispatcher:
|
||||
self.message_removed = Event(update_type=UpdateType.MESSAGE_REMOVED, router=self)
|
||||
self.user_added = Event(update_type=UpdateType.USER_ADDED, router=self)
|
||||
self.user_removed = Event(update_type=UpdateType.USER_REMOVED, router=self)
|
||||
self.on_started = Event(update_type=UpdateType.ON_STARTED, router=self)
|
||||
|
||||
def include_routers(self, *routers: 'Router'):
|
||||
for router in routers:
|
||||
for event in router.event_handlers:
|
||||
self.event_handlers.append(event)
|
||||
|
||||
def handle_webhook(self, bot: Bot, host: str = '0.0.0.0', port: int = 8080):
|
||||
def get_memory_context(self, chat_id: int, user_id: int):
|
||||
for ctx in self.contexts:
|
||||
if ctx.chat_id == chat_id and ctx.user_id == user_id:
|
||||
return ctx
|
||||
|
||||
new_ctx = MemoryContext(chat_id, user_id)
|
||||
self.contexts.append(new_ctx)
|
||||
return new_ctx
|
||||
|
||||
async def handle(self, event_object: UpdateUnion):
|
||||
for handler in self.event_handlers:
|
||||
|
||||
if not handler.update_type == event_object.update_type:
|
||||
continue
|
||||
|
||||
if handler.filters:
|
||||
if not filter_attrs(event_object, *handler.filters):
|
||||
continue
|
||||
|
||||
memory_context = self.get_memory_context(
|
||||
*event_object.get_ids()
|
||||
)
|
||||
|
||||
if not handler.state == await memory_context.get_state() \
|
||||
and handler.state:
|
||||
continue
|
||||
|
||||
func_args = handler.func_event.__annotations__.keys()
|
||||
|
||||
kwargs = {'context': memory_context}
|
||||
|
||||
for key in kwargs.copy().keys():
|
||||
if not key in func_args:
|
||||
del kwargs[key]
|
||||
|
||||
if kwargs:
|
||||
await handler.func_event(event_object, **kwargs)
|
||||
else:
|
||||
await handler.func_event(event_object, **kwargs)
|
||||
|
||||
logger_dp.info(f'Обработано: {event_object.update_type}')
|
||||
break
|
||||
|
||||
async def start_polling(self, bot: Bot):
|
||||
self.bot = bot
|
||||
|
||||
app = FastAPI()
|
||||
logger_dp.info(f'{len(self.event_handlers)} event handlers started')
|
||||
|
||||
@app.post("/")
|
||||
if self.on_started_func:
|
||||
await self.on_started_func()
|
||||
|
||||
while True:
|
||||
try:
|
||||
events = await self.bot.get_updates()
|
||||
|
||||
if isinstance(events, Error):
|
||||
logger_dp.info(f'Ошибка при получении обновлений: {events}')
|
||||
continue
|
||||
|
||||
self.bot.marker_updates = events.get('marker')
|
||||
|
||||
processed_events = await process_update_request(
|
||||
events=events,
|
||||
bot=self.bot
|
||||
)
|
||||
|
||||
for event in processed_events:
|
||||
try:
|
||||
await self.handle(event)
|
||||
except Exception as e:
|
||||
logger_dp.error(f"Ошибка при обработке события: {events['update_type']}: {e}")
|
||||
except Exception as e:
|
||||
logger_dp.error(f'Общая ошибка при обработке событий: {e}')
|
||||
|
||||
async def handle_webhook(self, bot: Bot, host: str = 'localhost', port: int = 8080):
|
||||
self.bot = bot
|
||||
|
||||
if self.on_started_func:
|
||||
await self.on_started_func()
|
||||
|
||||
@app.post('/')
|
||||
async def _(request: Request):
|
||||
try:
|
||||
event_json = await request.json()
|
||||
event = Update(**event_json)
|
||||
|
||||
event_object = None
|
||||
match event.update_type:
|
||||
case UpdateType.BOT_ADDED:
|
||||
event_object = BotAdded(**event_json)
|
||||
case UpdateType.BOT_REMOVED:
|
||||
event_object = BotRemoved(**event_json)
|
||||
case UpdateType.BOT_STARTED:
|
||||
event_object = BotStarted(**event_json)
|
||||
case UpdateType.CHAT_TITLE_CHANGED:
|
||||
event_object = ChatTitleChanged(**event_json)
|
||||
case UpdateType.MESSAGE_CALLBACK:
|
||||
event_object = MessageCallback(**event_json)
|
||||
event_object.message.bot = self.bot
|
||||
case UpdateType.MESSAGE_CHAT_CREATED:
|
||||
event_object = MessageChatCreated(**event_json)
|
||||
case UpdateType.MESSAGE_CREATED:
|
||||
event_object = MessageCreated(**event_json)
|
||||
event_object.message.bot = self.bot
|
||||
case UpdateType.MESSAGE_EDITED:
|
||||
event_object = MessageEdited(**event_json)
|
||||
case UpdateType.MESSAGE_REMOVED:
|
||||
event_object = MessageRemoved(**event_json)
|
||||
case UpdateType.USER_ADDED:
|
||||
event_object = UserAdded(**event_json)
|
||||
case UpdateType.USER_REMOVED:
|
||||
event_object = UserRemoved(**event_json)
|
||||
event_object = await process_update_webhook(
|
||||
event_json=event_json,
|
||||
bot=self.bot
|
||||
)
|
||||
|
||||
handlers: List[Handler] = self.event_handlers
|
||||
for handler in handlers:
|
||||
|
||||
if not handler.update_type == event.update_type:
|
||||
continue
|
||||
|
||||
if handler.filters:
|
||||
if not filter_m(event_object, *handler.filters):
|
||||
continue
|
||||
|
||||
await handler.func_event(event_object)
|
||||
break
|
||||
await self.handle(event_object)
|
||||
|
||||
return True
|
||||
return JSONResponse(content={'ok': True}, status_code=200)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
...
|
||||
logger_dp.error(f"Ошибка при обработке события: {event_json['update_type']}: {e}")
|
||||
|
||||
logger.info(f'{len(self.event_handlers)} event handlers started')
|
||||
uvicorn.run(app, host=host, port=port, log_level='critical')
|
||||
logger_dp.info(f'{len(self.event_handlers)} событий на обработку')
|
||||
config = Config(app=app, host=host, port=port, log_level="critical")
|
||||
server = Server(config)
|
||||
|
||||
await server.serve()
|
||||
|
||||
|
||||
class Router(Dispatcher):
|
||||
@ -139,13 +162,16 @@ class Event:
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
def decorator(func_event: Callable):
|
||||
self.router.event_handlers.append(
|
||||
Handler(
|
||||
func_event=func_event,
|
||||
update_type=self.update_type,
|
||||
*args, **kwargs
|
||||
if self.update_type == UpdateType.ON_STARTED:
|
||||
self.router.on_started_func = func_event
|
||||
else:
|
||||
self.router.event_handlers.append(
|
||||
Handler(
|
||||
func_event=func_event,
|
||||
update_type=self.update_type,
|
||||
*args, **kwargs
|
||||
)
|
||||
)
|
||||
)
|
||||
return func_event
|
||||
|
||||
return decorator
|
@ -4,4 +4,10 @@ class ApiPath(str, Enum):
|
||||
ME = '/me'
|
||||
CHATS = '/chats'
|
||||
MESSAGES = '/messages'
|
||||
UPDATES = '/updates'
|
||||
UPDATES = '/updates'
|
||||
VIDEOS = '/videos'
|
||||
ANSWERS = '/answers'
|
||||
ACTIONS = '/actions'
|
||||
PIN = '/pin'
|
||||
MEMBERS = '/members'
|
||||
ADMINS = '/admins'
|
@ -1,7 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class ButtonType(Enum):
|
||||
class ButtonType(str, Enum):
|
||||
REQUEST_CONTACT = 'request_contact'
|
||||
CALLBACK = 'callback'
|
||||
LINK = 'link'
|
||||
|
10
maxapi/enums/chat_permission.py
Normal file
10
maxapi/enums/chat_permission.py
Normal file
@ -0,0 +1,10 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class ChatPermission(str, Enum):
|
||||
READ_ALL_MESSAGES = 'read_all_messages'
|
||||
ADD_REMOVE_MEMBERS = 'add_remove_members'
|
||||
ADD_ADMINS = 'add_admins'
|
||||
CHANGE_CHAT_INFO = 'change_chat_info'
|
||||
PIN_MESSAGE = 'pin_message'
|
||||
WRITE = 'write'
|
@ -6,3 +6,4 @@ class HTTPMethod(str, Enum):
|
||||
GET = 'GET'
|
||||
PATCH = 'PATCH'
|
||||
PUT = 'PUT'
|
||||
DELETE = 'DELETE'
|
||||
|
9
maxapi/enums/sender_action.py
Normal file
9
maxapi/enums/sender_action.py
Normal file
@ -0,0 +1,9 @@
|
||||
from enum import Enum
|
||||
|
||||
class SenderAction(str, Enum):
|
||||
TYPING_ON = 'typing_on'
|
||||
SENDING_PHOTO = 'sending_photo'
|
||||
SENDING_VIDEO = 'sending_video'
|
||||
SENDING_AUDIO = 'sending_audio'
|
||||
SENDING_FILE = 'sending_file'
|
||||
MARK_SEEN = 'mark_seen'
|
@ -11,4 +11,6 @@ class UpdateType(str, Enum):
|
||||
MESSAGE_EDITED = 'message_edited'
|
||||
MESSAGE_REMOVED = 'message_removed'
|
||||
USER_ADDED = 'user_added'
|
||||
USER_REMOVED = 'user_removed'
|
||||
USER_REMOVED = 'user_removed'
|
||||
|
||||
ON_STARTED = 'on_started'
|
@ -6,7 +6,7 @@ from magic_filter.operations.comparator import ComparatorOperation as mf_compara
|
||||
F = MagicFilter()
|
||||
|
||||
|
||||
def filter_m(obj, *magic_args):
|
||||
def filter_attrs(obj, *magic_args):
|
||||
try:
|
||||
for arg in magic_args:
|
||||
|
||||
|
31
maxapi/filters/handler.py
Normal file
31
maxapi/filters/handler.py
Normal file
@ -0,0 +1,31 @@
|
||||
from typing import Callable
|
||||
|
||||
from magic_filter import F, MagicFilter
|
||||
|
||||
from ..types.command import Command
|
||||
from ..context.state_machine import State
|
||||
from ..enums.update import UpdateType
|
||||
|
||||
|
||||
class Handler:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*args,
|
||||
func_event: Callable,
|
||||
update_type: UpdateType,
|
||||
**kwargs
|
||||
):
|
||||
|
||||
self.func_event = func_event
|
||||
self.update_type = update_type
|
||||
self.filters = []
|
||||
self.state = None
|
||||
|
||||
for arg in args:
|
||||
if isinstance(arg, MagicFilter):
|
||||
self.filters.append(arg)
|
||||
elif isinstance(arg, State):
|
||||
self.state = arg
|
||||
elif isinstance(arg, Command):
|
||||
self.filters.insert(0, F.message.body.text == arg.command)
|
@ -1,4 +1,4 @@
|
||||
import logging
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger('bot')
|
||||
logger_bot = logging.getLogger('bot')
|
||||
logger_dp = logging.getLogger('dispatcher')
|
46
maxapi/methods/add_admin_chat.py
Normal file
46
maxapi/methods/add_admin_chat.py
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
|
||||
from re import findall
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from .types.added_admin_chat import AddedListAdminChat
|
||||
|
||||
from ..types.users import ChatAdmin
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class AddAdminChat(BaseConnection):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int,
|
||||
admins: List[ChatAdmin],
|
||||
marker: int = None
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
self.admins = admins
|
||||
self.marker = marker
|
||||
|
||||
async def request(self) -> AddedListAdminChat:
|
||||
json = {}
|
||||
|
||||
json['admins'] = [admin.model_dump() for admin in self.admins]
|
||||
json['marker'] = self.marker
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.POST,
|
||||
path=ApiPath.CHATS.value + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ADMINS,
|
||||
model=AddedListAdminChat,
|
||||
params=self.bot.params,
|
||||
json=json
|
||||
)
|
42
maxapi/methods/add_members_chat.py
Normal file
42
maxapi/methods/add_members_chat.py
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
|
||||
from re import findall
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from ..methods.types.added_members_chat import AddedMembersChat
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class AddMembersChat(BaseConnection):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int,
|
||||
user_ids: List[int],
|
||||
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
self.user_ids = user_ids
|
||||
|
||||
async def request(self) -> AddedMembersChat:
|
||||
json = {}
|
||||
|
||||
json['user_ids'] = self.user_ids
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.POST,
|
||||
path=ApiPath.CHATS.value + '/' + str(self.chat_id) + ApiPath.MEMBERS,
|
||||
model=AddedMembersChat,
|
||||
params=self.bot.params,
|
||||
json=json
|
||||
)
|
30
maxapi/methods/delete_bot_from_chat.py
Normal file
30
maxapi/methods/delete_bot_from_chat.py
Normal file
@ -0,0 +1,30 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ..methods.types.deleted_bot_from_chat import DeletedBotFromChat
|
||||
from ..methods.types.deleted_message import DeletedMessage
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class DeleteMeFromMessage(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int,
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
|
||||
async def request(self) -> DeletedBotFromChat:
|
||||
return await super().request(
|
||||
method=HTTPMethod.DELETE,
|
||||
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ME,
|
||||
model=DeletedBotFromChat,
|
||||
params=self.bot.params,
|
||||
)
|
29
maxapi/methods/delete_chat.py
Normal file
29
maxapi/methods/delete_chat.py
Normal file
@ -0,0 +1,29 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ..methods.types.deleted_chat import DeletedChat
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class DeleteChat(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
|
||||
async def request(self) -> DeletedChat:
|
||||
return await super().request(
|
||||
method=HTTPMethod.DELETE,
|
||||
path=ApiPath.CHATS.value + '/' + str(self.chat_id),
|
||||
model=DeletedChat,
|
||||
params=self.bot.params
|
||||
)
|
33
maxapi/methods/delete_message.py
Normal file
33
maxapi/methods/delete_message.py
Normal file
@ -0,0 +1,33 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ..methods.types.deleted_message import DeletedMessage
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class DeleteMessage(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
message_id: str,
|
||||
):
|
||||
self.bot = bot
|
||||
self.message_id = message_id
|
||||
|
||||
async def request(self) -> DeletedMessage:
|
||||
params = self.bot.params.copy()
|
||||
|
||||
params['message_id'] = self.message_id
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.DELETE,
|
||||
path=ApiPath.MESSAGES,
|
||||
model=DeletedMessage,
|
||||
params=params,
|
||||
)
|
29
maxapi/methods/delete_pin_message.py
Normal file
29
maxapi/methods/delete_pin_message.py
Normal file
@ -0,0 +1,29 @@
|
||||
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 ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class DeletePinMessage(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: str,
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
|
||||
async def request(self) -> DeletedPinMessage:
|
||||
return await super().request(
|
||||
method=HTTPMethod.DELETE,
|
||||
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.PIN,
|
||||
model=DeletedPinMessage,
|
||||
params=self.bot.params,
|
||||
)
|
68
maxapi/methods/edit_chat.py
Normal file
68
maxapi/methods/edit_chat.py
Normal file
@ -0,0 +1,68 @@
|
||||
|
||||
|
||||
from logging import getLogger
|
||||
from typing import Any, Dict, List, TYPE_CHECKING
|
||||
from collections import Counter
|
||||
|
||||
from ..types.attachments.image import PhotoAttachmentRequestPayload
|
||||
|
||||
from ..types.chats import Chat
|
||||
|
||||
from ..types.users import BotCommand, User
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class EditChat(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int,
|
||||
icon: PhotoAttachmentRequestPayload = None,
|
||||
title: str = None,
|
||||
pin: str = None,
|
||||
notify: bool = True,
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
self.icon = icon
|
||||
self.title = title
|
||||
self.pin = pin
|
||||
self.notify = notify
|
||||
|
||||
async def request(self) -> Chat:
|
||||
json = {}
|
||||
|
||||
if self.icon:
|
||||
dump = self.icon.model_dump()
|
||||
counter = Counter(dump.values())
|
||||
|
||||
if not None in counter or \
|
||||
not counter[None] == 2:
|
||||
return logger.error(
|
||||
'Все атрибуты модели Icon являются взаимоисключающими | '
|
||||
'https://dev.max.ru/docs-api/methods/PATCH/chats/-chatId-'
|
||||
)
|
||||
|
||||
json['icon'] = dump
|
||||
|
||||
if self.title: json['title'] = self.title
|
||||
if self.pin: json['pin'] = self.pin
|
||||
if self.notify: json['notify'] = self.notify
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.PATCH,
|
||||
path=ApiPath.CHATS.value + '/' + str(self.chat_id),
|
||||
model=Chat,
|
||||
params=self.bot.params,
|
||||
json=json
|
||||
)
|
@ -1,15 +1,11 @@
|
||||
|
||||
|
||||
from typing import List, TYPE_CHECKING
|
||||
|
||||
from aiomax.enums.parse_mode import ParseMode
|
||||
|
||||
from .types.edited_message import EditedMessage
|
||||
from ..types.message import NewMessageLink
|
||||
from ..types.attachments.attachment import Attachment
|
||||
|
||||
from ..enums.parse_mode import ParseMode
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from ..types.message import NewMessageLink
|
||||
from .types.edited_message import EditedMessage
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
@ -23,8 +19,8 @@ class EditMessage(BaseConnection):
|
||||
bot: 'Bot',
|
||||
message_id: str,
|
||||
text: str = None,
|
||||
attachments: List[Attachment] = None,
|
||||
link: NewMessageLink = None,
|
||||
attachments: List['Attachment'] = None,
|
||||
link: 'NewMessageLink' = None,
|
||||
notify: bool = True,
|
||||
parse_mode: ParseMode = None
|
||||
):
|
||||
@ -36,7 +32,7 @@ class EditMessage(BaseConnection):
|
||||
self.notify = notify
|
||||
self.parse_mode = parse_mode
|
||||
|
||||
async def request(self) -> 'EditedMessage':
|
||||
async def request(self) -> EditedMessage:
|
||||
params = self.bot.params.copy()
|
||||
|
||||
json = {}
|
||||
|
36
maxapi/methods/get_chat_by_id.py
Normal file
36
maxapi/methods/get_chat_by_id.py
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
|
||||
from re import findall
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ..types.chats import Chat
|
||||
|
||||
from ..types.users import User
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class GetChatById(BaseConnection):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
id: int
|
||||
):
|
||||
self.bot = bot
|
||||
self.id = id
|
||||
|
||||
async def request(self) -> Chat:
|
||||
return await super().request(
|
||||
method=HTTPMethod.GET,
|
||||
path=ApiPath.CHATS.value + '/' + str(self.id),
|
||||
model=Chat,
|
||||
params=self.bot.params
|
||||
)
|
41
maxapi/methods/get_chat_by_link.py
Normal file
41
maxapi/methods/get_chat_by_link.py
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
|
||||
from re import findall
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ..types.chats import Chat
|
||||
|
||||
from ..types.users import User
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class GetChatByLink(BaseConnection):
|
||||
|
||||
PATTERN_LINK = r'@?[a-zA-Z]+[a-zA-Z0-9-_]*'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
link: str
|
||||
):
|
||||
self.bot = bot
|
||||
self.link = findall(self.PATTERN_LINK, link)
|
||||
|
||||
if not self.link:
|
||||
return
|
||||
|
||||
async def request(self) -> Chat:
|
||||
return await super().request(
|
||||
method=HTTPMethod.GET,
|
||||
path=ApiPath.CHATS.value + '/' + self.link[-1],
|
||||
model=Chat,
|
||||
params=self.bot.params
|
||||
)
|
@ -17,13 +17,27 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class GetChats(BaseConnection):
|
||||
def __init__(self, bot: 'Bot'):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
count: int = 50,
|
||||
marker: int = None
|
||||
):
|
||||
self.bot = bot
|
||||
self.count = count
|
||||
self.marker = marker
|
||||
|
||||
async def request(self) -> Chats:
|
||||
params = self.bot.params.copy()
|
||||
|
||||
params['count'] = self.count
|
||||
|
||||
if self.marker:
|
||||
params['marker'] = self.marker
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.GET,
|
||||
path=ApiPath.CHATS,
|
||||
model=Chats,
|
||||
params=self.bot.params
|
||||
params=params
|
||||
)
|
34
maxapi/methods/get_list_admin_chat.py
Normal file
34
maxapi/methods/get_list_admin_chat.py
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
from re import findall
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ..methods.types.getted_list_admin_chat import GettedListAdminChat
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class GetListAdminChat(BaseConnection):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
|
||||
async def request(self) -> GettedListAdminChat:
|
||||
return await super().request(
|
||||
method=HTTPMethod.GET,
|
||||
path=ApiPath.CHATS.value + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ADMINS,
|
||||
model=GettedListAdminChat,
|
||||
params=self.bot.params
|
||||
)
|
34
maxapi/methods/get_me_from_chat.py
Normal file
34
maxapi/methods/get_me_from_chat.py
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ..types.chats import ChatMember, Chats
|
||||
|
||||
from ..types.users import User
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class GetMeFromChat(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
|
||||
async def request(self) -> ChatMember:
|
||||
return await super().request(
|
||||
method=HTTPMethod.GET,
|
||||
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.MEMBERS + ApiPath.ME,
|
||||
model=ChatMember,
|
||||
params=self.bot.params
|
||||
)
|
47
maxapi/methods/get_members_chat.py
Normal file
47
maxapi/methods/get_members_chat.py
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
|
||||
from re import findall
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from ..methods.types.getted_members_chat import GettedMembersChat
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class GetMembersChat(BaseConnection):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int,
|
||||
user_ids: List[str] = None,
|
||||
marker: int = None,
|
||||
count: int = None,
|
||||
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
self.user_ids = user_ids
|
||||
self.marker = marker
|
||||
self.count = count
|
||||
|
||||
async def request(self) -> GettedMembersChat:
|
||||
params = self.bot.params.copy()
|
||||
|
||||
if self.user_ids: params['user_ids'] = ','.join(self.user_ids)
|
||||
if self.marker: params['marker'] = self.marker
|
||||
if self.count: params['marker'] = self.count
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.GET,
|
||||
path=ApiPath.CHATS.value + '/' + str(self.chat_id) + ApiPath.MEMBERS,
|
||||
model=GettedMembersChat,
|
||||
params=params
|
||||
)
|
@ -1,6 +1,7 @@
|
||||
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from ..types.message import Messages
|
||||
from ..enums.http_method import HTTPMethod
|
||||
@ -13,15 +14,44 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class GetMessages(BaseConnection):
|
||||
def __init__(self, bot: 'Bot', chat_id: int = None):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int,
|
||||
message_ids: List[str] = None,
|
||||
from_time: datetime | int = None,
|
||||
to_time: datetime | int = None,
|
||||
count: int = 50,
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
self.message_ids = message_ids
|
||||
self.from_time = from_time
|
||||
self.to_time = to_time
|
||||
self.count = count
|
||||
|
||||
async def request(self) -> Messages:
|
||||
params = self.bot.params.copy()
|
||||
|
||||
if self.chat_id: params['chat_id'] = self.chat_id
|
||||
|
||||
if self.message_ids:
|
||||
params['message_ids'] = ','.join(self.message_ids)
|
||||
|
||||
if self.from_time:
|
||||
if isinstance(self.from_time, datetime):
|
||||
params['from_time'] = int(self.from_time.timestamp())
|
||||
else:
|
||||
params['from_time'] = self.from_time
|
||||
|
||||
if self.to_time:
|
||||
if isinstance(self.to_time, datetime):
|
||||
params['to_time'] = int(self.to_time.timestamp())
|
||||
else:
|
||||
params['to_time'] = self.to_time
|
||||
|
||||
params['count'] = self.count
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.GET,
|
||||
path=ApiPath.MESSAGES,
|
||||
|
32
maxapi/methods/get_pinned_message.py
Normal file
32
maxapi/methods/get_pinned_message.py
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from .types.getted_pineed_message import GettedPin
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class GetPinnedMessage(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int,
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
|
||||
async def request(self) -> GettedPin:
|
||||
return await super().request(
|
||||
method=HTTPMethod.GET,
|
||||
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.PIN,
|
||||
model=GettedPin,
|
||||
params=self.bot.params
|
||||
)
|
43
maxapi/methods/get_updates.py
Normal file
43
maxapi/methods/get_updates.py
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from ..types.updates import UpdateUnion
|
||||
|
||||
from ..methods.types.getted_updates import process_update_request
|
||||
|
||||
|
||||
from ..types.message import Messages
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class GetUpdates(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
limit: int = 100,
|
||||
):
|
||||
self.bot = bot
|
||||
self.limit = limit
|
||||
|
||||
async def request(self) -> UpdateUnion:
|
||||
params = self.bot.params.copy()
|
||||
|
||||
params['limit'] = self.limit
|
||||
|
||||
event_json = await super().request(
|
||||
method=HTTPMethod.GET,
|
||||
path=ApiPath.UPDATES,
|
||||
model=None,
|
||||
params=params,
|
||||
is_return_raw=True
|
||||
)
|
||||
|
||||
return event_json
|
34
maxapi/methods/get_video.py
Normal file
34
maxapi/methods/get_video.py
Normal file
@ -0,0 +1,34 @@
|
||||
from typing import List, TYPE_CHECKING
|
||||
|
||||
from ..types.attachments.video import Video
|
||||
|
||||
from .types.edited_message import EditedMessage
|
||||
from ..types.message import NewMessageLink
|
||||
from ..types.attachments.attachment import Attachment
|
||||
from ..enums.parse_mode import ParseMode
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class GetVideo(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
video_token: str
|
||||
):
|
||||
self.bot = bot
|
||||
self.video_token = video_token
|
||||
|
||||
async def request(self) -> Video:
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.GET,
|
||||
path=ApiPath.VIDEOS.value + '/' + self.video_token,
|
||||
model=Video,
|
||||
params=self.bot.params,
|
||||
)
|
42
maxapi/methods/pin_message.py
Normal file
42
maxapi/methods/pin_message.py
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from .types.pinned_message import PinnedMessage
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class PinMessage(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int,
|
||||
message_id: str,
|
||||
notify: bool = True
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
self.message_id = message_id
|
||||
self.notify = notify
|
||||
|
||||
async def request(self) -> PinnedMessage:
|
||||
json = {}
|
||||
|
||||
json['message_id'] = self.message_id
|
||||
json['notify'] = self.notify
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.PUT,
|
||||
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.PIN,
|
||||
model=PinnedMessage,
|
||||
params=self.bot.params,
|
||||
json=json
|
||||
)
|
36
maxapi/methods/remove_admin.py
Normal file
36
maxapi/methods/remove_admin.py
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from .types.removed_admin import RemovedAdmin
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class RemoveAdmin(BaseConnection):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int,
|
||||
user_id: int
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
self.user_id = user_id
|
||||
|
||||
async def request(self) -> RemovedAdmin:
|
||||
return await super().request(
|
||||
method=HTTPMethod.DELETE,
|
||||
path=ApiPath.CHATS.value + '/' + str(self.chat_id) + \
|
||||
ApiPath.MEMBERS + ApiPath.ADMINS + '/' + str(self.user_id),
|
||||
model=RemovedAdmin,
|
||||
params=self.bot.params,
|
||||
)
|
42
maxapi/methods/remove_member_chat.py
Normal file
42
maxapi/methods/remove_member_chat.py
Normal file
@ -0,0 +1,42 @@
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from .types.removed_member_chat import RemovedMemberChat
|
||||
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class RemoveMemberChat(BaseConnection):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int,
|
||||
user_id: int,
|
||||
block: bool = False,
|
||||
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
self.user_id = user_id
|
||||
self.block = block
|
||||
|
||||
async def request(self) -> RemovedMemberChat:
|
||||
params = self.bot.params.copy()
|
||||
|
||||
params['chat_id'] = self.chat_id
|
||||
params['user_id'] = self.user_id
|
||||
params['block'] = str(self.block).lower()
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.DELETE,
|
||||
path=ApiPath.CHATS.value + '/' + str(self.chat_id) + ApiPath.MEMBERS,
|
||||
model=RemovedMemberChat,
|
||||
params=params,
|
||||
)
|
43
maxapi/methods/send_action.py
Normal file
43
maxapi/methods/send_action.py
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
from typing import List, TYPE_CHECKING
|
||||
|
||||
from ..enums.sender_action import SenderAction
|
||||
from ..methods.types.sended_action import SendedAction
|
||||
|
||||
from .types.sended_message import SendedMessage
|
||||
from ..types.message import NewMessageLink
|
||||
from ..types.attachments.attachment import Attachment
|
||||
from ..enums.parse_mode import ParseMode
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class SendAction(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
chat_id: int = None,
|
||||
action: SenderAction = SenderAction.TYPING_ON
|
||||
):
|
||||
self.bot = bot
|
||||
self.chat_id = chat_id
|
||||
self.action = action
|
||||
|
||||
async def request(self) -> SendedAction:
|
||||
json = {}
|
||||
|
||||
json['action'] = self.action.value
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.POST,
|
||||
path=ApiPath.CHATS + '/' + str(self.chat_id) + ApiPath.ACTIONS,
|
||||
model=SendedAction,
|
||||
params=self.bot.params,
|
||||
json=json
|
||||
)
|
53
maxapi/methods/send_callback.py
Normal file
53
maxapi/methods/send_callback.py
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
|
||||
from typing import List, TYPE_CHECKING
|
||||
|
||||
from ..methods.types.sended_callback import SendedCallback
|
||||
|
||||
from .types.sended_message import SendedMessage
|
||||
from ..types.attachments.attachment import Attachment
|
||||
from ..enums.parse_mode import ParseMode
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
from ..types.message import Message
|
||||
|
||||
|
||||
class SendCallback(BaseConnection):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
callback_id: str,
|
||||
message: 'Message' = None,
|
||||
notification: str = None
|
||||
):
|
||||
self.bot = bot
|
||||
self.callback_id = callback_id
|
||||
self.message = message
|
||||
self.notification = notification
|
||||
|
||||
async def request(self) -> SendedCallback:
|
||||
try:
|
||||
params = self.bot.params.copy()
|
||||
|
||||
params['callback_id'] = self.callback_id
|
||||
|
||||
json = {}
|
||||
|
||||
if self.message: json['message'] = self.message.model_dump()
|
||||
if self.notification: json['notification'] = self.notification
|
||||
|
||||
return await super().request(
|
||||
method=HTTPMethod.POST,
|
||||
path=ApiPath.ANSWERS,
|
||||
model=SendedCallback,
|
||||
params=params,
|
||||
json=json
|
||||
)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
...
|
@ -2,15 +2,12 @@
|
||||
|
||||
from typing import List, TYPE_CHECKING
|
||||
|
||||
from ..enums.parse_mode import ParseMode
|
||||
|
||||
from .types.sended_message import SendedMessage
|
||||
from ..types.message import NewMessageLink
|
||||
|
||||
from ..types.attachments.attachment import Attachment
|
||||
|
||||
from ..enums.parse_mode import ParseMode
|
||||
from ..enums.http_method import HTTPMethod
|
||||
from ..enums.api_path import ApiPath
|
||||
from .types.sended_message import SendedMessage
|
||||
from ..connection.base import BaseConnection
|
||||
|
||||
|
||||
@ -41,7 +38,7 @@ class SendMessage(BaseConnection):
|
||||
self.notify = notify
|
||||
self.parse_mode = parse_mode
|
||||
|
||||
async def request(self) -> 'SendedMessage':
|
||||
async def request(self) -> SendedMessage:
|
||||
params = self.bot.params.copy()
|
||||
|
||||
json = {}
|
||||
@ -53,7 +50,7 @@ class SendMessage(BaseConnection):
|
||||
json['disable_link_preview'] = str(self.disable_link_preview).lower()
|
||||
|
||||
if self.attachments: json['attachments'] = \
|
||||
[att.model_dump() for att in self.attachments]
|
||||
[att.model_dump() for att in self.attachments]
|
||||
|
||||
if not self.link is None: json['link'] = self.link.model_dump()
|
||||
if not self.notify is None: json['notify'] = self.notify
|
||||
|
9
maxapi/methods/types/added_admin_chat.py
Normal file
9
maxapi/methods/types/added_admin_chat.py
Normal file
@ -0,0 +1,9 @@
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ...types.chats import ChatMember
|
||||
|
||||
|
||||
class AddedListAdminChat(BaseModel):
|
||||
success: bool
|
||||
message: Optional[str] = None
|
9
maxapi/methods/types/added_members_chat.py
Normal file
9
maxapi/methods/types/added_members_chat.py
Normal file
@ -0,0 +1,9 @@
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ...types.chats import ChatMember
|
||||
|
||||
|
||||
class AddedMembersChat(BaseModel):
|
||||
success: bool
|
||||
message: Optional[str] = None
|
7
maxapi/methods/types/deleted_bot_from_chat.py
Normal file
7
maxapi/methods/types/deleted_bot_from_chat.py
Normal file
@ -0,0 +1,7 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class DeletedBotFromChat(BaseModel):
|
||||
success: bool
|
||||
message: Optional[str] = None
|
7
maxapi/methods/types/deleted_chat.py
Normal file
7
maxapi/methods/types/deleted_chat.py
Normal file
@ -0,0 +1,7 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class DeletedChat(BaseModel):
|
||||
success: bool
|
||||
message: Optional[str] = None
|
7
maxapi/methods/types/deleted_message.py
Normal file
7
maxapi/methods/types/deleted_message.py
Normal file
@ -0,0 +1,7 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class DeletedMessage(BaseModel):
|
||||
success: bool
|
||||
message: Optional[str] = None
|
7
maxapi/methods/types/deleted_pin_message.py
Normal file
7
maxapi/methods/types/deleted_pin_message.py
Normal file
@ -0,0 +1,7 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class DeletedPinMessage(BaseModel):
|
||||
success: bool
|
||||
message: Optional[str] = None
|
@ -1,7 +1,7 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ...types.message import Message
|
||||
|
||||
|
||||
class EditedMessage(BaseModel):
|
||||
message: Message
|
||||
success: bool
|
||||
message: Optional[str] = None
|
9
maxapi/methods/types/getted_list_admin_chat.py
Normal file
9
maxapi/methods/types/getted_list_admin_chat.py
Normal file
@ -0,0 +1,9 @@
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ...types.chats import ChatMember
|
||||
|
||||
|
||||
class GettedListAdminChat(BaseModel):
|
||||
members: List[ChatMember]
|
||||
marker: Optional[int] = None
|
9
maxapi/methods/types/getted_members_chat.py
Normal file
9
maxapi/methods/types/getted_members_chat.py
Normal file
@ -0,0 +1,9 @@
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ...types.chats import ChatMember
|
||||
|
||||
|
||||
class GettedMembersChat(BaseModel):
|
||||
members: List[ChatMember]
|
||||
marker: Optional[int] = None
|
8
maxapi/methods/types/getted_pineed_message.py
Normal file
8
maxapi/methods/types/getted_pineed_message.py
Normal file
@ -0,0 +1,8 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ...types.message import Message
|
||||
|
||||
|
||||
class GettedPin(BaseModel):
|
||||
message: Optional[Message] = None
|
75
maxapi/methods/types/getted_updates.py
Normal file
75
maxapi/methods/types/getted_updates.py
Normal file
@ -0,0 +1,75 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ...enums.update import UpdateType
|
||||
from ...types.updates.bot_added import BotAdded
|
||||
from ...types.updates.bot_removed import BotRemoved
|
||||
from ...types.updates.bot_started import BotStarted
|
||||
from ...types.updates.chat_title_changed import ChatTitleChanged
|
||||
from ...types.updates.message_callback import MessageCallback
|
||||
from ...types.updates.message_chat_created import MessageChatCreated
|
||||
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
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
async def get_update_model(event: dict, bot: 'Bot'):
|
||||
event_object = None
|
||||
match event['update_type']:
|
||||
case UpdateType.BOT_ADDED:
|
||||
event_object = BotAdded(**event)
|
||||
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)
|
||||
case UpdateType.MESSAGE_CHAT_CREATED:
|
||||
event_object = MessageChatCreated(**event)
|
||||
case UpdateType.MESSAGE_CREATED:
|
||||
event_object = MessageCreated(**event)
|
||||
case UpdateType.MESSAGE_EDITED:
|
||||
event_object = MessageEdited(**event)
|
||||
case UpdateType.MESSAGE_REMOVED:
|
||||
event_object = MessageRemoved(**event)
|
||||
case UpdateType.USER_ADDED:
|
||||
event_object = UserAdded(**event)
|
||||
case UpdateType.USER_REMOVED:
|
||||
event_object = UserRemoved(**event)
|
||||
|
||||
if hasattr(event_object, 'bot'):
|
||||
event_object.bot = bot
|
||||
if hasattr(event_object, 'message'):
|
||||
event_object.message.bot = bot
|
||||
|
||||
return event_object
|
||||
|
||||
|
||||
async def process_update_request(events: dict, bot: 'Bot'):
|
||||
events = [event for event in events['updates']]
|
||||
|
||||
objects = []
|
||||
|
||||
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'):
|
||||
return await get_update_model(
|
||||
bot=bot,
|
||||
event=event_json
|
||||
)
|
7
maxapi/methods/types/pinned_message.py
Normal file
7
maxapi/methods/types/pinned_message.py
Normal file
@ -0,0 +1,7 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class PinnedMessage(BaseModel):
|
||||
success: bool
|
||||
message: Optional[str] = None
|
7
maxapi/methods/types/removed_admin.py
Normal file
7
maxapi/methods/types/removed_admin.py
Normal file
@ -0,0 +1,7 @@
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class RemovedAdmin(BaseModel):
|
||||
success: bool
|
||||
message: Optional[str] = None
|
9
maxapi/methods/types/removed_member_chat.py
Normal file
9
maxapi/methods/types/removed_member_chat.py
Normal file
@ -0,0 +1,9 @@
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ...types.chats import ChatMember
|
||||
|
||||
|
||||
class RemovedMemberChat(BaseModel):
|
||||
success: bool
|
||||
message: Optional[str] = None
|
7
maxapi/methods/types/sended_action.py
Normal file
7
maxapi/methods/types/sended_action.py
Normal file
@ -0,0 +1,7 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class SendedAction(BaseModel):
|
||||
success: bool
|
||||
message: Optional[str] = None
|
14
maxapi/methods/types/sended_callback.py
Normal file
14
maxapi/methods/types/sended_callback.py
Normal file
@ -0,0 +1,14 @@
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class SendedCallback(BaseModel):
|
||||
success: bool
|
||||
message: Optional[str] = None
|
||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
bot: Optional[Bot]
|
@ -1,3 +1,4 @@
|
||||
from typing import Any
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ...types.message import Message
|
||||
|
@ -0,0 +1,49 @@
|
||||
from ..types.updates.bot_added import BotAdded
|
||||
from ..types.updates.bot_removed import BotRemoved
|
||||
from ..types.updates.bot_started import BotStarted
|
||||
from ..types.updates.chat_title_changed import ChatTitleChanged
|
||||
from ..types.updates.message_callback import MessageCallback
|
||||
from ..types.updates.message_chat_created import MessageChatCreated
|
||||
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.attachments.attachment import PhotoAttachmentPayload
|
||||
from ..types.attachments.attachment import OtherAttachmentPayload
|
||||
from ..types.attachments.attachment import ContactAttachmentPayload
|
||||
from ..types.attachments.attachment import ButtonsPayload
|
||||
from ..types.attachments.attachment import StickerAttachmentPayload
|
||||
from ..types.attachments.buttons.callback_button import CallbackButton
|
||||
from ..types.attachments.buttons.chat_button import ChatButton
|
||||
from ..types.attachments.buttons.link_button import LinkButton
|
||||
from ..types.attachments.buttons.request_contact import RequestContact
|
||||
from ..types.attachments.buttons.request_geo_location_button import RequestGeoLocationButton
|
||||
|
||||
from ..types.command import Command
|
||||
|
||||
__all__ = [
|
||||
CallbackButton,
|
||||
ChatButton,
|
||||
LinkButton,
|
||||
RequestContact,
|
||||
RequestGeoLocationButton,
|
||||
Command,
|
||||
PhotoAttachmentPayload,
|
||||
OtherAttachmentPayload,
|
||||
ContactAttachmentPayload,
|
||||
ButtonsPayload,
|
||||
StickerAttachmentPayload,
|
||||
BotAdded,
|
||||
BotRemoved,
|
||||
BotStarted,
|
||||
ChatTitleChanged,
|
||||
MessageCallback,
|
||||
MessageChatCreated,
|
||||
MessageCreated,
|
||||
MessageEdited,
|
||||
MessageRemoved,
|
||||
UserAdded,
|
||||
UserRemoved
|
||||
]
|
@ -1,13 +1,9 @@
|
||||
from typing import List, Optional, Union
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ...types.attachments.buttons.chat_button import ChatButton
|
||||
from ...types.attachments.buttons.request_contact import RequestContact
|
||||
from ...types.attachments.buttons.request_geo_location_button import RequestGeoLocationButton
|
||||
from ...types.attachments.buttons.link_button import LinkButton
|
||||
from ...types.attachments.buttons import InlineButtonUnion
|
||||
from ...types.users import User
|
||||
from ...enums.attachment import AttachmentType
|
||||
from .buttons.callback_button import CallbackButton
|
||||
|
||||
AttachmentUnion = []
|
||||
|
||||
@ -34,15 +30,7 @@ class ContactAttachmentPayload(BaseModel):
|
||||
|
||||
|
||||
class ButtonsPayload(BaseModel):
|
||||
buttons: List[List[
|
||||
Union[
|
||||
LinkButton,
|
||||
CallbackButton,
|
||||
RequestGeoLocationButton,
|
||||
RequestContact,
|
||||
ChatButton
|
||||
]
|
||||
]]
|
||||
buttons: List[List[InlineButtonUnion]]
|
||||
|
||||
|
||||
class Attachment(BaseModel):
|
||||
|
@ -1,12 +1,15 @@
|
||||
from typing import Literal
|
||||
from pydantic import BaseModel
|
||||
from typing import Union
|
||||
|
||||
from ....enums.button_type import ButtonType
|
||||
from .callback_button import CallbackButton
|
||||
from .chat_button import ChatButton
|
||||
from .link_button import LinkButton
|
||||
from .request_contact import RequestContact
|
||||
from .request_geo_location_button import RequestGeoLocationButton
|
||||
|
||||
|
||||
class Button(BaseModel):
|
||||
type: ButtonType
|
||||
text: str
|
||||
|
||||
class Config:
|
||||
use_enum_values = True
|
||||
InlineButtonUnion = Union[
|
||||
CallbackButton,
|
||||
ChatButton,
|
||||
LinkButton,
|
||||
RequestContact,
|
||||
RequestGeoLocationButton
|
||||
]
|
12
maxapi/types/attachments/buttons/button.py
Normal file
12
maxapi/types/attachments/buttons/button.py
Normal file
@ -0,0 +1,12 @@
|
||||
from typing import Literal
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ....enums.button_type import ButtonType
|
||||
|
||||
|
||||
class Button(BaseModel):
|
||||
type: ButtonType
|
||||
text: str
|
||||
|
||||
class Config:
|
||||
use_enum_values = True
|
@ -1,9 +1,12 @@
|
||||
from typing import Optional
|
||||
|
||||
from maxapi.enums.button_type import ButtonType
|
||||
|
||||
from ....enums.intent import Intent
|
||||
from . import Button
|
||||
from .button import Button
|
||||
|
||||
|
||||
class CallbackButton(Button):
|
||||
type: ButtonType = ButtonType.CALLBACK
|
||||
payload: Optional[str] = None
|
||||
intent: Intent
|
||||
intent: Intent = Intent.DEFAULT
|
@ -1,6 +1,6 @@
|
||||
from typing import Optional
|
||||
|
||||
from ....types.attachments.buttons import Button
|
||||
from .button import Button
|
||||
|
||||
|
||||
class ChatButton(Button):
|
||||
|
@ -1,6 +1,6 @@
|
||||
from typing import Optional
|
||||
|
||||
from ....types.attachments.buttons import Button
|
||||
from .button import Button
|
||||
|
||||
|
||||
class LinkButton(Button):
|
||||
|
@ -1,4 +1,4 @@
|
||||
from ....types.attachments.buttons import Button
|
||||
from .button import Button
|
||||
|
||||
|
||||
class RequestContact(Button):
|
||||
|
@ -1,4 +1,4 @@
|
||||
from ....types.attachments.buttons import Button
|
||||
from .button import Button
|
||||
|
||||
|
||||
class RequestGeoLocationButton(Button):
|
||||
|
@ -1,6 +1,14 @@
|
||||
from typing import Literal
|
||||
from typing import Literal, Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
from .attachment import Attachment
|
||||
|
||||
|
||||
class PhotoAttachmentRequestPayload(BaseModel):
|
||||
url: Optional[str] = None
|
||||
token: Optional[str] = None
|
||||
photos: Optional[str] = None
|
||||
|
||||
|
||||
class Image(Attachment):
|
||||
type: Literal['image'] = 'image'
|
@ -1,9 +1,10 @@
|
||||
from typing import Optional
|
||||
from typing import Literal, Optional
|
||||
|
||||
from .attachment import Attachment
|
||||
|
||||
|
||||
class Share(Attachment):
|
||||
type: Literal['share'] = 'share'
|
||||
title: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
image_url: Optional[str] = None
|
||||
|
@ -1,16 +1,35 @@
|
||||
from typing import Literal, Optional
|
||||
from pydantic import BaseModel
|
||||
from typing import TYPE_CHECKING, Any, Literal, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from .attachment import Attachment
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class VideoUrl(BaseModel):
|
||||
mp4_1080: Optional[str] = None
|
||||
mp4_720: Optional[str] = None
|
||||
mp4_480: Optional[str] = None
|
||||
mp4_360: Optional[str] = None
|
||||
mp4_240: Optional[str] = None
|
||||
mp4_144: Optional[str] = None
|
||||
hls: Optional[str] = None
|
||||
|
||||
|
||||
class VideoThumbnail(BaseModel):
|
||||
url: str
|
||||
|
||||
|
||||
class Video(Attachment):
|
||||
type: Literal['video'] = 'video'
|
||||
type: Optional[Literal['video']] = 'video'
|
||||
token: Optional[str] = None
|
||||
urls: Optional[VideoUrl] = None
|
||||
thumbnail: VideoThumbnail
|
||||
width: Optional[int] = None
|
||||
height: Optional[int] = None
|
||||
duration: Optional[int] = None
|
||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
bot: Optional['Bot']
|
||||
|
@ -1,8 +1,10 @@
|
||||
from typing import Optional
|
||||
from typing import List, Optional, Union
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ..types.users import User
|
||||
|
||||
from ..types.users import User
|
||||
|
||||
|
||||
class Callback(BaseModel):
|
||||
timestamp: int
|
||||
|
@ -1,8 +1,10 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel, field_validator
|
||||
from typing import Dict, List, Optional
|
||||
from enum import Enum
|
||||
from datetime import datetime
|
||||
|
||||
from ..enums.chat_permission import ChatPermission
|
||||
|
||||
from ..types.users import User
|
||||
from ..types.message import Message
|
||||
|
||||
@ -20,6 +22,7 @@ class ChatStatus(str, Enum):
|
||||
class Icon(BaseModel):
|
||||
url: str
|
||||
|
||||
|
||||
class Chat(BaseModel):
|
||||
chat_id: int
|
||||
type: ChatType
|
||||
@ -29,7 +32,7 @@ class Chat(BaseModel):
|
||||
last_event_time: int
|
||||
participants_count: int
|
||||
owner_id: Optional[int] = None
|
||||
participants: None = None
|
||||
participants: Optional[Dict[str, datetime]] = None
|
||||
is_public: bool
|
||||
link: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
@ -38,9 +41,26 @@ class Chat(BaseModel):
|
||||
chat_message_id: Optional[str] = None
|
||||
pinned_message: Optional[Message] = None
|
||||
|
||||
@field_validator('participants', mode='before')
|
||||
@classmethod
|
||||
def convert_timestamps(cls, value: Dict[str, int]) -> Dict[str, datetime]:
|
||||
return {
|
||||
key: datetime.fromtimestamp(ts / 1000)
|
||||
for key, ts in value.items()
|
||||
}
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed=True
|
||||
|
||||
|
||||
class Chats(BaseModel):
|
||||
chats: List[Chat] = []
|
||||
chats: List[Chat] = []
|
||||
marker: Optional[int] = None
|
||||
|
||||
|
||||
class ChatMember(User):
|
||||
last_access_time: Optional[int] = None
|
||||
is_owner: Optional[bool] = None
|
||||
is_admin: Optional[bool] = None
|
||||
join_time: Optional[int] = None
|
||||
permissions: Optional[List[ChatPermission]] = None
|
9
maxapi/types/command.py
Normal file
9
maxapi/types/command.py
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
class Command:
|
||||
def __init__(self, text: str, prefix: str = '/'):
|
||||
self.text = text
|
||||
self.prefix = prefix
|
||||
|
||||
@property
|
||||
def command(self):
|
||||
return self.prefix + self.text
|
@ -87,7 +87,10 @@ class Message(BaseModel):
|
||||
body: Optional[MessageBody] = None
|
||||
stat: Optional[MessageStat] = None
|
||||
url: Optional[str] = None
|
||||
bot: Optional[Any] = None
|
||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
bot: Optional[Bot]
|
||||
|
||||
async def answer(self,
|
||||
text: str = None,
|
||||
@ -97,8 +100,7 @@ class Message(BaseModel):
|
||||
notify: bool = True,
|
||||
parse_mode: ParseMode = None
|
||||
):
|
||||
bot: Bot = self.bot
|
||||
return await bot.send_message(
|
||||
return await self.bot.send_message(
|
||||
chat_id=self.recipient.chat_id,
|
||||
user_id=self.recipient.user_id,
|
||||
text=text,
|
||||
@ -108,10 +110,43 @@ class Message(BaseModel):
|
||||
notify=notify,
|
||||
parse_mode=parse_mode
|
||||
)
|
||||
|
||||
async def edit(
|
||||
self,
|
||||
text: str = None,
|
||||
attachments: List[Attachment] = None,
|
||||
link: NewMessageLink = None,
|
||||
notify: bool = True,
|
||||
parse_mode: ParseMode = None
|
||||
):
|
||||
return await self.bot.edit_message(
|
||||
message_id=self.body.mid,
|
||||
text=text,
|
||||
attachments=attachments,
|
||||
link=link,
|
||||
notify=notify,
|
||||
parse_mode=parse_mode
|
||||
)
|
||||
|
||||
async def delete(self):
|
||||
return await self.bot.delete_message(
|
||||
message_id=self.body.mid,
|
||||
)
|
||||
|
||||
async def pin(self, notify: bool = True):
|
||||
return await self.bot.pin_message(
|
||||
chat_id=self.recipient.chat_id,
|
||||
message_id=self.body.mid,
|
||||
notify=notify
|
||||
)
|
||||
|
||||
|
||||
class Messages(BaseModel):
|
||||
messages: List[Message]
|
||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
bot: Optional[Bot]
|
||||
|
||||
|
||||
class NewMessageLink(BaseModel):
|
||||
|
@ -1,11 +1,27 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ...enums.update import UpdateType
|
||||
from typing import Union
|
||||
from ...types.updates.bot_added import BotAdded
|
||||
from ...types.updates.bot_removed import BotRemoved
|
||||
from ...types.updates.bot_started import BotStarted
|
||||
from ...types.updates.chat_title_changed import ChatTitleChanged
|
||||
from ...types.updates.message_callback import MessageCallback
|
||||
from ...types.updates.message_chat_created import MessageChatCreated
|
||||
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
|
||||
|
||||
|
||||
class Update(BaseModel):
|
||||
update_type: UpdateType
|
||||
timestamp: int
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed=True
|
||||
UpdateUnion = Union[
|
||||
BotAdded,
|
||||
BotRemoved,
|
||||
BotStarted,
|
||||
ChatTitleChanged,
|
||||
MessageCallback,
|
||||
MessageChatCreated,
|
||||
MessageCreated,
|
||||
MessageEdited,
|
||||
MessageRemoved,
|
||||
UserAdded,
|
||||
UserRemoved
|
||||
]
|
@ -1,8 +1,21 @@
|
||||
from typing import Optional
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from . import Update
|
||||
from pydantic import Field
|
||||
|
||||
from .update import Update
|
||||
from ...types.users import User
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class BotAdded(Update):
|
||||
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):
|
||||
return (self.chat_id, self.user.user_id)
|
@ -1,8 +1,21 @@
|
||||
from typing import Optional
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from . import Update
|
||||
from pydantic import Field
|
||||
|
||||
from .update import Update
|
||||
from ...types.users import User
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class BotRemoved(Update):
|
||||
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):
|
||||
return (self.chat_id, self.user.user_id)
|
@ -1,10 +1,23 @@
|
||||
from typing import Optional
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from . import Update
|
||||
from pydantic import Field
|
||||
|
||||
from .update import Update
|
||||
from ...types.users import User
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class BotStarted(Update):
|
||||
chat_id: Optional[int] = None
|
||||
user: User
|
||||
user_locale: Optional[str] = None
|
||||
payload: Optional[str] = None
|
||||
payload: Optional[str] = None
|
||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
bot: Optional[Bot]
|
||||
|
||||
def get_ids(self):
|
||||
return (self.chat_id, self.user.user_id)
|
@ -1,9 +1,22 @@
|
||||
from typing import Optional
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from . import Update
|
||||
from pydantic import Field
|
||||
|
||||
from .update import Update
|
||||
from ...types.users import User
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class ChatTitleChanged(Update):
|
||||
chat_id: Optional[int] = None
|
||||
user: User
|
||||
title: Optional[str] = None
|
||||
title: Optional[str] = None
|
||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
bot: Optional[Bot]
|
||||
|
||||
def get_ids(self):
|
||||
return (self.chat_id, self.user.user_id)
|
@ -1,11 +1,76 @@
|
||||
from typing import Optional
|
||||
from typing import Any, List, Optional, TYPE_CHECKING, Union
|
||||
|
||||
from . import Update
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from .update import Update
|
||||
from ...types.callback import Callback
|
||||
from ...types.message import Message
|
||||
|
||||
from ...enums.parse_mode import ParseMode
|
||||
from ...types.message import NewMessageLink
|
||||
from ...types.attachments.share import Share
|
||||
from ..attachments.buttons.attachment_button import AttachmentButton
|
||||
from ..attachments.sticker import Sticker
|
||||
from ..attachments.file import File
|
||||
from ..attachments.image import Image
|
||||
from ..attachments.video import Video
|
||||
from ..attachments.audio import Audio
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class MessageForCallback(BaseModel):
|
||||
text: Optional[str] = None
|
||||
attachments: Optional[
|
||||
List[
|
||||
Union[
|
||||
AttachmentButton,
|
||||
Audio,
|
||||
Video,
|
||||
File,
|
||||
Image,
|
||||
Sticker,
|
||||
Share
|
||||
]
|
||||
]
|
||||
] = []
|
||||
link: Optional[NewMessageLink] = None
|
||||
notify: Optional[bool] = True
|
||||
format: Optional[ParseMode] = None
|
||||
|
||||
|
||||
class MessageCallback(Update):
|
||||
message: Message
|
||||
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):
|
||||
return (self.message.recipient.chat_id, self.message.recipient.user_id)
|
||||
|
||||
async def answer(
|
||||
self,
|
||||
notification: str,
|
||||
new_text: str = None,
|
||||
link: NewMessageLink = None,
|
||||
notify: bool = True,
|
||||
format: ParseMode = None,
|
||||
):
|
||||
message = MessageForCallback()
|
||||
|
||||
message.text = new_text
|
||||
message.attachments = self.message.body.attachments
|
||||
message.link = link
|
||||
message.notify = notify
|
||||
message.format = format
|
||||
|
||||
return await self.bot.send_callback(
|
||||
callback_id=self.callback.callback_id,
|
||||
message=message,
|
||||
notification=notification
|
||||
)
|
@ -1,11 +1,24 @@
|
||||
from typing import Optional
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from ...types.chats import Chat
|
||||
|
||||
from . import Update
|
||||
from .update import Update
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class MessageChatCreated(Update):
|
||||
chat: Chat
|
||||
title: 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):
|
||||
return (self.chat_id, 0)
|
@ -1,9 +1,22 @@
|
||||
from typing import Optional
|
||||
from __future__ import annotations
|
||||
from typing import Any, Optional, TYPE_CHECKING, ForwardRef
|
||||
|
||||
from . import Update
|
||||
from pydantic import Field
|
||||
|
||||
from .update import Update
|
||||
from ...types.message import Message
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class MessageCreated(Update):
|
||||
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):
|
||||
return (self.message.recipient.chat_id, self.message.recipient.user_id)
|
@ -1,6 +1,19 @@
|
||||
from . import Update
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from pydantic import Field
|
||||
from .update import Update
|
||||
from ...types.message import Message
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class MessageEdited(Update):
|
||||
message: Message
|
||||
message: Message
|
||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
bot: Optional[Bot]
|
||||
|
||||
def get_ids(self):
|
||||
return (self.message.recipient.chat_id, self.message.recipient.user_id)
|
@ -1,9 +1,21 @@
|
||||
from typing import Optional
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from . import Update
|
||||
from pydantic import Field
|
||||
|
||||
from .update import Update
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class MessageRemoved(Update):
|
||||
message_id: Optional[str] = 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):
|
||||
return (self.chat_id, self.user_id)
|
11
maxapi/types/updates/update.py
Normal file
11
maxapi/types/updates/update.py
Normal file
@ -0,0 +1,11 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ...enums.update import UpdateType
|
||||
|
||||
|
||||
class Update(BaseModel):
|
||||
update_type: UpdateType
|
||||
timestamp: int
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed=True
|
@ -1,10 +1,23 @@
|
||||
from typing import Optional
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from . import Update
|
||||
from pydantic import Field
|
||||
|
||||
from .update import Update
|
||||
from ...types.users import User
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class UserAdded(Update):
|
||||
inviter_id: Optional[int] = None
|
||||
chat_id: Optional[int] = None
|
||||
user: User
|
||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
bot: Optional[Bot]
|
||||
|
||||
def get_ids(self):
|
||||
return (self.chat_id, self.inviter_id)
|
@ -1,10 +1,22 @@
|
||||
from typing import Optional
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from . import Update
|
||||
from pydantic import Field
|
||||
|
||||
from .update import Update
|
||||
from ...types.users import User
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...bot import Bot
|
||||
|
||||
|
||||
class UserRemoved(Update):
|
||||
admin_id: Optional[int] = None
|
||||
chat_id: Optional[int] = None
|
||||
user: User
|
||||
bot: Optional[Any] = Field(default=None, exclude=True)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
bot: Optional[Bot]
|
||||
|
||||
def get_ids(self):
|
||||
return (self.chat_id, self.admin_id)
|
@ -2,6 +2,8 @@ from pydantic import BaseModel
|
||||
from typing import List, Optional
|
||||
from datetime import datetime
|
||||
|
||||
from ..enums.chat_permission import ChatPermission
|
||||
|
||||
|
||||
class BotCommand(BaseModel):
|
||||
name: str
|
||||
@ -22,5 +24,10 @@ class User(BaseModel):
|
||||
|
||||
class Config:
|
||||
json_encoders = {
|
||||
datetime: lambda v: int(v.timestamp() * 1000) # Конвертация datetime в Unix-время (ms)
|
||||
}
|
||||
datetime: lambda v: int(v.timestamp() * 1000)
|
||||
}
|
||||
|
||||
|
||||
class ChatAdmin(BaseModel):
|
||||
user_id: int
|
||||
permissions: List[ChatPermission]
|
18
maxapi/utils/inline_keyboard.py
Normal file
18
maxapi/utils/inline_keyboard.py
Normal file
@ -0,0 +1,18 @@
|
||||
from ..enums.attachment import AttachmentType
|
||||
from ..types.attachments.attachment import Attachment, ButtonsPayload
|
||||
|
||||
|
||||
class InlineKeyboardBuilder:
|
||||
def __init__(self):
|
||||
self.payload = []
|
||||
|
||||
def row(self, *buttons):
|
||||
self.payload.append([*buttons])
|
||||
|
||||
def as_markup(self):
|
||||
return Attachment(
|
||||
type=AttachmentType.INLINE_KEYBOARD,
|
||||
payload=ButtonsPayload(
|
||||
buttons=self.payload
|
||||
)
|
||||
)
|
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@ -0,0 +1,5 @@
|
||||
aiohttp==3.11.16
|
||||
fastapi==0.115.13
|
||||
magic_filter==1.0.12
|
||||
pydantic==2.11.7
|
||||
uvicorn==0.34.3
|
Loading…
x
Reference in New Issue
Block a user