update get_message and @property chat for ButtonCallback

This commit is contained in:
apepenkov 2023-12-18 17:30:01 +03:00
parent 5b33b4b9c1
commit fbf0adb87b

View File

@ -4,8 +4,10 @@ import struct
import typing
from typing import TYPE_CHECKING, Dict, Optional, Self, Union
from .. import errors
from ...session import PackedType
from ...tl import abcs, functions, types
from ..types import Chat, Message, Channel
from ..types import Chat, Message, Channel, Group
from .event import Event
from ..types.chat import peer_id
from ..client.messages import CherryPickedList
@ -64,8 +66,8 @@ class ButtonCallback(Event):
@property
def message_id(self) -> typing.Union[int, abcs.InputBotInlineMessageId]:
"""
The ID of the message containing the button that was clicked.
The identifier of the message containing the button that was clicked.
If the message is inline, :class:`abcs.InputBotInlineMessageId` will be returned.
You can use it in :meth:`~telethon._tl.functions.messages.edit_inline_bot_message` to edit the message.
@ -81,38 +83,56 @@ class ButtonCallback(Event):
This may be :data:`None` if :data:`via_inline` is :data:`True`, as the bot might not be part of the chat.
"""
if isinstance(self._raw, types.UpdateInlineBotCallbackQuery):
# for that type of update, the msg_id and owner_id are present, however bot is not guaranteed
# to have "access" to the owner_id.
owner_id = None
if isinstance(self._raw.msg_id, types.InputBotInlineMessageId):
_, owner_id = struct.unpack("<ii", struct.pack("<q", self._raw.msg_id.id))
# telegram used to pack msg_id and peer_id into InputBotInlineMessageId.id
# I assume this is for the chats with IDs, fitting into 32-bit integer.
_, owner_id = struct.unpack(
"<ii", struct.pack("<q", self._raw.msg_id.id)
)
elif isinstance(self._raw.msg_id, types.InputBotInlineMessageId64):
_ = self._raw.msg_id.id
owner_id = self._raw.msg_id.owner_id
else:
raise RuntimeError(f"unexpected type of msg_id: {type(self._raw.msg_id)}")
if owner_id is None:
return None
if owner_id > 0:
# We can't know if it's really a chat with user, or an ID of the user who issued the inline query.
# So it's better to return None, then to return wrong chat.
# So it's better to return None, than to return wrong chat.
return None
owner_id = -owner_id
access_hash = 0
packed = self.client._chat_hashes.get(owner_id)
if packed:
access_hash = packed.access_hash
if owner := self._chat_map.get(owner_id):
return owner
return Channel._from_raw(
types.ChannelForbidden(
broadcast=True,
megagroup=False,
id=owner_id,
access_hash=access_hash,
title="",
until_date=None,
)
packed = self.client._chat_hashes.get(owner_id)
raw = types.ChannelForbidden(
broadcast=False,
megagroup=False,
id=owner_id,
access_hash=0,
title="",
until_date=None,
)
if packed:
raw.access_hash = packed.access_hash
if packed.ty == PackedType.MEGAGROUP or packed.ty == PackedType.GIGAGROUP:
if packed.ty == PackedType.GIGAGROUP:
raw.gigagroup = True
else:
raw.megagroup = True
return Group._from_raw(self.client, raw)
raw.broadcast = True
return Channel._from_raw(raw)
return self._chat_map.get(peer_id(self._raw.peer))
async def answer(
@ -149,54 +169,37 @@ class ButtonCallback(Event):
If the message is inline, or too old and is no longer accessible, :data:`None` is returned instead.
"""
chat = None
chat = self.chat
# numeric_id, received in this case, is:
# - a correct message id, if it was sent in a channel (or megagroup, gigagroup)
# - a sender's message id, if it was sent in a private chat. So it's not a correct ID from bot perspective,
# as each account has its own message id counter for private chats (pm, small group chats).
if isinstance(self._raw, types.UpdateInlineBotCallbackQuery):
# for that type of update, the msg_id and owner_id are present, however bot is not guaranteed
# to have "access" to the owner_id.
if isinstance(self._raw.msg_id, types.InputBotInlineMessageId):
# telegram used to pack msg_id and peer_id into InputBotInlineMessageId.id
# I assume this is for the chats with IDs, fitting into 32-bit integer.
msg_id, owner_id = struct.unpack(
"<ii", struct.pack("<q", self._raw.msg_id.id)
)
numeric_id, _ = struct.unpack("<ii", struct.pack("<q", self._raw.msg_id.id))
elif isinstance(self._raw.msg_id, types.InputBotInlineMessageId64):
msg_id = self._raw.msg_id.id
owner_id = self._raw.msg_id.owner_id
numeric_id = self._raw.msg_id.id
else:
return None
msg = types.InputMessageCallbackQuery(
id=msg_id, query_id=self._raw.query_id
)
if owner_id < 0:
# that means update's owner_id actually is the peer (channel), where the button was clicked.
# if it was positive, it'd be the user who issued the inline query.
try:
chat = await self._client._resolve_to_packed(-owner_id)
except ValueError:
pass
raise RuntimeError(f"unexpected type of msg_id: {type(self._raw.msg_id)}")
else:
pid = peer_id(self._raw.peer)
msg = types.InputMessageCallbackQuery(
id=self._raw.msg_id, query_id=self._raw.query_id
)
chat = self._chat_map.get(pid)
if not chat:
chat = await self._client._resolve_to_packed(pid)
numeric_id = self._raw.msg_id
if chat:
lst = CherryPickedList(self._client, chat, [])
lst._ids.append(msg)
res = await lst
if res:
return res[0] or None
lst = CherryPickedList(self._client, chat, [numeric_id])
try:
res = await lst
if res:
return res[0] or None
except errors.RpcError as e:
if e.name != "CHANNEL_INVALID" and e.name != "MESSAGE_IDS_EMPTY":
raise
# I didn't notice a single case, when this request returns a message.
# However, theoretically, self._raw.msg_id is a valid type of InputMessageID, so it may be possible.
res = await self._client(
functions.messages.get_messages(
id=[msg],
id=[self._raw.msg_id],
)
)
return res.messages[0] if res.messages else None