Always adjust administrator rights for supergroups and channels.

This commit is contained in:
levlam 2022-04-04 16:19:41 +03:00
parent 99b79911e0
commit c3996b4726
7 changed files with 97 additions and 65 deletions

View File

@ -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<Unit> &&promise) {
td_api::object_ptr<td_api::ChatMemberStatus> &&chat_member_status,
Promise<Unit> &&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<telegram_api::userFull> &&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<U
}
void ContactsManager::set_dialog_participant_status(DialogId dialog_id, DialogId participant_dialog_id,
DialogParticipantStatus &&status, Promise<Unit> &&promise) {
td_api::object_ptr<td_api::ChatMemberStatus> &&chat_member_status,
Promise<Unit> &&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<td_api::chatMemberStatusBanned>(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) {

View File

@ -537,7 +537,8 @@ class ContactsManager final : public Actor {
void add_dialog_participants(DialogId dialog_id, const vector<UserId> &user_ids, Promise<Unit> &&promise);
void set_dialog_participant_status(DialogId dialog_id, DialogId participant_dialog_id,
DialogParticipantStatus &&status, Promise<Unit> &&promise);
td_api::object_ptr<td_api::ChatMemberStatus> &&chat_member_status,
Promise<Unit> &&promise);
void ban_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id, int32 banned_until_date,
bool revoke_messages, Promise<Unit> &&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<Unit> &&promise);
void set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id,
DialogParticipantStatus status, Promise<Unit> &&promise);
void send_edit_chat_admin_query(ChatId chat_id, UserId user_id, bool is_administrator, Promise<Unit> &&promise);
void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise<Unit> &&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<Unit> &&promise);
void set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id,
td_api::object_ptr<td_api::ChatMemberStatus> &&chat_member_status,
Promise<Unit> &&promise);
void set_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id,
DialogParticipantStatus status, DialogParticipantStatus old_status,
Promise<Unit> &&promise);

View File

@ -18,7 +18,8 @@
namespace td {
AdministratorRights::AdministratorRights(const tl_object_ptr<telegram_api::chatAdminRights> &rights) {
AdministratorRights::AdministratorRights(const tl_object_ptr<telegram_api::chatAdminRights> &rights,
ChannelType channel_type) {
if (rights == nullptr) {
flags_ = 0;
return;
@ -27,12 +28,14 @@ AdministratorRights::AdministratorRights(const tl_object_ptr<telegram_api::chatA
if (!rights->other_) {
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<td_api::chatAdministratorRights> &rights) {
AdministratorRights::AdministratorRights(const td_api::object_ptr<td_api::chatAdministratorRights> &rights,
ChannelType channel_type) {
if (rights == nullptr) {
flags_ = 0;
return;
@ -40,13 +43,25 @@ AdministratorRights::AdministratorRights(const td_api::object_ptr<td_api::chatAd
*this = AdministratorRights(rights->is_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<uint32>(can_manage_dialog) * CAN_MANAGE_DIALOG) |
(static_cast<uint32>(can_change_info) * CAN_CHANGE_INFO_AND_SETTINGS) |
(static_cast<uint32>(can_post_messages) * CAN_POST_MESSAGES) |
@ -60,6 +75,9 @@ AdministratorRights::AdministratorRights(bool is_anonymous, bool can_manage_dial
(static_cast<uint32>(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<telegram_api::chatAdminRights> &&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<td_api::ChatMemberStatus> &status) {
DialogParticipantStatus get_dialog_participant_status(const td_api::object_ptr<td_api::ChatMemberStatus> &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_ptr<td_api
if (!clean_input_string(custom_title)) {
custom_title.clear();
}
return DialogParticipantStatus::Administrator(AdministratorRights(st->rights_), 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<telegram_api::ChatParticipant
}
}
DialogParticipant::DialogParticipant(tl_object_ptr<telegram_api::ChannelParticipant> &&participant_ptr) {
DialogParticipant::DialogParticipant(tl_object_ptr<telegram_api::ChannelParticipant> &&participant_ptr,
ChannelType channel_type) {
CHECK(participant_ptr != nullptr);
switch (participant_ptr->get_id()) {
@ -651,7 +673,7 @@ DialogParticipant::DialogParticipant(tl_object_ptr<telegram_api::ChannelParticip
auto participant = move_tl_object_as<telegram_api::channelParticipantAdmin>(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: {

View File

@ -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<telegram_api::chatAdminRights> &admin_rights);
AdministratorRights(const tl_object_ptr<telegram_api::chatAdminRights> &admin_rights, ChannelType channel_type);
explicit AdministratorRights(const td_api::object_ptr<td_api::chatAdministratorRights> &administrator_rights);
AdministratorRights(const td_api::object_ptr<td_api::chatAdministratorRights> &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<telegram_api::chatAdminRights> 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<telegram_api::chatAdminRights> &&admin_rights, string rank);
// forcely returns an administrator
DialogParticipantStatus(bool can_be_edited, tl_object_ptr<telegram_api::chatAdminRights> &&admin_rights, string rank,
ChannelType channel_type);
// forcely returns a restricted or banned
DialogParticipantStatus(bool is_member, tl_object_ptr<telegram_api::chatBannedRights> &&banned_rights);
RestrictedRights get_effective_restricted_rights() const;
@ -496,7 +501,8 @@ struct DialogParticipant {
DialogParticipant(tl_object_ptr<telegram_api::ChatParticipant> &&participant_ptr, int32 chat_creation_date,
bool is_creator);
explicit DialogParticipant(tl_object_ptr<telegram_api::ChannelParticipant> &&participant_ptr);
DialogParticipant(tl_object_ptr<telegram_api::ChannelParticipant> &&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<td_api::chatMembers> get_chat_members_object(Td *td) const;
};
DialogParticipantStatus get_dialog_participant_status(const tl_object_ptr<td_api::ChatMemberStatus> &status);
DialogParticipantStatus get_dialog_participant_status(const td_api::object_ptr<td_api::ChatMemberStatus> &status,
ChannelType channel_type);
} // namespace td

View File

@ -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 {

View File

@ -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<td_api::ChatMemberStatus> new_status = td_api::make_object<td_api::chatMemberStatusLeft>();
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<td_api::chatMemberStatusCreator>(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) {

View File

@ -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);