From b31be1762ef1d53868de2c6c48e91a8d5835575d Mon Sep 17 00:00:00 2001 From: KurimuzonAkuma Date: Thu, 24 Oct 2024 21:20:54 +0300 Subject: [PATCH] Renamed giveaway types and added some service messages to Message Co-authored-by: Shrimadhav U K --- compiler/docs/compiler.py | 16 +- pyrogram/enums/__init__.py | 4 + pyrogram/enums/chat_join_type.py | 34 +++ pyrogram/enums/message_media_type.py | 4 +- pyrogram/enums/message_service_type.py | 28 ++- pyrogram/enums/phone_call_discard_reason.py | 36 +++ pyrogram/filters.py | 10 +- pyrogram/methods/payments/send_star_gift.py | 3 +- pyrogram/types/messages_and_media/__init__.py | 16 +- .../messages_and_media/business_message.py | 7 +- .../messages_and_media/contact_registered.py | 29 +++ .../types/messages_and_media/gift_code.py | 70 ++++-- .../messages_and_media/giveaway_completed.py | 95 ++++++++ .../messages_and_media/giveaway_created.py | 57 +++++ .../messages_and_media/giveaway_result.py | 140 ------------ .../messages_and_media/giveaway_winners.py | 150 ++++++++++++ pyrogram/types/messages_and_media/message.py | 214 ++++++++++++++---- .../messages_and_media/refunded_payment.py | 81 +++++++ .../messages_and_media/screenshot_taken.py | 29 +++ .../types/messages_and_media/star_gift.py | 36 ++- .../messages_and_media/successful_payment.py | 1 - .../write_access_allowed.py | 57 +++++ pyrogram/types/user_and_chats/__init__.py | 4 + .../types/user_and_chats/phone_call_ended.py | 63 ++++++ .../user_and_chats/phone_call_started.py | 49 ++++ pyrogram/utils.py | 26 +-- 26 files changed, 1009 insertions(+), 250 deletions(-) create mode 100644 pyrogram/enums/chat_join_type.py create mode 100644 pyrogram/enums/phone_call_discard_reason.py create mode 100644 pyrogram/types/messages_and_media/contact_registered.py create mode 100644 pyrogram/types/messages_and_media/giveaway_completed.py create mode 100644 pyrogram/types/messages_and_media/giveaway_created.py delete mode 100644 pyrogram/types/messages_and_media/giveaway_result.py create mode 100644 pyrogram/types/messages_and_media/giveaway_winners.py create mode 100644 pyrogram/types/messages_and_media/refunded_payment.py create mode 100644 pyrogram/types/messages_and_media/screenshot_taken.py create mode 100644 pyrogram/types/messages_and_media/write_access_allowed.py create mode 100644 pyrogram/types/user_and_chats/phone_call_ended.py create mode 100644 pyrogram/types/user_and_chats/phone_call_started.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index c73a1696..7eb6691b 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -483,7 +483,6 @@ def pyrogram_api(): BusinessConnection BusinessInfo BusinessIntro - BusinessMessage BusinessRecipients BusinessWeeklyOpen BusinessWorkingHours @@ -512,6 +511,7 @@ def pyrogram_api(): """, messages_media=""" Messages & Media + BusinessMessage Message MessageEntity Photo @@ -533,11 +533,14 @@ def pyrogram_api(): PollOption Dice Reaction + RefundedPayment StarGift VideoChatScheduled VideoChatStarted VideoChatEnded VideoChatMembersInvited + PhoneCallStarted + PhoneCallEnded WebAppData MessageReactions ChatReactions @@ -545,7 +548,9 @@ def pyrogram_api(): MyBoost BoostsStatus Giveaway - GiveawayResult + GiveawayCreated + GiveawayCompleted + GiveawayWinners Invoice GiftCode CheckedGiftCode @@ -554,6 +559,9 @@ def pyrogram_api(): PaidMediaPreview PaymentForm ChatBoost + ContactRegistered + ScreenshotTaken + WriteAccessAllowed """, bot_keyboards=""" Bot keyboards @@ -825,7 +833,7 @@ def pyrogram_api(): """, star_gift=""" StarGift - StarGift.save + StarGift.show StarGift.hide """ ) @@ -868,6 +876,7 @@ def pyrogram_api(): BusinessSchedule ChatAction ChatEventAction + ChatJoinType ChatMemberStatus ChatMembersFilter ChatType @@ -878,6 +887,7 @@ def pyrogram_api(): MessagesFilter NextCodeType ParseMode + PhoneCallDiscardReason PollType PrivacyKey ProfileColor diff --git a/pyrogram/enums/__init__.py b/pyrogram/enums/__init__.py index 9fc111bc..9e9c0752 100644 --- a/pyrogram/enums/__init__.py +++ b/pyrogram/enums/__init__.py @@ -19,6 +19,7 @@ from .business_schedule import BusinessSchedule from .chat_action import ChatAction from .chat_event_action import ChatEventAction +from .chat_join_type import ChatJoinType from .chat_member_status import ChatMemberStatus from .chat_members_filter import ChatMembersFilter from .chat_type import ChatType @@ -30,6 +31,7 @@ from .message_service_type import MessageServiceType from .messages_filter import MessagesFilter from .next_code_type import NextCodeType from .parse_mode import ParseMode +from .phone_call_discard_reason import PhoneCallDiscardReason from .poll_type import PollType from .privacy_key import PrivacyKey from .profile_color import ProfileColor @@ -42,6 +44,7 @@ __all__ = [ 'BusinessSchedule', 'ChatAction', 'ChatEventAction', + 'ChatJoinType', 'ChatMemberStatus', 'ChatMembersFilter', 'ChatType', @@ -53,6 +56,7 @@ __all__ = [ 'MessagesFilter', 'NextCodeType', 'ParseMode', + 'PhoneCallDiscardReason', 'PollType', 'PrivacyKey', 'ProfileColor', diff --git a/pyrogram/enums/chat_join_type.py b/pyrogram/enums/chat_join_type.py new file mode 100644 index 00000000..a718e2d4 --- /dev/null +++ b/pyrogram/enums/chat_join_type.py @@ -0,0 +1,34 @@ +# 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 enum import auto + +from .auto_name import AutoName + + +class ChatJoinType(AutoName): + """How the service message :obj:`~pyrogram.enums.MessageServiceType.NEW_CHAT_MEMBERS` was used for the member to join the chat.""" + + BY_ADD = auto() + "A new member joined the chat via an invite link" + + BY_LINK = auto() + "A new member joined the chat via an invite link" + + BY_REQUEST = auto() + "A new member was accepted to the chat by an administrator" diff --git a/pyrogram/enums/message_media_type.py b/pyrogram/enums/message_media_type.py index b7df9a3b..5749cec4 100644 --- a/pyrogram/enums/message_media_type.py +++ b/pyrogram/enums/message_media_type.py @@ -72,8 +72,8 @@ class MessageMediaType(AutoName): GIVEAWAY = auto() "Giveaway media" - GIVEAWAY_RESULT = auto() - "Giveaway result media" + GIVEAWAY_WINNERS = auto() + "Giveaway winners media" STORY = auto() "Story media" diff --git a/pyrogram/enums/message_service_type.py b/pyrogram/enums/message_service_type.py index 74bfe100..5e5d4997 100644 --- a/pyrogram/enums/message_service_type.py +++ b/pyrogram/enums/message_service_type.py @@ -78,8 +78,8 @@ class MessageServiceType(AutoName): GAME_HIGH_SCORE = auto() "Game high score" - GIVEAWAY_LAUNCH = auto() - "Giveaway launch" + GIVEAWAY_CREATED = auto() + "Giveaway created" GIFT_CODE = auto() "Gift code" @@ -96,6 +96,12 @@ class MessageServiceType(AutoName): VIDEO_CHAT_MEMBERS_INVITED = auto() "Video chat members invited" + PHONE_CALL_STARTED = auto() + "Phone call started" + + PHONE_CALL_ENDED = auto() + "Phone call ended" + WEB_APP_DATA = auto() "Web app data" @@ -105,14 +111,26 @@ class MessageServiceType(AutoName): SUCCESSFUL_PAYMENT = auto() "Successful payment" + REFUNDED_PAYMENT = auto() + "Refunded payment" + CHAT_TTL_CHANGED = auto() "Chat TTL changed" BOOST_APPLY = auto() "Boost apply" - JOIN_REQUEST_APPROVED = auto() - "Join request approved" - STAR_GIFT = auto() "Star gift" + + CONNECTED_WEBSITE = auto() + "Connected website" + + WRITE_ACCESS_ALLOWED = auto() + "Write access allowed" + + SCREENSHOT_TAKEN = auto() + "Screenshot taken" + + CONTACT_REGISTERED = auto() + "Contact registered" diff --git a/pyrogram/enums/phone_call_discard_reason.py b/pyrogram/enums/phone_call_discard_reason.py new file mode 100644 index 00000000..1dd1827c --- /dev/null +++ b/pyrogram/enums/phone_call_discard_reason.py @@ -0,0 +1,36 @@ +# 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 pyrogram import raw +from .auto_name import AutoName + + +class PhoneCallDiscardReason(AutoName): + """Phone call discard reason enumeration used in :obj:`~pyrogram.types.PhoneCallEnded`.""" + + BUSY = raw.types.PhoneCallDiscardReasonBusy + "Busy" + + DISCONNECT = raw.types.PhoneCallDiscardReasonDisconnect + "Disconnect" + + HANGUP = raw.types.PhoneCallDiscardReasonHangup + "Hangup" + + MISSED = raw.types.PhoneCallDiscardReasonMissed + "Missed" diff --git a/pyrogram/filters.py b/pyrogram/filters.py index 3eb3d146..64cf0f5c 100644 --- a/pyrogram/filters.py +++ b/pyrogram/filters.py @@ -349,13 +349,13 @@ giveaway = create(giveaway_filter) # endregion -# region giveaway_result_filter -async def giveaway_result_filter(_, __, m: Message): - return bool(m.giveaway_result) +# region giveaway_winners_filter +async def giveaway_winners_filter(_, __, m: Message): + return bool(m.giveaway_winners) -giveaway_result = create(giveaway_result_filter) -"""Filter messages that contain :obj:`~pyrogram.types.GiveawayResult` objects.""" +giveaway_winners = create(giveaway_winners_filter) +"""Filter messages that contain :obj:`~pyrogram.types.GiveawayWinners` objects.""" # endregion diff --git a/pyrogram/methods/payments/send_star_gift.py b/pyrogram/methods/payments/send_star_gift.py index c12db86e..06e90792 100644 --- a/pyrogram/methods/payments/send_star_gift.py +++ b/pyrogram/methods/payments/send_star_gift.py @@ -59,6 +59,7 @@ class SendStarGift: hide_my_name (``bool``, *optional*): If True, your name will be hidden from visitors to the gift recipient's profile. + Defaults to None. Returns: ``bool``: On success, True is returned. @@ -80,7 +81,7 @@ class SendStarGift: user_id=peer, gift_id=star_gift_id, hide_name=hide_my_name, - message=raw.types.TextWithEntities(text=text, entities=entities) if text else None + message=raw.types.TextWithEntities(text=text, entities=entities or []) if text else None ) form = await self.invoke( diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index 39269539..bab0c21e 100644 --- a/pyrogram/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -23,6 +23,7 @@ from .boosts_status import BoostsStatus from .business_message import BusinessMessage from .chat_boost import ChatBoost from .checked_gift_code import CheckedGiftCode +from .contact_registered import ContactRegistered from .contact import Contact from .dice import Dice from .document import Document @@ -37,7 +38,9 @@ from .general_forum_topic_unhidden import GeneralTopicUnhidden from .gift_code import GiftCode from .invoice import Invoice from .giveaway import Giveaway -from .giveaway_result import GiveawayResult +from .giveaway_completed import GiveawayCompleted +from .giveaway_created import GiveawayCreated +from .giveaway_winners import GiveawayWinners from .location import Location from .message import Message from .message_entity import MessageEntity @@ -50,6 +53,8 @@ from .photo import Photo from .poll import Poll from .poll_option import PollOption from .reaction import Reaction +from .refunded_payment import RefundedPayment +from .screenshot_taken import ScreenshotTaken from .star_gift import StarGift from .sticker import Sticker from .story import Story @@ -62,6 +67,7 @@ from .video_note import VideoNote from .voice import Voice from .web_app_data import WebAppData from .web_page import WebPage +from .write_access_allowed import WriteAccessAllowed __all__ = [ "Animation", @@ -71,6 +77,7 @@ __all__ = [ "BusinessMessage", "ChatBoost", "CheckedGiftCode", + "ContactRegistered", "Contact", "Dice", "Document", @@ -85,7 +92,9 @@ __all__ = [ "GiftCode", "Giveaway", "Invoice", - "GiveawayResult", + "GiveawayCompleted", + "GiveawayCreated", + "GiveawayWinners", "Location", "Message", "MessageEntity", @@ -98,6 +107,8 @@ __all__ = [ "Poll", "PollOption", "Reaction", + "RefundedPayment", + "ScreenshotTaken", "StarGift", "Sticker", "Story", @@ -110,4 +121,5 @@ __all__ = [ "Voice", "WebAppData", "WebPage", + "WriteAccessAllowed", ] diff --git a/pyrogram/types/messages_and_media/business_message.py b/pyrogram/types/messages_and_media/business_message.py index 272bde4e..3a11b004 100644 --- a/pyrogram/types/messages_and_media/business_message.py +++ b/pyrogram/types/messages_and_media/business_message.py @@ -91,12 +91,7 @@ class BusinessMessage(Object): schedule = None if isinstance(message, raw.types.BusinessAwayMessage): - if isinstance(message.schedule, raw.types.BusinessAwayMessageScheduleAlways): - schedule = enums.BusinessSchedule.ALWAYS - elif isinstance(message.schedule, raw.types.BusinessAwayMessageScheduleOutsideWorkHours): - schedule = enums.BusinessSchedule.OUTSIDE_WORK_HOURS - elif isinstance(message.schedule, raw.types.BusinessAwayMessageScheduleCustom): - schedule = enums.BusinessSchedule.CUSTOM + schedule = enums.BusinessSchedule(type(message.schedule)) return BusinessMessage( shortcut_id=message.shortcut_id, diff --git a/pyrogram/types/messages_and_media/contact_registered.py b/pyrogram/types/messages_and_media/contact_registered.py new file mode 100644 index 00000000..030eea0e --- /dev/null +++ b/pyrogram/types/messages_and_media/contact_registered.py @@ -0,0 +1,29 @@ +# 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 ..object import Object + + +class ContactRegistered(Object): + """A service message that a contact has registered with Telegram. + + Currently holds no information. + """ + + def __init__(self): + super().__init__() diff --git a/pyrogram/types/messages_and_media/gift_code.py b/pyrogram/types/messages_and_media/gift_code.py index 100abe58..eb15993f 100644 --- a/pyrogram/types/messages_and_media/gift_code.py +++ b/pyrogram/types/messages_and_media/gift_code.py @@ -23,21 +23,20 @@ from ..object import Object class GiftCode(Object): - """Contains gift code data. + """Contains information about gift code. Parameters: - months (``int``): + id (``str``): + Identifier of gift code. + You can combine it with `t.me/giftcode/{id}` to get link for this gift. + + premium_subscription_month_count (``int``): Number of months of subscription. - slug (``str``): - Identifier of gift code. - You can combine it with `t.me/giftcode/{slug}` - to get link for this gift. - - text (``str``, *optional*): + caption (``str``, *optional*): Text message. - entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text. via_giveaway (``bool``, *optional*): @@ -49,6 +48,18 @@ class GiftCode(Object): boosted_chat (:obj:`~pyrogram.types.Chat`, *optional*): The channel where the gift code was won. + currency (``str``, *optional*): + Currency for the paid amount. + + amount (``int``, *optional*): + The paid amount, in the smallest units of the currency. + + cryptocurrency (``str``, *optional*): + Cryptocurrency used to pay for the gift. + + cryptocurrency_amount (``int``, *optional*): + The paid amount, in the smallest units of the cryptocurrency. + link (``str``, *property*): Generate a link to this gift code. """ @@ -56,37 +67,52 @@ class GiftCode(Object): def __init__( self, *, - months: int, - slug: str, - text: Optional[str] = None, - entities: List["types.MessageEntity"] = None, + id: str, + premium_subscription_month_count: int, + caption: Optional[str] = None, + caption_entities: List["types.MessageEntity"] = None, via_giveaway: Optional[bool] = None, is_unclaimed: Optional[bool] = None, - boosted_chat: Optional["types.Chat"] = None + boosted_chat: Optional["types.Chat"] = None, + currency: Optional[str] = None, + amount: Optional[int] = None, + cryptocurrency: Optional[str] = None, + cryptocurrency_amount: Optional[int] = None ): super().__init__() - self.months = months - self.slug = slug - self.text = text - self.entities = entities + self.id = id + self.premium_subscription_month_count = premium_subscription_month_count + self.caption = caption + self.caption_entities = caption_entities self.via_giveaway = via_giveaway self.is_unclaimed = is_unclaimed self.boosted_chat = boosted_chat + self.currency = currency + self.amount = amount + self.cryptocurrency = cryptocurrency + self.cryptocurrency_amount = cryptocurrency_amount @staticmethod def _parse(client, giftcode: "raw.types.MessageActionGiftCode", users, chats): peer = chats.get(utils.get_raw_peer_id(getattr(giftcode, "boost_peer"))) + message, entities = (utils.parse_text_with_entities(client, getattr(giftcode, "message", None), users)).values() + return GiftCode( - months=giftcode.months, - slug=giftcode.slug, + id=giftcode.slug, + premium_subscription_month_count=giftcode.months, + caption=message or None, + caption_entities=entities or None, via_giveaway=getattr(giftcode, "via_giveaway"), is_unclaimed=getattr(giftcode, "unclaimed"), boosted_chat=types.Chat._parse_chat(client, peer) if peer else None, - **utils.parse_text_with_entities(client, getattr(giftcode, "message", None), users) + currency=getattr(giftcode, "currency", None) or None, + amount=getattr(giftcode, "amount", None) or None, + cryptocurrency=getattr(giftcode, "cryptocurrency", None) or None, + cryptocurrency_amount=getattr(giftcode, "cryptocurrency_amount", None) or None ) @property def link(self) -> str: - return f"https://t.me/giftcode/{self.slug}" + return f"https://t.me/giftcode/{self.id}" diff --git a/pyrogram/types/messages_and_media/giveaway_completed.py b/pyrogram/types/messages_and_media/giveaway_completed.py new file mode 100644 index 00000000..1c58f60d --- /dev/null +++ b/pyrogram/types/messages_and_media/giveaway_completed.py @@ -0,0 +1,95 @@ +# 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 . + +import pyrogram + +from pyrogram import raw, types, errors +from ..object import Object + + + +class GiveawayCompleted(Object): + """This object represents a service message about the completion of a giveaway without public winners. + + Parameters: + winner_count (``int``): + Number of winners in the giveaway. + + unclaimed_prize_count (``int``, *optional*): + Number of undistributed prizes. + + giveaway_message_id (``int``, *optional*): + Identifier of the message with the giveaway in the chat. + + giveaway_message (:obj:`~pyrogram.types.Message`, *optional*): + Message with the giveaway that was completed, if it wasn't deleted. + + is_star_giveaway (``bool``, *optional*): + True, if the giveaway is a Telegram Star giveaway. Otherwise, currently, the giveaway is a Telegram Premium giveaway. + + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + winner_count: int, + unclaimed_prize_count: int = None, + giveaway_message_id: int = None, + giveaway_message: "types.Message" = None, + is_star_giveaway: bool = None + ): + super().__init__(client) + + self.winner_count = winner_count + self.unclaimed_prize_count = unclaimed_prize_count + self.giveaway_message_id = giveaway_message_id + self.giveaway_message = giveaway_message + self.is_star_giveaway = is_star_giveaway + + + @staticmethod + async def _parse( + client, + giveaway_results: "raw.types.MessageActionGiveawayResults", + chat: "types.Chat" = None, + message_id: int = None + ) -> "GiveawayCompleted": + if not isinstance(giveaway_results, raw.types.MessageActionGiveawayResults): + return + + giveaway_message = None + + if chat and message_id: + try: + giveaway_message = await client.get_messages( + chat.id, + message_id, + replies=0 + ) + except (errors.ChannelPrivate, errors.ChannelInvalid): + pass + + return GiveawayCompleted( + winner_count=giveaway_results.winners_count, + unclaimed_prize_count=giveaway_results.unclaimed_count, + giveaway_message_id=message_id, + giveaway_message=giveaway_message, + is_star_giveaway=getattr(giveaway_results, "stars", None), + client=client, + ) diff --git a/pyrogram/types/messages_and_media/giveaway_created.py b/pyrogram/types/messages_and_media/giveaway_created.py new file mode 100644 index 00000000..fe502605 --- /dev/null +++ b/pyrogram/types/messages_and_media/giveaway_created.py @@ -0,0 +1,57 @@ +# 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 +from ..object import Object + + + +class GiveawayCreated(Object): + """This object represents a service message about the creation of a scheduled giveaway. + + Parameters: + prize_star_count (``int``, *optional*): + The number of Telegram Stars to be split between giveaway winners. + For Telegram Star giveaways only. + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + prize_star_count: Optional[int] = None + ): + super().__init__(client) + + self.prize_star_count = prize_star_count + + + @staticmethod + def _parse( + client, + giveaway_launch: "raw.types.MessageActionGiveawayLaunch" + ) -> "GiveawayCreated": + if isinstance(giveaway_launch, raw.types.MessageActionGiveawayLaunch): + return GiveawayCreated( + client=client, + prize_star_count=getattr(giveaway_launch, "stars", None) + ) diff --git a/pyrogram/types/messages_and_media/giveaway_result.py b/pyrogram/types/messages_and_media/giveaway_result.py deleted file mode 100644 index baf35a31..00000000 --- a/pyrogram/types/messages_and_media/giveaway_result.py +++ /dev/null @@ -1,140 +0,0 @@ -# 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 List - -import pyrogram -from pyrogram import errors, raw, utils -from pyrogram import types -from ..object import Object - - -class GiveawayResult(Object): - """An giveaway result. - - Parameters: - chat (List of :obj:`~pyrogram.types.Chat`): - Channel which host the giveaway. - - quantity (``int``): - Total number of subscriptions in this giveaway. - - winners_count (``int``): - Number of winners who claimed their gift. - - unclaimed_count (``int``): - Unclaimed giveaway subscriptions count. - - winners (List of :obj:`~pyrogram.types.User`): - A list of giveaway winners. - - months (``int``): - Number of months for which a subscription is given. - - until_date (:py:obj:`~datetime.datetime`): - Date when the giveaway will end. - - launch_message_id (``int``): - Identifier of the original message with the giveaway. - - launch_message (:obj:`~pyrogram.types.Message`, *optional*): - Returns the original giveaway start message. - If the channel is private, returns None - - stars (``int``, *optional*): - Stars amount. - - description (``str``, *optional*): - Prize description. - - only_new_subscribers (``bool``, *optional*): - True, if this giveaway is for new subscribers only. - - is_refunded (``bool``, *optional*): - True, if this giveaway was refunded. - """ - - def __init__( - self, - *, - client: "pyrogram.Client" = None, - chat: "types.Chat", - quantity: int, - winners_count: int, - unclaimed_count: int, - winners: List["types.User"], - months: int, - until_date: datetime, - launch_message_id: int, - launch_message: "types.Message" = None, - stars: int = None, - description: str = None, - only_new_subscribers: bool = None, - is_refunded: bool = None - ): - super().__init__(client) - - self.chat = chat - self.quantity = quantity - self.winners_count = winners_count - self.unclaimed_count = unclaimed_count - self.winners = winners - self.months = months - self.until_date = until_date - self.launch_message_id = launch_message_id - self.launch_message = launch_message - self.stars = stars - self.description = description - self.only_new_subscribers = only_new_subscribers - self.is_refunded = is_refunded - - @staticmethod - async def _parse( - client, - giveaway_result: "raw.types.MessageMediaGiveawayResults", - users: dict, - chats: dict - ) -> "GiveawayResult": - launch_message = None - - try: - launch_message = await client.get_messages( - utils.get_channel_id(giveaway_result.channel_id), - giveaway_result.launch_msg_id, - replies=0 - ) - except (errors.ChannelPrivate, errors.ChannelInvalid): - pass - - return GiveawayResult( - chat=types.Chat._parse_channel_chat(client, chats[giveaway_result.channel_id]), - quantity=giveaway_result.winners_count + giveaway_result.unclaimed_count, - winners_count=giveaway_result.winners_count, - unclaimed_count=giveaway_result.unclaimed_count, - winners=types.List(types.User._parse(client, users.get(i)) for i in giveaway_result.winners) or None, - months=giveaway_result.months, - until_date=utils.timestamp_to_datetime(giveaway_result.until_date), - launch_message_id=giveaway_result.launch_msg_id, - only_new_subscribers=getattr(giveaway_result, "only_new_subscribers", None), - is_refunded=getattr(giveaway_result, "refunded", None), - launch_message=launch_message, - stars=getattr(giveaway_result, "stars", None), - description=getattr(giveaway_result, "prize_description", None) or None, - client=client - ) diff --git a/pyrogram/types/messages_and_media/giveaway_winners.py b/pyrogram/types/messages_and_media/giveaway_winners.py new file mode 100644 index 00000000..9a1dfd92 --- /dev/null +++ b/pyrogram/types/messages_and_media/giveaway_winners.py @@ -0,0 +1,150 @@ +# 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 List, Optional + +import pyrogram + +from pyrogram import raw, types, utils, errors +from ..object import Object + + + +class GiveawayWinners(Object): + """This object represents a message about the completion of a giveaway with public winners. + + Parameters: + chat (:obj:`~pyrogram.types.Chat`): + The chat that created the giveaway + + giveaway_message_id (``int``): + Identifier of the message with the giveaway in the chat + + winners_selection_date (:py:obj:`~datetime.datetime`): + Point in time (Unix timestamp) when winners of the giveaway were selected + + quantity (``int``): + Total number of subscriptions in this giveaway. + + winner_count (``int``): + Total number of winners in the giveaway + + unclaimed_prize_count (``int``): + Number of undistributed prizes + + winners (:obj:`~pyrogram.types.User`): + List of up to 100 winners of the giveaway + + giveaway_message (:obj:`~pyrogram.types.Message`, *optional*): + Returns the original giveaway start message. + + additional_chat_count (``int``, *optional*): + The number of other chats the user had to join in order to be eligible for the giveaway + + prize_star_count (``int``, *optional*): + The number of Telegram Stars to be split between giveaway winners; for Telegram Star giveaways only + + premium_subscription_month_count (``int``, *optional*): + The number of months the Telegram Premium subscription won from the giveaway will be active for + + only_new_members (``bool``, *optional*): + True, if only users who had joined the chats after the giveaway started were eligible to win + + was_refunded (``bool``, *optional*): + True, if the giveaway was canceled because the payment for it was refunded + + prize_description (``str``, *optional*): + Description of additional giveaway prize + + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + chat: "types.Chat", + giveaway_message_id: int, + winners_selection_date: datetime, + quantity: int, + winner_count: int, + unclaimed_prize_count: Optional[int] = None, + winners: List["types.User"], + giveaway_message: Optional["types.Message"] = None, + additional_chat_count: Optional[int] = None, + prize_star_count: Optional[int] = None, + premium_subscription_month_count: Optional[int] = None, + only_new_members: Optional[bool] = None, + was_refunded: Optional[bool] = None, + prize_description: Optional[str] = None + ): + super().__init__(client) + + self.chat = chat + self.giveaway_message_id = giveaway_message_id + self.winners_selection_date = winners_selection_date + self.quantity = quantity + self.winner_count = winner_count + self.unclaimed_prize_count = unclaimed_prize_count + self.winners = winners + self.giveaway_message = giveaway_message + self.additional_chat_count = additional_chat_count + self.prize_star_count = prize_star_count + self.premium_subscription_month_count = premium_subscription_month_count + self.only_new_members = only_new_members + self.was_refunded = was_refunded + self.prize_description = prize_description + + @staticmethod + async def _parse( + client, + chats: dict, + users: dict, + giveaway_media: "raw.types.MessageMediaGiveawayResults" + ) -> "GiveawayWinners": + if not isinstance(giveaway_media, raw.types.MessageMediaGiveawayResults): + return + + giveaway_message = None + + try: + giveaway_message = await client.get_messages( + utils.get_channel_id(giveaway_media.channel_id), + giveaway_media.launch_msg_id, + replies=0 + ) + except (errors.ChannelPrivate, errors.ChannelInvalid): + pass + + return GiveawayWinners( + chat=types.Chat._parse_channel_chat(client, chats[giveaway_media.channel_id]), + giveaway_message_id=giveaway_media.launch_msg_id, + giveaway_message=giveaway_message, + winners_selection_date=utils.timestamp_to_datetime(giveaway_media.until_date), + quantity=giveaway_media.winners_count + giveaway_media.unclaimed_count, + winner_count=giveaway_media.winners_count, + unclaimed_prize_count=giveaway_media.unclaimed_count, + winners=types.List(types.User._parse(client, users.get(i)) for i in giveaway_media.winners) or None, + additional_chat_count=getattr(giveaway_media, "additional_peers_count", None), + prize_star_count=giveaway_media.stars, + premium_subscription_month_count=getattr(giveaway_media, "months", None), + only_new_members=getattr(giveaway_media, "only_new_subscribers", None), + was_refunded=getattr(giveaway_media, "refunded", None), + prize_description=getattr(giveaway_media, "prize_description", None), + client=client + ) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 978dd5b9..708705d3 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -72,12 +72,27 @@ class Message(Object, Update): The supergroup itself for messages from anonymous group administrators. The linked channel for messages automatically forwarded to the discussion group. + sender_boost_count (``int``, *optional*): + If the sender of the message boosted the chat, the number of boosts added by the user. + + sender_business_bot (:obj:`~pyrogram.types.User`, *optional*): + The bot that actually sent the message on behalf of the business account. Available only for outgoing messages sent on behalf of the connected business account. + date (:py:obj:`~datetime.datetime`, *optional*): Date the message was sent. chat (:obj:`~pyrogram.types.Chat`, *optional*): Conversation the message belongs to. + topic_message (``bool``, *optional*): + True, if the message is sent to a forum topic. + + automatic_forward (``bool``, *optional*): + True, if the message is a channel post that was automatically forwarded to the connected discussion group. + + from_offline (``bool``, *optional*): + True, if the message was sent by an implicit action, for example, as an away or a greeting business message, or as a scheduled message. + topic (:obj:`~pyrogram.types.ForumTopic`, *optional*): Topic the message belongs to. @@ -262,6 +277,9 @@ class Message(Object, Update): left_chat_member (:obj:`~pyrogram.types.User`, *optional*): A member was removed from the group, information about them (this member may be the bot itself). + chat_join_type (:obj:`~pyrogram.enums.ChatJoinType`, *optional*): + This field will contain the enumeration type of how the user had joined the chat. + new_chat_title (``str``, *optional*): A chat title was changed to this value. @@ -313,9 +331,6 @@ class Message(Object, Update): forwards (``int``, *optional*): Channel post forwards. - sender_boost_count (``int``, *optional*): - The number of boosts applied by the sender. - via_bot (:obj:`~pyrogram.types.User`): The information of the bot that generated the message from an inline query of a user. @@ -326,7 +341,7 @@ class Message(Object, Update): An exception is made for your own personal chat; messages sent there will be incoming. quote (``bool``, *optional*): - The message contains a quote. + If True, message contains a quote. matches (List of regex Matches, *optional*): A list containing all `Match Objects `_ that match @@ -367,6 +382,12 @@ class Message(Object, Update): video_chat_members_invited (:obj:`~pyrogram.types.VoiceChatParticipantsInvited`, *optional*): Service message: new members were invited to the voice chat. + phone_call_started (:obj:`~pyrogram.types.PhoneCallStarted`, *optional*): + Service message: phone call started. + + phone_call_ended (:obj:`~pyrogram.types.PhoneCallEnded`, *optional*): + Service message: phone call ended. + web_app_data (:obj:`~pyrogram.types.WebAppData`, *optional*): Service message: web app data sent to the bot. @@ -382,17 +403,35 @@ class Message(Object, Update): successful_payment (:obj:`~pyrogram.types.SuccessfulPayment`, *optional*): Service message: successful payment. - giveaway_launched (``bool``, *optional*): + refunded_payment (:obj:`~pyrogram.types.RefundedPayment`, *optional*): + Service message: refunded payment. + + giveaway_created (``bool``, *optional*): Service message: giveaway launched. + giveaway_winners (:obj:`~pyrogram.types.GiveawayWinners`, *optional*): + A giveaway with public winners was completed. + + giveaway_completed (:obj:`~pyrogram.types.GiveawayCompleted`, *optional*): + Service message: a giveaway without public winners was completed. + chat_ttl_period (``int``, *optional*): Service message: chat TTL period changed. boosts_applied (``int``, *optional*): Service message: how many boosts were applied. - join_request_approved (``bool``, *optional*): - Service message: user join request approved + write_access_allowed (:obj:`~pyrogram.types.WriteAccessAllowed`, *optional*): + Service message: the user allowed the bot to write messages after adding it to the attachment or side menu, launching a Web App from a link, or accepting an explicit request from a Web App sent by the method `requestWriteAccess `__ + + connected_website (``str``, *optional*): + The domain name of the website on which the user has logged in. `More about Telegram Login `__ + + contact_registered (:obj:`~pyrogram.types.ContactRegistered`, *optional*): + Service message: contact registered in Telegram. + + screenshot_taken ((:obj:`~pyrogram.types.ScreenshotTaken`, *optional*): + Service message: screenshot of a message in the chat has been taken. business_connection_id (``str``, *optional*): Unique identifier of the business connection from which the message was received. @@ -413,7 +452,7 @@ class Message(Object, Update): Generate a link to this message, only for groups and channels. """ - # TODO: Add game missing field, connected_website + # TODO: Add game missing field def __init__( self, @@ -422,8 +461,15 @@ class Message(Object, Update): id: int, from_user: "types.User" = None, sender_chat: "types.Chat" = None, + sender_boost_count: int = None, + sender_business_bot: "types.User" = None, date: datetime = None, chat: "types.Chat" = None, + topic_message: bool = None, + automatic_forward: bool = None, + from_offline: bool = None, + show_caption_above_media: bool = None, + quote: bool = None, topic: "types.ForumTopic" = None, forward_from: "types.User" = None, forward_sender_name: str = None, @@ -446,7 +492,6 @@ class Message(Object, Update): from_scheduled: bool = None, media: "enums.MessageMediaType" = None, paid_media: "types.PaidMediaInfo" = None, - show_caption_above_media: bool = None, edit_date: datetime = None, edit_hidden: bool = None, media_group_id: int = None, @@ -465,7 +510,8 @@ class Message(Object, Update): animation: "types.Animation" = None, game: "types.Game" = None, giveaway: "types.Giveaway" = None, - giveaway_result: "types.GiveawayResult" = None, + giveaway_winners: "types.GiveawayWinners" = None, + giveaway_completed: "types.GiveawayCompleted" = None, invoice: "types.Invoice" = None, story: "types.Story" = None, video: "types.Video" = None, @@ -479,9 +525,9 @@ class Message(Object, Update): web_page: "types.WebPage" = None, poll: "types.Poll" = None, dice: "types.Dice" = None, - stars_amount: int = None, new_chat_members: List["types.User"] = None, left_chat_member: "types.User" = None, + chat_join_type: "enums.ChatJoinType" = None, new_chat_title: str = None, new_chat_photo: "types.Photo" = None, delete_chat_photo: bool = None, @@ -494,10 +540,8 @@ class Message(Object, Update): game_high_score: int = None, views: int = None, forwards: int = None, - sender_boost_count: int = None, via_bot: "types.User" = None, outgoing: bool = None, - quote: bool = None, matches: List[Match] = None, command: List[str] = None, forum_topic_created: "types.ForumTopicCreated" = None, @@ -510,15 +554,21 @@ class Message(Object, Update): video_chat_started: "types.VideoChatStarted" = None, video_chat_ended: "types.VideoChatEnded" = None, video_chat_members_invited: "types.VideoChatMembersInvited" = None, + phone_call_started: "types.PhoneCallStarted" = None, + phone_call_ended: "types.PhoneCallEnded" = None, web_app_data: "types.WebAppData" = None, gift_code: "types.GiftCode" = None, star_gift: "types.StarGift" = None, requested_chats: "types.RequestedChats" = None, successful_payment: "types.SuccessfulPayment" = None, - giveaway_launched: bool = None, + refunded_payment: "types.RefundedPayment" = None, + giveaway_created: bool = None, chat_ttl_period: int = None, boosts_applied: int = None, - join_request_approved: bool = None, + write_access_allowed: "types.WriteAccessAllowed" = None, + connected_website: str = None, + contact_registered: "types.ContactRegistered" = None, + screenshot_taken: "types.ScreenshotTaken" = None, business_connection_id: str = None, reply_markup: Union[ "types.InlineKeyboardMarkup", @@ -534,8 +584,15 @@ class Message(Object, Update): self.id = id self.from_user = from_user self.sender_chat = sender_chat + self.sender_boost_count = sender_boost_count + self.sender_business_bot = sender_business_bot self.date = date self.chat = chat + self.topic_message = topic_message + self.automatic_forward = automatic_forward + self.from_offline = from_offline + self.show_caption_above_media = show_caption_above_media + self.quote = quote self.topic = topic self.forward_from = forward_from self.forward_sender_name = forward_sender_name @@ -558,7 +615,6 @@ class Message(Object, Update): self.from_scheduled = from_scheduled self.media = media self.paid_media = paid_media - self.show_caption_above_media = show_caption_above_media self.edit_date = edit_date self.edit_hidden = edit_hidden self.media_group_id = media_group_id @@ -577,7 +633,8 @@ class Message(Object, Update): self.animation = animation self.game = game self.giveaway = giveaway - self.giveaway_result = giveaway_result + self.giveaway_winners = giveaway_winners + self.giveaway_completed = giveaway_completed self.invoice = invoice self.story = story self.video = video @@ -591,9 +648,9 @@ class Message(Object, Update): self.web_page = web_page self.poll = poll self.dice = dice - self.stars_amount = stars_amount self.new_chat_members = new_chat_members self.left_chat_member = left_chat_member + self.chat_join_type = chat_join_type self.new_chat_title = new_chat_title self.new_chat_photo = new_chat_photo self.delete_chat_photo = delete_chat_photo @@ -606,12 +663,11 @@ class Message(Object, Update): self.game_high_score = game_high_score self.views = views self.forwards = forwards - self.sender_boost_count = sender_boost_count self.via_bot = via_bot self.outgoing = outgoing - self.quote = quote self.matches = matches self.command = command + self.screenshot_taken = screenshot_taken self.business_connection_id = business_connection_id self.reply_markup = reply_markup self.forum_topic_created = forum_topic_created @@ -624,15 +680,20 @@ class Message(Object, Update): self.video_chat_started = video_chat_started self.video_chat_ended = video_chat_ended self.video_chat_members_invited = video_chat_members_invited + self.phone_call_started = phone_call_started + self.phone_call_ended = phone_call_ended self.web_app_data = web_app_data self.gift_code = gift_code self.star_gift = star_gift self.requested_chats = requested_chats self.successful_payment = successful_payment - self.giveaway_launched = giveaway_launched + self.refunded_payment = refunded_payment + self.giveaway_created = giveaway_created self.chat_ttl_period = chat_ttl_period self.boosts_applied = boosts_applied - self.join_request_approved = join_request_approved + self.write_access_allowed = write_access_allowed + self.connected_website = connected_website + self.contact_registered = contact_registered self.reactions = reactions self.raw = raw @@ -701,25 +762,38 @@ class Message(Object, Update): video_chat_started = None video_chat_ended = None video_chat_members_invited = None + phone_call_started = None + phone_call_ended = None web_app_data = None gift_code = None - giveaway_launched = None + giveaway_created = None requested_chats = None successful_payment = None + refunded_payment = None chat_ttl_period = None boosts_applied = None - join_request_approved = None - stars_amount = None star_gift = None + giveaway_completed = None + connected_website = None + write_access_allowed = None + screenshot_taken = None + chat_join_type = None + contact_registered = None service_type = None if isinstance(action, raw.types.MessageActionChatAddUser): new_chat_members = [types.User._parse(client, users[i]) for i in action.users] service_type = enums.MessageServiceType.NEW_CHAT_MEMBERS + chat_join_type = enums.ChatJoinType.BY_ADD elif isinstance(action, raw.types.MessageActionChatJoinedByLink): new_chat_members = [types.User._parse(client, users[utils.get_raw_peer_id(message.from_id)])] service_type = enums.MessageServiceType.NEW_CHAT_MEMBERS + chat_join_type = enums.ChatJoinType.BY_LINK + elif isinstance(action, raw.types.MessageActionChatJoinedByRequest): + new_chat_members = [types.User._parse(client, users[utils.get_raw_peer_id(message.from_id)])] + service_type = enums.MessageServiceType.NEW_CHAT_MEMBERS + chat_join_type = enums.ChatJoinType.BY_REQUEST elif isinstance(action, raw.types.MessageActionChatDeleteUser): left_chat_member = types.User._parse(client, users[action.user_id]) service_type = enums.MessageServiceType.LEFT_CHAT_MEMBERS @@ -780,13 +854,35 @@ class Message(Object, Update): elif isinstance(action, raw.types.MessageActionInviteToGroupCall): video_chat_members_invited = types.VideoChatMembersInvited._parse(client, action, users) service_type = enums.MessageServiceType.VIDEO_CHAT_MEMBERS_INVITED + elif isinstance(action, raw.types.MessageActionPhoneCall): + if action.reason: + phone_call_ended = types.PhoneCallEnded._parse(action) + service_type = enums.MessageServiceType.PHONE_CALL_ENDED + else: + phone_call_started = types.PhoneCallStarted._parse(action) + service_type = enums.MessageServiceType.PHONE_CALL_STARTED elif isinstance(action, raw.types.MessageActionWebViewDataSentMe): web_app_data = types.WebAppData._parse(action) service_type = enums.MessageServiceType.WEB_APP_DATA elif isinstance(action, raw.types.MessageActionGiveawayLaunch): - giveaway_launched = True - stars_amount = getattr(action, "stars", None) - service_type = enums.MessageServiceType.GIVEAWAY_LAUNCH + giveaway_created = await types.GiveawayCreated._parse(client, action) + service_type = enums.MessageServiceType.GIVEAWAY_CREATED + elif isinstance(action, raw.types.MessageActionGiveawayResults): + service_type = enums.MessageServiceType.GIVEAWAY_COMPLETED + giveaway_completed = await types.GiveawayCompleted._parse( + client, + action, + types.Chat._parse(client, message, users, chats, is_chat=True), + getattr( + getattr( + message, + "reply_to", + None + ), + "reply_to_msg_id", + None + ) + ) elif isinstance(action, raw.types.MessageActionGiftCode): gift_code = types.GiftCode._parse(client, action, users, chats) service_type = enums.MessageServiceType.GIFT_CODE @@ -794,20 +890,33 @@ class Message(Object, Update): requested_chats = types.RequestedChats._parse(client, action) service_type = enums.MessageServiceType.REQUESTED_CHAT elif isinstance(action, (raw.types.MessageActionPaymentSent, raw.types.MessageActionPaymentSentMe)): - successful_payment = types.SuccessfulPayment._parse(client, action) + successful_payment = types.SuccessfulPayment._parse(action) service_type = enums.MessageServiceType.SUCCESSFUL_PAYMENT + elif isinstance(action, raw.types.MessageActionPaymentRefunded): + refunded_payment = types.RefundedPayment._parse(action) + service_type = enums.MessageServiceType.REFUNDED_PAYMENT elif isinstance(action, raw.types.MessageActionSetMessagesTTL): chat_ttl_period = action.period service_type = enums.MessageServiceType.CHAT_TTL_CHANGED elif isinstance(action, raw.types.MessageActionBoostApply): boosts_applied = action.boosts service_type = enums.MessageServiceType.BOOST_APPLY - elif isinstance(action, raw.types.MessageActionChatJoinedByRequest): - join_request_approved = True - service_type = enums.MessageServiceType.JOIN_REQUEST_APPROVED elif isinstance(action, raw.types.MessageActionStarGift): star_gift = await types.StarGift._parse_action(client, message, users) service_type = enums.MessageServiceType.STAR_GIFT + elif isinstance(action, raw.types.MessageActionBotAllowed): + connected_website = getattr(action, "domain", None) + if connected_website: + service_type = enums.MessageServiceType.CONNECTED_WEBSITE + else: + write_access_allowed = types.WriteAccessAllowed._parse(action) + service_type = enums.MessageServiceType.WRITE_ACCESS_ALLOWED + elif isinstance(action, raw.types.MessageActionScreenshotTaken): + service_type = enums.MessageServiceType.SCREENSHOT_TAKEN + screenshot_taken = types.ScreenshotTaken() + elif isinstance(action, raw.types.MessageActionContactSignUp): + service_type = enums.MessageServiceType.CONTACT_REGISTERED + contact_registered = types.ContactRegistered() from_user = types.User._parse(client, users.get(user_id, None)) sender_chat = types.Chat._parse(client, message, users, chats, is_chat=False) if not from_user else None @@ -840,17 +949,24 @@ class Message(Object, Update): video_chat_started=video_chat_started, video_chat_ended=video_chat_ended, video_chat_members_invited=video_chat_members_invited, + phone_call_started=phone_call_started, + phone_call_ended=phone_call_ended, web_app_data=web_app_data, - giveaway_launched=giveaway_launched, + giveaway_created=giveaway_created, + giveaway_completed=giveaway_completed, gift_code=gift_code, star_gift=star_gift, - stars_amount=stars_amount, requested_chats=requested_chats, successful_payment=successful_payment, + refunded_payment=refunded_payment, chat_ttl_period=chat_ttl_period, boosts_applied=boosts_applied, - join_request_approved=join_request_approved, + chat_join_type=chat_join_type, business_connection_id=business_connection_id, + connected_website=connected_website, + write_access_allowed=write_access_allowed, + contact_registered=contact_registered, + screenshot_taken=screenshot_taken, raw=message, client=client # TODO: supergroup_chat_created @@ -885,6 +1001,7 @@ class Message(Object, Update): client.message_cache[(parsed_message.chat.id, parsed_message.id)] = parsed_message if message.reply_to and message.reply_to.forum_topic: + parsed_message.topic_message = True if message.reply_to.reply_to_top_id: parsed_message.message_thread_id = message.reply_to.reply_to_top_id else: @@ -928,7 +1045,7 @@ class Message(Object, Update): venue = None game = None giveaway = None - giveaway_result = None + giveaway_winners = None invoice = None story = None audio = None @@ -969,8 +1086,8 @@ class Message(Object, Update): giveaway = types.Giveaway._parse(client, media, chats) media_type = enums.MessageMediaType.GIVEAWAY elif isinstance(media, raw.types.MessageMediaGiveawayResults): - giveaway_result = await types.GiveawayResult._parse(client, media, users, chats) - media_type = enums.MessageMediaType.GIVEAWAY_RESULT + giveaway_winners = await types.GiveawayWinners._parse(client, media, users, chats) + media_type = enums.MessageMediaType.GIVEAWAY_WINNERS elif isinstance(media, raw.types.MessageMediaInvoice): invoice = types.Invoice._parse(client, media) media_type = enums.MessageMediaType.INVOICE @@ -1098,6 +1215,10 @@ class Message(Object, Update): chat=types.Chat._parse(client, message, users, chats, is_chat=True), from_user=from_user, sender_chat=sender_chat, + sender_business_bot=types.User._parse( + client, + users.get(getattr(message, "via_business_bot_id", None)) + ), text=( Str(message.message).init(entities) or None if media is None or web_page is not None @@ -1145,7 +1266,7 @@ class Message(Object, Update): animation=animation, game=game, giveaway=giveaway, - giveaway_result=giveaway_result, + giveaway_winners=giveaway_winners, invoice=invoice, story=story, video=video, @@ -1164,6 +1285,7 @@ class Message(Object, Update): business_connection_id=business_connection_id, reply_markup=reply_markup, reactions=reactions, + from_offline=getattr(message, "offline", None), raw=message, client=client ) @@ -1171,12 +1293,26 @@ class Message(Object, Update): if any((isinstance(entity, raw.types.MessageEntityBlockquote) for entity in message.entities)): parsed_message.quote = True + if ( + forward_header and + forward_header.saved_from_peer and + forward_header.saved_from_msg_id + ): + saved_from_peer_id = utils.get_raw_peer_id(forward_header.saved_from_peer) + saved_from_peer_chat = chats.get(saved_from_peer_id) + if ( + isinstance(saved_from_peer_chat, raw.types.Channel) and + not saved_from_peer_chat.megagroup + ): + parsed_message.automatic_forward = True + if message.reply_to: if isinstance(message.reply_to, raw.types.MessageReplyHeader): parsed_message.reply_to_message_id = getattr(message.reply_to, "reply_to_msg_id", None) parsed_message.reply_to_top_message_id = getattr(message.reply_to, "reply_to_top_id", None) if message.reply_to.forum_topic: + parsed_message.topic_message = True if message.reply_to.reply_to_top_id: parsed_message.message_thread_id = message.reply_to.reply_to_top_id else: diff --git a/pyrogram/types/messages_and_media/refunded_payment.py b/pyrogram/types/messages_and_media/refunded_payment.py new file mode 100644 index 00000000..f9728b14 --- /dev/null +++ b/pyrogram/types/messages_and_media/refunded_payment.py @@ -0,0 +1,81 @@ +# 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 pyrogram import raw + +from ..object import Object + + +class RefundedPayment(Object): + """This object contains basic information about a refunded payment. + + Parameters: + currency (``str``): + Three-letter ISO 4217 `currency `_ code, or ``XTR`` for payments in `Telegram Stars `_. + + total_amount (``int``): + Total price in the smallest units of the currency (integer, **not** float/double). For example, for a price of ``US$ 1.45`` pass ``amount = 145``. See the __exp__ parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). + + invoice_payload (``str``): + Bot specified invoice payload. Only available to the bot that received the payment. + + telegram_payment_charge_id (``str``): + Telegram payment identifier. Only available to the bot that received the payment. + + provider_payment_charge_id (``str``): + Provider payment identifier. Only available to the bot that received the payment. + """ + + def __init__( + self, + *, + currency: str, + total_amount: str, + invoice_payload: str, + telegram_payment_charge_id: str, + provider_payment_charge_id: str + ): + + super().__init__() + + self.currency = currency + self.total_amount = total_amount + self.invoice_payload = invoice_payload + self.telegram_payment_charge_id = telegram_payment_charge_id + self.provider_payment_charge_id = provider_payment_charge_id + + @staticmethod + def _parse( + refunded_payment: "raw.types.MessageActionPaymentRefunded" + ) -> "RefundedPayment": + invoice_payload = None + + # Try to decode invoice payload into string. If that fails, fallback to bytes instead of decoding by + # ignoring/replacing errors, this way, button clicks will still work. + try: + invoice_payload = refunded_payment.payload.decode() + except (UnicodeDecodeError, AttributeError): + invoice_payload = getattr(refunded_payment, "payload", None) + + return RefundedPayment( + currency=refunded_payment.currency, + total_amount=refunded_payment.total_amount, + invoice_payload=invoice_payload, + telegram_payment_charge_id=refunded_payment.charge.id, + provider_payment_charge_id=refunded_payment.charge.provider_charge_id + ) diff --git a/pyrogram/types/messages_and_media/screenshot_taken.py b/pyrogram/types/messages_and_media/screenshot_taken.py new file mode 100644 index 00000000..d41232f0 --- /dev/null +++ b/pyrogram/types/messages_and_media/screenshot_taken.py @@ -0,0 +1,29 @@ +# 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 ..object import Object + + +class ScreenshotTaken(Object): + """A service message that a screenshot of a message in the chat has been taken. + + Currently holds no information. + """ + + def __init__(self): + super().__init__() diff --git a/pyrogram/types/messages_and_media/star_gift.py b/pyrogram/types/messages_and_media/star_gift.py index 94d3a531..420c641e 100644 --- a/pyrogram/types/messages_and_media/star_gift.py +++ b/pyrogram/types/messages_and_media/star_gift.py @@ -36,10 +36,10 @@ class StarGift(Object): sticker (:obj:`~pyrogram.types.Sticker`): Information about the star gift sticker. - text (``str``, *optional*): + caption (``str``, *optional*): Text message. - entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text. message_id (``int``, *optional*): @@ -81,8 +81,8 @@ class StarGift(Object): client: "pyrogram.Client" = None, id: int, sticker: "types.Sticker", - text: Optional[str] = None, - entities: List["types.MessageEntity"] = None, + caption: Optional[str] = None, + caption_entities: List["types.MessageEntity"] = None, message_id: Optional[int] = None, date: Optional[datetime] = None, from_user: Optional["types.User"] = None, @@ -98,8 +98,8 @@ class StarGift(Object): self.id = id self.sticker = sticker - self.text = text - self.entities = entities + self.caption = caption + self.caption_entities = caption_entities self.message_id = message_id self.date = date self.from_user = from_user @@ -139,6 +139,12 @@ class StarGift(Object): doc = user_star_gift.gift.sticker attributes = {type(i): i for i in doc.attributes} + message, entities = ( + utils.parse_text_with_entities( + client, getattr(user_star_gift, "message", None), users + ) + ).values() + return StarGift( id=user_star_gift.gift.id, sticker=await types.Sticker._parse(client, doc, attributes), @@ -152,7 +158,8 @@ class StarGift(Object): is_saved=not user_star_gift.unsaved if getattr(user_star_gift, "unsaved", None) else None, from_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), - **utils.parse_text_with_entities(client, getattr(user_star_gift, "message", None), users), + caption=message, + caption_entities=entities, client=client ) @@ -167,6 +174,12 @@ class StarGift(Object): doc = action.gift.sticker attributes = {type(i): i for i in doc.attributes} + message, entities = ( + utils.parse_text_with_entities( + client, getattr(action, "message", None), users + ) + ).values() + return StarGift( id=action.gift.id, sticker=await types.Sticker._parse(client, doc, attributes), @@ -180,12 +193,13 @@ class StarGift(Object): is_saved=getattr(action, "saved", None), from_user=types.User._parse(client, users.get(utils.get_raw_peer_id(message.peer_id))), message_id=message.id, - **utils.parse_text_with_entities(client, getattr(action, "message", None), users), + caption=message, + caption_entities=entities, client=client ) - async def save(self) -> bool: - """Bound method *save* of :obj:`~pyrogram.types.StarGift`. + async def show(self) -> bool: + """Bound method *show* of :obj:`~pyrogram.types.StarGift`. Use as a shortcut for: @@ -199,7 +213,7 @@ class StarGift(Object): Example: .. code-block:: python - await star_gift.save() + await star_gift.show() Returns: ``bool``: On success, True is returned. diff --git a/pyrogram/types/messages_and_media/successful_payment.py b/pyrogram/types/messages_and_media/successful_payment.py index 53ff98ce..90ae415a 100644 --- a/pyrogram/types/messages_and_media/successful_payment.py +++ b/pyrogram/types/messages_and_media/successful_payment.py @@ -86,7 +86,6 @@ class SuccessfulPayment(Object): @staticmethod def _parse( - client: "pyrogram.Client", successful_payment: Union[ "raw.types.MessageActionPaymentSent", "raw.types.MessageActionPaymentSentMe" diff --git a/pyrogram/types/messages_and_media/write_access_allowed.py b/pyrogram/types/messages_and_media/write_access_allowed.py new file mode 100644 index 00000000..ce88286a --- /dev/null +++ b/pyrogram/types/messages_and_media/write_access_allowed.py @@ -0,0 +1,57 @@ +# 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 pyrogram import raw +from ..object import Object + + +class WriteAccessAllowed(Object): + """This object represents a service message about a user allowing a bot to write messages after adding it to the attachment menu, launching a Web App from a link, or accepting an explicit request from a Web App sent by the method `requestWriteAccess `__. + + Parameters: + from_request (``bool``, *optional*): + True, if the access was granted after the user accepted an explicit request from a Web App sent by the method `requestWriteAccess `__ + + web_app_name (``str``, *optional*): + Name of the Web App, if the access was granted when the Web App was launched from a link + + from_attachment_menu (``bool``, *optional*): + True, if the access was granted when the bot was added to the attachment or side menu + + """ + + def __init__( + self, + *, + from_request: bool = None, + web_app_name: str = None, + from_attachment_menu: bool = None, + ): + super().__init__() + + self.from_request = from_request + self.web_app_name = web_app_name + self.from_attachment_menu = from_attachment_menu + + @staticmethod + def _parse(action: "raw.types.MessageActionBotAllowed"): + return WriteAccessAllowed( + from_request=action.from_request if action.from_request else None, + web_app_name=action.app.short_name if action.app is not None else None, + from_attachment_menu=action.attach_menu if action.attach_menu else None, + ) diff --git a/pyrogram/types/user_and_chats/__init__.py b/pyrogram/types/user_and_chats/__init__.py index 756304cc..b14caefa 100644 --- a/pyrogram/types/user_and_chats/__init__.py +++ b/pyrogram/types/user_and_chats/__init__.py @@ -43,6 +43,8 @@ from .folder import Folder from .found_contacts import FoundContacts from .group_call_member import GroupCallMember from .invite_link_importer import InviteLinkImporter +from .phone_call_ended import PhoneCallEnded +from .phone_call_started import PhoneCallStarted from .privacy_rule import PrivacyRule from .restriction import Restriction from .user import User @@ -72,6 +74,8 @@ __all__ = [ "ChatEventFilter", "ChatInviteLink", "InviteLinkImporter", + "PhoneCallEnded", + "PhoneCallStarted", "PrivacyRule", "ChatAdminWithInviteLinks", "ChatColor", diff --git a/pyrogram/types/user_and_chats/phone_call_ended.py b/pyrogram/types/user_and_chats/phone_call_ended.py new file mode 100644 index 00000000..8705fc42 --- /dev/null +++ b/pyrogram/types/user_and_chats/phone_call_ended.py @@ -0,0 +1,63 @@ +# 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 + +from pyrogram import raw, enums +from ..object import Object + + +class PhoneCallEnded(Object): + """A service message about a phone_call ended in the chat. + + Parameters: + id (``int``): + Unique call identifier. + + is_video (``bool``): + True, if call was a video call. + + reason (:obj:`~pyrogram.enums.PhoneCallDiscardReason`): + The reason enumeration why the call was discarded. + + duration (``int``, *optional*): + Voice chat duration; in seconds. + """ + + def __init__( + self, *, + id: int, + is_video: bool, + reason: "enums.PhoneCallDiscardReason", + duration: Optional[int] = None + ): + super().__init__() + + self.id = id + self.is_video = is_video + self.reason = reason + self.duration = duration + + @staticmethod + def _parse(action: "raw.types.MessageActionPhoneCall") -> "PhoneCallEnded": + return PhoneCallEnded( + id=action.call_id, + is_video=action.video, + reason=enums.PhoneCallDiscardReason(type(action.reason)), + duration=getattr(action, "duration", None) + ) diff --git a/pyrogram/types/user_and_chats/phone_call_started.py b/pyrogram/types/user_and_chats/phone_call_started.py new file mode 100644 index 00000000..11b0dc2a --- /dev/null +++ b/pyrogram/types/user_and_chats/phone_call_started.py @@ -0,0 +1,49 @@ +# 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 pyrogram import raw +from ..object import Object + + +class PhoneCallStarted(Object): + """A service message about a phone_call started in the chat. + + Parameters: + id (``int``): + Unique call identifier. + + is_video (``bool``): + True, if call was a video call. + """ + + def __init__( + self, *, + id: int, + is_video: bool + ): + super().__init__() + + self.id = id + self.is_video = is_video + + @staticmethod + def _parse(action: "raw.types.MessageActionPhoneCall") -> "PhoneCallStarted": + return PhoneCallStarted( + id=action.call_id, + is_video=action.video + ) diff --git a/pyrogram/utils.py b/pyrogram/utils.py index 9fe5f0a2..e1db0a27 100644 --- a/pyrogram/utils.py +++ b/pyrogram/utils.py @@ -31,10 +31,8 @@ from typing import Union, List, Dict, Optional import pyrogram from pyrogram import raw, enums from pyrogram import types -from pyrogram.errors import AuthBytesInvalid +from pyrogram.types.messages_and_media.message import Str from pyrogram.file_id import FileId, FileType, PHOTO_TYPES, DOCUMENT_TYPES -from pyrogram.session import Session -from pyrogram.session.auth import Auth async def ainput(prompt: str = "", *, hide: bool = False): @@ -501,15 +499,17 @@ def get_first_url(text): def parse_text_with_entities(client, message: "raw.types.TextWithEntities", users): + entities = types.List( + filter( + lambda x: x is not None, + [ + types.MessageEntity._parse(client, entity, users) + for entity in getattr(message, "entities", []) + ] + ) + ) + return { - "text": getattr(message, "text", None), - "entities": types.List( - filter( - lambda x: x is not None, - [ - types.MessageEntity._parse(client, entity, users) - for entity in getattr(message, "entities", []) - ] - ) - ) or None + "text": Str(getattr(message, "text", "")).init(entities) or None, + "entities": entities or None }