diff --git a/aiogram/bot/api.py b/aiogram/bot/api.py index 29edff20..879415f9 100644 --- a/aiogram/bot/api.py +++ b/aiogram/bot/api.py @@ -116,6 +116,15 @@ class Methods: GET_CHAT_ADMINISTRATORS = 'getChatAdministrators' GET_CHAT_MEMBERS_COUNT = 'getChatMembersCount' GET_CHAT_MEMBER = 'getChatMember' + RESTRICT_CHAT_MEMBER = 'restrictChatMember' + PROMOTE_CHAT_MEMBER = 'promoteChatMember' + EXPORT_CHAT_INVITE_LINK = 'exportChatInviteLink' + SET_CHAT_PHOTO = 'setChatPhoto' + DELETE_CHAT_PHOTO = 'deleteChatPhoto' + SET_CHAT_TITLE = 'setChatTitle' + SET_CHAT_DESCRIPTION = 'setChatDescription' + PIN_CHAT_MESSAGE = 'pinChatMessage' + UNPIN_CHAT_MESSAGE = 'unpinChatMessage' ANSWER_CALLBACK_QUERY = 'answerCallbackQuery' ANSWER_INLINE_QUERY = 'answerInlineQuery' EDIT_MESSAGE_TEXT = 'editMessageText' diff --git a/aiogram/bot/base.py b/aiogram/bot/base.py index c957bf44..599e77a8 100644 --- a/aiogram/bot/base.py +++ b/aiogram/bot/base.py @@ -119,7 +119,7 @@ class BaseBot: 'sticker': api.Methods.SEND_STICKER, 'video': api.Methods.SEND_VIDEO, 'voice': api.Methods.SEND_VOICE, - 'video_note': api.Methods.SEND_VIDEO_NOTE + 'video_note': api.Methods.SEND_VIDEO_NOTE, } method = methods[file_type] @@ -274,10 +274,70 @@ class BaseBot: payload = generate_payload(**locals()) return await self.request(api.Methods.GET_FILE, payload) - async def kick_chat_user(self, chat_id, user_id) -> bool: + async def kick_chat_member(self, chat_id, user_id) -> bool: payload = generate_payload(**locals()) return await self.request(api.Methods.KICK_CHAT_MEMBER, payload) + async def promote_chat_member(self, chat_id: int, user_id: int, can_change_info: bool, can_post_messages: bool, + can_edit_messages: bool, can_delete_messages: bool, can_invite_users: bool, + can_restrict_members: bool, can_pin_messages: bool, + can_promote_members: bool) -> bool: + payload = generate_payload(**locals()) + + return await self.request(api.Methods.PROMOTE_CHAT_MEMBER, payload) + + async def restrict_chat_member(self, chat_id: int, user_id: int, until_date: int, can_send_messages: bool, + can_send_media_messages: bool, can_send_other_messages: bool, + can_add_web_page_previews: bool) -> bool: + payload = generate_payload(**locals()) + + return await self.request(api.Methods.RESTRICT_CHAT_MEMBER, payload) + + async def export_chat_invite_link(self, chat_id: int) -> str: + payload = generate_payload(**locals()) + + return await self.request(api.Methods.EXPORT_CHAT_INVITE_LINK, payload) + + async def set_chat_photo(self, chat_id: int, photo) -> bool: + payload = generate_payload(**locals(), exclude=['photo']) + + if isinstance(photo, str): + payload['photo'] = photo + req = self.request(api.Methods.SET_CHAT_PHOTO, payload) + elif isinstance(photo, io.IOBase): + data = {'photo': photo.read()} + req = self.request(api.Methods.SET_CHAT_PHOTO, payload, data) + else: + data = {'photo': photo} + req = self.request(api.Methods.SET_CHAT_PHOTO, payload, data) + + return await req + + async def delete_chat_photo(self, chat_id: int) -> bool: + payload = generate_payload(**locals()) + + return await self.request(api.Methods.DELETE_CHAT_PHOTO, payload) + + async def set_chat_title(self, chat_id: int, title: str) -> bool: + payload = generate_payload(**locals()) + + return await self.request(api.Methods.SET_CHAT_TITLE, payload) + + async def set_chat_description(self, chat_id: int, description: str) -> bool: + payload = generate_payload(**locals()) + + return await self.request(api.Methods.SET_CHAT_DESCRIPTION, payload) + + async def pin_chat_message(self, chat_id: int, message_id: int, disable_notification: bool) -> bool: + payload = generate_payload(**locals()) + + return await self.request(api.Methods.PIN_CHAT_MESSAGE, payload) + + async def unpin_chat_message(self, chat_id: int) -> bool: + payload = generate_payload(**locals()) + + return await self.request(api.Methods.UNPIN_CHAT_MESSAGE, payload) + async def unban_chat_member(self, chat_id, user_id) -> bool: payload = generate_payload(**locals()) return await self.request(api.Methods.UNBAN_CHAT_MEMBER, payload) @@ -407,4 +467,4 @@ class BaseBot: inline_message_id: str = None) -> dict: payload = generate_payload(**locals()) - return await self.request(api.Methods.GET_GAME_HIGH_SCORES, payload) \ No newline at end of file + return await self.request(api.Methods.GET_GAME_HIGH_SCORES, payload) diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index fe4b84ae..ffec10f4 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -1,7 +1,9 @@ +import datetime import json +import time -from .. import types from .base import BaseBot +from .. import types class Bot(BaseBot): @@ -431,7 +433,7 @@ class Bot(BaseBot): file = await super(Bot, self).get_file(file_id) return self.prepare_object(types.File.de_json(file)) - async def kick_chat_user(self, chat_id, user_id) -> bool: + async def kick_chat_member(self, chat_id, user_id) -> bool: """ Use this method to kick a user from a group or a supergroup. In the case of supergroups, the user will not be able to return to the group on their own using invite links, etc., @@ -441,7 +443,133 @@ class Bot(BaseBot): :param user_id: int :return: bool """ - return await super(Bot, self).kick_chat_user(chat_id, user_id) + return await super(Bot, self).kick_chat_member(chat_id, user_id) + + async def promote_chat_member(self, chat_id: int, user_id: int, can_change_info: bool, can_post_messages: bool, + can_edit_messages: bool, can_delete_messages: bool, can_invite_users: bool, + can_restrict_members: bool, can_pin_messages: bool, + can_promote_members: bool) -> bool: + """ + Use this method to promote or demote a user in a supergroup or a channel. + The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + Pass False for all boolean parameters to demote a user. + + :param chat_id: int + :param user_id: int + :param can_change_info: bool + :param can_post_messages: bool + :param can_edit_messages: bool + :param can_delete_messages: bool + :param can_invite_users: bool + :param can_restrict_members: bool + :param can_pin_messages: bool + :param can_promote_members: bool + :return: bool + """ + return await super(Bot, self).promote_chat_member(chat_id, user_id, can_change_info, can_post_messages, + can_edit_messages, can_delete_messages, can_invite_users, + can_restrict_members, can_pin_messages, can_promote_members) + + async def restrict_chat_member(self, chat_id: int, user_id: int, until_date: int, can_send_messages: bool, + can_send_media_messages: bool, can_send_other_messages: bool, + can_add_web_page_previews: bool) -> bool: + """ + Use this method to restrict a user in a supergroup. + The bot must be an administrator in the supergroup for this to work and must have the appropriate admin rights. + Pass True for all boolean parameters to lift restrictions from a user. + + :param chat_id: int + :param user_id: int + :param until_date: int + :param can_send_messages: bool + :param can_send_media_messages: bool + :param can_send_other_messages: bool + :param can_add_web_page_previews: bool + :return: bool + """ + if isinstance(until_date, datetime.datetime): + until_date = int(time.mktime(until_date.timetuple())) + return await super(Bot, self).restrict_chat_member(chat_id, user_id, until_date, can_send_messages, + can_send_media_messages, can_send_other_messages, + can_add_web_page_previews) + + async def export_chat_invite_link(self, chat_id: int) -> str: + """ + Use this method to export an invite link to a supergroup or a channel. + The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + + :param chat_id: int + :return: + """ + return await super(Bot, self).export_chat_invite_link(chat_id) + + async def set_chat_photo(self, chat_id: int, photo) -> bool: + """ + Use this method to set a new profile photo for the chat. + Photos can't be changed for private chats. + The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + + :param chat_id: int + :param photo: file or str + :return: bool + """ + return await super(Bot, self).set_chat_photo(chat_id, photo) + + async def delete_chat_photo(self, chat_id: int) -> bool: + """ + Use this method to delete a chat photo. + Photos can't be changed for private chats. + The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + + :param chat_id: int + :return: bool + """ + return await super(Bot, self).delete_chat_photo(chat_id) + + async def set_chat_title(self, chat_id: int, title: str) -> bool: + """ + Use this method to change the title of a chat. + Titles can't be changed for private chats. + The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + + :param chat_id: int + :param title: str + :return: bool + """ + return await super(Bot, self).set_chat_title(chat_id, title) + + async def set_chat_description(self, chat_id: int, description: str) -> bool: + """ + Use this method to change the description of a supergroup or a channel. + The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + + :param chat_id: int + :param description: str + :return: bool + """ + return await super(Bot, self).set_chat_description(chat_id, description) + + async def pin_chat_message(self, chat_id: int, message_id: int, disable_notification: bool) -> bool: + """ + Use this method to pin a message in a supergroup. + The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + + :param chat_id: int + :param message_id: int + :param disable_notification: bool + :return: bool + """ + return await super(Bot, self).pin_chat_message(chat_id, message_id, disable_notification) + + async def unpin_chat_message(self, chat_id: int) -> bool: + """ + Use this method to unpin a message in a supergroup chat. + The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. + + :param chat_id: int + :return: bool + """ + return await super(Bot, self).unpin_chat_message(chat_id) async def unban_chat_member(self, chat_id, user_id) -> bool: """ diff --git a/aiogram/types/__init__.py b/aiogram/types/__init__.py index 52ad44fe..67af8891 100644 --- a/aiogram/types/__init__.py +++ b/aiogram/types/__init__.py @@ -3,6 +3,7 @@ from .audio import Audio from .callback_query import CallbackQuery from .chat import Chat, ChatType, ChatActions from .chat_member import ChatMember, ChatMemberStatus +from .chat_photo import ChatPhoto from .chosen_inline_result import ChosenInlineResult from .contact import Contact from .document import Document @@ -52,6 +53,7 @@ __all__ = [ 'ChatActions', 'ChatMember', 'ChatMemberStatus', + 'ChatPhoto', 'ChatType', 'ChosenInlineResult', 'Contact', diff --git a/aiogram/types/chat.py b/aiogram/types/chat.py index 52040cc1..55632167 100644 --- a/aiogram/types/chat.py +++ b/aiogram/types/chat.py @@ -1,3 +1,4 @@ +from . import ChatPhoto from .base import Deserializable @@ -8,7 +9,8 @@ class Chat(Deserializable): https://core.telegram.org/bots/api#chat """ - def __init__(self, id, type, title, username, first_name, last_name, all_members_are_administrators): + def __init__(self, id, type, title, username, first_name, last_name, all_members_are_administrators, photo, + description, invite_link): self.id: int = id self.type: str = type self.title: str = title @@ -16,6 +18,9 @@ class Chat(Deserializable): self.first_name: str = first_name self.last_name: str = last_name self.all_members_are_administrators: bool = all_members_are_administrators + self.photo: ChatPhoto = photo + self.description: str = description + self.invite_link: str = invite_link @classmethod def de_json(cls, raw_data) -> 'Chat': @@ -28,8 +33,12 @@ class Chat(Deserializable): first_name: str = raw_data.get('first_name') last_name: str = raw_data.get('last_name') all_members_are_administrators: bool = raw_data.get('all_members_are_administrators', False) + photo = raw_data.get('photo') + description = raw_data.get('description') + invite_link = raw_data.get('invite_link') - return Chat(id, type, title, username, first_name, last_name, all_members_are_administrators) + return Chat(id, type, title, username, first_name, last_name, all_members_are_administrators, photo, + description, invite_link) @property def full_name(self): diff --git a/aiogram/types/chat_member.py b/aiogram/types/chat_member.py index c61dd1fb..189aaa8b 100644 --- a/aiogram/types/chat_member.py +++ b/aiogram/types/chat_member.py @@ -1,3 +1,5 @@ +import datetime + from .base import Deserializable from .user import User @@ -8,10 +10,34 @@ class ChatMember(Deserializable): https://core.telegram.org/bots/api#chatmember """ - def __init__(self, user, status): + + def __init__(self, user, status, until_date, can_be_edited, can_change_info, can_post_messages, + can_edit_messages, can_delete_messages, can_invite_users, can_restrict_members, + can_pin_messages, can_promote_members, can_send_messages, can_send_media_messages, + can_send_other_messages, can_add_web_page_previews + ): self.user: User = user self.status: str = status + self.until_date: datetime.datetime = until_date + self.can_be_edited: bool = can_be_edited + self.can_change_info: bool = can_change_info + self.can_post_messages: bool = can_post_messages + self.can_edit_messages: bool = can_edit_messages + self.can_delete_messages: bool = can_delete_messages + self.can_invite_users: bool = can_invite_users + self.can_restrict_members: bool = can_restrict_members + self.can_pin_messages: bool = can_pin_messages + self.can_promote_members: bool = can_promote_members + self.can_send_messages: bool = can_send_messages + self.can_send_media_messages: bool = can_send_media_messages + self.can_send_other_messages: bool = can_send_other_messages + self.can_add_web_page_previews: bool = can_add_web_page_previews + + @classmethod + def _parse_date(cls, unix_time): + return datetime.datetime.fromtimestamp(unix_time) + @classmethod def de_json(cls, raw_data): raw_data = cls.check_json(raw_data) @@ -19,7 +45,26 @@ class ChatMember(Deserializable): user = User.deserialize(raw_data.get('user')) status = raw_data.get('status') - return ChatMember(user, status) + until_date = cls._parse_date(raw_data.get('until_date')) + can_be_edited = raw_data.get('can_be_edited') + can_change_info = raw_data.get('can_change_info') + can_post_messages = raw_data.get('can_post_messages') + can_edit_messages = raw_data.get('can_edit_messages') + can_delete_messages = raw_data.get('can_delete_messages') + can_invite_users = raw_data.get('can_invite_users') + can_restrict_members = raw_data.get('can_restrict_members') + can_pin_messages = raw_data.get('can_pin_messages') + can_promote_members = raw_data.get('can_promote_members') + can_send_messages = raw_data.get('can_send_messages') + can_send_media_messages = raw_data.get('can_send_media_messages') + can_send_other_messages = raw_data.get('can_send_other_messages') + can_add_web_page_previews = raw_data.get('can_add_web_page_previews') + + return ChatMember(user, status, until_date, can_be_edited, can_change_info, can_post_messages, + can_edit_messages, can_delete_messages, can_invite_users, can_restrict_members, + can_pin_messages, can_promote_members, can_send_messages, can_send_media_messages, + can_send_other_messages, can_add_web_page_previews + ) class ChatMemberStatus: diff --git a/aiogram/types/chat_photo.py b/aiogram/types/chat_photo.py new file mode 100644 index 00000000..4ea30a15 --- /dev/null +++ b/aiogram/types/chat_photo.py @@ -0,0 +1,22 @@ +from .base import Deserializable + + +class ChatPhoto(Deserializable): + """ + This object represents a chat photo. + + https://core.telegram.org/bots/api#chatphoto + """ + + def __init__(self, small_file_id, big_file_id): + self.small_file_id: str = small_file_id + self.big_file_id: str = big_file_id + + @classmethod + def de_json(cls, raw_data): + raw_data = cls.check_json(raw_data) + + small_file_id = raw_data.get('small_file_id') + big_file_id = raw_data.get('big_file_id') + + return ChatPhoto(small_file_id, big_file_id)