diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 46be7881b..10efcea81 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -3171,6 +3171,10 @@ setChatTitle chat_id:int53 title:string = Ok; //@chat_id Chat identifier @photo New chat photo. You can use a zero InputFileId to delete the chat photo. Files that are accessible only by HTTP URL are not acceptable setChatPhoto chat_id:int53 photo:InputFile = Ok; +//@description Changes the chat members permissions. Supported only for basic groups and supergroups. Requires can_restrict_members administrator right +//@chat_id Chat identifier @permissions New members permissions in the chat +setChatPermissions chat_id:int53 permissions:chatPermissions = Ok; + //@description Changes the draft message in a chat @chat_id Chat identifier @draft_message New draft message; may be null setChatDraftMessage chat_id:int53 draft_message:draftMessage = Ok; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 6320182bb..91482afe3 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 21232c52a..b260f1765 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -10119,7 +10119,8 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co int32 unban_date = (channel.flags_ & CHANNEL_FLAG_HAS_UNBAN_DATE) != 0 ? channel.until_date_ : 0; on_update_channel_status(c, channel_id, DialogParticipantStatus::Banned(unban_date)); on_update_channel_username(c, channel_id, ""); // don't know if channel username is empty, but update it anyway - on_update_channel_default_permissions(c, channel_id, get_restricted_rights(nullptr)); + tl_object_ptr banned_rights; // == nullptr + on_update_channel_default_permissions(c, channel_id, get_restricted_rights(banned_rights)); bool sign_messages = false; bool is_megagroup = (channel.flags_ & CHANNEL_FLAG_IS_MEGAGROUP) != 0; diff --git a/td/telegram/DialogParticipant.cpp b/td/telegram/DialogParticipant.cpp index 4f9d587c5..de768382d 100644 --- a/td/telegram/DialogParticipant.cpp +++ b/td/telegram/DialogParticipant.cpp @@ -545,6 +545,18 @@ RestrictedRights get_restricted_rights(const tl_object_ptr &permissions) { + bool can_send_polls = permissions->can_send_polls_; + bool can_send_media = permissions->can_send_media_messages_ || permissions->can_send_other_messages_ || + permissions->can_add_web_page_previews_; + bool can_send_messages = permissions->can_send_messages_ || can_send_media || can_send_polls; + return RestrictedRights(can_send_messages, can_send_media, permissions->can_send_other_messages_, + permissions->can_send_other_messages_, permissions->can_send_other_messages_, + permissions->can_send_other_messages_, permissions->can_add_web_page_previews_, + permissions->can_send_polls_, permissions->can_change_info_, permissions->can_invite_users_, + permissions->can_pin_messages_); +} + StringBuilder &operator<<(StringBuilder &string_builder, const DialogParticipant &dialog_participant) { return string_builder << '[' << dialog_participant.user_id << " invited by " << dialog_participant.inviter_user_id << " at " << dialog_participant.joined_date << " with status " << dialog_participant.status diff --git a/td/telegram/DialogParticipant.h b/td/telegram/DialogParticipant.h index 7cc572c3c..61cb12342 100644 --- a/td/telegram/DialogParticipant.h +++ b/td/telegram/DialogParticipant.h @@ -406,4 +406,6 @@ DialogParticipantStatus get_dialog_participant_status( RestrictedRights get_restricted_rights(const tl_object_ptr &banned_rights); +RestrictedRights get_restricted_rights(const td_api::object_ptr &permissions); + } // namespace td diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 07a32712c..afd1ecbb7 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -756,6 +756,48 @@ class EditDialogTitleQuery : public Td::ResultHandler { } }; +class EditDialogDefaultBannedRightsQuery : public Td::ResultHandler { + Promise promise_; + DialogId dialog_id_; + + public: + explicit EditDialogDefaultBannedRightsQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(DialogId dialog_id, RestrictedRights permissions) { + dialog_id_ = dialog_id; + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Write); + CHECK(input_peer != nullptr); + send_query(G()->net_query_creator().create(create_storer(telegram_api::messages_editChatDefaultBannedRights( + std::move(input_peer), permissions.get_chat_banned_rights())))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for editDialogPermissions " << to_string(ptr); + td->updates_manager_->on_get_updates(std::move(ptr)); + + promise_.set_value(Unit()); + } + + void on_error(uint64 id, Status status) override { + if (status.message() == "CHAT_NOT_MODIFIED") { + if (!td->auth_manager_->is_bot()) { + promise_.set_value(Unit()); + return; + } + } else { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "EditDialogDefaultBannedRightsQuery"); + } + promise_.set_error(std::move(status)); + } +}; + class SaveDraftMessageQuery : public Td::ResultHandler { Promise promise_; DialogId dialog_id_; @@ -21369,7 +21411,7 @@ SearchMessagesFilter MessagesManager::get_search_messages_filter( void MessagesManager::set_dialog_photo(DialogId dialog_id, const tl_object_ptr &photo, Promise &&promise) { - LOG(INFO) << "Receive SetChatPhoto request to change photo of " << dialog_id; + LOG(INFO) << "Receive setChatPhoto request to change photo of " << dialog_id; if (!have_dialog_force(dialog_id)) { return promise.set_error(Status::Error(3, "Chat not found")); @@ -21443,7 +21485,7 @@ void MessagesManager::upload_dialog_photo(DialogId dialog_id, FileId file_id, Pr } void MessagesManager::set_dialog_title(DialogId dialog_id, const string &title, Promise &&promise) { - LOG(INFO) << "Receive SetChatTitle request to change title of " << dialog_id << " to \"" << title << '"'; + LOG(INFO) << "Receive setChatTitle request to change title of " << dialog_id << " to \"" << title << '"'; if (!have_dialog_force(dialog_id)) { return promise.set_error(Status::Error(3, "Chat not found")); @@ -21489,6 +21531,62 @@ void MessagesManager::set_dialog_title(DialogId dialog_id, const string &title, td_->create_handler(std::move(promise))->send(dialog_id, new_title); } +void MessagesManager::set_dialog_permissions(DialogId dialog_id, + const td_api::object_ptr &permissions, + Promise &&promise) { + LOG(INFO) << "Receive setChatPermissions request to change permissions of " << dialog_id << " to " + << to_string(permissions); + + if (!have_dialog_force(dialog_id)) { + return promise.set_error(Status::Error(3, "Chat not found")); + } + if (!have_input_peer(dialog_id, AccessRights::Write)) { + return promise.set_error(Status::Error(3, "Can't access the chat")); + } + + if (permissions == nullptr) { + return promise.set_error(Status::Error(3, "New permissions must not be empty")); + } + + switch (dialog_id.get_type()) { + case DialogType::User: + return promise.set_error(Status::Error(3, "Can't change private chat permissions")); + case DialogType::Chat: { + auto chat_id = dialog_id.get_chat_id(); + auto status = td_->contacts_manager_->get_chat_status(chat_id); + if (!status.can_restrict_members()) { + return promise.set_error(Status::Error(3, "Not enough rights to change chat permissions")); + } + break; + } + case DialogType::Channel: { + if (is_broadcast_channel(dialog_id)) { + return promise.set_error(Status::Error(3, "Can't change channel chat permissions")); + } + auto status = td_->contacts_manager_->get_channel_status(dialog_id.get_channel_id()); + if (!status.can_restrict_members()) { + return promise.set_error(Status::Error(3, "Not enough rights to change chat permissions")); + } + break; + } + case DialogType::SecretChat: + return promise.set_error(Status::Error(3, "Can't change secret chat permissions")); + case DialogType::None: + default: + UNREACHABLE(); + } + + auto new_permissions = get_restricted_rights(permissions); + + // TODO this can be wrong if there was previous change title requests + if (get_dialog_permissions(dialog_id) == new_permissions) { + return promise.set_value(Unit()); + } + + // TODO invoke after + td_->create_handler(std::move(promise))->send(dialog_id, new_permissions); +} + void MessagesManager::set_dialog_description(DialogId dialog_id, const string &description, Promise &&promise) { LOG(INFO) << "Receive setChatDescription request to set description of " << dialog_id << " to \"" << description << '"'; @@ -21620,7 +21718,7 @@ void MessagesManager::set_dialog_participant_status(DialogId dialog_id, UserId u const tl_object_ptr &chat_member_status, Promise &&promise) { auto status = get_dialog_participant_status(chat_member_status); - LOG(INFO) << "Receive SetChatMemberStatus request with " << user_id << " and " << dialog_id << " to " << status; + LOG(INFO) << "Receive setChatMemberStatus request with " << user_id << " and " << dialog_id << " to " << status; if (!have_dialog_force(dialog_id)) { return promise.set_error(Status::Error(3, "Chat not found")); } @@ -21728,7 +21826,7 @@ std::pair> MessagesManager::search_private_chat std::pair> MessagesManager::search_dialog_participants( DialogId dialog_id, const string &query, int32 limit, DialogParticipantsFilter filter, int64 &random_id, bool force, Promise &&promise) { - LOG(INFO) << "Receive SearchChatMembers request to search for " << query << " in " << dialog_id; + LOG(INFO) << "Receive searchChatMembers request to search for " << query << " in " << dialog_id; if (!have_dialog_force(dialog_id)) { promise.set_error(Status::Error(3, "Chat not found")); return {}; diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 8a422bac5..3eecda2ed 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -420,6 +420,9 @@ class MessagesManager : public Actor { void set_dialog_description(DialogId dialog_id, const string &description, Promise &&promise); + void set_dialog_permissions(DialogId dialog_id, const td_api::object_ptr &permissions, + Promise &&promise); + void pin_dialog_message(DialogId dialog_id, MessageId message_id, bool disable_notification, bool is_unpin, Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 73c059789..7e1bedd4f 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5664,6 +5664,11 @@ void Td::on_request(uint64 id, const td_api::setChatPhoto &request) { messages_manager_->set_dialog_photo(DialogId(request.chat_id_), request.photo_, std::move(promise)); } +void Td::on_request(uint64 id, const td_api::setChatPermissions &request) { + CREATE_OK_REQUEST_PROMISE(); + messages_manager_->set_dialog_permissions(DialogId(request.chat_id_), request.permissions_, std::move(promise)); +} + void Td::on_request(uint64 id, td_api::setChatDraftMessage &request) { CHECK_IS_USER(); answer_ok_query( diff --git a/td/telegram/Td.h b/td/telegram/Td.h index f7205b2b2..86c8cd551 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -638,6 +638,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::setChatPhoto &request); + void on_request(uint64 id, const td_api::setChatPermissions &request); + void on_request(uint64 id, td_api::setChatDraftMessage &request); void on_request(uint64 id, const td_api::toggleChatIsPinned &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index a2feba542..9a986ea48 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -3160,6 +3160,20 @@ class CliClient final : public Actor { std::tie(chat_id, photo_path) = split(args); send_request(td_api::make_object(as_chat_id(chat_id), as_input_file(photo_path))); + } else if (op == "scperm") { + string chat_id; + string permissions; + + std::tie(chat_id, permissions) = split(args); + if (permissions.size() == 8) { + auto &s = permissions; + send_request(td_api::make_object( + as_chat_id(chat_id), + td_api::make_object(s[0] == '1', s[1] == '1', s[2] == '1', s[3] == '1', + s[4] == '1', s[5] == '1', s[6] == '1', s[7] == '1'))); + } else { + LOG(ERROR) << "Wrong permissions size, expected 8"; + } } else if (op == "scpid") { string chat_id; string file_id;