Add new features from new layer (#3676)

Updated some documentation regarding raw API.
get_permissions has been adjusted.
Expose more parameters when sending messages.
Update chat action.
Support sending spoilers.
Update buttons.
This commit is contained in:
Devesh Pal 2022-01-24 17:45:02 +05:30 committed by GitHub
parent a25f019964
commit 539e3cb808
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 88 additions and 23 deletions

View File

@ -25,7 +25,7 @@ you should use :tl:`GetFullUser`:
# or even # or even
full = await client(GetFullUserRequest('username')) full = await client(GetFullUserRequest('username'))
bio = full.about bio = full.full_user.about
See :tl:`UserFull` to know what other fields you can access. See :tl:`UserFull` to know what other fields you can access.

View File

@ -634,13 +634,8 @@ async def get_permissions(
entity = await self.get_entity(entity) entity = await self.get_entity(entity)
if not user: if not user:
if isinstance(entity, _tl.Channel): if helpers._entity_type(entity) != helpers._EntityType.USER:
FullChat = await self(_tl.fn.channels.GetFullChannel(entity)) return entity.default_banned_rights
elif isinstance(entity, _tl.Chat):
FullChat = await self(_tl.fn.messages.GetFullChat(entity))
else:
return
return FullChat.chats[0].default_banned_rights
entity = await self.get_input_entity(entity) entity = await self.get_input_entity(entity)
user = await self.get_input_entity(user) user = await self.get_input_entity(user)

View File

@ -426,8 +426,10 @@ async def send_message(
ttl: int = None, ttl: int = None,
# - Send options # - Send options
reply_to: 'typing.Union[int, _tl.Message]' = None, reply_to: 'typing.Union[int, _tl.Message]' = None,
send_as: 'hints.EntityLike' = None,
clear_draft: bool = False, clear_draft: bool = False,
background: bool = None, background: bool = None,
noforwards: bool = None,
schedule: 'hints.DateLike' = None, schedule: 'hints.DateLike' = None,
comment_to: 'typing.Union[int, _tl.Message]' = None, comment_to: 'typing.Union[int, _tl.Message]' = None,
) -> '_tl.Message': ) -> '_tl.Message':
@ -483,7 +485,7 @@ async def send_message(
entity, message._file._media, reply_to_msg_id=reply_to, message=message._text, entity, message._file._media, reply_to_msg_id=reply_to, message=message._text,
entities=message._fmt_entities, reply_markup=message._reply_markup, silent=message._silent, entities=message._fmt_entities, reply_markup=message._reply_markup, silent=message._silent,
schedule_date=schedule, clear_draft=clear_draft, schedule_date=schedule, clear_draft=clear_draft,
background=background background=background, noforwards=noforwards, send_as=send_as
) )
else: else:
request = _tl.fn.messages.SendMessage( request = _tl.fn.messages.SendMessage(
@ -496,7 +498,9 @@ async def send_message(
silent=silent, silent=silent,
background=background, background=background,
reply_markup=_custom.button.build_reply_markup(buttons), reply_markup=_custom.button.build_reply_markup(buttons),
schedule_date=schedule schedule_date=schedule,
noforwards=noforwards,
send_as=send_as
) )
result = await self(request) result = await self(request)
@ -525,7 +529,9 @@ async def forward_messages(
with_my_score: bool = None, with_my_score: bool = None,
silent: bool = None, silent: bool = None,
as_album: bool = None, as_album: bool = None,
schedule: 'hints.DateLike' = None schedule: 'hints.DateLike' = None,
noforwards: bool = None,
send_as: 'hints.EntityLike' = None
) -> 'typing.Sequence[_tl.Message]': ) -> 'typing.Sequence[_tl.Message]':
if as_album is not None: if as_album is not None:
warnings.warn('the as_album argument is deprecated and no longer has any effect') warnings.warn('the as_album argument is deprecated and no longer has any effect')
@ -565,7 +571,9 @@ async def forward_messages(
silent=silent, silent=silent,
background=background, background=background,
with_my_score=with_my_score, with_my_score=with_my_score,
schedule_date=schedule schedule_date=schedule,
noforwards=noforwards,
send_as=send_as
) )
result = await self(req) result = await self(req)
sent.extend(self._get_response_message(req, result, entity)) sent.extend(self._get_response_message(req, result, entity))

View File

@ -113,6 +113,8 @@ async def send_file(
reply_to: 'typing.Union[int, _tl.Message]' = None, reply_to: 'typing.Union[int, _tl.Message]' = None,
clear_draft: bool = False, clear_draft: bool = False,
background: bool = None, background: bool = None,
noforwards: bool = None,
send_as: 'hints.EntityLike' = None,
schedule: 'hints.DateLike' = None, schedule: 'hints.DateLike' = None,
comment_to: 'typing.Union[int, _tl.Message]' = None, comment_to: 'typing.Union[int, _tl.Message]' = None,
) -> '_tl.Message': ) -> '_tl.Message':
@ -146,13 +148,16 @@ async def send_file(
background=background, background=background,
schedule=schedule, schedule=schedule,
comment_to=comment_to, comment_to=comment_to,
noforwards=noforwards,
send_as=send_as
) )
async def _send_album(self: 'TelegramClient', entity, files, caption='', async def _send_album(self: 'TelegramClient', entity, files, caption='',
progress_callback=None, reply_to=None, progress_callback=None, reply_to=None,
parse_mode=(), silent=None, schedule=None, parse_mode=(), silent=None, schedule=None,
supports_streaming=None, clear_draft=None, supports_streaming=None, clear_draft=None,
force_document=False, background=None, ttl=None): force_document=False, background=None, ttl=None,
send_as=None, noforwards=None):
"""Specialized version of .send_file for albums""" """Specialized version of .send_file for albums"""
# We don't care if the user wants to avoid cache, we will use it # We don't care if the user wants to avoid cache, we will use it
# anyway. Why? The cached version will be exactly the same thing # anyway. Why? The cached version will be exactly the same thing
@ -212,7 +217,7 @@ async def _send_album(self: 'TelegramClient', entity, files, caption='',
request = _tl.fn.messages.SendMultiMedia( request = _tl.fn.messages.SendMultiMedia(
entity, reply_to_msg_id=reply_to, multi_media=media, entity, reply_to_msg_id=reply_to, multi_media=media,
silent=silent, schedule_date=schedule, clear_draft=clear_draft, silent=silent, schedule_date=schedule, clear_draft=clear_draft,
background=background background=background, noforwards=noforwards, send_as=send_as
) )
result = await self(request) result = await self(request)

View File

@ -76,6 +76,11 @@ class ChatAction(EventBuilder):
return cls.Event(msg, return cls.Event(msg,
added_by=added_by, added_by=added_by,
users=action.users) users=action.users)
elif isinstance(action, _tl.MessageActionChatJoinedByRequest):
# user joined from join request (after getting admin approval)
return cls.Event(msg,
from_approval=True,
users=msg.from_id)
elif isinstance(action, _tl.MessageActionChatDeleteUser): elif isinstance(action, _tl.MessageActionChatDeleteUser):
return cls.Event(msg, return cls.Event(msg,
kicked_by=utils.get_peer_id(msg.from_id) if msg.from_id else True, kicked_by=utils.get_peer_id(msg.from_id) if msg.from_id else True,
@ -138,6 +143,10 @@ class ChatAction(EventBuilder):
user_kicked (`bool`): user_kicked (`bool`):
`True` if the user was kicked by some other. `True` if the user was kicked by some other.
user_approved (`bool`):
`True` if the user's join request was approved.
along with `user_joined` will be also True.
created (`bool`, optional): created (`bool`, optional):
`True` if this chat was just created. `True` if this chat was just created.
@ -152,7 +161,7 @@ class ChatAction(EventBuilder):
""" """
def __init__(self, where, new_photo=None, def __init__(self, where, new_photo=None,
added_by=None, kicked_by=None, created=None, added_by=None, kicked_by=None, created=None, from_approval=None,
users=None, new_title=None, pin_ids=None, pin=None, new_score=None): users=None, new_title=None, pin_ids=None, pin=None, new_score=None):
if isinstance(where, _tl.MessageService): if isinstance(where, _tl.MessageService):
self.action_message = where self.action_message = where
@ -177,11 +186,12 @@ class ChatAction(EventBuilder):
self.user_added = self.user_joined = self.user_left = \ self.user_added = self.user_joined = self.user_left = \
self.user_kicked = self.unpin = False self.user_kicked = self.unpin = False
if added_by is True: if added_by is True or from_approval is True:
self.user_joined = True self.user_joined = True
elif added_by: elif added_by:
self.user_added = True self.user_added = True
self._added_by = added_by self._added_by = added_by
self.user_approved = from_approval
# If `from_id` was not present (it's `True`) or the affected # If `from_id` was not present (it's `True`) or the affected
# user was "kicked by itself", then it left. Else it was kicked. # user was "kicked by itself", then it left. Else it was kicked.

View File

@ -47,6 +47,8 @@ class HTMLToTelegramParser(HTMLParser):
EntityType = _tl.MessageEntityUnderline EntityType = _tl.MessageEntityUnderline
elif tag == 'del' or tag == 's': elif tag == 'del' or tag == 's':
EntityType = _tl.MessageEntityStrike EntityType = _tl.MessageEntityStrike
elif tag == 'tg-spoiler':
EntityType = _tl.MessageEntitySpoiler
elif tag == 'blockquote': elif tag == 'blockquote':
EntityType = _tl.MessageEntityBlockquote EntityType = _tl.MessageEntityBlockquote
elif tag == 'code': elif tag == 'code':

View File

@ -19,6 +19,7 @@ DELIMITERS = {
_tl.MessageEntityCode: ('`', '`'), _tl.MessageEntityCode: ('`', '`'),
_tl.MessageEntityItalic: ('_', '_'), _tl.MessageEntityItalic: ('_', '_'),
_tl.MessageEntityStrike: ('~~', '~~'), _tl.MessageEntityStrike: ('~~', '~~'),
_tl.MessageEntitySpoiler: ('||', '||'),
_tl.MessageEntityUnderline: ('# ', ''), _tl.MessageEntityUnderline: ('# ', ''),
} }

View File

@ -1,6 +1,8 @@
import typing
from .messagebutton import MessageButton from .messagebutton import MessageButton
from ... import _tl from ... import _tl
from ..._misc import utils from ..._misc import utils, hints
class Button: class Button:
@ -54,6 +56,7 @@ class Button:
_tl.KeyboardButtonCallback, _tl.KeyboardButtonCallback,
_tl.KeyboardButtonGame, _tl.KeyboardButtonGame,
_tl.KeyboardButtonSwitchInline, _tl.KeyboardButtonSwitchInline,
_tl.KeyboardButtonUserProfile,
_tl.KeyboardButtonUrl, _tl.KeyboardButtonUrl,
_tl.InputKeyboardButtonUrlAuth _tl.InputKeyboardButtonUrlAuth
)) ))
@ -166,6 +169,29 @@ class Button:
fwd_text=fwd_text fwd_text=fwd_text
) )
@staticmethod
def mention(text, input_entity):
"""
Creates a new inline button linked to the profile of user.
Args:
input_entity:
Input entity of :tl:User to use for profile button.
By default, this is the logged in user (itself), although
you may pass a different input peer.
.. note::
For now, you cannot use ID or username for this argument.
If you want to use different user, you must manually use
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`.
"""
return _tl.InputKeyboardButtonUserProfile(
text,
utils.get_input_user(input_entity or _tl.InputUserSelf())
)
@classmethod @classmethod
def text(cls, text, *, resize=None, single_use=None, selective=None): def text(cls, text, *, resize=None, single_use=None, selective=None):
""" """
@ -387,4 +413,4 @@ def build_reply_markup(
return _tl.ReplyInlineMarkup(rows) return _tl.ReplyInlineMarkup(rows)
# elif is_normal: # elif is_normal:
return _tl.ReplyKeyboardMarkup( return _tl.ReplyKeyboardMarkup(
rows, resize=resize, single_use=single_use, selective=selective) rows, resize=resize, single_use=single_use, selective=selective)

View File

@ -104,7 +104,7 @@ class InlineResult:
async def click(self, entity=None, reply_to=None, comment_to=None, async def click(self, entity=None, reply_to=None, comment_to=None,
silent=False, clear_draft=False, hide_via=False, silent=False, clear_draft=False, hide_via=False,
background=None): background=None, send_as=None):
""" """
Clicks this result and sends the associated `message`. Clicks this result and sends the associated `message`.
@ -137,6 +137,9 @@ class InlineResult:
background (`bool`, optional): background (`bool`, optional):
Whether the message should be send in background. Whether the message should be send in background.
send_as (`entity`, optional):
The channel entity on behalf of which, message should be send.
""" """
if entity: if entity:
entity = await self._client.get_input_entity(entity) entity = await self._client.get_input_entity(entity)
@ -158,7 +161,8 @@ class InlineResult:
background=background, background=background,
clear_draft=clear_draft, clear_draft=clear_draft,
hide_via=hide_via, hide_via=hide_via,
reply_to_msg_id=reply_id reply_to_msg_id=reply_id,
send_as=send_as
) )
return self._client._get_response_message( return self._client._get_response_message(
req, await self._client(req), entity) req, await self._client(req), entity)

View File

@ -189,6 +189,10 @@ class Message(ChatGetter, SenderGetter):
The number of times this message has been forwarded. The number of times this message has been forwarded.
""") """)
noforwards = _fwd('noforwards', """
does the message was sent with noforwards restriction.
""")
replies = _fwd('replies', """ replies = _fwd('replies', """
The number of times another message has replied to this message. The number of times another message has replied to this message.
""") """)
@ -205,13 +209,17 @@ class Message(ChatGetter, SenderGetter):
grouped_id = _fwd('grouped_id', """ grouped_id = _fwd('grouped_id', """
If this message belongs to a group of messages If this message belongs to a group of messages
(photo albums or video albums), all of them will (photo albums or video albums), all of them will
have the same value here. have the same value here.""")
restriction_reason (List[:tl:`RestrictionReason`]) restriction_reason = _fwd('restriction_reason', """
An optional list of reasons why this message was restricted. An optional list of reasons why this message was restricted.
If the list is `None`, this message has not been restricted. If the list is `None`, this message has not been restricted.
""") """)
reactions = _fwd('reactions', """
emoji reactions attached to the message.
""")
ttl_period = _fwd('ttl_period', """ ttl_period = _fwd('ttl_period', """
The Time To Live period configured for this message. The Time To Live period configured for this message.
The message should be erased from wherever it's stored (memory, a The message should be erased from wherever it's stored (memory, a

View File

@ -71,6 +71,10 @@ class MessageButton:
If it's an inline :tl:`KeyboardButtonCallback` with text and data, If it's an inline :tl:`KeyboardButtonCallback` with text and data,
it will be "clicked" and the :tl:`BotCallbackAnswer` returned. it will be "clicked" and the :tl:`BotCallbackAnswer` returned.
If it's an inline :tl:`KeyboardButtonUserProfile` button, the
`client.get_entity` will be called and the resulting :tl:User will be
returned.
If it's an inline :tl:`KeyboardButtonSwitchInline` button, the If it's an inline :tl:`KeyboardButtonSwitchInline` button, the
:tl:`StartBot` will be invoked and the resulting updates :tl:`StartBot` will be invoked and the resulting updates
returned. returned.
@ -107,6 +111,8 @@ class MessageButton:
return await self._client(req) return await self._client(req)
except BotResponseTimeoutError: except BotResponseTimeoutError:
return None return None
elif isinstance(self.button, _tl.KeyboardButtonUserProfile):
return await self._client.get_entity(self.button.user_id)
elif isinstance(self.button, _tl.KeyboardButtonSwitchInline): elif isinstance(self.button, _tl.KeyboardButtonSwitchInline):
return await self._client(_tl.fn.messages.StartBot( return await self._client(_tl.fn.messages.StartBot(
bot=self._bot, peer=self._chat, start_param=self.button.query bot=self._bot, peer=self._chat, start_param=self.button.query
@ -143,4 +149,4 @@ class MessageButton:
long, lat = share_geo long, lat = share_geo
share_geo = _tl.InputMediaGeoPoint(_tl.InputGeoPoint(lat=lat, long=long)) share_geo = _tl.InputMediaGeoPoint(_tl.InputGeoPoint(lat=lat, long=long))
return await self._client.send_file(self._chat, share_geo) return await self._client.send_file(self._chat, share_geo)