import re import struct import asyncio import functools from .base import EventBuilder from .._misc import utils from .. import _tl from ..types import _custom def auto_answer(func): @functools.wraps(func) async def wrapped(self, *args, **kwargs): if self._answered: return await func(*args, **kwargs) else: return (await asyncio.gather( self._answer(), func(*args, **kwargs), ))[1] return wrapped class CallbackQuery(EventBuilder, _custom.chatgetter.ChatGetter, _custom.sendergetter.SenderGetter): """ Occurs whenever you sign in as a bot and a user clicks one of the inline buttons on your messages. Note that the `chats` parameter will **not** work with normal IDs or peers if the clicked inline button comes from a "via bot" message. The `chats` parameter also supports checking against the `chat_instance` which should be used for inline callbacks. Members: query (:tl:`UpdateBotCallbackQuery`): The original :tl:`UpdateBotCallbackQuery`. data_match (`obj`, optional): The object returned by the ``data=`` parameter when creating the event builder, if any. Similar to ``pattern_match`` for the new message event. pattern_match (`obj`, optional): Alias for ``data_match``. Example .. code-block:: python from telethon import events, Button # Handle all callback queries and check data inside the handler @client.on(events.CallbackQuery) async def handler(event): if event.data == b'yes': await event.answer('Correct answer!') # Handle only callback queries with data being b'no' @client.on(events.CallbackQuery(data=b'no')) async def handler(event): # Pop-up message with alert await event.answer('Wrong answer!', alert=True) # Send a message with buttons users can click async def main(): await client.send_message(user, 'Yes or no?', buttons=[ Button.inline('Yes!', b'yes'), Button.inline('Nope', b'no') ]) """ def __init__(self, query, peer, msg_id): _custom.chatgetter.ChatGetter.__init__(self, peer) _custom.sendergetter.SenderGetter.__init__(self, query.user_id) self.query = query self.data_match = None self.pattern_match = None self._message = None self._answered = False @classmethod def _build(cls, update, others=None, self_id=None, *todo, **todo2): if isinstance(update, _tl.UpdateBotCallbackQuery): return cls.Event(update, update.peer, update.msg_id) elif isinstance(update, _tl.UpdateInlineBotCallbackQuery): # See https://github.com/LonamiWebs/Telethon/pull/1005 # The long message ID is actually just msg_id + peer_id mid, pid = struct.unpack('`, since the message object is normally not present. """ if isinstance(self.query.msg_id, _tl.InputBotInlineMessageID): return await self._client.edit_message( None, self.query.msg_id, *args, **kwargs ) else: return await self._client.edit_message( await self.get_input_chat(), self.query.msg_id, *args, **kwargs ) @auto_answer async def delete(self, *args, **kwargs): """ Deletes the message. Shorthand for `telethon.client.messages.MessageMethods.delete_messages` with ``entity`` and ``message_ids`` already set. If you need to delete more than one message at once, don't use this `delete` method. Use a `telethon.client.telegramclient.TelegramClient` instance directly. This method will also `answer` the callback if necessary. This method will likely fail if `via_inline` is `True`. """ return await self._client.delete_messages( await self.get_input_chat(), [self.query.msg_id], *args, **kwargs )