From c3996b4726451e33f7b428c4c3df94af84c05f59 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 4 Apr 2022 16:19:41 +0300 Subject: [PATCH] Always adjust administrator rights for supergroups and channels. --- td/telegram/ContactsManager.cpp | 27 ++++++++------ td/telegram/ContactsManager.h | 16 +++++---- td/telegram/DialogParticipant.cpp | 60 +++++++++++++++++++++---------- td/telegram/DialogParticipant.h | 21 +++++++---- td/telegram/LinkManager.cpp | 15 ++------ td/telegram/Td.cpp | 21 ++++++----- td/telegram/Td.h | 2 +- 7 files changed, 97 insertions(+), 65 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 4852c1d66..1fcbc2ce2 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -6962,11 +6962,13 @@ void ContactsManager::add_channel_participants(ChannelId channel_id, const vecto } void ContactsManager::set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id, - DialogParticipantStatus status, Promise &&promise) { + td_api::object_ptr &&chat_member_status, + Promise &&promise) { auto c = get_channel(channel_id); if (c == nullptr) { return promise.set_error(Status::Error(400, "Chat info not found")); } + auto status = get_dialog_participant_status(chat_member_status, get_channel_type(c)); if (participant_dialog_id == DialogId(get_my_id())) { // fast path is needed, because get_channel_status may return Creator, while GetChannelParticipantQuery returning Left @@ -10505,8 +10507,8 @@ void ContactsManager::on_get_user_full(tl_object_ptr &&u bool can_be_called = user->phone_calls_available_ && !user->phone_calls_private_; bool supports_video_calls = user->video_calls_available_ && !user->phone_calls_private_; bool has_private_calls = user->phone_calls_private_; - AdministratorRights group_administrator_rights(user->bot_group_admin_rights_); - AdministratorRights broadcast_administrator_rights(user->bot_broadcast_admin_rights_); + AdministratorRights group_administrator_rights(user->bot_group_admin_rights_, ChannelType::Megagroup); + AdministratorRights broadcast_administrator_rights(user->bot_broadcast_admin_rights_, ChannelType::Broadcast); if (user_full->can_be_called != can_be_called || user_full->supports_video_calls != supports_video_calls || user_full->has_private_calls != has_private_calls || user_full->private_forward_name != user->private_forward_name_ || @@ -15122,7 +15124,8 @@ void ContactsManager::add_dialog_participants(DialogId dialog_id, const vector &&promise) { + td_api::object_ptr &&chat_member_status, + Promise &&promise) { if (!td_->messages_manager_->have_dialog_force(dialog_id, "set_dialog_participant_status")) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -15130,7 +15133,8 @@ void ContactsManager::set_dialog_participant_status(DialogId dialog_id, DialogId switch (dialog_id.get_type()) { case DialogType::User: return promise.set_error(Status::Error(400, "Chat member status can't be changed in private chats")); - case DialogType::Chat: + case DialogType::Chat: { + auto status = get_dialog_participant_status(chat_member_status, ChannelType::Unknown); if (participant_dialog_id.get_type() != DialogType::User) { if (status == DialogParticipantStatus::Left()) { return promise.set_value(Unit()); @@ -15140,9 +15144,10 @@ void ContactsManager::set_dialog_participant_status(DialogId dialog_id, DialogId } return set_chat_participant_status(dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), status, std::move(promise)); + } case DialogType::Channel: - return set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id, status, - std::move(promise)); + return set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id, + std::move(chat_member_status), std::move(promise)); case DialogType::SecretChat: return promise.set_error(Status::Error(400, "Chat member status can't be changed in secret chats")); case DialogType::None: @@ -15168,7 +15173,8 @@ void ContactsManager::ban_dialog_participant(DialogId dialog_id, DialogId partic std::move(promise)); case DialogType::Channel: return set_channel_participant_status(dialog_id.get_channel_id(), participant_dialog_id, - DialogParticipantStatus::Banned(banned_until_date), std::move(promise)); + td_api::make_object(banned_until_date), + std::move(promise)); case DialogType::SecretChat: return promise.set_error(Status::Error(400, "Can't ban members in secret chats")); case DialogType::None: @@ -15685,7 +15691,7 @@ void ContactsManager::on_chat_update(telegram_api::chat &chat, const char *sourc if (is_creator) { return DialogParticipantStatus::Creator(!has_left, false, string()); } else if (chat.admin_rights_ != nullptr) { - return DialogParticipantStatus(false, std::move(chat.admin_rights_), string()); + return DialogParticipantStatus(false, std::move(chat.admin_rights_), string(), ChannelType::Unknown); } else if (has_left) { return DialogParticipantStatus::Left(); } else { @@ -15864,7 +15870,8 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char (channel.admin_rights_->flags_ & telegram_api::chatAdminRights::ANONYMOUS_MASK) != 0; return DialogParticipantStatus::Creator(!has_left, is_anonymous, string()); } else if (channel.admin_rights_ != nullptr) { - return DialogParticipantStatus(false, std::move(channel.admin_rights_), string()); + return DialogParticipantStatus(false, std::move(channel.admin_rights_), string(), + is_megagroup ? ChannelType::Megagroup : ChannelType::Broadcast); } else if (channel.banned_rights_ != nullptr) { return DialogParticipantStatus(!has_left, std::move(channel.banned_rights_)); } else if (has_left) { diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index e676a9ee3..ec0e1ac74 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -537,7 +537,8 @@ class ContactsManager final : public Actor { void add_dialog_participants(DialogId dialog_id, const vector &user_ids, Promise &&promise); void set_dialog_participant_status(DialogId dialog_id, DialogId participant_dialog_id, - DialogParticipantStatus &&status, Promise &&promise); + td_api::object_ptr &&chat_member_status, + Promise &&promise); void ban_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id, int32 banned_until_date, bool revoke_messages, Promise &&promise); @@ -1560,12 +1561,6 @@ class ContactsManager final : public Actor { void update_dialogs_for_discussion(DialogId dialog_id, bool is_suitable); - void set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status, - Promise &&promise); - - void set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id, - DialogParticipantStatus status, Promise &&promise); - void send_edit_chat_admin_query(ChatId chat_id, UserId user_id, bool is_administrator, Promise &&promise); void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise &&promise); @@ -1588,6 +1583,13 @@ class ContactsManager final : public Actor { const DialogParticipant *get_channel_participant_from_cache(ChannelId channel_id, DialogId participant_dialog_id); + void set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status, + Promise &&promise); + + void set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id, + td_api::object_ptr &&chat_member_status, + Promise &&promise); + void set_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id, DialogParticipantStatus status, DialogParticipantStatus old_status, Promise &&promise); diff --git a/td/telegram/DialogParticipant.cpp b/td/telegram/DialogParticipant.cpp index 82df65d2e..166e2539f 100644 --- a/td/telegram/DialogParticipant.cpp +++ b/td/telegram/DialogParticipant.cpp @@ -18,7 +18,8 @@ namespace td { -AdministratorRights::AdministratorRights(const tl_object_ptr &rights) { +AdministratorRights::AdministratorRights(const tl_object_ptr &rights, + ChannelType channel_type) { if (rights == nullptr) { flags_ = 0; return; @@ -27,12 +28,14 @@ AdministratorRights::AdministratorRights(const tl_object_ptrother_) { LOG(ERROR) << "Receive wrong other flag in " << to_string(rights); } - *this = AdministratorRights(rights->anonymous_, rights->other_, rights->change_info_, rights->post_messages_, - rights->edit_messages_, rights->delete_messages_, rights->invite_users_, - rights->ban_users_, rights->pin_messages_, rights->add_admins_, rights->manage_call_); + *this = + AdministratorRights(rights->anonymous_, rights->other_, rights->change_info_, rights->post_messages_, + rights->edit_messages_, rights->delete_messages_, rights->invite_users_, rights->ban_users_, + rights->pin_messages_, rights->add_admins_, rights->manage_call_, channel_type); } -AdministratorRights::AdministratorRights(const td_api::object_ptr &rights) { +AdministratorRights::AdministratorRights(const td_api::object_ptr &rights, + ChannelType channel_type) { if (rights == nullptr) { flags_ = 0; return; @@ -40,13 +43,25 @@ AdministratorRights::AdministratorRights(const td_api::object_ptris_anonymous_, rights->can_manage_chat_, rights->can_change_info_, rights->can_post_messages_, rights->can_edit_messages_, rights->can_delete_messages_, rights->can_invite_users_, rights->can_restrict_members_, rights->can_pin_messages_, - rights->can_promote_members_, rights->can_manage_video_chats_); + rights->can_promote_members_, rights->can_manage_video_chats_, channel_type); } AdministratorRights::AdministratorRights(bool is_anonymous, bool can_manage_dialog, bool can_change_info, bool can_post_messages, bool can_edit_messages, bool can_delete_messages, bool can_invite_users, bool can_restrict_members, bool can_pin_messages, - bool can_promote_members, bool can_manage_calls) { + bool can_promote_members, bool can_manage_calls, ChannelType channel_type) { + switch (channel_type) { + case ChannelType::Broadcast: + can_pin_messages = false; + is_anonymous = false; + break; + case ChannelType::Megagroup: + can_post_messages = false; + can_edit_messages = false; + break; + case ChannelType::Unknown: + break; + } flags_ = (static_cast(can_manage_dialog) * CAN_MANAGE_DIALOG) | (static_cast(can_change_info) * CAN_CHANGE_INFO_AND_SETTINGS) | (static_cast(can_post_messages) * CAN_POST_MESSAGES) | @@ -60,6 +75,9 @@ AdministratorRights::AdministratorRights(bool is_anonymous, bool can_manage_dial (static_cast(is_anonymous) * IS_ANONYMOUS); if (flags_ != 0) { flags_ |= CAN_MANAGE_DIALOG; + if (channel_type == ChannelType::Broadcast) { + flags_ |= CAN_RESTRICT_MEMBERS; + } } } @@ -357,22 +375,24 @@ DialogParticipantStatus DialogParticipantStatus::Banned(int32 banned_until_date) } DialogParticipantStatus DialogParticipantStatus::GroupAdministrator(bool is_creator) { - return Administrator(AdministratorRights(false, true, true, false, false, true, true, true, true, false, true), - string(), is_creator); + return Administrator( + AdministratorRights(false, true, true, false, false, true, true, true, true, false, true, ChannelType::Unknown), + string(), is_creator); } DialogParticipantStatus DialogParticipantStatus::ChannelAdministrator(bool is_creator, bool is_megagroup) { - auto rights = is_megagroup - ? AdministratorRights(false, true, true, false, false, true, true, true, true, false, false) - : AdministratorRights(false, true, false, true, true, true, false, true, false, false, false); + auto rights = is_megagroup ? AdministratorRights(false, true, true, false, false, true, true, true, true, false, + false, ChannelType::Megagroup) + : AdministratorRights(false, true, false, true, true, true, false, true, false, false, + false, ChannelType::Broadcast); return Administrator(rights, string(), is_creator); } DialogParticipantStatus::DialogParticipantStatus(bool can_be_edited, tl_object_ptr &&admin_rights, - string rank) { + string rank, ChannelType channel_type) { CHECK(admin_rights != nullptr); - uint32 flags = AdministratorRights(std::move(admin_rights)).flags_ | AdministratorRights::CAN_MANAGE_DIALOG; + uint32 flags = AdministratorRights(admin_rights, channel_type).flags_ | AdministratorRights::CAN_MANAGE_DIALOG; if (can_be_edited) { flags |= CAN_BE_EDITED; } @@ -546,7 +566,8 @@ StringBuilder &operator<<(StringBuilder &string_builder, const DialogParticipant } } -DialogParticipantStatus get_dialog_participant_status(const tl_object_ptr &status) { +DialogParticipantStatus get_dialog_participant_status(const td_api::object_ptr &status, + ChannelType channel_type) { auto constructor_id = status == nullptr ? td_api::chatMemberStatusMember::ID : status->get_id(); switch (constructor_id) { case td_api::chatMemberStatusCreator::ID: { @@ -563,8 +584,8 @@ DialogParticipantStatus get_dialog_participant_status(const tl_object_ptrrights_), std::move(custom_title), - true /*st->can_be_edited_*/); + return DialogParticipantStatus::Administrator(AdministratorRights(st->rights_, channel_type), + std::move(custom_title), true /*st->can_be_edited_*/); } case td_api::chatMemberStatusMember::ID: return DialogParticipantStatus::Member(); @@ -624,7 +645,8 @@ DialogParticipant::DialogParticipant(tl_object_ptr &&participant_ptr) { +DialogParticipant::DialogParticipant(tl_object_ptr &&participant_ptr, + ChannelType channel_type) { CHECK(participant_ptr != nullptr); switch (participant_ptr->get_id()) { @@ -651,7 +673,7 @@ DialogParticipant::DialogParticipant(tl_object_ptr(participant_ptr); *this = {DialogId(UserId(participant->user_id_)), UserId(participant->promoted_by_), participant->date_, DialogParticipantStatus(participant->can_edit_, std::move(participant->admin_rights_), - std::move(participant->rank_))}; + std::move(participant->rank_), channel_type)}; break; } case telegram_api::channelParticipantLeft::ID: { diff --git a/td/telegram/DialogParticipant.h b/td/telegram/DialogParticipant.h index 1640a9b61..bcbf3f023 100644 --- a/td/telegram/DialogParticipant.h +++ b/td/telegram/DialogParticipant.h @@ -6,6 +6,7 @@ // #pragma once +#include "td/telegram/ChannelType.h" #include "td/telegram/DialogId.h" #include "td/telegram/MessageId.h" #include "td/telegram/td_api.h" @@ -50,14 +51,15 @@ class AdministratorRights { AdministratorRights() : flags_(0) { } - explicit AdministratorRights(const tl_object_ptr &admin_rights); + AdministratorRights(const tl_object_ptr &admin_rights, ChannelType channel_type); - explicit AdministratorRights(const td_api::object_ptr &administrator_rights); + AdministratorRights(const td_api::object_ptr &administrator_rights, + ChannelType channel_type); AdministratorRights(bool is_anonymous, bool can_manage_dialog, bool can_change_info, bool can_post_messages, bool can_edit_messages, bool can_delete_messages, bool can_invite_users, - bool can_restrict_members, bool can_pin_messages, bool can_promote_members, - bool can_manage_calls); + bool can_restrict_members, bool can_pin_messages, bool can_promote_members, bool can_manage_calls, + ChannelType channel_type); telegram_api::object_ptr get_chat_admin_rights() const; @@ -289,8 +291,11 @@ class DialogParticipantStatus { // legacy rights static DialogParticipantStatus ChannelAdministrator(bool is_creator, bool is_megagroup); - DialogParticipantStatus(bool can_be_edited, tl_object_ptr &&admin_rights, string rank); + // forcely returns an administrator + DialogParticipantStatus(bool can_be_edited, tl_object_ptr &&admin_rights, string rank, + ChannelType channel_type); + // forcely returns a restricted or banned DialogParticipantStatus(bool is_member, tl_object_ptr &&banned_rights); RestrictedRights get_effective_restricted_rights() const; @@ -496,7 +501,8 @@ struct DialogParticipant { DialogParticipant(tl_object_ptr &&participant_ptr, int32 chat_creation_date, bool is_creator); - explicit DialogParticipant(tl_object_ptr &&participant_ptr); + DialogParticipant(tl_object_ptr &&participant_ptr, + ChannelType channel_type = ChannelType::Unknown); static DialogParticipant left(DialogId dialog_id) { return {dialog_id, UserId(), 0, DialogParticipantStatus::Left()}; @@ -546,6 +552,7 @@ struct DialogParticipants { td_api::object_ptr get_chat_members_object(Td *td) const; }; -DialogParticipantStatus get_dialog_participant_status(const tl_object_ptr &status); +DialogParticipantStatus get_dialog_participant_status(const td_api::object_ptr &status, + ChannelType channel_type); } // namespace td diff --git a/td/telegram/LinkManager.cpp b/td/telegram/LinkManager.cpp index 06f88cff1..e6b46c965 100644 --- a/td/telegram/LinkManager.cpp +++ b/td/telegram/LinkManager.cpp @@ -8,6 +8,7 @@ #include "td/telegram/AccessRights.h" #include "td/telegram/ChannelId.h" +#include "td/telegram/ChannelType.h" #include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" @@ -140,20 +141,10 @@ static AdministratorRights get_administrator_rights(Slice rights, bool for_chann can_manage_dialog = true; } } - if (for_channel) { - can_pin_messages = false; - is_anonymous = false; - if (can_manage_dialog || can_change_info || can_post_messages || can_edit_messages || can_delete_messages || - can_invite_users || can_promote_members || can_manage_calls) { - can_restrict_members = true; - } - } else { - can_post_messages = false; - can_edit_messages = false; - } return AdministratorRights(is_anonymous, can_manage_dialog, can_change_info, can_post_messages, can_edit_messages, can_delete_messages, can_invite_users, can_restrict_members, can_pin_messages, - can_promote_members, can_manage_calls); + can_promote_members, can_manage_calls, + for_channel ? ChannelType::Broadcast : ChannelType::Megagroup); } class LinkManager::InternalLinkActiveSessions final : public InternalLink { diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index e9b06d1f0..6612139fe 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -20,6 +20,7 @@ #include "td/telegram/CallId.h" #include "td/telegram/CallManager.h" #include "td/telegram/ChannelId.h" +#include "td/telegram/ChannelType.h" #include "td/telegram/ChatId.h" #include "td/telegram/ConfigManager.h" #include "td/telegram/ConfigShared.h" @@ -6204,7 +6205,7 @@ void Td::on_request(uint64 id, const td_api::joinChat &request) { void Td::on_request(uint64 id, const td_api::leaveChat &request) { CREATE_OK_REQUEST_PROMISE(); DialogId dialog_id(request.chat_id_); - auto new_status = DialogParticipantStatus::Left(); + td_api::object_ptr new_status = td_api::make_object(); if (dialog_id.get_type() == DialogType::Channel && messages_manager_->have_dialog_force(dialog_id, "leaveChat")) { auto status = contacts_manager_->get_channel_status(dialog_id.get_channel_id()); if (status.is_creator()) { @@ -6212,8 +6213,8 @@ void Td::on_request(uint64 id, const td_api::leaveChat &request) { return promise.set_value(Unit()); } - auto rank = status.get_rank(); - new_status = DialogParticipantStatus::Creator(false, status.is_anonymous(), std::move(rank)); + new_status = + td_api::make_object(status.get_rank(), status.is_anonymous(), false); } } contacts_manager_->set_dialog_participant_status(dialog_id, DialogId(contacts_manager_->get_my_id()), @@ -6234,12 +6235,12 @@ void Td::on_request(uint64 id, const td_api::addChatMembers &request) { std::move(promise)); } -void Td::on_request(uint64 id, const td_api::setChatMemberStatus &request) { +void Td::on_request(uint64 id, td_api::setChatMemberStatus &request) { CREATE_OK_REQUEST_PROMISE(); TRY_RESULT_PROMISE(promise, participant_dialog_id, get_message_sender_dialog_id(this, request.member_id_, false, false)); contacts_manager_->set_dialog_participant_status(DialogId(request.chat_id_), participant_dialog_id, - get_dialog_participant_status(request.status_), std::move(promise)); + std::move(request.status_), std::move(promise)); } void Td::on_request(uint64 id, const td_api::banChatMember &request) { @@ -6792,15 +6793,17 @@ void Td::on_request(uint64 id, td_api::getCommands &request) { void Td::on_request(uint64 id, const td_api::setDefaultGroupAdministratorRights &request) { CHECK_IS_BOT(); CREATE_OK_REQUEST_PROMISE(); - set_default_group_administrator_rights(this, AdministratorRights(request.default_group_administrator_rights_), - std::move(promise)); + set_default_group_administrator_rights( + this, AdministratorRights(request.default_group_administrator_rights_, ChannelType::Megagroup), + std::move(promise)); } void Td::on_request(uint64 id, const td_api::setDefaultChannelAdministratorRights &request) { CHECK_IS_BOT(); CREATE_OK_REQUEST_PROMISE(); - set_default_channel_administrator_rights(this, AdministratorRights(request.default_channel_administrator_rights_), - std::move(promise)); + set_default_channel_administrator_rights( + this, AdministratorRights(request.default_channel_administrator_rights_, ChannelType::Broadcast), + std::move(promise)); } void Td::on_request(uint64 id, const td_api::setLocation &request) { diff --git a/td/telegram/Td.h b/td/telegram/Td.h index c0da4721d..9eace99f0 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -873,7 +873,7 @@ class Td final : public Actor { void on_request(uint64 id, const td_api::addChatMembers &request); - void on_request(uint64 id, const td_api::setChatMemberStatus &request); + void on_request(uint64 id, td_api::setChatMemberStatus &request); void on_request(uint64 id, const td_api::banChatMember &request);