diff --git a/aiogram/bot/api.py b/aiogram/bot/api.py index 48904446..a9c6978a 100644 --- a/aiogram/bot/api.py +++ b/aiogram/bot/api.py @@ -238,6 +238,9 @@ class Methods(Helper): ANSWER_SHIPPING_QUERY = Item() # answerShippingQuery ANSWER_PRE_CHECKOUT_QUERY = Item() # answerPreCheckoutQuery + # Telegram Passport + SET_PASSPORT_DATA_ERRORS = Item() # setPassportDataErrors + # Games SEND_GAME = Item() # sendGame SET_GAME_SCORE = Item() # setGameScore diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index fefdef9f..868b7aa0 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -1759,6 +1759,38 @@ class Bot(BaseBot): # === Games === # https://core.telegram.org/bots/api#games + async def set_passport_data_errors(self, + user_id: base.Integer, + errors: typing.List[types.PassportElementError]) -> base.Boolean: + """ + Informs a user that some of the Telegram Passport elements they provided contains errors. + The user will not be able to re-submit their Passport to you until the errors are fixed + (the contents of the field for which you returned the error must change). + Returns True on success. + + Use this if the data submitted by the user doesn't satisfy the standards your service + requires for any reason. For example, if a birthday date seems invalid, a submitted document + is blurry, a scan shows evidence of tampering, etc. Supply some details in the error message + to make sure the user knows how to correct the issues. + + Source https://core.telegram.org/bots/api#setpassportdataerrors + + :param user_id: User identifier + :type user_id: :obj:`base.Integer` + :param errors: A JSON-serialized array describing the errors + :type errors: :obj:`typing.List[types.PassportElementError]` + :return: Returns True on success. + :rtype: :obj:`base.Boolean` + """ + errors = prepare_arg(errors) + payload = generate_payload(**locals()) + result = await self.request(api.Methods.SET_PASSPORT_DATA_ERRORS, payload) + + return result + + # === Games === + # https://core.telegram.org/bots/api#games + async def send_game(self, chat_id: base.Integer, game_short_name: base.String, disable_notification: typing.Union[base.Boolean, None] = None, reply_to_message_id: typing.Union[base.Integer, None] = None, diff --git a/aiogram/types/__init__.py b/aiogram/types/__init__.py index cc7abb11..08e3118c 100644 --- a/aiogram/types/__init__.py +++ b/aiogram/types/__init__.py @@ -11,6 +11,8 @@ from .chat_photo import ChatPhoto from .chosen_inline_result import ChosenInlineResult from .contact import Contact from .document import Document +from .encrypted_credentials import EncryptedCredentials +from .encrypted_passport_element import EncryptedPassportElement from .file import File from .force_reply import ForceReply from .game import Game @@ -34,6 +36,11 @@ from .mask_position import MaskPosition from .message import ContentType, Message, ParseMode from .message_entity import MessageEntity, MessageEntityType from .order_info import OrderInfo +from .passport_data import PassportData +from .passport_element_error import PassportElementError, PassportElementErrorDataField, PassportElementErrorFile, \ + PassportElementErrorFiles, PassportElementErrorFrontSide, PassportElementErrorReverseSide, \ + PassportElementErrorSelfie +from .passport_file import PassportFile from .photo_size import PhotoSize from .pre_checkout_query import PreCheckoutQuery from .reply_keyboard import KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove @@ -70,6 +77,8 @@ __all__ = ( 'Contact', 'ContentType', 'Document', + 'EncryptedCredentials', + 'EncryptedPassportElement', 'File', 'ForceReply', 'Game', @@ -116,6 +125,15 @@ __all__ = ( 'MessageEntity', 'MessageEntityType', 'OrderInfo', + 'PassportData', + 'PassportElementError', + 'PassportElementErrorDataField', + 'PassportElementErrorFile', + 'PassportElementErrorFiles', + 'PassportElementErrorFrontSide', + 'PassportElementErrorReverseSide', + 'PassportElementErrorSelfie', + 'PassportFile', 'ParseMode', 'PhotoSize', 'PreCheckoutQuery', diff --git a/aiogram/types/encrypted_credentials.py b/aiogram/types/encrypted_credentials.py new file mode 100644 index 00000000..d649c8d9 --- /dev/null +++ b/aiogram/types/encrypted_credentials.py @@ -0,0 +1,16 @@ +from . import base +from . import fields + + +class EncryptedCredentials(base.TelegramObject): + """ + Contains data required for decrypting and authenticating EncryptedPassportElement. + See the Telegram Passport Documentation for a complete description of the data decryption + and authentication processes. + + https://core.telegram.org/bots/api#encryptedcredentials + """ + + data: base.String = fields.Field() + hash: base.String = fields.Field() + secret: base.String = fields.Field() diff --git a/aiogram/types/encrypted_passport_element.py b/aiogram/types/encrypted_passport_element.py new file mode 100644 index 00000000..68630649 --- /dev/null +++ b/aiogram/types/encrypted_passport_element.py @@ -0,0 +1,21 @@ +from . import base +from . import fields +import typing +from .passport_file import PassportFile + + +class EncryptedPassportElement(base.TelegramObject): + """ + Contains information about documents or other Telegram Passport elements shared with the bot by the user. + + https://core.telegram.org/bots/api#encryptedpassportelement + """ + + encrypted_passport_element_type: base.String = fields.Field(alias="type") + data: base.String = fields.Field() + phone_number: base.String = fields.Field() + email: base.String = fields.Field() + files: typing.List[PassportFile] = fields.ListField(base=PassportFile) + front_side: PassportFile = fields.Field(base=PassportFile) + reverse_side: PassportFile = fields.Field(base=PassportFile) + selfie: PassportFile = fields.Field(base=PassportFile) diff --git a/aiogram/types/message.py b/aiogram/types/message.py index c107220a..ead27faa 100644 --- a/aiogram/types/message.py +++ b/aiogram/types/message.py @@ -14,6 +14,7 @@ from .game import Game from .invoice import Invoice from .location import Location from .message_entity import MessageEntity +from .passport_data import PassportData from .photo_size import PhotoSize from .sticker import Sticker from .successful_payment import SuccessfulPayment @@ -75,6 +76,7 @@ class Message(base.TelegramObject): invoice: Invoice = fields.Field(base=Invoice) successful_payment: SuccessfulPayment = fields.Field(base=SuccessfulPayment) connected_website: base.String = fields.Field() + passport_data: PassportData = fields.Field(base=PassportData) @property @functools.lru_cache() @@ -129,6 +131,8 @@ class Message(base.TelegramObject): return ContentType.DELETE_CHAT_PHOTO[0] elif self.group_chat_created: return ContentType.GROUP_CHAT_CREATED[0] + elif self.passport_data: + return ContentType.PASSPORT_DATA[0] else: return ContentType.UNKNOWN[0] @@ -774,6 +778,7 @@ class ContentType(helper.Helper): NEW_CHAT_PHOTO = helper.ListItem() # new_chat_photo DELETE_CHAT_PHOTO = helper.ListItem() # delete_chat_photo GROUP_CHAT_CREATED = helper.ListItem() # group_chat_created + PASSPORT_DATA = helper.ListItem() # passport_data UNKNOWN = helper.ListItem() # unknown ANY = helper.ListItem() # any diff --git a/aiogram/types/passport_data.py b/aiogram/types/passport_data.py new file mode 100644 index 00000000..06cbad1c --- /dev/null +++ b/aiogram/types/passport_data.py @@ -0,0 +1,16 @@ +from . import base +from . import fields +import typing +from .encrypted_passport_element import EncryptedPassportElement +from .encrypted_credentials import EncryptedCredentials + + +class PassportData(base.TelegramObject): + """ + Contains information about Telegram Passport data shared with the bot by the user. + + https://core.telegram.org/bots/api#passportdata + """ + + data: typing.List[EncryptedPassportElement] = fields.ListField(base=EncryptedPassportElement) + credentials: EncryptedCredentials = fields.Field(base=EncryptedCredentials) diff --git a/aiogram/types/passport_element_error.py b/aiogram/types/passport_element_error.py new file mode 100644 index 00000000..f673ba16 --- /dev/null +++ b/aiogram/types/passport_element_error.py @@ -0,0 +1,110 @@ +import typing + +from . import base +from . import fields + + +class PassportElementError(base.TelegramObject): + """ + This object represents an error in the Telegram Passport element which was submitted that + should be resolved by the user. + + https://core.telegram.org/bots/api#passportelementerror + """ + + source: base.String = fields.Field() + type: base.String = fields.Field() + message: base.String = fields.Field() + + +class PassportElementErrorDataField(PassportElementError): + """ + Represents an issue in one of the data fields that was provided by the user. + The error is considered resolved when the field's value changes. + + https://core.telegram.org/bots/api#passportelementerrordatafield + """ + + field_name: base.String = fields.Field() + data_hash: base.String = fields.Field() + + def __init__(self, source: base.String, type: base.String, field_name: base.String, + data_hash: base.String, message: base.String): + super(PassportElementErrorDataField, self).__init__(source=source, type=type, field_name=field_name, + data_hash=data_hash, message=message) + + +class PassportElementErrorFile(PassportElementError): + """ + Represents an issue with a document scan. + The error is considered resolved when the file with the document scan changes. + + https://core.telegram.org/bots/api#passportelementerrorfile + """ + + file_hash: base.String = fields.Field() + + def __init__(self, source: base.String, type: base.String, file_hash: base.String, message: base.String): + super(PassportElementErrorFile, self).__init__(source=source, type=type, file_hash=file_hash, + message=message) + + +class PassportElementErrorFiles(PassportElementError): + """ + Represents an issue with a list of scans. + The error is considered resolved when the list of files containing the scans changes. + + https://core.telegram.org/bots/api#passportelementerrorfiles + """ + + file_hashes: typing.List[base.String] = fields.ListField() + + def __init__(self, source: base.String, type: base.String, file_hashes: typing.List[base.String], + message: base.String): + super(PassportElementErrorFiles, self).__init__(source=source, type=type, file_hashes=file_hashes, + message=message) + + +class PassportElementErrorFrontSide(PassportElementError): + """ + Represents an issue with the front side of a document. + The error is considered resolved when the file with the front side of the document changes. + + https://core.telegram.org/bots/api#passportelementerrorfrontside + """ + + file_hash: base.String = fields.Field() + + def __init__(self, source: base.String, type: base.String, file_hash: base.String, message: base.String): + super(PassportElementErrorFrontSide, self).__init__(source=source, type=type, file_hash=file_hash, + message=message) + + +class PassportElementErrorReverseSide(PassportElementError): + """ + Represents an issue with the reverse side of a document. + The error is considered resolved when the file with reverse side of the document changes. + + https://core.telegram.org/bots/api#passportelementerrorreverseside + """ + + file_hash: base.String = fields.Field() + + def __init__(self, source: base.String, type: base.String, file_hash: base.String, message: base.String): + super(PassportElementErrorReverseSide, self).__init__(source=source, type=type, file_hash=file_hash, + message=message) + + +class PassportElementErrorSelfie(PassportElementError): + """ + Represents an issue with the selfie with a document. + The error is considered resolved when the file with the selfie changes. + + https://core.telegram.org/bots/api#passportelementerrorselfie + """ + + file_hash: base.String = fields.Field() + + def __init__(self, source: base.String, type: base.String, file_hash: base.String, message: base.String): + super(PassportElementErrorSelfie, self).__init__(source=source, type=type, file_hash=file_hash, + message=message) diff --git a/aiogram/types/passport_file.py b/aiogram/types/passport_file.py new file mode 100644 index 00000000..f00e80c7 --- /dev/null +++ b/aiogram/types/passport_file.py @@ -0,0 +1,15 @@ +from . import base +from . import fields + + +class PassportFile(base.TelegramObject): + """ + This object represents a file uploaded to Telegram Passport. + Currently all Telegram Passport files are in JPEG format when decrypted and don't exceed 10MB. + + https://core.telegram.org/bots/api#passportfile + """ + + file_id: base.String = fields.Field() + file_size: base.Integer = fields.Field() + file_date: base.Integer = fields.Field()