mirror of
https://github.com/aiogram/aiogram.git
synced 2025-12-08 17:13:56 +00:00
Merge branch 'master' into dev-2.x
# Conflicts: # aiogram/__init__.py # aiogram/utils/json.py
This commit is contained in:
commit
272cf155f2
21 changed files with 623 additions and 14 deletions
|
|
@ -236,6 +236,7 @@ class Methods(Helper):
|
|||
SEND_AUDIO = Item() # sendAudio
|
||||
SEND_DOCUMENT = Item() # sendDocument
|
||||
SEND_VIDEO = Item() # sendVideo
|
||||
SEND_ANIMATION = Item() # sendAnimation
|
||||
SEND_VOICE = Item() # sendVoice
|
||||
SEND_VIDEO_NOTE = Item() # sendVideoNote
|
||||
SEND_MEDIA_GROUP = Item() # sendMediaGroup
|
||||
|
|
@ -270,6 +271,7 @@ class Methods(Helper):
|
|||
# Updating messages
|
||||
EDIT_MESSAGE_TEXT = Item() # editMessageText
|
||||
EDIT_MESSAGE_CAPTION = Item() # editMessageCaption
|
||||
EDIT_MESSAGE_MEDIA = Item() # editMessageMedia
|
||||
EDIT_MESSAGE_REPLY_MARKUP = Item() # editMessageReplyMarkup
|
||||
DELETE_MESSAGE = Item() # deleteMessage
|
||||
|
||||
|
|
@ -290,6 +292,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
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ class Bot(BaseBot):
|
|||
duration: typing.Union[base.Integer, None] = None,
|
||||
performer: typing.Union[base.String, None] = None,
|
||||
title: typing.Union[base.String, None] = None,
|
||||
thumb: typing.Union[base.InputFile, base.String, None] = None,
|
||||
disable_notification: typing.Union[base.Boolean, None] = None,
|
||||
reply_to_message_id: typing.Union[base.Integer, None] = None,
|
||||
reply_markup: typing.Union[types.InlineKeyboardMarkup,
|
||||
|
|
@ -317,6 +318,8 @@ class Bot(BaseBot):
|
|||
:param performer: Performer
|
||||
:type performer: :obj:`typing.Union[base.String, None]`
|
||||
:param title: Track name
|
||||
:param thumb: Thumbnail of the file sent.
|
||||
:param :obj:`typing.Union[base.InputFile, base.String, None]`
|
||||
:type title: :obj:`typing.Union[base.String, None]`
|
||||
:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
|
||||
:type disable_notification: :obj:`typing.Union[base.Boolean, None]`
|
||||
|
|
@ -339,6 +342,7 @@ class Bot(BaseBot):
|
|||
|
||||
async def send_document(self, chat_id: typing.Union[base.Integer, base.String],
|
||||
document: typing.Union[base.InputFile, base.String],
|
||||
thumb: typing.Union[base.InputFile, base.String, None] = None,
|
||||
caption: typing.Union[base.String, None] = None,
|
||||
parse_mode: typing.Union[base.String, None] = None,
|
||||
disable_notification: typing.Union[base.Boolean, None] = None,
|
||||
|
|
@ -358,6 +362,8 @@ class Bot(BaseBot):
|
|||
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
|
||||
:param document: File to send.
|
||||
:type document: :obj:`typing.Union[base.InputFile, base.String]`
|
||||
:param thumb: Thumbnail of the file sent.
|
||||
:param :obj:`typing.Union[base.InputFile, base.String, None]`
|
||||
:param caption: Document caption (may also be used when resending documents by file_id), 0-200 characters
|
||||
:type caption: :obj:`typing.Union[base.String, None]`
|
||||
:param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic,
|
||||
|
|
@ -387,6 +393,7 @@ class Bot(BaseBot):
|
|||
duration: typing.Union[base.Integer, None] = None,
|
||||
width: typing.Union[base.Integer, None] = None,
|
||||
height: typing.Union[base.Integer, None] = None,
|
||||
thumb: typing.Union[base.InputFile, base.String, None] = None,
|
||||
caption: typing.Union[base.String, None] = None,
|
||||
parse_mode: typing.Union[base.String, None] = None,
|
||||
supports_streaming: typing.Union[base.Boolean, None] = None,
|
||||
|
|
@ -412,6 +419,8 @@ class Bot(BaseBot):
|
|||
:type width: :obj:`typing.Union[base.Integer, None]`
|
||||
:param height: Video height
|
||||
:type height: :obj:`typing.Union[base.Integer, None]`
|
||||
:param thumb: Thumbnail of the file sent.
|
||||
:param :obj:`typing.Union[base.InputFile, base.String, None]`
|
||||
:param caption: Video caption (may also be used when resending videos by file_id), 0-200 characters
|
||||
:type caption: :obj:`typing.Union[base.String, None]`
|
||||
:param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic,
|
||||
|
|
@ -438,6 +447,60 @@ class Bot(BaseBot):
|
|||
|
||||
return types.Message(**result)
|
||||
|
||||
async def send_animation(self,
|
||||
chat_id: typing.Union[base.Integer, base.String],
|
||||
animation: typing.Union[base.InputFile, base.String],
|
||||
duration: typing.Union[base.Integer, None] = None,
|
||||
width: typing.Union[base.Integer, None] = None,
|
||||
height: typing.Union[base.Integer, None] = None,
|
||||
thumb: typing.Union[typing.Union[base.InputFile, base.String], None] = None,
|
||||
caption: typing.Union[base.String, None] = None,
|
||||
parse_mode: typing.Union[base.String, None] = None,
|
||||
disable_notification: typing.Union[base.Boolean, None] = None,
|
||||
reply_to_message_id: typing.Union[base.Integer, None] = None,
|
||||
reply_markup: typing.Union[typing.Union[types.InlineKeyboardMarkup,
|
||||
types.ReplyKeyboardMarkup,
|
||||
types.ReplyKeyboardRemove,
|
||||
types.ForceReply], None] = None,) -> types.Message:
|
||||
"""
|
||||
Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound).
|
||||
|
||||
On success, the sent Message is returned.
|
||||
Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future.
|
||||
|
||||
Source https://core.telegram.org/bots/api#sendanimation
|
||||
|
||||
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername)
|
||||
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
|
||||
:param animation: Animation to send. Pass a file_id as String to send an animation that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an animation from the Internet, or upload a new animation using multipart/form-data.
|
||||
:type animation: :obj:`typing.Union[base.InputFile, base.String]`
|
||||
:param duration: Duration of sent animation in seconds
|
||||
:type duration: :obj:`typing.Union[base.Integer, None]`
|
||||
:param width: Animation width
|
||||
:type width: :obj:`typing.Union[base.Integer, None]`
|
||||
:param height: Animation height
|
||||
:type height: :obj:`typing.Union[base.Integer, None]`
|
||||
:param thumb: Thumbnail of the file sent. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail‘s width and height should not exceed 90. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can’t be reused and can be only uploaded as a new file, so you can pass “attach://<file_attach_name>” if the thumbnail was uploaded using multipart/form-data under <file_attach_name>.
|
||||
:type thumb: :obj:`typing.Union[typing.Union[base.InputFile, base.String], None]`
|
||||
:param caption: Animation caption (may also be used when resending animation by file_id), 0-200 characters
|
||||
:type caption: :obj:`typing.Union[base.String, None]`
|
||||
:param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.
|
||||
:type parse_mode: :obj:`typing.Union[base.String, None]`
|
||||
:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
|
||||
:type disable_notification: :obj:`typing.Union[base.Boolean, None]`
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:type reply_to_message_id: :obj:`typing.Union[base.Integer, None]`
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user.
|
||||
:type reply_markup: :obj:`typing.Union[typing.Union[types.InlineKeyboardMarkup, types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply], None]`
|
||||
:return: On success, the sent Message is returned.
|
||||
:rtype: :obj:`types.Message`
|
||||
"""
|
||||
reply_markup = prepare_arg(reply_markup)
|
||||
payload = generate_payload(**locals(), exclude=["animation"])
|
||||
result = await self.send_file("animation", api.Methods.SEND_ANIMATION, thumb, payload)
|
||||
|
||||
return types.Message(**result)
|
||||
|
||||
async def send_voice(self, chat_id: typing.Union[base.Integer, base.String],
|
||||
voice: typing.Union[base.InputFile, base.String],
|
||||
caption: typing.Union[base.String, None] = None,
|
||||
|
|
@ -492,6 +555,7 @@ class Bot(BaseBot):
|
|||
video_note: typing.Union[base.InputFile, base.String],
|
||||
duration: typing.Union[base.Integer, None] = None,
|
||||
length: typing.Union[base.Integer, None] = None,
|
||||
thumb: typing.Union[base.InputFile, base.String, None] = None,
|
||||
disable_notification: typing.Union[base.Boolean, None] = None,
|
||||
reply_to_message_id: typing.Union[base.Integer, None] = None,
|
||||
reply_markup: typing.Union[types.InlineKeyboardMarkup,
|
||||
|
|
@ -512,6 +576,8 @@ class Bot(BaseBot):
|
|||
:type duration: :obj:`typing.Union[base.Integer, None]`
|
||||
:param length: Video width and height
|
||||
:type length: :obj:`typing.Union[base.Integer, None]`
|
||||
:param thumb: Thumbnail of the file sent.
|
||||
:param :obj:`typing.Union[base.InputFile, base.String, None]`
|
||||
:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
|
||||
:type disable_notification: :obj:`typing.Union[base.Boolean, None]`
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
|
|
@ -675,6 +741,7 @@ class Bot(BaseBot):
|
|||
latitude: base.Float, longitude: base.Float,
|
||||
title: base.String, address: base.String,
|
||||
foursquare_id: typing.Union[base.String, None] = None,
|
||||
foursquare_type: typing.Union[base.String, None] = None,
|
||||
disable_notification: typing.Union[base.Boolean, None] = None,
|
||||
reply_to_message_id: typing.Union[base.Integer, None] = None,
|
||||
reply_markup: typing.Union[types.InlineKeyboardMarkup,
|
||||
|
|
@ -698,6 +765,8 @@ class Bot(BaseBot):
|
|||
:type address: :obj:`base.String`
|
||||
:param foursquare_id: Foursquare identifier of the venue
|
||||
:type foursquare_id: :obj:`typing.Union[base.String, None]`
|
||||
:param foursquare_type: Foursquare type of the venue, if known.
|
||||
:type foursquare_type: :obj:`typing.Union[base.String, None]`
|
||||
:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
|
||||
:type disable_notification: :obj:`typing.Union[base.Boolean, None]`
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
|
|
@ -717,6 +786,7 @@ class Bot(BaseBot):
|
|||
async def send_contact(self, chat_id: typing.Union[base.Integer, base.String],
|
||||
phone_number: base.String, first_name: base.String,
|
||||
last_name: typing.Union[base.String, None] = None,
|
||||
vcard: typing.Union[base.String, None] = None,
|
||||
disable_notification: typing.Union[base.Boolean, None] = None,
|
||||
reply_to_message_id: typing.Union[base.Integer, None] = None,
|
||||
reply_markup: typing.Union[types.InlineKeyboardMarkup,
|
||||
|
|
@ -736,6 +806,8 @@ class Bot(BaseBot):
|
|||
:type first_name: :obj:`base.String`
|
||||
:param last_name: Contact's last name
|
||||
:type last_name: :obj:`typing.Union[base.String, None]`
|
||||
:param vcard: vcard
|
||||
:type vcard: :obj:`typing.Union[base.String, None]`
|
||||
:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
|
||||
:type disable_notification: :obj:`typing.Union[base.Boolean, None]`
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
|
|
@ -1352,6 +1424,54 @@ class Bot(BaseBot):
|
|||
|
||||
return types.Message(**result)
|
||||
|
||||
async def edit_message_media(self,
|
||||
media: types.InputMedia,
|
||||
chat_id: typing.Union[typing.Union[base.Integer, base.String], None] = None,
|
||||
message_id: typing.Union[base.Integer, None] = None,
|
||||
inline_message_id: typing.Union[base.String, None] = None,
|
||||
reply_markup: typing.Union[types.InlineKeyboardMarkup, None] = None,
|
||||
) -> typing.Union[types.Message, base.Boolean]:
|
||||
"""
|
||||
Use this method to edit audio, document, photo, or video messages.
|
||||
If a message is a part of a message album, then it can be edited only to a photo or a video.
|
||||
Otherwise, message type can be changed arbitrarily.
|
||||
When inline message is edited, new file can't be uploaded.
|
||||
Use previously uploaded file via its file_id or specify a URL.
|
||||
|
||||
On success, if the edited message was sent by the bot,
|
||||
the edited Message is returned, otherwise True is returned.
|
||||
|
||||
Source https://core.telegram.org/bots/api#editmessagemedia
|
||||
|
||||
:param chat_id: Required if inline_message_id is not specified.
|
||||
:type chat_id: :obj:`typing.Union[typing.Union[base.Integer, base.String], None]`
|
||||
:param message_id: Required if inline_message_id is not specified. Identifier of the sent message
|
||||
:type message_id: :obj:`typing.Union[base.Integer, None]`
|
||||
:param inline_message_id: Required if chat_id and message_id are not specified. Identifier of the inline message
|
||||
:type inline_message_id: :obj:`typing.Union[base.String, None]`
|
||||
:param media: A JSON-serialized object for a new media content of the message
|
||||
:type media: :obj:`types.InputMedia`
|
||||
:param reply_markup: A JSON-serialized object for a new inline keyboard.
|
||||
:type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup, None]`
|
||||
:return: On success, if the edited message was sent by the bot, the edited Message is returned, otherwise True is returned.
|
||||
:rtype: :obj:`typing.Union[types.Message, base.Boolean]`
|
||||
"""
|
||||
|
||||
if isinstance(media, types.InputMedia) and media.file:
|
||||
files = {media.attachment_key: media.file}
|
||||
else:
|
||||
files = None
|
||||
|
||||
reply_markup = prepare_arg(reply_markup)
|
||||
payload = generate_payload(**locals())
|
||||
|
||||
result = await self.request(api.Methods.EDIT_MESSAGE_MEDIA, payload, files)
|
||||
|
||||
if isinstance(result, bool):
|
||||
return result
|
||||
|
||||
return types.Message(**result)
|
||||
|
||||
async def edit_message_reply_markup(self,
|
||||
chat_id: typing.Union[base.Integer, base.String, None] = None,
|
||||
message_id: typing.Union[base.Integer, None] = None,
|
||||
|
|
@ -1770,6 +1890,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,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import typing
|
|||
from typing import Dict, List, Optional, Union
|
||||
|
||||
from aiohttp import web
|
||||
from aiohttp.web_exceptions import HTTPGone
|
||||
|
||||
|
||||
from .. import types
|
||||
|
|
@ -129,8 +130,14 @@ class WebhookRequestHandler(web.View):
|
|||
response = self.get_response(results)
|
||||
|
||||
if response:
|
||||
return response.get_web_response()
|
||||
return web.Response(text='ok')
|
||||
web_response = response.get_web_response()
|
||||
else:
|
||||
web_response = web.Response(text='ok')
|
||||
|
||||
if self.request.app.get('RETRY_AFTER', None):
|
||||
web_response.headers['Retry-After'] = self.request.app['RETRY_AFTER']
|
||||
|
||||
return web_response
|
||||
|
||||
async def get(self):
|
||||
self.validate_ip()
|
||||
|
|
@ -247,6 +254,19 @@ class WebhookRequestHandler(web.View):
|
|||
# context.set_value('TELEGRAM_IP', ip_address)
|
||||
|
||||
|
||||
class GoneRequestHandler(web.View):
|
||||
"""
|
||||
If a webhook returns the HTTP error 410 Gone for all requests for more than 23 hours successively,
|
||||
it can be automatically removed.
|
||||
"""
|
||||
|
||||
async def get(self):
|
||||
raise HTTPGone()
|
||||
|
||||
async def post(self):
|
||||
raise HTTPGone()
|
||||
|
||||
|
||||
def configure_app(dispatcher, app: web.Application, path=DEFAULT_WEB_PATH):
|
||||
"""
|
||||
You can prepare web.Application for working with webhook handler.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -24,7 +26,8 @@ from .inline_query_result import InlineQueryResult, InlineQueryResultArticle, In
|
|||
InlineQueryResultGame, InlineQueryResultGif, InlineQueryResultLocation, InlineQueryResultMpeg4Gif, \
|
||||
InlineQueryResultPhoto, InlineQueryResultVenue, InlineQueryResultVideo, InlineQueryResultVoice
|
||||
from .input_file import InputFile
|
||||
from .input_media import InputMediaPhoto, InputMediaVideo, MediaGroup
|
||||
from .input_media import InputMedia, InputMediaAnimation, InputMediaAudio, InputMediaDocument, InputMediaPhoto, \
|
||||
InputMediaVideo, MediaGroup
|
||||
from .input_message_content import InputContactMessageContent, InputLocationMessageContent, InputMessageContent, \
|
||||
InputTextMessageContent, InputVenueMessageContent
|
||||
from .invoice import Invoice
|
||||
|
|
@ -34,6 +37,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 +78,8 @@ __all__ = (
|
|||
'Contact',
|
||||
'ContentType',
|
||||
'Document',
|
||||
'EncryptedCredentials',
|
||||
'EncryptedPassportElement',
|
||||
'File',
|
||||
'ForceReply',
|
||||
'Game',
|
||||
|
|
@ -100,6 +110,10 @@ __all__ = (
|
|||
'InlineQueryResultVoice',
|
||||
'InputContactMessageContent',
|
||||
'InputFile',
|
||||
'InputMedia',
|
||||
'InputMediaAnimation',
|
||||
'InputMediaAudio',
|
||||
'InputMediaDocument',
|
||||
'InputMediaPhoto',
|
||||
'InputMediaVideo',
|
||||
'InputLocationMessageContent',
|
||||
|
|
@ -116,6 +130,15 @@ __all__ = (
|
|||
'MessageEntity',
|
||||
'MessageEntityType',
|
||||
'OrderInfo',
|
||||
'PassportData',
|
||||
'PassportElementError',
|
||||
'PassportElementErrorDataField',
|
||||
'PassportElementErrorFile',
|
||||
'PassportElementErrorFiles',
|
||||
'PassportElementErrorFrontSide',
|
||||
'PassportElementErrorReverseSide',
|
||||
'PassportElementErrorSelfie',
|
||||
'PassportFile',
|
||||
'ParseMode',
|
||||
'PhotoSize',
|
||||
'PreCheckoutQuery',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from . import base
|
||||
from . import fields
|
||||
from . import mixins
|
||||
from .photo_size import PhotoSize
|
||||
|
||||
|
||||
class Audio(base.TelegramObject, mixins.Downloadable):
|
||||
|
|
@ -15,3 +16,4 @@ class Audio(base.TelegramObject, mixins.Downloadable):
|
|||
title: base.String = fields.Field()
|
||||
mime_type: base.String = fields.Field()
|
||||
file_size: base.Integer = fields.Field()
|
||||
thumb: PhotoSize = fields.Field(base=PhotoSize)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ class Contact(base.TelegramObject):
|
|||
first_name: base.String = fields.Field()
|
||||
last_name: base.String = fields.Field()
|
||||
user_id: base.Integer = fields.Field()
|
||||
vcard: base.String = fields.Field()
|
||||
|
||||
@property
|
||||
def full_name(self):
|
||||
|
|
|
|||
16
aiogram/types/encrypted_credentials.py
Normal file
16
aiogram/types/encrypted_credentials.py
Normal file
|
|
@ -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()
|
||||
21
aiogram/types/encrypted_passport_element.py
Normal file
21
aiogram/types/encrypted_passport_element.py
Normal file
|
|
@ -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
|
||||
"""
|
||||
|
||||
type: base.String = fields.Field()
|
||||
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)
|
||||
|
|
@ -405,6 +405,7 @@ class InlineQueryResultVenue(InlineQueryResult):
|
|||
thumb_url: base.String = fields.Field()
|
||||
thumb_width: base.Integer = fields.Field()
|
||||
thumb_height: base.Integer = fields.Field()
|
||||
foursquare_type: base.String = fields.Field()
|
||||
|
||||
def __init__(self, *,
|
||||
id: base.String,
|
||||
|
|
@ -417,12 +418,14 @@ class InlineQueryResultVenue(InlineQueryResult):
|
|||
input_message_content: typing.Optional[InputMessageContent] = None,
|
||||
thumb_url: typing.Optional[base.String] = None,
|
||||
thumb_width: typing.Optional[base.Integer] = None,
|
||||
thumb_height: typing.Optional[base.Integer] = None):
|
||||
thumb_height: typing.Optional[base.Integer] = None,
|
||||
foursquare_type: typing.Optional[base.String] = None):
|
||||
super(InlineQueryResultVenue, self).__init__(id=id, latitude=latitude, longitude=longitude,
|
||||
title=title, address=address, foursquare_id=foursquare_id,
|
||||
reply_markup=reply_markup,
|
||||
input_message_content=input_message_content, thumb_url=thumb_url,
|
||||
thumb_width=thumb_width, thumb_height=thumb_height)
|
||||
thumb_width=thumb_width, thumb_height=thumb_height,
|
||||
foursquare_type=foursquare_type)
|
||||
|
||||
|
||||
class InlineQueryResultContact(InlineQueryResult):
|
||||
|
|
@ -441,10 +444,12 @@ class InlineQueryResultContact(InlineQueryResult):
|
|||
phone_number: base.String = fields.Field()
|
||||
first_name: base.String = fields.Field()
|
||||
last_name: base.String = fields.Field()
|
||||
vcard: base.String = fields.Field()
|
||||
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
|
||||
thumb_url: base.String = fields.Field()
|
||||
thumb_width: base.Integer = fields.Field()
|
||||
thumb_height: base.Integer = fields.Field()
|
||||
foursquare_type: base.String = fields.Field()
|
||||
|
||||
def __init__(self, *,
|
||||
id: base.String,
|
||||
|
|
@ -455,12 +460,14 @@ class InlineQueryResultContact(InlineQueryResult):
|
|||
input_message_content: typing.Optional[InputMessageContent] = None,
|
||||
thumb_url: typing.Optional[base.String] = None,
|
||||
thumb_width: typing.Optional[base.Integer] = None,
|
||||
thumb_height: typing.Optional[base.Integer] = None):
|
||||
thumb_height: typing.Optional[base.Integer] = None,
|
||||
foursquare_type: typing.Optional[base.String] = None):
|
||||
super(InlineQueryResultContact, self).__init__(id=id, phone_number=phone_number,
|
||||
first_name=first_name, last_name=last_name,
|
||||
reply_markup=reply_markup,
|
||||
input_message_content=input_message_content, thumb_url=thumb_url,
|
||||
thumb_width=thumb_width, thumb_height=thumb_height)
|
||||
thumb_width=thumb_width, thumb_height=thumb_height,
|
||||
foursquare_type=foursquare_type)
|
||||
|
||||
|
||||
class InlineQueryResultGame(InlineQueryResult):
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ class InputMedia(base.TelegramObject):
|
|||
"""
|
||||
type: base.String = fields.Field(default='photo')
|
||||
media: base.String = fields.Field()
|
||||
thumb: typing.Union[base.InputFile, base.String] = fields.Field()
|
||||
caption: base.String = fields.Field()
|
||||
parse_mode: base.Boolean = fields.Field()
|
||||
|
||||
|
|
@ -51,6 +52,77 @@ class InputMedia(base.TelegramObject):
|
|||
self.conf['attachment_key'] = value
|
||||
|
||||
|
||||
class InputMediaAnimation(InputMedia):
|
||||
"""
|
||||
Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent.
|
||||
|
||||
https://core.telegram.org/bots/api#inputmediaanimation
|
||||
"""
|
||||
|
||||
width: base.Integer = fields.Field()
|
||||
height: base.Integer = fields.Field()
|
||||
duration: base.Integer = fields.Field()
|
||||
|
||||
def __init__(self, media: base.InputFile,
|
||||
thumb: typing.Union[base.InputFile, base.String] = None,
|
||||
caption: base.String = None,
|
||||
width: base.Integer = None, height: base.Integer = None, duration: base.Integer = None,
|
||||
parse_mode: base.Boolean = None, **kwargs):
|
||||
super(InputMediaAnimation, self).__init__(type='animation', media=media, thumb=thumb, caption=caption,
|
||||
width=width, height=height, duration=duration,
|
||||
parse_mode=parse_mode, conf=kwargs)
|
||||
|
||||
if isinstance(media, (io.IOBase, InputFile)):
|
||||
self.file = media
|
||||
|
||||
|
||||
class InputMediaDocument(InputMedia):
|
||||
"""
|
||||
Represents a photo to be sent.
|
||||
|
||||
https://core.telegram.org/bots/api#inputmediadocument
|
||||
"""
|
||||
|
||||
def __init__(self, media: base.InputFile, thumb: typing.Union[base.InputFile, base.String] = None,
|
||||
caption: base.String = None, parse_mode: base.Boolean = None, **kwargs):
|
||||
super(InputMediaDocument, self).__init__(type='document', media=media, thumb=thumb,
|
||||
caption=caption, parse_mode=parse_mode,
|
||||
conf=kwargs)
|
||||
|
||||
if isinstance(media, (io.IOBase, InputFile)):
|
||||
self.file = media
|
||||
|
||||
|
||||
class InputMediaAudio(InputMedia):
|
||||
"""
|
||||
Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent.
|
||||
|
||||
https://core.telegram.org/bots/api#inputmediaanimation
|
||||
"""
|
||||
|
||||
width: base.Integer = fields.Field()
|
||||
height: base.Integer = fields.Field()
|
||||
duration: base.Integer = fields.Field()
|
||||
performer: base.String = fields.Field()
|
||||
title: base.String = fields.Field()
|
||||
|
||||
def __init__(self, media: base.InputFile,
|
||||
thumb: typing.Union[base.InputFile, base.String] = None,
|
||||
caption: base.String = None,
|
||||
width: base.Integer = None, height: base.Integer = None,
|
||||
duration: base.Integer = None,
|
||||
performer: base.String = None,
|
||||
title: base.String = None,
|
||||
parse_mode: base.Boolean = None, **kwargs):
|
||||
super(InputMediaAudio, self).__init__(type='audio', media=media, thumb=thumb, caption=caption,
|
||||
width=width, height=height, duration=duration,
|
||||
performer=performer, title=title,
|
||||
parse_mode=parse_mode, conf=kwargs)
|
||||
|
||||
if isinstance(media, (io.IOBase, InputFile)):
|
||||
self.file = media
|
||||
|
||||
|
||||
class InputMediaPhoto(InputMedia):
|
||||
"""
|
||||
Represents a photo to be sent.
|
||||
|
|
@ -58,8 +130,10 @@ class InputMediaPhoto(InputMedia):
|
|||
https://core.telegram.org/bots/api#inputmediaphoto
|
||||
"""
|
||||
|
||||
def __init__(self, media: base.InputFile, caption: base.String = None, parse_mode: base.Boolean = None, **kwargs):
|
||||
super(InputMediaPhoto, self).__init__(type='photo', media=media, caption=caption, parse_mode=parse_mode,
|
||||
def __init__(self, media: base.InputFile, thumb: typing.Union[base.InputFile, base.String] = None,
|
||||
caption: base.String = None, parse_mode: base.Boolean = None, **kwargs):
|
||||
super(InputMediaPhoto, self).__init__(type='photo', media=media, thumb=thumb,
|
||||
caption=caption, parse_mode=parse_mode,
|
||||
conf=kwargs)
|
||||
|
||||
if isinstance(media, (io.IOBase, InputFile)):
|
||||
|
|
@ -126,14 +200,89 @@ class MediaGroup(base.TelegramObject):
|
|||
media = InputMediaPhoto(**media)
|
||||
elif media_type == 'video':
|
||||
media = InputMediaVideo(**media)
|
||||
# elif media_type == 'document':
|
||||
# media = InputMediaDocument(**media)
|
||||
# elif media_type == 'audio':
|
||||
# media = InputMediaAudio(**media)
|
||||
# elif media_type == 'animation':
|
||||
# media = InputMediaAnimation(**media)
|
||||
else:
|
||||
raise TypeError(f"Invalid media type '{media_type}'!")
|
||||
|
||||
elif not isinstance(media, InputMedia):
|
||||
raise TypeError(f"Media must be an instance of InputMedia or dict, not {type(media).__name__}")
|
||||
|
||||
elif media.type in ['document', 'audio', 'animation']:
|
||||
raise ValueError(f"This type of media is not supported by media groups!")
|
||||
|
||||
self.media.append(media)
|
||||
|
||||
'''
|
||||
def attach_animation(self, animation: base.InputFile,
|
||||
thumb: typing.Union[base.InputFile, base.String] = None,
|
||||
caption: base.String = None,
|
||||
width: base.Integer = None, height: base.Integer = None, duration: base.Integer = None,
|
||||
parse_mode: base.Boolean = None):
|
||||
"""
|
||||
Attach animation
|
||||
|
||||
:param animation:
|
||||
:param thumb:
|
||||
:param caption:
|
||||
:param width:
|
||||
:param height:
|
||||
:param duration:
|
||||
:param parse_mode:
|
||||
"""
|
||||
if not isinstance(animation, InputMedia):
|
||||
animation = InputMediaAnimation(media=animation, thumb=thumb, caption=caption,
|
||||
width=width, height=height, duration=duration,
|
||||
parse_mode=parse_mode)
|
||||
self.attach(animation)
|
||||
|
||||
def attach_audio(self, audio: base.InputFile,
|
||||
thumb: typing.Union[base.InputFile, base.String] = None,
|
||||
caption: base.String = None,
|
||||
width: base.Integer = None, height: base.Integer = None,
|
||||
duration: base.Integer = None,
|
||||
performer: base.String = None,
|
||||
title: base.String = None,
|
||||
parse_mode: base.Boolean = None):
|
||||
"""
|
||||
Attach animation
|
||||
|
||||
:param audio:
|
||||
:param thumb:
|
||||
:param caption:
|
||||
:param width:
|
||||
:param height:
|
||||
:param duration:
|
||||
:param performer:
|
||||
:param title:
|
||||
:param parse_mode:
|
||||
"""
|
||||
if not isinstance(audio, InputMedia):
|
||||
audio = InputMediaAudio(media=audio, thumb=thumb, caption=caption,
|
||||
width=width, height=height, duration=duration,
|
||||
performer=performer, title=title,
|
||||
parse_mode=parse_mode)
|
||||
self.attach(audio)
|
||||
|
||||
def attach_document(self, document: base.InputFile, thumb: typing.Union[base.InputFile, base.String] = None,
|
||||
caption: base.String = None, parse_mode: base.Boolean = None):
|
||||
"""
|
||||
Attach document
|
||||
|
||||
:param parse_mode:
|
||||
:param caption:
|
||||
:param thumb:
|
||||
:param document:
|
||||
"""
|
||||
if not isinstance(document, InputMedia):
|
||||
document = InputMediaDocument(media=document, thumb=thumb, caption=caption, parse_mode=parse_mode)
|
||||
self.attach(document)
|
||||
'''
|
||||
|
||||
def attach_photo(self, photo: typing.Union[InputMediaPhoto, base.InputFile],
|
||||
caption: base.String = None):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ class InputContactMessageContent(InputMessageContent):
|
|||
phone_number: base.String = fields.Field()
|
||||
first_name: base.String = fields.Field()
|
||||
last_name: base.String = fields.Field()
|
||||
vcard: base.String = fields.Field()
|
||||
|
||||
def __init__(self, phone_number: base.String,
|
||||
first_name: typing.Optional[base.String] = None,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import typing
|
|||
|
||||
from . import base
|
||||
from . import fields
|
||||
from .animation import Animation
|
||||
from .audio import Audio
|
||||
from .chat import Chat
|
||||
from .contact import Contact
|
||||
|
|
@ -15,6 +16,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
|
||||
|
|
@ -51,6 +53,7 @@ class Message(base.TelegramObject):
|
|||
caption_entities: typing.List[MessageEntity] = fields.ListField(base=MessageEntity)
|
||||
audio: Audio = fields.Field(base=Audio)
|
||||
document: Document = fields.Field(base=Document)
|
||||
animation: Animation = fields.Field(base=Animation)
|
||||
game: Game = fields.Field(base=Game)
|
||||
photo: typing.List[PhotoSize] = fields.ListField(base=PhotoSize)
|
||||
sticker: Sticker = fields.Field(base=Sticker)
|
||||
|
|
@ -75,6 +78,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()
|
||||
|
|
@ -83,6 +87,8 @@ class Message(base.TelegramObject):
|
|||
return ContentType.TEXT[0]
|
||||
elif self.audio:
|
||||
return ContentType.AUDIO[0]
|
||||
elif self.animation:
|
||||
return ContentType.ANIMATION[0]
|
||||
elif self.document:
|
||||
return ContentType.DOCUMENT[0]
|
||||
elif self.game:
|
||||
|
|
@ -127,6 +133,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]
|
||||
|
||||
|
|
@ -750,6 +758,7 @@ class ContentType(helper.Helper):
|
|||
TEXT = helper.ListItem() # text
|
||||
AUDIO = helper.ListItem() # audio
|
||||
DOCUMENT = helper.ListItem() # document
|
||||
ANIMATION = helper.ListItem() # animation
|
||||
GAME = helper.ListItem() # game
|
||||
PHOTO = helper.ListItem() # photo
|
||||
STICKER = helper.ListItem() # sticker
|
||||
|
|
@ -771,6 +780,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
|
||||
|
|
|
|||
|
|
@ -83,9 +83,11 @@ class MessageEntityType(helper.Helper):
|
|||
|
||||
:key: MENTION
|
||||
:key: HASHTAG
|
||||
:key: CASHTAG
|
||||
:key: BOT_COMMAND
|
||||
:key: URL
|
||||
:key: EMAIL
|
||||
:key: PHONE_NUMBER
|
||||
:key: BOLD
|
||||
:key: ITALIC
|
||||
:key: CODE
|
||||
|
|
@ -97,9 +99,11 @@ class MessageEntityType(helper.Helper):
|
|||
|
||||
MENTION = helper.Item() # mention - @username
|
||||
HASHTAG = helper.Item() # hashtag
|
||||
CASHTAG = helper.Item() # cashtag
|
||||
BOT_COMMAND = helper.Item() # bot_command
|
||||
URL = helper.Item() # url
|
||||
EMAIL = helper.Item() # email
|
||||
PHONE_NUMBER = helper.Item() # phone_number
|
||||
BOLD = helper.Item() # bold - bold text
|
||||
ITALIC = helper.Item() # italic - italic text
|
||||
CODE = helper.Item() # code - monowidth string
|
||||
|
|
|
|||
16
aiogram/types/passport_data.py
Normal file
16
aiogram/types/passport_data.py
Normal file
|
|
@ -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)
|
||||
110
aiogram/types/passport_element_error.py
Normal file
110
aiogram/types/passport_element_error.py
Normal file
|
|
@ -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)
|
||||
15
aiogram/types/passport_file.py
Normal file
15
aiogram/types/passport_file.py
Normal file
|
|
@ -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()
|
||||
|
|
@ -13,3 +13,5 @@ class Venue(base.TelegramObject):
|
|||
title: base.String = fields.Field()
|
||||
address: base.String = fields.Field()
|
||||
foursquare_id: base.String = fields.Field()
|
||||
foursquare_type: base.String = fields.Field()
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ TelegramAPIError
|
|||
MessageIdentifierNotSpecified
|
||||
MessageTextIsEmpty
|
||||
MessageCantBeEdited
|
||||
MessageCantBeDeleted
|
||||
MessageToEditNotFound
|
||||
ToMuchMessages
|
||||
ObjectExpectedAsReplyMarkup
|
||||
|
|
@ -171,6 +172,10 @@ class MessageTextIsEmpty(MessageError):
|
|||
|
||||
class MessageCantBeEdited(MessageError):
|
||||
match = 'message can\'t be edited'
|
||||
|
||||
|
||||
class MessageCantBeDeleted(MessageError):
|
||||
match = 'message can\'t be deleted'
|
||||
|
||||
|
||||
class MessageToEditNotFound(MessageError):
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ def start_polling(dispatcher, *, loop=None, skip_updates=False, reset_webhook=Tr
|
|||
|
||||
|
||||
def start_webhook(dispatcher, webhook_path, *, loop=None, skip_updates=None,
|
||||
on_startup=None, on_shutdown=None, check_ip=False, **kwargs):
|
||||
on_startup=None, on_shutdown=None, check_ip=False, retry_after=None, **kwargs):
|
||||
"""
|
||||
Start bot in webhook mode
|
||||
|
||||
|
|
@ -53,7 +53,8 @@ def start_webhook(dispatcher, webhook_path, *, loop=None, skip_updates=None,
|
|||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
executor = Executor(dispatcher, skip_updates=skip_updates, check_ip=check_ip, loop=loop)
|
||||
executor = Executor(dispatcher, skip_updates=skip_updates, check_ip=check_ip, retry_after=retry_after,
|
||||
loop=loop)
|
||||
_setup_callbacks(executor, on_startup, on_shutdown)
|
||||
|
||||
executor.start_webhook(webhook_path, **kwargs)
|
||||
|
|
@ -83,12 +84,13 @@ class Executor:
|
|||
Main executor class
|
||||
"""
|
||||
|
||||
def __init__(self, dispatcher, skip_updates=None, check_ip=False, loop=None):
|
||||
def __init__(self, dispatcher, skip_updates=None, check_ip=False, retry_after=None, loop=None):
|
||||
if loop is None:
|
||||
loop = dispatcher.loop
|
||||
self.dispatcher = dispatcher
|
||||
self.skip_updates = skip_updates
|
||||
self.check_ip = check_ip
|
||||
self.retry_after = retry_after
|
||||
self.loop = loop
|
||||
|
||||
self._identity = secrets.token_urlsafe(16)
|
||||
|
|
@ -190,6 +192,9 @@ class Executor:
|
|||
if app is None:
|
||||
self._web_app = app = web.Application()
|
||||
|
||||
if self.retry_after:
|
||||
app['RETRY_AFTER'] = self.retry_after
|
||||
|
||||
if self._identity == app.get(self._identity):
|
||||
# App is already configured
|
||||
return
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ BUILDDIR = build
|
|||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
45
examples/webhook_example_2.py
Normal file
45
examples/webhook_example_2.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import asyncio
|
||||
import logging
|
||||
|
||||
from aiogram import Bot, types
|
||||
from aiogram.dispatcher import Dispatcher
|
||||
from aiogram.utils.executor import start_webhook
|
||||
|
||||
API_TOKEN = 'BOT TOKEN HERE'
|
||||
|
||||
# webhook settings
|
||||
WEBHOOK_HOST = 'https://your.domain'
|
||||
WEBHOOK_PATH = '/path/to/api'
|
||||
WEBHOOK_URL = f"{WEBHOOK_HOST}{WEBHOOK_PATH}"
|
||||
|
||||
# webserver settings
|
||||
WEBAPP_HOST = 'localhost' # or ip
|
||||
WEBAPP_PORT = 3001
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
bot = Bot(token=API_TOKEN, loop=loop)
|
||||
dp = Dispatcher(bot)
|
||||
|
||||
|
||||
@dp.message_handler()
|
||||
async def echo(message: types.Message):
|
||||
await bot.send_message(message.chat.id, message.text)
|
||||
|
||||
|
||||
async def on_startup(dp):
|
||||
await bot.set_webhook(WEBHOOK_URL)
|
||||
# insert code here to run it after start
|
||||
#
|
||||
|
||||
|
||||
async def on_shutdown(dp):
|
||||
# insert code here to run it before shutdown
|
||||
#
|
||||
await bot.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
start_webhook(dispatcher=dp, webhook_path=WEBHOOK_PATH, on_startup=on_startup, on_shutdown=on_shutdown,
|
||||
skip_updates=True, host=WEBAPP_HOST, port=WEBAPP_PORT)
|
||||
Loading…
Add table
Add a link
Reference in a new issue