diff --git a/README.md b/README.md index b3492b3..48b6e1c 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ * [The listener mechanism](#the-listener-mechanism) * [Using web hooks](#using-web-hooks) * [Logging](#logging) + * [Proxy](#proxy) * [F.A.Q.](#faq) * [Bot 2.0](#bot-20) * [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat) @@ -125,6 +126,10 @@ All types are defined in types.py. They are all completely in line with the [Tel The Message object also has a `content_type`attribute, which defines the type of the Message. `content_type` can be one of the following strings: `text`, `audio`, `document`, `photo`, `sticker`, `video`, `video_note`, `voice`, `location`, `contact`, `new_chat_member`, `left_chat_member`, `new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`, `supergroup_chat_created`, `channel_chat_created`, `migrate_to_chat_id`, `migrate_from_chat_id`, `pinned_message`. +You can use some types in one function. Example: + +```content_types=["text", "sticker", "pinned_message", "photo", "audio"]``` + ### Methods All [API methods](https://core.telegram.org/bots/api#available-methods) are located in the TeleBot class. They are renamed to follow common Python naming conventions. E.g. `getMe` is renamed to `get_me` and `sendMessage` to `send_message`. @@ -488,6 +493,26 @@ logger = telebot.logger telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console. ``` +### Proxy + +You can use proxy for request. `apihelper.proxy` object will use by call `requests` proxies argument. + +```python +from telebot import apihelper + +apihelper.proxy = {'http', 'http://10.10.1.10:3128'} +``` + +If you want to use socket5 proxy you need install dependency `pip install requests[socks]`. + +```python +proxies = { + 'http': 'socks5://user:pass@host:port', + 'https': 'socks5://user:pass@host:port' +} +``` + + ## F.A.Q. ### Bot 2.0 diff --git a/examples/download_file_example.py b/examples/download_file_example.py index d9003d1..157cdc7 100644 --- a/examples/download_file_example.py +++ b/examples/download_file_example.py @@ -5,7 +5,7 @@ CHAT_ID = 'YOUR CHAT ID' bot = telebot.TeleBot(TOKEN) -ret_msg = bot.send_voice(CHAT_ID, open('tests/test_data/record.ogg')) +ret_msg = bot.send_voice(CHAT_ID, open('tests/test_data/record.ogg', 'rb')) file_info = bot.get_file(ret_msg.voice.file_id) diff --git a/setup.py b/setup.py index cad62e0..4d1dc2a 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ def readme(): return f.read() setup(name='pyTelegramBotAPI', - version='3.0.1', + version='3.1.1', description='Python Telegram bot api. ', long_description=readme(), author='eternnoir', diff --git a/telebot/__init__.py b/telebot/__init__.py index 8059e63..6356b80 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -44,7 +44,26 @@ class TeleBot: sendChatAction getUserProfilePhotos getUpdates - """ + getFile + kickChatMember + unbanChatMember + restrictChatMember + promoteChatMember + exportChatInviteLink + setChatPhoto + deleteChatPhoto + setChatTitle + setChatDescription + pinChatMessage + unpinChatMessage + leaveChat + getChat + getChatAdministrators + getChatMembersCount + getChatMember + answerCallbackQuery + answerInlineQuery + """ def __init__(self, token, threaded=True, skip_pending=False, num_threads=2): """ @@ -601,18 +620,162 @@ class TeleBot: """ return apihelper.send_chat_action(self.token, chat_id, action) - def kick_chat_member(self, chat_id, user_id): + def kick_chat_member(self, chat_id, user_id, until_date=None): """ Use this method to kick a user from a group or a supergroup. :param chat_id: Int or string : Unique identifier for the target group or username of the target supergroup :param user_id: Int : Unique identifier of the target user + :param until_date: Date when the user will be unbanned, unix time. If user is banned for more than 366 days or + less than 30 seconds from the current time they are considered to be banned forever :return: types.Message """ - return apihelper.kick_chat_member(self.token, chat_id, user_id) + return apihelper.kick_chat_member(self.token, chat_id, user_id, until_date) def unban_chat_member(self, chat_id, user_id): return apihelper.unban_chat_member(self.token, chat_id, user_id) + def restrict_chat_member(self, chat_id, user_id, until_date=None, can_send_messages=None, + can_send_media_messages=None, can_send_other_messages=None, + can_add_web_page_previews=None): + """ + 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. + Returns True on success. + :param chat_id: Int or String : Unique identifier for the target group or username of the target supergroup + or channel (in the format @channelusername) + :param user_id: Int : Unique identifier of the target user + :param until_date: Date when restrictions will be lifted for the user, unix time. + If user is restricted for more than 366 days or less than 30 seconds from the current time, + they are considered to be restricted forever + :param can_send_messages: Pass True, if the user can send text messages, contacts, locations and venues + :param can_send_media_messages Pass True, if the user can send audios, documents, photos, videos, video notes + and voice notes, implies can_send_messages + :param can_send_other_messages: Pass True, if the user can send animations, games, stickers and + use inline bots, implies can_send_media_messages + :param can_add_web_page_previews: Pass True, if the user may add web page previews to their messages, + implies can_send_media_messages + :return: types.Message + """ + return apihelper.restrict_chat_member(self.token, chat_id, user_id, until_date, can_send_messages, + can_send_media_messages, can_send_other_messages, + can_add_web_page_previews) + + def promote_chat_member(self, chat_id, user_id, can_change_info=None, can_post_messages=None, + can_edit_messages=None, can_delete_messages=None, can_invite_users=None, + can_restrict_members=None, can_pin_messages=None, can_promote_members=None): + """ + 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. Returns True on success. + :param chat_id: Unique identifier for the target chat or username of the target channel ( + in the format @channelusername) + :param user_id: Int : Unique identifier of the target user + :param can_change_info: Bool: Pass True, if the administrator can change chat title, photo and other settings + :param can_post_messages: Bool : Pass True, if the administrator can create channel posts, channels only + :param can_edit_messages: Bool : Pass True, if the administrator can edit messages of other users, channels only + :param can_delete_messages: Bool : Pass True, if the administrator can delete messages of other users + :param can_invite_users: Bool : Pass True, if the administrator can invite new users to the chat + :param can_restrict_members: Bool: Pass True, if the administrator can restrict, ban or unban chat members + :param can_pin_messages: Bool: Pass True, if the administrator can pin messages, supergroups only + :param can_promote_members: Bool: Pass True, if the administrator can add new administrators with a subset + of his own privileges or demote administrators that he has promoted, directly or indirectly + (promoted by administrators that were appointed by him) + :return: + """ + return apihelper.promote_chat_member(self.token, 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) + + def export_chat_invite_link(self, chat_id): + """ + 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. + Returns exported invite link as String on success. + :param chat_id: Id: Unique identifier for the target chat or username of the target channel + (in the format @channelusername) + :return: + """ + return apihelper.export_chat_invite_link(self.token, chat_id) + + def set_chat_photo(self, chat_id, photo): + """ + 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. + Returns True on success. + Note: In regular groups (non-supergroups), this method will only work if the ‘All Members Are Admins’ + setting is off in the target group. + :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel + (in the format @channelusername) + :param photo: InputFile: New chat photo, uploaded using multipart/form-data + :return: + """ + return apihelper.set_chat_photo(self.token, chat_id, photo) + + def delete_chat_photo(self, chat_id): + """ + 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. + Returns True on success. + Note: In regular groups (non-supergroups), this method will only work if the ‘All Members Are Admins’ + setting is off in the target group. + :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel + (in the format @channelusername) + :return: + """ + return apihelper.delete_chat_photo(self.token, chat_id) + + def set_chat_title(self, chat_id, title): + """ + 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. + Returns True on success. + Note: In regular groups (non-supergroups), this method will only work if the ‘All Members Are Admins’ + setting is off in the target group. + :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel + (in the format @channelusername) + :param title: New chat title, 1-255 characters + :return: + """ + return apihelper.set_chat_title(self.token, chat_id, title) + + def set_chat_description(self, chat_id, description): + """ + 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. + Returns True on success. + :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel + (in the format @channelusername) + :param description: Str: New chat description, 0-255 characters + :return: + """ + return apihelper.set_chat_description(self.token, chat_id, description) + + def pin_chat_message(self, chat_id, message_id, disable_notification=False): + """ + 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. + Returns True on success. + :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel + (in the format @channelusername) + :param message_id: Int: Identifier of a message to pin + :param disable_notification: Bool: Pass True, if it is not necessary to send a notification + to all group members about the new pinned message + :return: + """ + return apihelper.pin_chat_message(self.token, chat_id, message_id, disable_notification) + + def unpin_chat_message(self, chat_id): + """ + 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. + Returns True on success. + :param chat_id: Int or Str: Unique identifier for the target chat or username of the target channel + (in the format @channelusername) + :return: + """ + return apihelper.unpin_chat_message(self.token, chat_id) + def edit_message_text(self, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None, disable_web_page_preview=None, reply_markup=None): result = apihelper.edit_message_text(self.token, text, chat_id, message_id, inline_message_id, parse_mode, diff --git a/telebot/apihelper.py b/telebot/apihelper.py index b5372cd..e554730 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -1,5 +1,10 @@ # -*- coding: utf-8 -*- +try: + import ujson as json +except ImportError: + import json + import requests try: @@ -14,6 +19,7 @@ from telebot import util logger = telebot.logger req_session = requests.session() +proxy = None API_URL = "https://api.telegram.org/bot{0}/{1}" FILE_URL = "https://api.telegram.org/file/bot{0}/{1}" @@ -42,7 +48,7 @@ def _make_request(token, method_name, method='get', params=None, files=None, bas if 'timeout' in params: read_timeout = params['timeout'] + 10 if 'connect-timeout' in params: connect_timeout = params['connect-timeout'] + 10 result = req_session.request(method, request_url, params=params, files=files, - timeout=(connect_timeout, read_timeout)) + timeout=(connect_timeout, read_timeout), proxies=proxy) logger.debug("The server returned: '{0}'".format(result.text.encode('utf8'))) return _check_result(method_name, result)['result'] @@ -137,7 +143,7 @@ def set_webhook(token, url=None, certificate=None, max_connections=None, allowed if max_connections: payload['max_connections'] = max_connections if allowed_updates: - payload['allowed_updates'] = allowed_updates + payload['allowed_updates'] = json.dumps(allowed_updates) return _make_request(token, method_url, params=payload, files=files) @@ -162,7 +168,7 @@ def get_updates(token, offset=None, limit=None, timeout=None, allowed_updates=No if timeout: payload['timeout'] = timeout if allowed_updates: - payload['allowed_updates'] = allowed_updates + payload['allowed_updates'] = json.dumps(allowed_updates) return _make_request(token, method_url, params=payload) @@ -414,9 +420,11 @@ def get_method_by_type(data_type): return r'sendSticker' -def kick_chat_member(token, chat_id, user_id): +def kick_chat_member(token, chat_id, user_id, until_date=None): method_url = 'kickChatMember' payload = {'chat_id': chat_id, 'user_id': user_id} + if until_date: + payload['until_date'] = until_date return _make_request(token, method_url, params=payload, method='post') @@ -426,6 +434,96 @@ def unban_chat_member(token, chat_id, user_id): return _make_request(token, method_url, params=payload, method='post') +def restrict_chat_member(token, chat_id, user_id, until_date=None, can_send_messages=None, + can_send_media_messages=None, can_send_other_messages=None, + can_add_web_page_previews=None): + method_url = 'restrictChatMember' + payload = {'chat_id': chat_id, 'user_id': user_id} + if until_date: + payload['until_date'] = until_date + if can_send_messages: + payload['can_send_messages'] = can_send_messages + if can_send_media_messages: + payload['can_send_media_messages'] = can_send_media_messages + if can_send_other_messages: + payload['can_send_other_messages'] = can_send_other_messages + if can_add_web_page_previews: + payload['can_add_web_page_previews'] = can_add_web_page_previews + + return _make_request(token, method_url, params=payload, method='post') + + +def promote_chat_member(token, chat_id, user_id, can_change_info=None, can_post_messages=None, + can_edit_messages=None, can_delete_messages=None, can_invite_users=None, + can_restrict_members=None, can_pin_messages=None, can_promote_members=None): + method_url = 'promoteChatMember' + payload = {'chat_id': chat_id, 'user_id': user_id} + if can_change_info: + payload['can_change_info'] = can_change_info + if can_post_messages: + payload['can_post_messages'] = can_post_messages + if can_edit_messages: + payload['can_edit_messages'] = can_edit_messages + if can_delete_messages: + payload['can_delete_messages'] = can_delete_messages + if can_invite_users: + payload['can_invite_users'] = can_invite_users + if can_restrict_members: + payload['can_restrict_members'] = can_restrict_members + if can_pin_messages: + payload['can_pin_messages'] = can_pin_messages + if can_promote_members: + payload['can_promote_members'] = can_promote_members + return _make_request(token, method_url, params=payload, method='post') + + +def export_chat_invite_link(token, chat_id): + method_url = 'exportChatInviteLink' + payload = {'chat_id': chat_id} + return _make_request(token, method_url, params=payload, method='post') + + +def set_chat_photo(token, chat_id, photo): + method_url = 'setChatPhoto' + payload = {'chat_id': chat_id} + files = None + if not util.is_string(photo): + files = {'photo': photo} + else: + payload['photo'] = photo + return _make_request(token, method_url, params=payload, files=files, method='post') + + +def delete_chat_photo(token, chat_id): + method_url = 'deleteChatPhoto' + payload = {'chat_id': chat_id} + return _make_request(token, method_url, params=payload, method='post') + + +def set_chat_title(token, chat_id, title): + method_url = 'setChatTitle' + payload = {'chat_id': chat_id, 'title': title} + return _make_request(token, method_url, params=payload, method='post') + + +def set_chat_description(token, chat_id, description): + method_url = 'setChatDescription' + payload = {'chat_id': chat_id, 'description': description} + return _make_request(token, method_url, params=payload, method='post') + + +def pin_chat_message(token, chat_id, message_id, disable_notification=False): + method_url = 'pinChatMessage' + payload = {'chat_id': chat_id, 'message_id': message_id, 'disable_notification': disable_notification} + return _make_request(token, method_url, params=payload, method='post') + + +def unpin_chat_message(token, chat_id): + method_url = 'unpinChatMessage' + payload = {'chat_id': chat_id} + return _make_request(token, method_url, params=payload, method='post') + + # Updating messages def edit_message_text(token, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None, diff --git a/telebot/types.py b/telebot/types.py index 5d84b20..6912db3 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -215,10 +215,16 @@ class Chat(JsonDeserializable): first_name = obj.get('first_name') last_name = obj.get('last_name') all_members_are_administrators = obj.get('all_members_are_administrators') - return cls(id, type, title, username, first_name, last_name, all_members_are_administrators) + photo = None + if 'photo' in obj: + photo = ChatPhoto.de_json(obj['photo']) + description = obj.get('description') + invite_link = obj.get('invite_link') + return cls(id, type, title, username, first_name, last_name, all_members_are_administrators, + photo, description, invite_link) def __init__(self, id, type, title=None, username=None, first_name=None, last_name=None, - all_members_are_administrators=None): + all_members_are_administrators=None, photo=None, description=None, invite_link=None): self.type = type self.last_name = last_name self.first_name = first_name @@ -226,6 +232,9 @@ class Chat(JsonDeserializable): self.id = id self.title = title self.all_members_are_administrators = all_members_are_administrators + self.photo = photo + self.description = description + self.invite_link = invite_link class Message(JsonDeserializable): @@ -296,7 +305,11 @@ class Message(JsonDeserializable): opts['new_chat_member'] = User.de_json(obj['new_chat_member']) content_type = 'new_chat_member' if 'new_chat_members' in obj: - opts['new_chat_members'] = obj['new_chat_members'] + chat_members = obj['new_chat_members'] + nms = [] + for m in chat_members: + nms.append(User.de_json(m)) + opts['new_chat_members'] = nms content_type = 'new_chat_members' if 'left_chat_member' in obj: opts['left_chat_member'] = User.de_json(obj['left_chat_member']) @@ -373,6 +386,7 @@ class Message(JsonDeserializable): self.location = None self.venue = None self.new_chat_member = None + self.new_chat_members = None self.left_chat_member = None self.new_chat_title = None self.new_chat_photo = None @@ -850,18 +864,62 @@ class CallbackQuery(JsonDeserializable): self.inline_message_id = inline_message_id +class ChatPhoto(JsonDeserializable): + @classmethod + def de_json(cls, json_type): + obj = cls.check_json(json_type) + small_file_id = obj['small_file_id'] + big_file_id = obj['big_file_id'] + return cls(small_file_id, big_file_id) + + def __init__(self, small_file_id, big_file_id): + self.small_file_id = small_file_id + self.big_file_id = big_file_id + + class ChatMember(JsonDeserializable): @classmethod def de_json(cls, json_type): obj = cls.check_json(json_type) user = User.de_json(obj['user']) status = obj['status'] - return cls(user, status) + until_date = obj.get('until_date') + can_be_edited = obj.get('can_be_edited') + can_change_info = obj.get('can_change_info') + can_post_messages = obj.get('can_post_messages') + can_edit_messages = obj.get('can_edit_messages') + can_delete_messages = obj.get('can_delete_messages') + can_invite_users = obj.get('can_invite_users') + can_restrict_members = obj.get('can_restrict_members') + can_pin_messages = obj.get('can_pin_messages') + can_promote_members = obj.get('can_promote_members') + can_send_messages = obj.get('can_send_messages') + can_send_media_messages = obj.get('can_send_media_messages') + can_send_other_messages = obj.get('can_send_other_messages') + can_add_web_page_previews = obj.get('can_add_web_page_previews') + return cls(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) - 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 self.status = status - + self.until_date = until_date + self.can_be_edited = can_be_edited + self.can_change_info = can_change_info + self.can_post_messages = can_post_messages + self.can_edit_messages = can_edit_messages + self.can_delete_messages = can_delete_messages + self.can_invite_users = can_invite_users + self.can_restrict_members = can_restrict_members + self.can_pin_messages = can_pin_messages + self.can_promote_members = can_promote_members + self.can_send_messages = can_send_messages + self.can_send_media_messages = can_send_media_messages + self.can_send_other_messages = can_send_other_messages + self.can_add_web_page_previews = can_add_web_page_previews # InlineQuery