Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Bot API 8.0: Gifts #4576

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

Merged
merged 8 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/source/inclusions/bot_methods.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
- Used for sending documents
* - :meth:`~telegram.Bot.send_game`
- Used for sending a game
* - :meth:`~telegram.Bot.send_gift`
- Used for sending a gift
* - :meth:`~telegram.Bot.send_invoice`
- Used for sending an invoice
* - :meth:`~telegram.Bot.send_location`
Expand Down Expand Up @@ -369,6 +371,8 @@
- Used for logging out from cloud Bot API server
* - :meth:`~telegram.Bot.get_file`
- Used for getting basic info about a file
* - :meth:`~telegram.Bot.get_available_gifts`
- Used for getting information about gifts available for sending
* - :meth:`~telegram.Bot.get_me`
- Used for getting basic information about the bot
* - :meth:`~telegram.Bot.get_star_transactions`
Expand Down
1 change: 0 additions & 1 deletion docs/source/telegram.at-tree.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ Available Types
telegram.inputpaidmediaphoto
telegram.inputpaidmediavideo
telegram.inputpolloption
telegram.inputsticker
telegram.keyboardbutton
telegram.keyboardbuttonpolltype
telegram.keyboardbuttonrequestchat
Expand Down
6 changes: 6 additions & 0 deletions docs/source/telegram.gift.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Gift
====

.. autoclass:: telegram.Gift
:members:
:show-inheritance:
6 changes: 6 additions & 0 deletions docs/source/telegram.gifts.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Gifts
=====

.. autoclass:: telegram.Gifts
:members:
:show-inheritance:
3 changes: 3 additions & 0 deletions docs/source/telegram.stickers-tree.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ The following methods and objects allow your bot to handle stickers and sticker
.. toctree::
:titlesonly:

telegram.gift
telegram.gifts
telegram.inputsticker
telegram.maskposition
telegram.sticker
telegram.stickerset
3 changes: 3 additions & 0 deletions telegram/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@
"GameHighScore",
"GeneralForumTopicHidden",
"GeneralForumTopicUnhidden",
"Gift",
"Gifts",
"Giveaway",
"GiveawayCompleted",
"GiveawayCreated",
Expand Down Expand Up @@ -373,6 +375,7 @@
from ._games.callbackgame import CallbackGame
from ._games.game import Game
from ._games.gamehighscore import GameHighScore
from ._gifts import Gift, Gifts
from ._giveaway import Giveaway, GiveawayCompleted, GiveawayCreated, GiveawayWinners
from ._inline.inlinekeyboardbutton import InlineKeyboardButton
from ._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
Expand Down
98 changes: 98 additions & 0 deletions telegram/_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
from telegram._files.voice import Voice
from telegram._forumtopic import ForumTopic
from telegram._games.gamehighscore import GameHighScore
from telegram._gifts import Gift, Gifts
from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
from telegram._menubutton import MenuButton
from telegram._message import Message
Expand Down Expand Up @@ -9475,6 +9476,99 @@ async def edit_chat_subscription_invite_link(

return ChatInviteLink.de_json(result, self) # type: ignore[return-value]

async def get_available_gifts(
self,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: Optional[JSONDict] = None,
) -> Gifts:
"""Returns the list of gifts that can be sent by the bot to users.
Requires no parameters.

.. versionadded:: NEXT.VERSION

Returns:
:class:`telegram.Gifts`

Raises:
:class:`telegram.error.TelegramError`
"""
return Gifts.de_json( # type: ignore[return-value]
await self._post(
"getAvailableGifts",
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)
)

async def send_gift(
self,
user_id: int,
gift_id: Union[str, Gift],
text: Optional[str] = None,
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
text_entities: Optional[Sequence["MessageEntity"]] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: Optional[JSONDict] = None,
) -> bool:
"""Sends a gift to the given user.
The gift can't be converted to Telegram Stars by the user

.. versionadded:: NEXT.VERSION

Args:
user_id (:obj:`int`): Unique identifier of the target user that will receive the gift
gift_id (:obj:`str` | :class:`~telegram.Gift`): Identifier of the gift or a
:class:`~telegram.Gift` object
text (:obj:`str`, optional): Text that will be shown along with the gift;
0- :tg-const:`telegram.constants.GiftLimit.MAX_TEXT_LENGTH` characters
text_parse_mode (:obj:`str`, optional): Mode for parsing entities.
See :class:`telegram.constants.ParseMode` and
`formatting options <https://core.telegram.org/bots/api#formatting-options>`__ for
more details. Entities other than :attr:`~MessageEntity.BOLD`,
:attr:`~MessageEntity.ITALIC`, :attr:`~MessageEntity.UNDERLINE`,
:attr:`~MessageEntity.STRIKETHROUGH`, :attr:`~MessageEntity.SPOILER`, and
:attr:`~MessageEntity.CUSTOM_EMOJI` are ignored.
text_entities (Sequence[:class:`telegram.MessageEntity`], optional): A list of special
entities that appear in the gift text. It can be specified instead of
:paramref:`text_parse_mode`. Entities other than :attr:`~MessageEntity.BOLD`,
:attr:`~MessageEntity.ITALIC`, :attr:`~MessageEntity.UNDERLINE`,
:attr:`~MessageEntity.STRIKETHROUGH`, :attr:`~MessageEntity.SPOILER`, and
:attr:`~MessageEntity.CUSTOM_EMOJI` are ignored.

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

Raises:
:class:`telegram.error.TelegramError`
"""
data: JSONDict = {
"user_id": user_id,
"gift_id": gift_id.id if isinstance(gift_id, Gift) else gift_id,
"text": text,
"text_parse_mode": text_parse_mode,
"text_entities": text_entities,
}
return await self._post(
"sendGift",
data,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)

def to_dict(self, recursive: bool = True) -> JSONDict: # noqa: ARG002
"""See :meth:`telegram.TelegramObject.to_dict`."""
data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name}
Expand Down Expand Up @@ -9735,3 +9829,7 @@ def to_dict(self, recursive: bool = True) -> JSONDict: # noqa: ARG002
"""Alias for :meth:`create_chat_subscription_invite_link`"""
editChatSubscriptionInviteLink = edit_chat_subscription_invite_link
"""Alias for :meth:`edit_chat_subscription_invite_link`"""
getAvailableGifts = get_available_gifts
"""Alias for :meth:`get_available_gifts`"""
sendGift = send_gift
"""Alias for :meth:`send_gift`"""
41 changes: 41 additions & 0 deletions telegram/_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
ChatMember,
Contact,
Document,
Gift,
InlineKeyboardMarkup,
InputMediaAudio,
InputMediaDocument,
Expand Down Expand Up @@ -3436,6 +3437,46 @@ async def send_paid_media(
allow_paid_broadcast=allow_paid_broadcast,
)

async def send_gift(
self,
gift_id: Union[str, "Gift"],
text: Optional[str] = None,
text_parse_mode: ODVInput[str] = DEFAULT_NONE,
text_entities: Optional[Sequence["MessageEntity"]] = None,
*,
read_timeout: ODVInput[float] = DEFAULT_NONE,
write_timeout: ODVInput[float] = DEFAULT_NONE,
connect_timeout: ODVInput[float] = DEFAULT_NONE,
pool_timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: Optional[JSONDict] = None,
) -> bool:
"""Shortcut for::

await bot.send_gift(user_id=update.effective_chat.id, *args, **kwargs )

For the documentation of the arguments, please see :meth:`telegram.Bot.send_gift`.

Caution:
Can only work, if the chat is a private chat, see :attr:`type`.

.. versionadded:: NEXT.VERSION

Returns:
:obj:`bool`: On success, :obj:`True` is returned.
"""
return await self.get_bot().send_gift(
user_id=self.id,
gift_id=gift_id,
text=text,
text_parse_mode=text_parse_mode,
text_entities=text_entities,
read_timeout=read_timeout,
write_timeout=write_timeout,
connect_timeout=connect_timeout,
pool_timeout=pool_timeout,
api_kwargs=api_kwargs,
)


class Chat(_ChatBase):
"""This object represents a chat.
Expand Down
136 changes: 136 additions & 0 deletions telegram/_gifts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/usr/bin/env python
# pylint: disable=redefined-builtin
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2024
# Leandro Toledo de Souza <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/]
"""This module contains classes related to gifs sent by bots."""
from collections.abc import Sequence
from typing import TYPE_CHECKING, Optional

from telegram._files.sticker import Sticker
from telegram._telegramobject import TelegramObject
from telegram._utils.argumentparsing import parse_sequence_arg
from telegram._utils.types import JSONDict

if TYPE_CHECKING:
from telegram import Bot


class Gift(TelegramObject):
"""This object represents a gift that can be sent by the bot.

Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal if their :attr:`id` is equal.

.. versionadded:: NEXT.VERSION

Args:
id (:obj:`str`): Unique identifier of the gift
sticker (:class:`~telegram.Sticker`): The sticker that represents the gift
star_count (:obj:`int`): The number of Telegram Stars that must be paid to send the sticker
total_count (:obj:`int`, optional): The total number of the gifts of this type that can be
sent; for limited gifts only
remaining_count (:obj:`int`, optional): The number of remaining gifts of this type that can
be sent; for limited gifts only

Attributes:
id (:obj:`str`): Unique identifier of the gift
sticker (:class:`~telegram.Sticker`): The sticker that represents the gift
star_count (:obj:`int`): The number of Telegram Stars that must be paid to send the sticker
total_count (:obj:`int`): Optional. The total number of the gifts of this type that can be
sent; for limited gifts only
remaining_count (:obj:`int`): Optional. The number of remaining gifts of this type that can
be sent; for limited gifts only

"""

__slots__ = ("id", "remaining_count", "star_count", "sticker", "total_count")

def __init__(
self,
id: str,
sticker: Sticker,
star_count: int,
total_count: Optional[int] = None,
remaining_count: Optional[int] = None,
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.id: str = id
self.sticker: Sticker = sticker
self.star_count: int = star_count
self.total_count: Optional[int] = total_count
self.remaining_count: Optional[int] = remaining_count

self._id_attrs = (self.id,)

self._freeze()

@classmethod
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Gift"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)

if not data:
return None

data["sticker"] = Sticker.de_json(data.get("sticker"), bot)
return cls(**data)


class Gifts(TelegramObject):
"""This object represent a list of gifts.

Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal if their :attr:`gifts` are equal.

.. versionadded:: NEXT.VERSION

Args:
gifts (Sequence[:class:`Gift`]): The sequence of gifts

Attributes:
gifts (tuple[:class:`Gift`]): The sequence of gifts

"""

__slots__ = ("gifts",)

def __init__(
self,
gifts: Sequence[Gift],
*,
api_kwargs: Optional[JSONDict] = None,
):
super().__init__(api_kwargs=api_kwargs)
self.gifts: tuple[Gift, ...] = parse_sequence_arg(gifts)

self._id_attrs = (self.gifts,)

self._freeze()

@classmethod
def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Gifts"]:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)

if not data:
return None

data["gifts"] = Gift.de_list(data.get("gifts"), bot)
return cls(**data)
Loading
Loading