diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index a074b9d1..01d7d13a 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -392,6 +392,11 @@ def pyrogram_api(): get_bot_info set_bot_info get_collectible_item_info + get_available_gifts + get_user_gifts + sell_gift + send_gift + toggle_gift_is_saved """, business=""" Telegram Business @@ -575,6 +580,8 @@ def pyrogram_api(): ExtendedMediaPreview GiftCode GiftedPremium + Gift + UserGift InputStarsTransaction Invoice LabeledPrice @@ -773,6 +780,7 @@ def pyrogram_api(): Message.react Message.translate Message.wait_for_click + UserGift.toggle """, chat=""" Chat diff --git a/compiler/errors/source/400_BAD_REQUEST.tsv b/compiler/errors/source/400_BAD_REQUEST.tsv index 290728e1..773098ec 100644 --- a/compiler/errors/source/400_BAD_REQUEST.tsv +++ b/compiler/errors/source/400_BAD_REQUEST.tsv @@ -310,6 +310,7 @@ PHOTO_SAVE_FILE_INVALID The photo you tried to send cannot be saved by Telegram PHOTO_THUMB_URL_EMPTY The photo thumb URL is empty PHOTO_THUMB_URL_INVALID The photo thumb URL is invalid PINNED_DIALOGS_TOO_MUCH Too many pinned dialogs +PINNED_TOPIC_NOT_MODIFIED The pinned topic was not modified. PIN_RESTRICTED You can't pin messages in private chats with other people POLL_ANSWERS_INVALID The poll answers are invalid POLL_ANSWER_INVALID One of the poll answers is not acceptable diff --git a/pyrogram/enums/message_service_type.py b/pyrogram/enums/message_service_type.py index 1739ab6e..2b40f9a6 100644 --- a/pyrogram/enums/message_service_type.py +++ b/pyrogram/enums/message_service_type.py @@ -127,5 +127,8 @@ class MessageServiceType(AutoName): GIFT_CODE = auto() "Gift code" + USER_GIFT = auto() + "Star gift" + SCREENSHOT_TAKEN = auto() "Screenshot taken" diff --git a/pyrogram/filters.py b/pyrogram/filters.py index 410f1aef..894da9fc 100644 --- a/pyrogram/filters.py +++ b/pyrogram/filters.py @@ -337,6 +337,34 @@ game = create(game_filter) # endregion +# region giveaway_filter +async def giveaway_filter(_, __, m: Message): + return bool(m.giveaway) +giveaway = create(giveaway_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Giveaway` objects.""" +# endregion + +# region giveaway_result_filter +async def giveaway_result_filter(_, __, m: Message): + return bool(m.giveaway_winners or m.giveaway_completed) +giveaway_result = create(giveaway_result_filter) +"""Filter messages that contain :obj:`~pyrogram.types.GiveawayWinners` or :obj:`~pyrogram.types.GiveawayCompleted` objects.""" +# endregion + +# region gift_code_filter +async def gift_code_filter(_, __, m: Message): + return bool(m.gift_code) +gift_code = create(gift_code_filter) +"""Filter messages that contain :obj:`~pyrogram.types.GiftCode` objects.""" +# endregion + +# region user_gift +async def user_gift_filter(_, __, m: Message): + return bool(m.user_gift) +user_gift = create(user_gift_filter) +"""Filter messages that contain :obj:`~pyrogram.types.UserGift` objects.""" +# endregion + # region video_filter async def video_filter(_, __, m: Message): return bool(m.video) diff --git a/pyrogram/methods/business/__init__.py b/pyrogram/methods/business/__init__.py index f018dfed..58c0aec2 100644 --- a/pyrogram/methods/business/__init__.py +++ b/pyrogram/methods/business/__init__.py @@ -18,10 +18,20 @@ from .answer_pre_checkout_query import AnswerPreCheckoutQuery from .get_business_connection import GetBusinessConnection +from .get_available_gifts import GetAvailableGifts +from .get_user_gifts import GetUserGifts +from .sell_gift import SellGift +from .send_gift import SendGift +from .toggle_gift_is_saved import ToggleGiftIsSaved class TelegramBusiness( AnswerPreCheckoutQuery, - GetBusinessConnection + GetBusinessConnection, + GetAvailableGifts, + GetUserGifts, + SellGift, + SendGift, + ToggleGiftIsSaved, ): pass diff --git a/pyrogram/methods/business/get_available_gifts.py b/pyrogram/methods/business/get_available_gifts.py new file mode 100644 index 00000000..65a1c521 --- /dev/null +++ b/pyrogram/methods/business/get_available_gifts.py @@ -0,0 +1,44 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram 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 General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . +from typing import List + +import pyrogram +from pyrogram import raw, types + + +class GetAvailableGifts: + async def get_available_gifts( + self: "pyrogram.Client", + ) -> List["types.Gift"]: + """Get all gifts that can be sent to other users. + + .. include:: /_includes/usable-by/users.rst + + Returns: + List of :obj:`~pyrogram.types.Gift`: On success, a list of star gifts is returned. + + Example: + .. code-block:: python + + app.get_available_gifts() + """ + r = await self.invoke( + raw.functions.payments.GetStarGifts(hash=0) + ) + + return types.List([await types.Gift._parse(self, gift) for gift in r.gifts]) diff --git a/pyrogram/methods/business/get_user_gifts.py b/pyrogram/methods/business/get_user_gifts.py new file mode 100644 index 00000000..fa83477f --- /dev/null +++ b/pyrogram/methods/business/get_user_gifts.py @@ -0,0 +1,97 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram 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 General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Union, Optional, AsyncGenerator + +import pyrogram +from pyrogram import raw, types + + +class GetUserGifts: + async def get_user_gifts( + self: "pyrogram.Client", + user_id: Union[int, str], + offset: str = "", + limit: int = 0, + ) -> Optional[AsyncGenerator["types.UserGift", None]]: + """Get gifts saved to profile by the given user. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + user_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target user. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + + offset (``str``, *optional*): + Offset of the first entry to return as received from the previous request; use empty string to get the first chunk of results. + + limit (``int``, *optional*): + The maximum number of gifts to be returned; must be positive and can't be greater than 100. For optimal performance, the number of returned objects is chosen by Telegram Server and can be smaller than the specified limit. + + Returns: + ``Generator``: A generator yielding :obj:`~pyrogram.types.UserGift` objects. + + Example: + .. code-block:: python + + async for user_gift in app.get_user_gifts(user_id): + print(user_gift) + """ + peer = await self.resolve_peer(user_id) + + if not isinstance(peer, (raw.types.InputPeerUser, raw.types.InputPeerSelf)): + raise ValueError("user_id must belong to a user.") + + current = 0 + total = abs(limit) or (1 << 31) - 1 + limit = min(100, total) + + while True: + r = await self.invoke( + raw.functions.payments.GetUserStarGifts( + user_id=peer, + offset=offset, + limit=limit + ), + sleep_threshold=max(60, self.sleep_threshold) + ) + + users = {u.id: u for u in r.users} + + user_gifts = [ + await types.UserGift._parse(self, gift, users) + for gift in r.gifts + ] + + if not user_gifts: + return + + for user_gift in user_gifts: + yield user_gift + + current += 1 + + if current >= total: + return + + offset = r.next_offset + + if not offset: + return diff --git a/pyrogram/methods/business/sell_gift.py b/pyrogram/methods/business/sell_gift.py new file mode 100644 index 00000000..9deec455 --- /dev/null +++ b/pyrogram/methods/business/sell_gift.py @@ -0,0 +1,67 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram 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 General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + + +from typing import Union + +import pyrogram +from pyrogram import raw + + +class SellGift: + async def sell_gift( + self: "pyrogram.Client", + sender_user_id: Union[int, str], + message_id: int + ) -> bool: + """Sells a gift received by the current user for Telegram Stars. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + sender_user_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the user that sent the gift. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + + message_id (``int``): + Unique identifier of the message with the gift in the chat with the user. + + Returns: + ``bool``: On success, True is returned. + + Example: + .. code-block:: python + + # Convert gift + app.sell_gift(sender_user_id=user_id, message_id=123) + + """ + peer = await self.resolve_peer(sender_user_id) + + if not isinstance(peer, (raw.types.InputPeerUser, raw.types.InputPeerSelf)): + raise ValueError("sender_user_id must belong to a user.") + + r = await self.invoke( + raw.functions.payments.ConvertStarGift( + user_id=peer, + msg_id=message_id + ) + ) + + return r diff --git a/pyrogram/methods/business/send_gift.py b/pyrogram/methods/business/send_gift.py new file mode 100644 index 00000000..3f5a2f7d --- /dev/null +++ b/pyrogram/methods/business/send_gift.py @@ -0,0 +1,105 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram 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 General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + + +from typing import Optional, Union, List + +import pyrogram +from pyrogram import raw, types, enums, utils + + +class SendGift: + async def send_gift( + self: "pyrogram.Client", + user_id: Union[int, str], + gift_id: int, + text: Optional[str] = None, + parse_mode: Optional["enums.ParseMode"] = None, + entities: Optional[List["types.MessageEntity"]] = None, + is_private: Optional[bool] = None, + ) -> bool: + """Sends a gift to another user. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + user_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the user that will receive the gift. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + + gift_id (``int``): + Unique identifier of the gift to send. + + text (``str``, *optional*): + Text of the message to be sent. 0-``gift_text_length_max`` characters. + + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + List of special entities that appear in message text, which can be specified instead of *parse_mode*. + Only Bold, Italic, Underline, Strikethrough, Spoiler, and CustomEmoji entities are allowed. + + is_private (``bool``, *optional*): + Pass True to show the current user as sender and gift text only to the gift receiver; otherwise, everyone will be able to see them. + + Returns: + ``bool``: On success, True is returned. + + Raises: + RPCError: In case of a Telegram RPC error. + + Example: + .. code-block:: python + + # Send gift + app.send_gift(user_id=user_id, gift_id=123) + + """ + peer = await self.resolve_peer(user_id) + + if not isinstance(peer, (raw.types.InputPeerUser, raw.types.InputPeerSelf)): + raise ValueError("user_id must belong to a user.") + + text, entities = (await utils.parse_text_entities(self, text, parse_mode, entities)).values() + + invoice = raw.types.InputInvoiceStarGift( + user_id=peer, + gift_id=gift_id, + hide_name=is_private, + message=raw.types.TextWithEntities( + text=text, entities=entities or [] + ) if text else None + ) + + form = await self.invoke( + raw.functions.payments.GetPaymentForm( + invoice=invoice + ) + ) + + await self.invoke( + raw.functions.payments.SendStarsForm( + form_id=form.form_id, + invoice=invoice + ) + ) + + return True diff --git a/pyrogram/methods/business/toggle_gift_is_saved.py b/pyrogram/methods/business/toggle_gift_is_saved.py new file mode 100644 index 00000000..b4592eae --- /dev/null +++ b/pyrogram/methods/business/toggle_gift_is_saved.py @@ -0,0 +1,71 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram 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 General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + + +from typing import Union + +import pyrogram +from pyrogram import raw + + +class ToggleGiftIsSaved: + async def toggle_gift_is_saved( + self: "pyrogram.Client", + sender_user_id: Union[int, str], + message_id: int, + is_saved: bool + ) -> bool: + """Toggles whether a gift is shown on the current user's profile page. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + sender_user_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target user that sent the gift. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + For a contact that exists in your Telegram address book you can use his phone number (str). + + message_id (``int``): + Unique message identifier of the message with the gift in the chat with the user. + + is_saved (``bool``): + Pass True to display the gift on the user's profile page; pass False to remove it from the profile page. + + Returns: + ``bool``: On success, True is returned. + + Example: + .. code-block:: python + + # Hide gift + app.toggle_gift_is_saved(sender_user_id=user_id, message_id=123, is_saved=False) + """ + peer = await self.resolve_peer(sender_user_id) + + if not isinstance(peer, (raw.types.InputPeerUser, raw.types.InputPeerSelf)): + raise ValueError("sender_user_id must belong to a user.") + + r = await self.invoke( + raw.functions.payments.SaveStarGift( + user_id=peer, + msg_id=message_id, + unsave=not is_saved + ) + ) + + return r diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index b628d3a4..40d90e12 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -412,8 +412,12 @@ class Message(Object, Update): The raw message object, as received from the Telegram API. gift_code (:obj:`~pyrogram.types.GiftCode`, *optional*): + Service message: gift code information. Contains a `Telegram Premium giftcode link `_. + user_gift (:obj:`~pyrogram.types.UserGift`, *optional*): + Service message: Represents a gift received by a user. + gifted_premium (:obj:`~pyrogram.types.GiftedPremium`, *optional*): Info about a gifted Telegram Premium subscription @@ -494,6 +498,7 @@ class Message(Object, Update): chat_wallpaper_updated: "types.ChatWallpaper" = None, contact_registered: "types.ContactRegistered" = None, gift_code: "types.GiftCode" = None, + user_gift: "types.UserGift" = None, screenshot_taken: "types.ScreenshotTaken" = None, invoice: "types.Invoice" = None, story: Union["types.MessageStory", "types.Story"] = None, @@ -613,6 +618,7 @@ class Message(Object, Update): self.chat_wallpaper_updated = chat_wallpaper_updated self.contact_registered = contact_registered self.gift_code = gift_code + self.user_gift = user_gift self.screenshot_taken = screenshot_taken self.invoice = invoice self.story = story @@ -775,6 +781,7 @@ class Message(Object, Update): chat_wallpaper_updated = None contact_registered = None gift_code = None + user_gift = None screenshot_taken = None service_type = None @@ -891,6 +898,9 @@ class Message(Object, Update): elif isinstance(action, raw.types.MessageActionGiftCode): gift_code = types.GiftCode._parse(client, action, chats) service_type = enums.MessageServiceType.GIFT_CODE + elif isinstance(action, raw.types.MessageActionStarGift): + user_gift = await types.UserGift._parse_action(client, message, users) + service_type = enums.MessageServiceType.USER_GIFT elif isinstance(action, raw.types.MessageActionScreenshotTaken): screenshot_taken = types.ScreenshotTaken() service_type = enums.MessageServiceType.SCREENSHOT_TAKEN @@ -931,6 +941,7 @@ class Message(Object, Update): giveaway_launched=giveaway_launched, giveaway_result=giveaway_result, successful_payment=successful_payment, + user_gift=user_gift, payment_refunded=payment_refunded, boosts_applied=boosts_applied, chat_theme_updated=chat_theme_updated, diff --git a/pyrogram/types/payments/__init__.py b/pyrogram/types/payments/__init__.py index 98d33726..595bd2b5 100644 --- a/pyrogram/types/payments/__init__.py +++ b/pyrogram/types/payments/__init__.py @@ -19,6 +19,7 @@ from .extended_media_preview import ExtendedMediaPreview from .checked_gift_code import CheckedGiftCode +from .gift import Gift from .gift_code import GiftCode from .gifted_premium import GiftedPremium from .input_stars_transaction import InputStarsTransaction @@ -33,11 +34,13 @@ from .star_gift import StarGift from .stars_status import StarsStatus from .stars_transaction import StarsTransaction from .successful_payment import SuccessfulPayment +from .user_gift import UserGift from .user_star_gift import UserStarGift __all__ = [ "ExtendedMediaPreview", "CheckedGiftCode", + "Gift", "GiftCode", "GiftedPremium", "InputStarsTransaction", @@ -52,5 +55,6 @@ __all__ = [ "StarsStatus", "StarsTransaction", "SuccessfulPayment", + "UserGift", "UserStarGift" ] diff --git a/pyrogram/types/payments/gift.py b/pyrogram/types/payments/gift.py new file mode 100644 index 00000000..7f7b5dd4 --- /dev/null +++ b/pyrogram/types/payments/gift.py @@ -0,0 +1,92 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram 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 General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Optional + +import pyrogram +from pyrogram import raw, types, utils +from ..object import Object + + +class Gift(Object): + """Describes a gift that can be sent to another user. + + Parameters: + id (``int``): + Unique identifier of the gift. + + sticker (:obj:`~pyrogram.types.Sticker`): + The sticker representing the gift. + + star_count (``int``): + Number of Telegram Stars that must be paid for the gift. + + default_sell_star_count (``int``): + Number of Telegram Stars that can be claimed by the receiver instead of the gift by default. If the gift was paid with just bought Telegram Stars, then full value can be claimed. + + remaining_count (``int``, *optional*): + Number of remaining times the gift can be purchased by all users; None if not limited or the gift was sold out. + + total_count (``int``, *optional*): + Number of total times the gift can be purchased by all users; None if not limited. + + is_limited (``bool``, *optional*): + True, if the number of gifts is limited. + + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + id: int, + sticker: "types.Sticker", + star_count: int, + default_sell_star_count: int, + remaining_count: Optional[int] = None, + total_count: Optional[int] = None, + is_limited: Optional[bool] = None, + ): + super().__init__(client) + + self.id = id + self.sticker = sticker + self.star_count = star_count + self.default_sell_star_count = default_sell_star_count + self.remaining_count = remaining_count + self.total_count = total_count + self.is_limited = is_limited + + @staticmethod + async def _parse( + client, + star_gift: "raw.types.StarGift", + ) -> "Gift": + doc = star_gift.sticker + attributes = {type(i): i for i in doc.attributes} + + return Gift( + id=star_gift.id, + sticker=await types.Sticker._parse(client, doc, attributes), + star_count=star_gift.stars, + default_sell_star_count=star_gift.convert_stars, + remaining_count=getattr(star_gift, "availability_remains", None), + total_count=getattr(star_gift, "availability_total", None), + is_limited=getattr(star_gift, "limited", None), + client=client + ) diff --git a/pyrogram/types/payments/user_gift.py b/pyrogram/types/payments/user_gift.py new file mode 100644 index 00000000..2dd1d9b9 --- /dev/null +++ b/pyrogram/types/payments/user_gift.py @@ -0,0 +1,178 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram 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 General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from datetime import datetime +from typing import Optional, List + +import pyrogram +from pyrogram import raw, types, utils +from ..messages_and_media.message import Str +from ..object import Object + + +class UserGift(Object): + """Represents a gift received by a user. + + Parameters: + sender_user (:obj:`~pyrogram.types.User`, *optional*): + Identifier of the user that sent the gift; None if unknown. + + text (``str``, *optional*): + Message added to the gift. + + entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text. + + is_private (``bool``, *optional*): + True, if the sender and gift text are shown only to the gift receiver; otherwise, everyone are able to see them. + + is_saved (``bool``, *optional*): + True, if the gift is displayed on the user's profile page; may be False only for the receiver of the gift. + + date (``datetime``): + Date when the gift was sent. + + gift (:obj:`~pyrogram.types.Gift`, *optional*): + Information about the gift. + + message_id (``int``, *optional*): + Identifier of the message with the gift in the chat with the sender of the gift; can be None or an identifier of a deleted message; only for the gift receiver. + + sell_star_count (``int``, *optional*): + Number of Telegram Stars that can be claimed by the receiver instead of the gift; only for the gift receiver. + + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + sender_user: Optional["types.User"] = None, + text: Optional[str] = None, + entities: List["types.MessageEntity"] = None, + date: datetime, + is_private: Optional[bool] = None, + is_saved: Optional[bool] = None, + gift: Optional["types.Gift"] = None, + message_id: Optional[int] = None, + sell_star_count: Optional[int] = None + ): + super().__init__(client) + + self.date = date + self.gift = gift + self.is_private = is_private + self.is_saved = is_saved + self.sender_user = sender_user + self.text = text + self.entities = entities + self.message_id = message_id + self.sell_star_count = sell_star_count + + @staticmethod + async def _parse( + client, + user_star_gift: "raw.types.UserStarGift", + users: dict + ) -> "UserGift": + text, entities = None, None + if getattr(user_star_gift, "message", None): + text = user_star_gift.message.text or None + entities = [types.MessageEntity._parse(client, entity, users) for entity in user_star_gift.message.entities] + entities = types.List(filter(lambda x: x is not None, entities)) + + return UserGift( + date=utils.timestamp_to_datetime(user_star_gift.date), + gift=await types.Gift._parse(client, user_star_gift.gift), + is_private=getattr(user_star_gift, "name_hidden", None), + is_saved=not user_star_gift.unsaved if getattr(user_star_gift, "unsaved", None) else None, + sender_user=types.User._parse(client, users.get(user_star_gift.from_id)) if getattr(user_star_gift, "from_id", None) else None, + message_id=getattr(user_star_gift, "msg_id", None), + sell_star_count=getattr(user_star_gift, "convert_stars", None), + text=Str(text).init(entities) if text else None, + entities=entities, + client=client + ) + + @staticmethod + async def _parse_action( + client, + message: "raw.base.Message", + users: dict + ) -> "UserGift": + action = message.action + + doc = action.gift.sticker + attributes = {type(i): i for i in doc.attributes} + + text, entities = None, None + if getattr(action, "message", None): + text = action.message.text or None + entities = [types.MessageEntity._parse(client, entity, users) for entity in action.message.entities] + entities = types.List(filter(lambda x: x is not None, entities)) + + return UserGift( + gift=types.Gift( + id=action.gift.id, + sticker=await types.Sticker._parse(client, doc, attributes), + star_count=action.gift.stars, + default_sell_star_count=action.gift.convert_stars, + remaining_count=getattr(action.gift, "availability_remains", None), + total_count=getattr(action.gift, "availability_total", None), + is_limited=getattr(action.gift, "limited", None), + ), + date=utils.timestamp_to_datetime(message.date), + is_private=getattr(action, "name_hidden", None), + is_saved=getattr(action, "saved", None), + sender_user=types.User._parse(client, users.get(utils.get_raw_peer_id(message.peer_id))), + message_id=message.id, + text=Str(text).init(entities) if text else None, + entities=entities, + client=client + ) + + async def toggle(self, is_saved: bool) -> bool: + """Bound method *toggle* of :obj:`~pyrogram.types.UserGift`. + + Use as a shortcut for: + + .. code-block:: python + + await client.toggle_gift_is_saved( + sender_user_id=user_id, + message_id=message_id + ) + + Parameters: + is_saved (``bool``): + Pass True to display the gift on the user's profile page; pass False to remove it from the profile page. + + Example: + .. code-block:: python + + await user_gift.toggle(is_saved=False) + + Returns: + ``bool``: On success, True is returned. + + """ + return await self._client.toggle_gift_is_saved( + sender_user_id=self.sender_user.id, + message_id=self.message_id, + is_saved=is_saved + )