From 0b51acefe9b6c461704470c1b8ff3d1fbff7784d Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Dec 2023 21:03:11 +0300 Subject: [PATCH] Add td_api::messagePremiumGiveawayWinners. --- td/generate/scheme/td_api.tl | 16 +- td/telegram/DialogAction.cpp | 1 + td/telegram/MessageContent.cpp | 236 ++++++++++++++++++++++++++++- td/telegram/MessageContentType.cpp | 6 + td/telegram/MessageContentType.h | 3 +- td/telegram/MessagesManager.cpp | 1 + td/telegram/RepliedMessageInfo.cpp | 1 + 7 files changed, 259 insertions(+), 5 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 061f76623..e75896f0d 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2908,12 +2908,26 @@ messagePremiumGiveawayCreated = MessageContent; //@sticker A sticker to be shown in the message; may be null if unknown messagePremiumGiveaway parameters:premiumGiveawayParameters winner_count:int32 month_count:int32 sticker:sticker = MessageContent; -//@description A Telegram Premium giveaway has been completed for the chat +//@description A Telegram Premium giveaway without public winners has been completed for the chat //@giveaway_message_id Identifier of the message with the giveaway; can be 0 if the message was deleted //@winner_count Number of winners in the giveaway //@unclaimed_prize_count Number of undistributed prizes messagePremiumGiveawayCompleted giveaway_message_id:int53 winner_count:int32 unclaimed_prize_count:int32 = MessageContent; +//@description A Telegram Premium giveaway with public winners has been completed for the chat +//@boosted_chat_id Identifier of the channel chat, which was automatically boosted by the winners of the giveaway for duration of the Premium subscription +//@giveaway_message_id Identifier of the message with the giveaway in the boosted chat +//@additional_chat_count Number of other chats that participated in the giveaway +//@actual_winners_selection_date Point in time (Unix timestamp) when the winners were selected. May be bigger than winners selection date specified in parameters of the giveaway +//@only_new_members True, if only new members of the chats were eligible for the giveaway +//@was_refunded True, if the giveaway was canceled and was fully refunded +//@month_count Number of month the Telegram Premium subscription will be active after code activation +//@prize_description Additional description of the giveaway prize +//@winner_count Total number of winners in the giveaway +//@winner_user_ids Up to 100 user identifiers of the winners of the giveaway +//@unclaimed_prize_count Number of undistributed prizes +messagePremiumGiveawayWinners boosted_chat_id:int53 giveaway_message_id:int53 additional_chat_count:int32 actual_winners_selection_date:int32 only_new_members:Bool was_refunded:Bool month_count:int32 prize_description:string winner_count:int32 winner_user_ids:vector unclaimed_prize_count:int32 = MessageContent; + //@description A contact has registered with Telegram messageContactRegistered = MessageContent; diff --git a/td/telegram/DialogAction.cpp b/td/telegram/DialogAction.cpp index bb58e56b1..ddc0fdd6b 100644 --- a/td/telegram/DialogAction.cpp +++ b/td/telegram/DialogAction.cpp @@ -417,6 +417,7 @@ bool DialogAction::is_canceled_by_message_of_type(MessageContentType message_con case MessageContentType::Giveaway: case MessageContentType::GiveawayLaunch: case MessageContentType::GiveawayResults: + case MessageContentType::GiveawayWinners: return false; default: UNREACHABLE(); diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 2917a3e6e..d2d99f906 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -498,7 +498,7 @@ class MessageChatSetTtl final : public MessageContent { class MessageUnsupported final : public MessageContent { public: - static constexpr int32 CURRENT_VERSION = 25; + static constexpr int32 CURRENT_VERSION = 26; int32 version = CURRENT_VERSION; MessageUnsupported() = default; @@ -1032,6 +1032,43 @@ class MessageGiveawayResults final : public MessageContent { } }; +class MessageGiveawayWinners final : public MessageContent { + public: + MessageId giveaway_message_id; + ChannelId boosted_channel_id; + int32 additional_dialog_count = 0; + int32 month_count = 0; + string prize_description; + int32 winners_selection_date = 0; + bool only_new_subscribers = false; + bool was_refunded = false; + int32 winner_count = 0; + int32 unclaimed_count = 0; + vector winner_user_ids; + + MessageGiveawayWinners() = default; + MessageGiveawayWinners(MessageId giveaway_message_id, ChannelId boosted_channel_id, int32 additional_dialog_count, + int32 month_count, string &&prize_description, int32 winners_selection_date, + bool only_new_subscribers, bool was_refunded, int32 winner_count, int32 unclaimed_count, + vector &&winner_user_ids) + : giveaway_message_id(giveaway_message_id) + , boosted_channel_id(boosted_channel_id) + , additional_dialog_count(additional_dialog_count) + , month_count(month_count) + , prize_description(std::move(prize_description)) + , winners_selection_date(winners_selection_date) + , only_new_subscribers(only_new_subscribers) + , was_refunded(was_refunded) + , winner_count(winner_count) + , unclaimed_count(unclaimed_count) + , winner_user_ids(std::move(winner_user_ids)) { + } + + MessageContentType get_type() const final { + return MessageContentType::GiveawayWinners; + } +}; + template static void store(const MessageContent *content, StorerT &storer) { CHECK(content != nullptr); @@ -1516,6 +1553,59 @@ static void store(const MessageContent *content, StorerT &storer) { } break; } + case MessageContentType::GiveawayWinners: { + const auto *m = static_cast(content); + bool has_giveaway_message_id = m->giveaway_message_id.is_valid(); + bool has_boosted_channel_id = m->boosted_channel_id.is_valid(); + bool has_additional_dialog_count = m->additional_dialog_count != 0; + bool has_month_count = m->month_count != 0; + bool has_prize_description = !m->prize_description.empty(); + bool has_winners_selection_date = m->winners_selection_date != 0; + bool has_winner_count = m->winner_count != 0; + bool has_unclaimed_count = m->unclaimed_count != 0; + bool has_winner_user_ids = !m->winner_user_ids.empty(); + BEGIN_STORE_FLAGS(); + STORE_FLAG(m->only_new_subscribers); + STORE_FLAG(m->was_refunded); + STORE_FLAG(has_giveaway_message_id); + STORE_FLAG(has_boosted_channel_id); + STORE_FLAG(has_additional_dialog_count); + STORE_FLAG(has_month_count); + STORE_FLAG(has_prize_description); + STORE_FLAG(has_winners_selection_date); + STORE_FLAG(has_winner_count); + STORE_FLAG(has_unclaimed_count); + STORE_FLAG(has_winner_user_ids); + END_STORE_FLAGS(); + if (has_giveaway_message_id) { + store(m->giveaway_message_id, storer); + } + if (has_boosted_channel_id) { + store(m->boosted_channel_id, storer); + } + if (has_additional_dialog_count) { + store(m->additional_dialog_count, storer); + } + if (has_month_count) { + store(m->month_count, storer); + } + if (has_prize_description) { + store(m->prize_description, storer); + } + if (has_winners_selection_date) { + store(m->winners_selection_date, storer); + } + if (has_winner_count) { + store(m->winner_count, storer); + } + if (has_unclaimed_count) { + store(m->unclaimed_count, storer); + } + if (has_winner_user_ids) { + store(m->winner_user_ids, storer); + } + break; + } default: UNREACHABLE(); } @@ -2156,6 +2246,63 @@ static void parse(unique_ptr &content, ParserT &parser) { content = std::move(m); break; } + case MessageContentType::GiveawayWinners: { + auto m = make_unique(); + bool has_giveaway_message_id; + bool has_boosted_channel_id; + bool has_additional_dialog_count; + bool has_month_count; + bool has_prize_description; + bool has_winners_selection_date; + bool has_winner_count; + bool has_unclaimed_count; + bool has_winner_user_ids; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(m->only_new_subscribers); + PARSE_FLAG(m->was_refunded); + PARSE_FLAG(has_giveaway_message_id); + PARSE_FLAG(has_boosted_channel_id); + PARSE_FLAG(has_additional_dialog_count); + PARSE_FLAG(has_month_count); + PARSE_FLAG(has_prize_description); + PARSE_FLAG(has_winners_selection_date); + PARSE_FLAG(has_winner_count); + PARSE_FLAG(has_unclaimed_count); + PARSE_FLAG(has_winner_user_ids); + END_PARSE_FLAGS(); + if (has_giveaway_message_id) { + parse(m->giveaway_message_id, parser); + } + if (has_boosted_channel_id) { + parse(m->boosted_channel_id, parser); + } + if (has_additional_dialog_count) { + parse(m->additional_dialog_count, parser); + } + if (has_month_count) { + parse(m->month_count, parser); + } + if (has_prize_description) { + parse(m->prize_description, parser); + } + if (has_winners_selection_date) { + parse(m->winners_selection_date, parser); + } + if (has_winner_count) { + parse(m->winner_count, parser); + } + if (has_unclaimed_count) { + parse(m->unclaimed_count, parser); + } + if (has_winner_user_ids) { + parse(m->winner_user_ids, parser); + } + if (m->winner_count < 0 || m->unclaimed_count < 0) { + is_bad = true; + } + content = std::move(m); + break; + } default: is_bad = true; @@ -2770,6 +2917,7 @@ bool can_have_input_media(const Td *td, const MessageContent *content, bool is_s return td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read) != nullptr; } case MessageContentType::Giveaway: + case MessageContentType::GiveawayWinners: return is_server; case MessageContentType::Unsupported: case MessageContentType::ChatCreate: @@ -2951,6 +3099,7 @@ SecretInputMedia get_secret_input_media(const MessageContent *content, Td *td, case MessageContentType::Giveaway: case MessageContentType::GiveawayLaunch: case MessageContentType::GiveawayResults: + case MessageContentType::GiveawayWinners: break; default: UNREACHABLE(); @@ -3088,6 +3237,7 @@ static tl_object_ptr get_input_media_impl( case MessageContentType::Giveaway: case MessageContentType::GiveawayLaunch: case MessageContentType::GiveawayResults: + case MessageContentType::GiveawayWinners: break; default: UNREACHABLE(); @@ -3289,6 +3439,7 @@ void delete_message_content_thumbnail(MessageContent *content, Td *td) { case MessageContentType::Giveaway: case MessageContentType::GiveawayLaunch: case MessageContentType::GiveawayResults: + case MessageContentType::GiveawayWinners: break; default: UNREACHABLE(); @@ -3370,6 +3521,14 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten return Status::Error(400, "Giveaways can't be sent to secret chats"); } break; + case MessageContentType::GiveawayWinners: + if (!permissions.can_send_messages()) { + return Status::Error(400, "Not enough rights to send giveaway winners to the chat"); + } + if (dialog_type == DialogType::SecretChat) { + return Status::Error(400, "Giveaway winners can't be sent to secret chats"); + } + break; case MessageContentType::Invoice: if (!permissions.can_send_messages()) { return Status::Error(400, "Not enough rights to send invoice messages to the chat"); @@ -3646,6 +3805,7 @@ static int32 get_message_content_media_index_mask(const MessageContent *content, case MessageContentType::Giveaway: case MessageContentType::GiveawayLaunch: case MessageContentType::GiveawayResults: + case MessageContentType::GiveawayWinners: return 0; default: UNREACHABLE(); @@ -3919,6 +4079,10 @@ vector get_message_content_min_user_ids(const Td *td, const MessageConte break; case MessageContentType::GiveawayResults: break; + case MessageContentType::GiveawayWinners: { + const auto *content = static_cast(message_content); + return content->winner_user_ids; + } default: UNREACHABLE(); break; @@ -3959,6 +4123,10 @@ vector get_message_content_min_channel_ids(const Td *td, const Messag const auto *content = static_cast(message_content); return content->giveaway_parameters.get_channel_ids(); } + case MessageContentType::GiveawayWinners: { + const auto *content = static_cast(message_content); + return {content->boosted_channel_id}; + } default: break; } @@ -4316,6 +4484,7 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo case MessageContentType::Giveaway: case MessageContentType::GiveawayLaunch: case MessageContentType::GiveawayResults: + case MessageContentType::GiveawayWinners: break; default: UNREACHABLE(); @@ -4462,6 +4631,7 @@ bool merge_message_content_file_id(Td *td, MessageContent *message_content, File case MessageContentType::Giveaway: case MessageContentType::GiveawayLaunch: case MessageContentType::GiveawayResults: + case MessageContentType::GiveawayWinners: LOG(ERROR) << "Receive new file " << new_file_id << " in a sent message of the type " << content_type; break; default: @@ -4970,6 +5140,20 @@ void compare_message_contents(Td *td, const MessageContent *old_content, const M } break; } + case MessageContentType::GiveawayWinners: { + const auto *lhs = static_cast(old_content); + const auto *rhs = static_cast(new_content); + if (lhs->giveaway_message_id != rhs->giveaway_message_id || lhs->boosted_channel_id != rhs->boosted_channel_id || + lhs->additional_dialog_count != rhs->additional_dialog_count || lhs->month_count != rhs->month_count || + lhs->prize_description != rhs->prize_description || + lhs->winners_selection_date != rhs->winners_selection_date || + lhs->only_new_subscribers != rhs->only_new_subscribers || lhs->was_refunded != rhs->was_refunded || + lhs->winner_count != rhs->winner_count || lhs->unclaimed_count != rhs->unclaimed_count || + lhs->winner_user_ids != rhs->winner_user_ids) { + need_update = true; + } + break; + } default: UNREACHABLE(); break; @@ -5796,8 +5980,31 @@ unique_ptr get_message_content(Td *td, FormattedText message, std::move(media->prize_description_)}, media->quantity_, media->months_); } - case telegram_api::messageMediaGiveawayResults::ID: - return make_unique(); + case telegram_api::messageMediaGiveawayResults::ID: { + auto media = move_tl_object_as(media_ptr); + auto giveaway_message_id = MessageId(ServerMessageId(media->launch_msg_id_)); + auto boosted_channel_id = ChannelId(media->channel_id_); + if (!giveaway_message_id.is_valid() || !boosted_channel_id.is_valid() || media->additional_peers_count_ < 0 || + media->months_ <= 0 || media->until_date_ <= 0 || media->winners_count_ < 0 || media->unclaimed_count_ < 0) { + LOG(ERROR) << "Receive " << to_string(media); + break; + } + td->messages_manager_->force_create_dialog(DialogId(boosted_channel_id), "messageMediaGiveawayResults", true); + vector winner_user_ids; + for (auto winner : media->winners_) { + UserId winner_user_id(winner); + if (winner_user_id.is_valid()) { + winner_user_ids.push_back(winner_user_id); + } else { + LOG(ERROR) << "Receive " << to_string(media); + break; + } + } + return td::make_unique( + giveaway_message_id, boosted_channel_id, media->additional_peers_count_, media->months_, + std::move(media->prize_description_), media->until_date_, media->only_new_subscribers_, media->refunded_, + media->winners_count_, media->unclaimed_count_, std::move(winner_user_ids)); + } case telegram_api::messageMediaUnsupported::ID: return make_unique(); default: @@ -5890,6 +6097,11 @@ unique_ptr dup_message_content(Td *td, DialogId dialog_id, const return nullptr; } return make_unique(*static_cast(content)); + case MessageContentType::GiveawayWinners: + if (type != MessageContentDupType::Forward) { + return nullptr; + } + return make_unique(*static_cast(content)); case MessageContentType::Invoice: if (type == MessageContentDupType::Copy) { return nullptr; @@ -6859,6 +7071,15 @@ tl_object_ptr get_message_content_object(const MessageCo return td_api::make_object(m->giveaway_message_id.get(), m->winner_count, m->unclaimed_count); } + case MessageContentType::GiveawayWinners: { + const auto *m = static_cast(content); + return td_api::make_object( + td->messages_manager_->get_chat_id_object(DialogId(m->boosted_channel_id), "messagePremiumGiveawayWinners"), + m->giveaway_message_id.get(), m->additional_dialog_count, m->winners_selection_date, m->only_new_subscribers, + m->was_refunded, m->month_count, m->prize_description, m->winner_count, + td->contacts_manager_->get_user_ids_object(m->winner_user_ids, "messagePremiumGiveawayWinners"), + m->unclaimed_count); + } default: UNREACHABLE(); return nullptr; @@ -7290,6 +7511,7 @@ string get_message_content_search_text(const Td *td, const MessageContent *conte case MessageContentType::Giveaway: case MessageContentType::GiveawayLaunch: case MessageContentType::GiveawayResults: + case MessageContentType::GiveawayWinners: return string(); default: UNREACHABLE(); @@ -7612,6 +7834,14 @@ void add_message_content_dependencies(Dependencies &dependencies, const MessageC break; case MessageContentType::GiveawayResults: break; + case MessageContentType::GiveawayWinners: { + const auto *content = static_cast(message_content); + dependencies.add_dialog_and_dependencies(DialogId(content->boosted_channel_id)); + for (auto &user_id : content->winner_user_ids) { + dependencies.add(user_id); + } + break; + } default: UNREACHABLE(); break; diff --git a/td/telegram/MessageContentType.cpp b/td/telegram/MessageContentType.cpp index be3755790..8acc7ea44 100644 --- a/td/telegram/MessageContentType.cpp +++ b/td/telegram/MessageContentType.cpp @@ -136,6 +136,8 @@ StringBuilder &operator<<(StringBuilder &string_builder, MessageContentType cont return string_builder << "GiveawayLaunch"; case MessageContentType::GiveawayResults: return string_builder << "GiveawayResults"; + case MessageContentType::GiveawayWinners: + return string_builder << "GiveawayWinners"; default: return string_builder << "Invalid type " << static_cast(content_type); } @@ -206,6 +208,7 @@ bool is_allowed_media_group_content(MessageContentType content_type) { case MessageContentType::Giveaway: case MessageContentType::GiveawayLaunch: case MessageContentType::GiveawayResults: + case MessageContentType::GiveawayWinners: return false; default: UNREACHABLE(); @@ -285,6 +288,7 @@ bool is_secret_message_content(int32 ttl, MessageContentType content_type) { case MessageContentType::Giveaway: case MessageContentType::GiveawayLaunch: case MessageContentType::GiveawayResults: + case MessageContentType::GiveawayWinners: return false; default: UNREACHABLE(); @@ -301,6 +305,7 @@ bool is_service_message_content(MessageContentType content_type) { case MessageContentType::Document: case MessageContentType::Game: case MessageContentType::Giveaway: + case MessageContentType::GiveawayWinners: case MessageContentType::Invoice: case MessageContentType::LiveLocation: case MessageContentType::Location: @@ -429,6 +434,7 @@ bool can_have_message_content_caption(MessageContentType content_type) { case MessageContentType::Giveaway: case MessageContentType::GiveawayLaunch: case MessageContentType::GiveawayResults: + case MessageContentType::GiveawayWinners: return false; default: UNREACHABLE(); diff --git a/td/telegram/MessageContentType.h b/td/telegram/MessageContentType.h index a91723969..16a513a11 100644 --- a/td/telegram/MessageContentType.h +++ b/td/telegram/MessageContentType.h @@ -75,7 +75,8 @@ enum class MessageContentType : int32 { GiftCode, Giveaway, GiveawayLaunch, - GiveawayResults + GiveawayResults, + GiveawayWinners }; // increase MessageUnsupported::CURRENT_VERSION each time a new message content type is added diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 733247c00..364c6f5e7 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -26525,6 +26525,7 @@ bool MessagesManager::can_edit_message(DialogId dialog_id, const Message *m, boo case MessageContentType::Contact: case MessageContentType::Dice: case MessageContentType::Giveaway: + case MessageContentType::GiveawayWinners: case MessageContentType::Location: case MessageContentType::Sticker: case MessageContentType::Venue: diff --git a/td/telegram/RepliedMessageInfo.cpp b/td/telegram/RepliedMessageInfo.cpp index 87431a973..d541f5bd1 100644 --- a/td/telegram/RepliedMessageInfo.cpp +++ b/td/telegram/RepliedMessageInfo.cpp @@ -118,6 +118,7 @@ RepliedMessageInfo::RepliedMessageInfo(Td *td, tl_object_ptr