From 1904aa77b13b2089d6018eac74e482d0a7b09097 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 21 Jun 2021 04:01:13 +0300 Subject: [PATCH] Add bot_commands to *Full. --- td/generate/scheme/td_api.tl | 6 +- td/telegram/BotCommand.h | 4 + td/telegram/ContactsManager.cpp | 128 +++++++++++++++++++++++--------- td/telegram/ContactsManager.h | 7 ++ 4 files changed, 109 insertions(+), 36 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 4a7ce7ade..713a52ad1 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -609,7 +609,8 @@ basicGroup id:int32 member_count:int32 status:ChatMemberStatus is_active:Bool up //@creator_user_id User identifier of the creator of the group; 0 if unknown //@members Group members //@invite_link Primary invite link for this group; may be null. For chat administrators with can_invite_users right only. Updated only after the basic group is opened -basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int32 members:vector invite_link:chatInviteLink = BasicGroupFullInfo; +//@bot_commands List of commands of bots in the group +basicGroupFullInfo photo:chatPhoto description:string creator_user_id:int32 members:vector invite_link:chatInviteLink bot_commands:vector = BasicGroupFullInfo; //@description Represents a supergroup or channel with zero or more members (subscribers in the case of channels). From the point of view of the system, a channel is a special kind of a supergroup: only administrators can post and see the list of members, and posts from all administrators use the name and photo of the channel instead of individual names and profile photos. Unlike supergroups, channels can have an unlimited number of subscribers @@ -649,9 +650,10 @@ supergroup id:int32 username:string date:int32 status:ChatMemberStatus member_co //@sticker_set_id Identifier of the supergroup sticker set; 0 if none //@location Location to which the supergroup is connected; may be null //@invite_link Primary invite link for this chat; may be null. For chat administrators with can_invite_users right only +//@bot_commands List of commands of bots in the group //@upgraded_from_basic_group_id Identifier of the basic group from which supergroup was upgraded; 0 if none //@upgraded_from_max_message_id Identifier of the last message in the basic group from which supergroup was upgraded; 0 if none -supergroupFullInfo photo:chatPhoto description:string member_count:int32 administrator_count:int32 restricted_count:int32 banned_count:int32 linked_chat_id:int53 slow_mode_delay:int32 slow_mode_delay_expires_in:double can_get_members:Bool can_set_username:Bool can_set_sticker_set:Bool can_set_location:Bool can_get_statistics:Bool is_all_history_available:Bool sticker_set_id:int64 location:chatLocation invite_link:chatInviteLink upgraded_from_basic_group_id:int32 upgraded_from_max_message_id:int53 = SupergroupFullInfo; +supergroupFullInfo photo:chatPhoto description:string member_count:int32 administrator_count:int32 restricted_count:int32 banned_count:int32 linked_chat_id:int53 slow_mode_delay:int32 slow_mode_delay_expires_in:double can_get_members:Bool can_set_username:Bool can_set_sticker_set:Bool can_set_location:Bool can_get_statistics:Bool is_all_history_available:Bool sticker_set_id:int64 location:chatLocation invite_link:chatInviteLink bot_commands:vector upgraded_from_basic_group_id:int32 upgraded_from_max_message_id:int53 = SupergroupFullInfo; //@class SecretChatState @description Describes the current secret chat state diff --git a/td/telegram/BotCommand.h b/td/telegram/BotCommand.h index a0d48fd82..33444f3b5 100644 --- a/td/telegram/BotCommand.h +++ b/td/telegram/BotCommand.h @@ -62,6 +62,10 @@ class BotCommands { td_api::object_ptr get_bot_commands_object(Td *td) const; + UserId get_bot_user_id() const { + return bot_user_id_; + } + template void store(StorerT &storer) const { td::store(bot_user_id_, storer); diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 8f1d669d8..61541057c 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -4100,12 +4100,14 @@ void ContactsManager::ChatFull::store(StorerT &storer) const { bool has_legacy_invite_link = false; bool has_photo = !photo.is_empty(); bool has_invite_link = invite_link.is_valid(); + bool has_bot_commands = !bot_commands.empty(); BEGIN_STORE_FLAGS(); STORE_FLAG(has_description); STORE_FLAG(has_legacy_invite_link); STORE_FLAG(can_set_username); STORE_FLAG(has_photo); STORE_FLAG(has_invite_link); + STORE_FLAG(has_bot_commands); END_STORE_FLAGS(); store(version, storer); store(creator_user_id, storer); @@ -4119,6 +4121,9 @@ void ContactsManager::ChatFull::store(StorerT &storer) const { if (has_invite_link) { store(invite_link, storer); } + if (has_bot_commands) { + store(bot_commands, storer); + } } template @@ -4128,12 +4133,14 @@ void ContactsManager::ChatFull::parse(ParserT &parser) { bool legacy_has_invite_link; bool has_photo; bool has_invite_link; + bool has_bot_commands; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_description); PARSE_FLAG(legacy_has_invite_link); PARSE_FLAG(can_set_username); PARSE_FLAG(has_photo); PARSE_FLAG(has_invite_link); + PARSE_FLAG(has_bot_commands); END_PARSE_FLAGS(); parse(version, parser); parse(creator_user_id, parser); @@ -4151,6 +4158,9 @@ void ContactsManager::ChatFull::parse(ParserT &parser) { if (has_invite_link) { parse(invite_link, parser); } + if (has_bot_commands) { + parse(bot_commands, parser); + } } template @@ -4341,6 +4351,7 @@ void ContactsManager::ChannelFull::store(StorerT &storer) const { bool has_photo = !photo.is_empty(); bool legacy_has_active_group_call_id = false; bool has_invite_link = invite_link.is_valid(); + bool has_bot_commands = !bot_commands.empty(); BEGIN_STORE_FLAGS(); STORE_FLAG(has_description); STORE_FLAG(has_administrator_count); @@ -4367,6 +4378,7 @@ void ContactsManager::ChannelFull::store(StorerT &storer) const { STORE_FLAG(can_view_statistics); STORE_FLAG(legacy_has_active_group_call_id); STORE_FLAG(has_invite_link); + STORE_FLAG(has_bot_commands); END_STORE_FLAGS(); if (has_description) { store(description, storer); @@ -4415,6 +4427,9 @@ void ContactsManager::ChannelFull::store(StorerT &storer) const { if (has_invite_link) { store(invite_link, storer); } + if (has_bot_commands) { + store(bot_commands, storer); + } } template @@ -4438,6 +4453,7 @@ void ContactsManager::ChannelFull::parse(ParserT &parser) { bool has_photo; bool legacy_has_active_group_call_id; bool has_invite_link; + bool has_bot_commands; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_description); PARSE_FLAG(has_administrator_count); @@ -4464,6 +4480,7 @@ void ContactsManager::ChannelFull::parse(ParserT &parser) { PARSE_FLAG(can_view_statistics); PARSE_FLAG(legacy_has_active_group_call_id); PARSE_FLAG(has_invite_link); + PARSE_FLAG(has_bot_commands); END_PARSE_FLAGS(); if (has_description) { parse(description, parser); @@ -4520,6 +4537,9 @@ void ContactsManager::ChannelFull::parse(ParserT &parser) { if (has_invite_link) { parse(invite_link, parser); } + if (has_bot_commands) { + parse(bot_commands, parser); + } if (legacy_can_view_statistics) { LOG(DEBUG) << "Ignore legacy can view statistics flag"; @@ -9589,12 +9609,6 @@ void ContactsManager::on_load_chat_full_from_database(ChatId chat_id, string val return; } - for (auto &participant : chat_full->participants) { - if (participant.dialog_id.get_type() == DialogType::User) { - get_bot_info_force(participant.dialog_id.get_user_id()); - } - } - Chat *c = get_chat(chat_id); CHECK(c != nullptr); @@ -9701,10 +9715,6 @@ void ContactsManager::on_load_channel_full_from_database(ChannelId channel_id, s return; } - for (auto &user_id : channel_full->bot_user_ids) { - get_bot_info_force(user_id); - } - Channel *c = get_channel(channel_id); CHECK(c != nullptr); @@ -10149,6 +10159,10 @@ void ContactsManager::update_chat_full(ChatFull *chat_full, ChatId chat_id, bool } } } + td::remove_if(chat_full->bot_commands, [&bot_user_ids](const BotCommands &commands) { + return !td::contains(bot_user_ids, commands.get_bot_user_id()); + }); + on_update_dialog_administrators(DialogId(chat_id), std::move(administrators), chat_full->version != -1, from_database); send_closure_later(G()->messages_manager(), &MessagesManager::on_dialog_bots_updated, DialogId(chat_id), @@ -10194,6 +10208,13 @@ void ContactsManager::update_channel_full(ChannelFull *channel_full, ChannelId c channel_full->is_slow_mode_next_send_date_changed = false; } + if (channel_full->need_save_to_database) { + channel_full->is_changed |= td::remove_if( + channel_full->bot_commands, [bot_user_ids = &channel_full->bot_user_ids](const BotCommands &commands) { + return !td::contains(*bot_user_ids, commands.get_bot_user_id()); + }); + } + channel_full->need_send_update |= channel_full->is_changed; channel_full->need_save_to_database |= channel_full->is_changed; channel_full->is_changed = false; @@ -10494,6 +10515,43 @@ void ContactsManager::on_get_chats(vector> &&c } } +vector ContactsManager::get_bot_commands(vector> &&bot_infos, + const vector *participants) { + vector result; + for (auto &bot_info : bot_infos) { + if (bot_info->commands_.empty()) { + continue; + } + + auto user_id = UserId(bot_info->user_id_); + if (!have_user_force(user_id)) { + LOG(ERROR) << "Receive unknown " << user_id; + continue; + } + if (!is_user_bot(user_id)) { + if (!is_user_deleted(user_id)) { + LOG(ERROR) << "Receive non-bot " << user_id; + } + continue; + } + if (participants != nullptr) { + bool is_participant = false; + for (auto &participant : *participants) { + if (participant.dialog_id == DialogId(user_id)) { + is_participant = true; + break; + } + } + if (!is_participant) { + LOG(ERROR) << "Skip commands of non-member bot " << user_id; + continue; + } + } + result.emplace_back(user_id, std::move(bot_info->commands_)); + } + return result; +} + void ContactsManager::on_get_chat_full(tl_object_ptr &&chat_full_ptr, Promise &&promise) { LOG(INFO) << "Receive " << to_string(chat_full_ptr); if (chat_full_ptr->get_id() == telegram_api::chatFull::ID) { @@ -10562,13 +10620,6 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c on_update_chat_full_invite_link(chat_full, std::move(chat->exported_invite_)); on_update_chat_full_photo(chat_full, chat_id, get_photo(td_->file_manager_.get(), std::move(chat->chat_photo_), DialogId(chat_id))); - - for (auto &bot_info : chat->bot_info_) { - if (on_update_bot_info(std::move(bot_info))) { - chat_full->need_send_update = true; - } - } - if (chat_full->description != chat->about_) { chat_full->description = std::move(chat->about_); chat_full->is_changed = true; @@ -10583,6 +10634,12 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c td_->messages_manager_->on_update_dialog_notify_settings(DialogId(chat_id), std::move(chat->notify_settings_), "on_get_chat_full"); + auto bot_commands = get_bot_commands(std::move(chat->bot_info_), &chat_full->participants); + if (chat_full->bot_commands != bot_commands) { + chat_full->bot_commands = std::move(bot_commands); + chat_full->is_changed = true; + } + update_chat_full(chat_full, chat_id); } else { CHECK(chat_full_ptr->get_id() == telegram_api::channelFull::ID); @@ -10771,17 +10828,22 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c } vector bot_user_ids; - for (auto &bot_info : channel->bot_info_) { + for (const auto &bot_info : channel->bot_info_) { UserId user_id(bot_info->user_id_); if (!is_user_bot(user_id)) { continue; } bot_user_ids.push_back(user_id); - on_update_bot_info(std::move(bot_info)); } on_update_channel_full_bot_user_ids(channel_full, channel_id, std::move(bot_user_ids)); + auto bot_commands = get_bot_commands(std::move(channel->bot_info_), nullptr); + if (channel_full->bot_commands != bot_commands) { + channel_full->bot_commands = std::move(bot_commands); + channel_full->is_changed = true; + } + ChannelId linked_channel_id; if ((channel->flags_ & CHANNEL_FULL_FLAG_HAS_LINKED_CHANNEL_ID) != 0) { linked_channel_id = ChannelId(channel->linked_chat_id_); @@ -12038,6 +12100,7 @@ void ContactsManager::speculative_add_channel_participants(ChannelId channel_id, if (channel_full != nullptr && is_user_bot(user_id) && !td::contains(channel_full->bot_user_ids, user_id)) { channel_full->bot_user_ids.push_back(user_id); channel_full->need_save_to_database = true; + reload_channel_full(channel_id, Promise(), "speculative_add_channel_participants"); } } if (is_participants_cache_changed) { @@ -12211,6 +12274,7 @@ void ContactsManager::speculative_add_channel_user(ChannelId channel_id, UserId if (!td::contains(channel_full->bot_user_ids, user_id)) { channel_full->bot_user_ids.push_back(user_id); channel_full->need_save_to_database = true; + reload_channel_full(channel_id, Promise(), "speculative_add_channel_user"); } } else { if (td::remove(channel_full->bot_user_ids, user_id)) { @@ -13211,6 +13275,7 @@ void ContactsManager::drop_chat_full(ChatId chat_id) { on_update_chat_full_photo(chat_full, chat_id, Photo()); // chat_full->creator_user_id = UserId(); chat_full->participants.clear(); + chat_full->bot_commands.clear(); chat_full->version = -1; on_update_chat_full_invite_link(chat_full, nullptr); update_chat_online_member_count(chat_full, chat_id, true); @@ -14181,23 +14246,11 @@ bool ContactsManager::is_chat_full_outdated(const ChatFull *chat_full, const Cha } if (chat_full->version != c->version) { - LOG(INFO) << "Have outdated ChatFull " << chat_id << " with current version " - << (chat_full ? chat_full->version : -123456789) << " and chat version " << c->version; + LOG(INFO) << "Have outdated ChatFull " << chat_id << " with current version " << chat_full->version + << " and chat version " << c->version; return true; } - for (const auto &participant : chat_full->participants) { - if (participant.dialog_id.get_type() == DialogType::User) { - auto user_id = participant.dialog_id.get_user_id(); - auto u = get_user(user_id); - if (u != nullptr && is_bot_info_expired(user_id, u->bot_info_version)) { - LOG(INFO) << "Have outdated botInfo for " << user_id << " in " << chat_id << "; expected version " - << u->bot_info_version; - return true; - } - } - } - if (c->is_active && c->status.can_manage_invite_links() && !chat_full->invite_link.is_valid()) { LOG(INFO) << "Have outdated invite link in " << chat_id; return true; @@ -16082,12 +16135,15 @@ tl_object_ptr ContactsManager::get_basic_group_full_ tl_object_ptr ContactsManager::get_basic_group_full_info_object( const ChatFull *chat_full) const { CHECK(chat_full != nullptr); + auto bot_commands = transform(chat_full->bot_commands, [td = td_](const BotCommands &commands) { + return commands.get_bot_commands_object(td); + }); return make_tl_object( get_chat_photo_object(td_->file_manager_.get(), chat_full->photo), chat_full->description, get_user_id_object(chat_full->creator_user_id, "basicGroupFullInfo"), transform(chat_full->participants, [this](const DialogParticipant &chat_participant) { return get_chat_member_object(chat_participant); }), - chat_full->invite_link.get_chat_invite_link_object(this)); + chat_full->invite_link.get_chat_invite_link_object(this), std::move(bot_commands)); } td_api::object_ptr ContactsManager::get_update_unknown_supergroup_object( @@ -16132,6 +16188,9 @@ tl_object_ptr ContactsManager::get_supergroup_full_i if (channel_full->slow_mode_next_send_date != 0) { slow_mode_delay_expires_in = max(channel_full->slow_mode_next_send_date - G()->server_time(), 1e-3); } + auto bot_commands = transform(channel_full->bot_commands, [td = td_](const BotCommands &commands) { + return commands.get_bot_commands_object(td); + }); return td_api::make_object( get_chat_photo_object(td_->file_manager_.get(), channel_full->photo), channel_full->description, channel_full->participant_count, channel_full->administrator_count, channel_full->restricted_count, @@ -16140,6 +16199,7 @@ tl_object_ptr ContactsManager::get_supergroup_full_i channel_full->can_set_sticker_set, channel_full->can_set_location, channel_full->can_view_statistics, channel_full->is_all_history_available, channel_full->sticker_set_id.get(), channel_full->location.get_chat_location_object(), channel_full->invite_link.get_chat_invite_link_object(this), + std::move(bot_commands), get_basic_group_id_object(channel_full->migrated_from_chat_id, "get_supergroup_full_info_object"), channel_full->migrated_from_max_message_id.get()); } diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 14449f97e..2867bd0b0 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -763,6 +763,8 @@ class ContactsManager : public Actor { DialogInviteLink invite_link; + vector bot_commands; + bool can_set_username = false; bool is_changed = true; // have new changes that need to be sent to the client and database @@ -842,6 +844,8 @@ class ContactsManager : public Actor { DialogInviteLink invite_link; + vector bot_commands; + uint32 speculative_version = 1; uint32 repair_request_version = 0; @@ -1421,6 +1425,9 @@ class ContactsManager : public Actor { void add_channel_participants(ChannelId channel_id, const vector &user_ids, Promise &&promise); + vector get_bot_commands(vector> &&bot_infos, + const vector *participants); + const DialogParticipant *get_chat_participant(ChatId chat_id, UserId user_id) const; static const DialogParticipant *get_chat_full_participant(const ChatFull *chat_full, DialogId dialog_id);