Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Api 5.5 #2809

Merged
merged 12 commits into from Dec 11, 2021
93 changes: 93 additions & 0 deletions telegram/bot.py
Expand Up @@ -2408,6 +2408,58 @@ def ban_chat_member(

return result # type: ignore[return-value]

@log
def ban_chat_sender_chat(
self,
chat_id: Union[str, int],
sender_chat_id: int,
until_date: Union[int, datetime] = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""
Use this method to ban a channel chat in a supergroup or a channel. The owner of the chat
will not be able to send messages and join live streams on behalf of the chat, unless it
is unbanned first. The bot must be an administrator in the supergroup or channel for this
to work and must have the appropriate administrator rights.

.. versionadded:: 13.9

Args:
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target group or username
of the target supergroup or channel (in the format ``@channelusername``).
sender_chat_id (:obj:`int`): Unique identifier of the target sender chat
until_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the sender chat
will be unbanned, unix time. If the chat is banned for more than 366 days or less
than 30 seconds from the current time they are considered to be banned forever.
For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
bot will be used.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
the read timeout from the server (instead of the one specified during creation of
the connection pool).
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
Telegram API.

Returns:
:obj:`bool`: On success, :obj:`True` is returned.

Raises:
:class:`telegram.error.TelegramError`

"""
data: JSONDict = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}

if until_date is not None:
if isinstance(until_date, datetime):
until_date = to_timestamp(
until_date, tzinfo=self.defaults.tzinfo if self.defaults else None
)
data['until_date'] = until_date

result = self._post('banChatSenderChat', data, timeout=timeout, api_kwargs=api_kwargs)

return result # type: ignore[return-value]

@log
def unban_chat_member(
self,
Expand Down Expand Up @@ -2452,6 +2504,43 @@ def unban_chat_member(

return result # type: ignore[return-value]

@log
def unban_chat_sender_chat(
self,
chat_id: Union[str, int],
sender_chat_id: int,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> bool:
"""Use this method to unban a previously banned channel in a supergroup or channel.
The bot must be an administrator for this to work and must have the
appropriate administrator rights.

.. versionadded:: 13.9

Args:
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
of the target supergroup or channel (in the format ``@channelusername``).
sender_chat_id (:obj:`int`): Unique identifier of the target sender chat.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
the read timeout from the server (instead of the one specified during creation of
the connection pool).
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
Telegram API.

Returns:
:obj:`bool` On success, :obj:`True` is returned.

Raises:
:class:`telegram.error.TelegramError`

"""
data: JSONDict = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}

result = self._post('unbanChatSenderChat', data, timeout=timeout, api_kwargs=api_kwargs)

return result # type: ignore[return-value]

@log
def answer_callback_query(
self,
Expand Down Expand Up @@ -5499,10 +5588,14 @@ def __hash__(self) -> int:
"""Alias for :meth:`get_file`"""
banChatMember = ban_chat_member
"""Alias for :meth:`ban_chat_member`"""
banChatSenderChat = ban_chat_sender_chat
"""Alias for :meth:`ban_chat_sender_chat`"""
kickChatMember = kick_chat_member
"""Alias for :meth:`kick_chat_member`"""
unbanChatMember = unban_chat_member
"""Alias for :meth:`unban_chat_member`"""
unbanChatSenderChat = unban_chat_sender_chat
"""Alias for :meth:`ban_chat_sender_chat`"""
answerCallbackQuery = answer_callback_query
"""Alias for :meth:`answer_callback_query`"""
editMessageText = edit_message_text
Expand Down
24 changes: 24 additions & 0 deletions telegram/chat.py
Expand Up @@ -81,6 +81,11 @@ class Chat(TelegramObject):
Returned only in :meth:`telegram.Bot.get_chat`.
bio (:obj:`str`, optional): Bio of the other party in a private chat. Returned only in
:meth:`telegram.Bot.get_chat`.
has_private_forwards (:obj:`bool`, optional): :obj:`True`, if privacy settings of the other
party in the private chat allows to use ``tg://user?id=<user_id>`` links only in chats
with the user. Returned only in :meth:`telegram.Bot.get_chat`.

.. versionadded:: 13.9
description (:obj:`str`, optional): Description, for groups, supergroups and channel chats.
Returned only in :meth:`telegram.Bot.get_chat`.
invite_link (:obj:`str`, optional): Primary invite link, for groups, supergroups and
Expand All @@ -97,6 +102,10 @@ class Chat(TelegramObject):
:meth:`telegram.Bot.get_chat`.

.. versionadded:: 13.4
has_protected_content (:obj:`bool`, optional): :obj:`True`, if messages from the chat can't
be forwarded to other chats. Returned only in :meth:`telegram.Bot.get_chat`.

.. versionadded:: 13.9
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
sticker_set_name (:obj:`str`, optional): For supergroups, name of group sticker set.
Returned only in :meth:`telegram.Bot.get_chat`.
Expand All @@ -119,6 +128,11 @@ class Chat(TelegramObject):
photo (:class:`telegram.ChatPhoto`): Optional. Chat photo.
bio (:obj:`str`): Optional. Bio of the other party in a private chat. Returned only in
:meth:`telegram.Bot.get_chat`.
has_private_forwards (:obj:`bool`): Optional. :obj:`True`, if privacy settings of the other
party in the private chat allows to use ``tg://user?id=<user_id>`` links only in chats
with the user.

.. versionadded:: 13.9
description (:obj:`str`): Optional. Description, for groups, supergroups and channel chats.
invite_link (:obj:`str`): Optional. Primary invite link, for groups, supergroups and
channel. Returned only in :meth:`telegram.Bot.get_chat`.
Expand All @@ -134,6 +148,10 @@ class Chat(TelegramObject):
:meth:`telegram.Bot.get_chat`.

.. versionadded:: 13.4
has_protected_content (:obj:`bool`): Optional. :obj:`True`, if messages from the chat can't
be forwarded to other chats.

.. versionadded:: 13.9
sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set.
can_set_sticker_set (:obj:`bool`): Optional. :obj:`True`, if the bot can change group the
sticker set.
Expand Down Expand Up @@ -166,6 +184,8 @@ class Chat(TelegramObject):
'linked_chat_id',
'all_members_are_administrators',
'message_auto_delete_time',
'has_protected_content',
'has_private_forwards',
'_id_attrs',
)

Expand Down Expand Up @@ -204,6 +224,8 @@ def __init__(
linked_chat_id: int = None,
location: ChatLocation = None,
message_auto_delete_time: int = None,
has_private_forwards: bool = None,
has_protected_content: bool = None,
**_kwargs: Any,
):
# Required
Expand All @@ -218,6 +240,7 @@ def __init__(
self.all_members_are_administrators = _kwargs.get('all_members_are_administrators')
self.photo = photo
self.bio = bio
self.has_private_forwards = has_private_forwards
self.description = description
self.invite_link = invite_link
self.pinned_message = pinned_message
Expand All @@ -226,6 +249,7 @@ def __init__(
self.message_auto_delete_time = (
int(message_auto_delete_time) if message_auto_delete_time is not None else None
)
self.has_protected_content = has_protected_content
self.sticker_set_name = sticker_set_name
self.can_set_sticker_set = can_set_sticker_set
self.linked_chat_id = linked_chat_id
Expand Down
6 changes: 6 additions & 0 deletions telegram/chatjoinrequest.py
Expand Up @@ -36,6 +36,12 @@ class ChatJoinRequest(TelegramObject):

.. versionadded:: 13.8

Bots are now allowed to contact users who sent a join request to a chat where the bot is
an administrator with the can_invite_users administrator right – even if the user
never interacted with the bot before.

.. versionchanged:: 13.9

harshil21 marked this conversation as resolved.
Show resolved Hide resolved
Args:
chat (:class:`telegram.Chat`): Chat to which the request was sent.
from_user (:class:`telegram.User`): User that sent the join request.
Expand Down
14 changes: 12 additions & 2 deletions telegram/inline/inlinekeyboardbutton.py
Expand Up @@ -45,6 +45,12 @@ class InlineKeyboardButton(TelegramObject):

.. versionadded:: 13.6

* Added support for mentioning users by their ID in inline keyboards. This will only work
in Telegram versions released after December 7, 2021. Older clients will display
*unsupported message*.

.. versionadded:: 13.9

harshil21 marked this conversation as resolved.
Show resolved Hide resolved
Warning:
If your bot allows your arbitrary callback data, buttons whose callback data is a
non-hashable object will be come unhashable. Trying to evaluate ``hash(button)`` will
Expand All @@ -54,7 +60,9 @@ class InlineKeyboardButton(TelegramObject):

Args:
text (:obj:`str`): Label text on the button.
url (:obj:`str`, optional): HTTP or tg:// url to be opened when button is pressed.
url (:obj:`str`, optional): HTTP or tg:// url to be opened when the button is pressed.
Links <code>tg://user?id=&lt;user_id&gt;</code> can be used to mention a user by
their ID without using a username, if this is allowed by their privacy settings.
login_url (:class:`telegram.LoginUrl`, optional): An HTTP URL used to automatically
authorize the user. Can be used as a replacement for the Telegram Login Widget.
callback_data (:obj:`str` | :obj:`Any`, optional): Data to be sent in a callback query to
Expand All @@ -81,7 +89,9 @@ class InlineKeyboardButton(TelegramObject):

Attributes:
text (:obj:`str`): Label text on the button.
url (:obj:`str`): Optional. HTTP or tg:// url to be opened when button is pressed.
url (:obj:`str`): Optional. HTTP or tg:// url to be opened when the button is pressed.
Links <code>tg://user?id=&lt;user_id&gt;</code> can be used to mention a user by
their ID without using a username, if this is allowed by their privacy settings.
login_url (:class:`telegram.LoginUrl`): Optional. An HTTP URL used to automatically
authorize the user. Can be used as a replacement for the Telegram Login Widget.
callback_data (:obj:`str` | :obj:`object`): Optional. Data to be sent in a callback query
Expand Down
22 changes: 22 additions & 0 deletions telegram/message.py
Expand Up @@ -109,9 +109,17 @@ class Message(TelegramObject):
who disallow adding a link to their account in forwarded messages.
forward_date (:class:`datetime.datetime`, optional): For forwarded messages, date the
original message was sent in Unix time. Converted to :class:`datetime.datetime`.
is_automatic_forward (:obj:`bool`, optional): :obj:`True`, if the message is a channel post
that was automatically forwarded to the connected discussion group.

.. versionadded:: 13.9
reply_to_message (:class:`telegram.Message`, optional): For replies, the original message.
edit_date (:class:`datetime.datetime`, optional): Date the message was last edited in Unix
time. Converted to :class:`datetime.datetime`.
has_protected_content (:obj:`bool`, optional): :obj:`True`, if the message can't be
forwarded.

.. versionadded:: 13.9
media_group_id (:obj:`str`, optional): The unique identifier of a media message group this
message belongs to.
text (str, optional): For text messages, the actual UTF-8 text of the message, 0-4096
Expand Down Expand Up @@ -238,10 +246,18 @@ class Message(TelegramObject):
forward_from_message_id (:obj:`int`): Optional. Identifier of the original message in the
channel.
forward_date (:class:`datetime.datetime`): Optional. Date the original message was sent.
is_automatic_forward (:obj:`bool`): Optional. :obj:`True`, if the message is a channel post
that was automatically forwarded to the connected discussion group.

.. versionadded:: 13.9
reply_to_message (:class:`telegram.Message`): Optional. For replies, the original message.
Note that the Message object in this field will not contain further
``reply_to_message`` fields even if it itself is a reply.
edit_date (:class:`datetime.datetime`): Optional. Date the message was last edited.
has_protected_content (:obj:`bool`): Optional. :obj:`True`, if the message can't be
forwarded.

.. versionadded:: 13.9
media_group_id (:obj:`str`): Optional. The unique identifier of a media message group this
message belongs to.
text (:obj:`str`): Optional. The actual UTF-8 text of the message.
Expand Down Expand Up @@ -390,6 +406,8 @@ class Message(TelegramObject):
'voice_chat_participants_invited',
'voice_chat_started',
'voice_chat_scheduled',
'is_automatic_forward',
'has_protected_content',
'_id_attrs',
)

Expand Down Expand Up @@ -492,6 +510,8 @@ def __init__(
voice_chat_participants_invited: VoiceChatParticipantsInvited = None,
message_auto_delete_timer_changed: MessageAutoDeleteTimerChanged = None,
voice_chat_scheduled: VoiceChatScheduled = None,
is_automatic_forward: bool = None,
has_protected_content: bool = None,
**_kwargs: Any,
):
# Required
Expand All @@ -504,8 +524,10 @@ def __init__(
self.forward_from = forward_from
self.forward_from_chat = forward_from_chat
self.forward_date = forward_date
self.is_automatic_forward = is_automatic_forward
self.reply_to_message = reply_to_message
self.edit_date = edit_date
self.has_protected_content = has_protected_content
self.text = text
self.entities = entities or []
self.caption_entities = caption_entities or []
Expand Down
19 changes: 19 additions & 0 deletions telegram/user.py
Expand Up @@ -22,6 +22,7 @@
from typing import TYPE_CHECKING, Any, List, Optional, Union, Tuple

from telegram import TelegramObject, constants
from telegram.inline.inlinekeyboardbutton import InlineKeyboardButton
from telegram.utils.helpers import (
mention_html as util_mention_html,
DEFAULT_NONE,
Expand Down Expand Up @@ -233,6 +234,24 @@ def mention_html(self, name: str = None) -> str:
return util_mention_html(self.id, name)
return util_mention_html(self.id, self.full_name)

def mention_button(self, name: str = None) -> InlineKeyboardButton:
"""
Shortcut for::

InlineKeyboardButton(text=name, url=f"tg://user?id={update.effective_user.id}")

.. versionadded:: 13.9

Args:
name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`.

Returns:
:obj:`InlineKeyboardButton`: InlineButton with url set to the user mention
"""
if name:
return InlineKeyboardButton(text=name, url=f"tg://user?id={self.id}")
return InlineKeyboardButton(text=self.full_name, url=f"tg://user?id={self.id}")
harshil21 marked this conversation as resolved.
Show resolved Hide resolved

def pin_message(
self,
message_id: int,
Expand Down
10 changes: 10 additions & 0 deletions tests/test_chat.py
Expand Up @@ -41,6 +41,8 @@ def chat(bot):
bio=TestChat.bio,
linked_chat_id=TestChat.linked_chat_id,
location=TestChat.location,
has_private_forwards=True,
has_protected_content=True,
)


Expand All @@ -62,6 +64,8 @@ class TestChat:
bio = "I'm a Barbie Girl in a Barbie World"
linked_chat_id = 11880
location = ChatLocation(Location(123, 456), 'Barbie World')
has_protected_content = True
has_private_forwards = True

def test_slot_behaviour(self, chat, recwarn, mro_slots):
for attr in chat.__slots__:
Expand All @@ -84,6 +88,8 @@ def test_de_json(self, bot):
'slow_mode_delay': self.slow_mode_delay,
'message_auto_delete_time': self.message_auto_delete_time,
'bio': self.bio,
'has_protected_content': self.has_protected_content,
'has_private_forwards': self.has_private_forwards,
'linked_chat_id': self.linked_chat_id,
'location': self.location.to_dict(),
}
Expand All @@ -100,6 +106,8 @@ def test_de_json(self, bot):
assert chat.slow_mode_delay == self.slow_mode_delay
assert chat.message_auto_delete_time == self.message_auto_delete_time
assert chat.bio == self.bio
assert chat.has_protected_content == self.has_protected_content
assert chat.has_private_forwards == self.has_private_forwards
assert chat.linked_chat_id == self.linked_chat_id
assert chat.location.location == self.location.location
assert chat.location.address == self.location.address
Expand All @@ -117,6 +125,8 @@ def test_to_dict(self, chat):
assert chat_dict['slow_mode_delay'] == chat.slow_mode_delay
assert chat_dict['message_auto_delete_time'] == chat.message_auto_delete_time
assert chat_dict['bio'] == chat.bio
assert chat_dict['has_private_forwards'] == chat.has_private_forwards
assert chat_dict['has_protected_content'] == chat.has_protected_content
assert chat_dict['linked_chat_id'] == chat.linked_chat_id
assert chat_dict['location'] == chat.location.to_dict()

Expand Down