diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 384f138cb..1b9ef021c 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -8779,16 +8779,17 @@ joinChat chat_id:int53 = Ok; //@description Removes the current user from chat members. Private and secret chats can't be left using this method @chat_id Chat identifier leaveChat chat_id:int53 = Ok; -//@description Adds a new member to a chat; requires can_invite_users member right. Members can't be added to private or secret chats +//@description Adds a new member to a chat; requires can_invite_users member right. Members can't be added to private or secret chats. Returns information about members that weren't added //@chat_id Chat identifier //@user_id Identifier of the user //@forward_limit The number of earlier messages from the chat to be forwarded to the new member; up to 100. Ignored for supergroups and channels, or if the added user is a bot -addChatMember chat_id:int53 user_id:int53 forward_limit:int32 = Ok; +addChatMember chat_id:int53 user_id:int53 forward_limit:int32 = FailedToAddMembers; -//@description Adds multiple new members to a chat; requires can_invite_users member right. Currently, this method is only available for supergroups and channels. This method can't be used to join a chat. Members can't be added to a channel if it has more than 200 members +//@description Adds multiple new members to a chat; requires can_invite_users member right. Currently, this method is only available for supergroups and channels. +//-This method can't be used to join a chat. Members can't be added to a channel if it has more than 200 members. Returns information about members that weren't added //@chat_id Chat identifier //@user_ids Identifiers of the users to be added to the chat. The maximum number of added users is 20 for supergroups and 100 for channels -addChatMembers chat_id:int53 user_ids:vector = Ok; +addChatMembers chat_id:int53 user_ids:vector = FailedToAddMembers; //@description Changes the status of a chat member; requires can_invite_users member right to add a chat member, can_promote_members administrator right to change administrator rights of the member, //-and can_restrict_members administrator right to change restrictions of a user. This function is currently not suitable for transferring chat ownership; use transferChatOwnership instead. diff --git a/td/telegram/DialogParticipantManager.cpp b/td/telegram/DialogParticipantManager.cpp index b648112a1..12aaa32ea 100644 --- a/td/telegram/DialogParticipantManager.cpp +++ b/td/telegram/DialogParticipantManager.cpp @@ -17,6 +17,7 @@ #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/MessagesManager.h" #include "td/telegram/misc.h" +#include "td/telegram/MissingInvitee.h" #include "td/telegram/PasswordManager.h" #include "td/telegram/StoryManager.h" #include "td/telegram/Td.h" @@ -423,12 +424,13 @@ class GetChannelParticipantsQuery final : public Td::ResultHandler { }; class AddChatUserQuery final : public Td::ResultHandler { - Promise promise_; + Promise> promise_; ChatId chat_id_; UserId user_id_; public: - explicit AddChatUserQuery(Promise &&promise) : promise_(std::move(promise)) { + explicit AddChatUserQuery(Promise> &&promise) + : promise_(std::move(promise)) { } void send(ChatId chat_id, UserId user_id, tl_object_ptr &&input_user, int32 forward_limit) { @@ -446,15 +448,15 @@ class AddChatUserQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for AddChatUserQuery: " << to_string(ptr); - td_->updates_manager_->on_get_updates(std::move(ptr->updates_), std::move(promise_)); + td_->updates_manager_->on_get_updates( + std::move(ptr->updates_), + PromiseCreator::lambda( + [missing_invitees = MissingInvitees(std::move(ptr->missing_invitees_)) + .get_failed_to_add_members_object(td_->user_manager_.get()), + promise = std::move(promise_)](Result) mutable { promise.set_value(std::move(missing_invitees)); })); } void on_error(Status status) final { - if (!td_->auth_manager_->is_bot() && status.message() == "USER_PRIVACY_RESTRICTED") { - td_->dialog_participant_manager_->send_update_add_chat_members_privacy_forbidden(DialogId(chat_id_), {user_id_}, - "AddChatUserQuery"); - return promise_.set_error(Status::Error(406, "USER_PRIVACY_RESTRICTED")); - } promise_.set_error(std::move(status)); } }; @@ -569,12 +571,13 @@ class JoinChannelQuery final : public Td::ResultHandler { }; class InviteToChannelQuery final : public Td::ResultHandler { - Promise promise_; + Promise> promise_; ChannelId channel_id_; vector user_ids_; public: - explicit InviteToChannelQuery(Promise &&promise) : promise_(std::move(promise)) { + explicit InviteToChannelQuery(Promise> &&promise) + : promise_(std::move(promise)) { } void send(ChannelId channel_id, vector user_ids, @@ -596,15 +599,15 @@ class InviteToChannelQuery final : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(INFO) << "Receive result for InviteToChannelQuery: " << to_string(ptr); td_->chat_manager_->invalidate_channel_full(channel_id_, false, "InviteToChannelQuery"); - td_->updates_manager_->on_get_updates(std::move(std::move(ptr->updates_)), std::move(promise_)); + td_->updates_manager_->on_get_updates( + std::move(std::move(ptr->updates_)), + PromiseCreator::lambda( + [missing_invitees = MissingInvitees(std::move(ptr->missing_invitees_)) + .get_failed_to_add_members_object(td_->user_manager_.get()), + promise = std::move(promise_)](Result) mutable { promise.set_value(std::move(missing_invitees)); })); } void on_error(Status status) final { - if (!td_->auth_manager_->is_bot() && status.message() == "USER_PRIVACY_RESTRICTED") { - td_->dialog_participant_manager_->send_update_add_chat_members_privacy_forbidden( - DialogId(channel_id_), std::move(user_ids_), "InviteToChannelQuery"); - return promise_.set_error(Status::Error(406, "USER_PRIVACY_RESTRICTED")); - } td_->chat_manager_->on_get_channel_error(channel_id_, status, "InviteToChannelQuery"); td_->chat_manager_->invalidate_channel_full(channel_id_, false, "InviteToChannelQuery"); promise_.set_error(std::move(status)); @@ -1978,8 +1981,9 @@ void DialogParticipantManager::search_dialog_participants(DialogId dialog_id, co } } -void DialogParticipantManager::add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, - Promise &&promise) { +void DialogParticipantManager::add_dialog_participant( + DialogId dialog_id, UserId user_id, int32 forward_limit, + Promise> &&promise) { if (!td_->dialog_manager_->have_dialog_force(dialog_id, "add_dialog_participant")) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -2000,8 +2004,9 @@ void DialogParticipantManager::add_dialog_participant(DialogId dialog_id, UserId } } -void DialogParticipantManager::add_dialog_participants(DialogId dialog_id, const vector &user_ids, - Promise &&promise) { +void DialogParticipantManager::add_dialog_participants( + DialogId dialog_id, const vector &user_ids, + Promise> &&promise) { if (!td_->dialog_manager_->have_dialog_force(dialog_id, "add_dialog_participants")) { return promise.set_error(Status::Error(400, "Chat not found")); } @@ -2113,8 +2118,24 @@ void DialogParticipantManager::leave_dialog(DialogId dialog_id, Promise && } } +Promise> DialogParticipantManager::wrap_failed_to_add_members_promise( + Promise &&promise) { + return PromiseCreator::lambda( + [promise = std::move(promise)](Result> &&result) mutable { + if (result.is_ok()) { + if (result.ok()->failed_to_add_members_.empty()) { + promise.set_value(Unit()); + } else { + promise.set_error(Status::Error(403, "USER_PRIVACY_RESTRICTED")); + } + } else { + promise.set_error(result.move_as_error()); + } + }); +} + void DialogParticipantManager::add_chat_participant(ChatId chat_id, UserId user_id, int32 forward_limit, - Promise &&promise) { + Promise> &&promise) { if (!td_->chat_manager_->get_chat_is_active(chat_id)) { if (!td_->chat_manager_->have_chat(chat_id)) { return promise.set_error(Status::Error(400, "Chat info not found")); @@ -2180,7 +2201,7 @@ void DialogParticipantManager::set_chat_participant_status(ChatId chat_id, UserI auto participant = td_->chat_manager_->get_chat_participant(chat_id, user_id); if (participant == nullptr && !status.is_administrator()) { // the user isn't a member, but needs to be added - return add_chat_participant(chat_id, user_id, 0, std::move(promise)); + return add_chat_participant(chat_id, user_id, 0, wrap_failed_to_add_members_promise(std::move(promise))); } auto permissions = td_->chat_manager_->get_chat_permissions(chat_id); @@ -2195,15 +2216,19 @@ void DialogParticipantManager::set_chat_participant_status(ChatId chat_id, UserI if (participant == nullptr) { // the user must be added first CHECK(status.is_administrator()); - auto add_chat_participant_promise = PromiseCreator::lambda( - [actor_id = actor_id(this), chat_id, user_id, promise = std::move(promise)](Result &&result) mutable { + auto add_chat_participant_promise = + PromiseCreator::lambda([actor_id = actor_id(this), chat_id, user_id, promise = std::move(promise)]( + Result> &&result) mutable { if (result.is_error()) { promise.set_error(result.move_as_error()); + } else if (!result.ok()->failed_to_add_members_.empty()) { + promise.set_error(Status::Error(403, "USER_PRIVACY_RESTRICTED")); } else { send_closure(actor_id, &DialogParticipantManager::send_edit_chat_admin_query, chat_id, user_id, true, std::move(promise)); } }); + return add_chat_participant(chat_id, user_id, 0, std::move(add_chat_participant_promise)); } @@ -2271,9 +2296,9 @@ void DialogParticipantManager::delete_chat_participant(ChatId chat_id, UserId us td_->create_handler(std::move(promise))->send(chat_id, std::move(input_user), revoke_messages); } -void DialogParticipantManager::add_channel_participant(ChannelId channel_id, UserId user_id, - const DialogParticipantStatus &old_status, - Promise &&promise) { +void DialogParticipantManager::add_channel_participant( + ChannelId channel_id, UserId user_id, const DialogParticipantStatus &old_status, + Promise> &&promise) { if (td_->auth_manager_->is_bot()) { return promise.set_error(Status::Error(400, "Bots can't add new chat members")); } @@ -2290,7 +2315,7 @@ void DialogParticipantManager::add_channel_participant(ChannelId channel_id, Use return promise.set_error(Status::Error(400, "Can't return to kicked from chat")); } if (my_status.is_member()) { - return promise.set_value(Unit()); + return promise.set_value(MissingInvitees().get_failed_to_add_members_object(td_->user_manager_.get())); } auto &queries = join_channel_queries_[channel_id]; @@ -2329,14 +2354,17 @@ void DialogParticipantManager::on_join_channel(ChannelId channel_id, Resultuser_manager_.get())); + } } else { fail_promises(promises, result.move_as_error()); } } -void DialogParticipantManager::add_channel_participants(ChannelId channel_id, const vector &user_ids, - Promise &&promise) { +void DialogParticipantManager::add_channel_participants( + ChannelId channel_id, const vector &user_ids, + Promise> &&promise) { if (td_->auth_manager_->is_bot()) { return promise.set_error(Status::Error(400, "Bots can't add new chat members")); } @@ -2364,7 +2392,7 @@ void DialogParticipantManager::add_channel_participants(ChannelId channel_id, co } if (input_users.empty()) { - return promise.set_value(Unit()); + return promise.set_value(MissingInvitees().get_failed_to_add_members_object(td_->user_manager_.get())); } td_->create_handler(std::move(promise))->send(channel_id, user_ids, std::move(input_users)); @@ -2493,7 +2521,8 @@ void DialogParticipantManager::set_channel_participant_status_impl(ChannelId cha if (participant_dialog_id.get_type() != DialogType::User) { return promise.set_error(Status::Error(400, "Can't add chats as chat members")); } - return add_channel_participant(channel_id, participant_dialog_id.get_user_id(), old_status, std::move(promise)); + return add_channel_participant(channel_id, participant_dialog_id.get_user_id(), old_status, + wrap_failed_to_add_members_promise(std::move(promise))); } } @@ -2628,13 +2657,14 @@ void DialogParticipantManager::restrict_channel_participant(ChannelId channel_id create_actor( "AddChannelParticipantSleepActor", 1.0, PromiseCreator::lambda([actor_id, channel_id, participant_dialog_id, old_status = std::move(old_status), - promise = std::move(promise)](Result<> result) mutable { + promise = std::move(promise)](Result result) mutable { if (result.is_error()) { return promise.set_error(result.move_as_error()); } send_closure(actor_id, &DialogParticipantManager::add_channel_participant, channel_id, - participant_dialog_id.get_user_id(), old_status, std::move(promise)); + participant_dialog_id.get_user_id(), old_status, + wrap_failed_to_add_members_promise(std::move(promise))); })) .release(); }); diff --git a/td/telegram/DialogParticipantManager.h b/td/telegram/DialogParticipantManager.h index c7b554e1f..8efd67caf 100644 --- a/td/telegram/DialogParticipantManager.h +++ b/td/telegram/DialogParticipantManager.h @@ -109,9 +109,14 @@ class DialogParticipantManager final : public Actor { void search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, DialogParticipantFilter filter, Promise &&promise); - void add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, Promise &&promise); + static Promise> wrap_failed_to_add_members_promise( + Promise &&promise); - void add_dialog_participants(DialogId dialog_id, const vector &user_ids, Promise &&promise); + void add_dialog_participant(DialogId dialog_id, UserId user_id, int32 forward_limit, + Promise> &&promise); + + 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, td_api::object_ptr &&chat_member_status, @@ -221,18 +226,20 @@ class DialogParticipantManager final : public Actor { void set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status, bool is_recursive, Promise &&promise); - void add_chat_participant(ChatId chat_id, UserId user_id, int32 forward_limit, Promise &&promise); + void add_chat_participant(ChatId chat_id, UserId user_id, int32 forward_limit, + 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); void add_channel_participant(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &old_status, - Promise &&promise); + Promise> &&promise); void on_join_channel(ChannelId channel_id, Result &&result); - void add_channel_participants(ChannelId channel_id, const vector &user_ids, Promise &&promise); + void add_channel_participants(ChannelId channel_id, const vector &user_ids, + Promise> &&promise); void set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id, td_api::object_ptr &&chat_member_status, @@ -299,7 +306,8 @@ class DialogParticipantManager final : public Actor { FlatHashMap, ChannelIdHash> cached_channel_participants_; - FlatHashMap>, ChannelIdHash> join_channel_queries_; + FlatHashMap>>, ChannelIdHash> + join_channel_queries_; MultiTimeout update_dialog_online_member_count_timeout_{"UpdateDialogOnlineMemberCountTimeout"}; MultiTimeout channel_participant_cache_timeout_{"ChannelParticipantCacheTimeout"}; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 56f375551..3c63208c0 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -7054,8 +7054,9 @@ void Td::on_request(uint64 id, const td_api::unpinAllMessageThreadMessages &requ void Td::on_request(uint64 id, const td_api::joinChat &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - dialog_participant_manager_->add_dialog_participant(DialogId(request.chat_id_), user_manager_->get_my_id(), 0, - std::move(promise)); + dialog_participant_manager_->add_dialog_participant( + DialogId(request.chat_id_), user_manager_->get_my_id(), 0, + DialogParticipantManager::wrap_failed_to_add_members_promise(std::move(promise))); } void Td::on_request(uint64 id, const td_api::leaveChat &request) { @@ -7079,14 +7080,14 @@ void Td::on_request(uint64 id, const td_api::leaveChat &request) { void Td::on_request(uint64 id, const td_api::addChatMember &request) { CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); + CREATE_REQUEST_PROMISE(); dialog_participant_manager_->add_dialog_participant(DialogId(request.chat_id_), UserId(request.user_id_), request.forward_limit_, std::move(promise)); } void Td::on_request(uint64 id, const td_api::addChatMembers &request) { CHECK_IS_USER(); - CREATE_OK_REQUEST_PROMISE(); + CREATE_REQUEST_PROMISE(); dialog_participant_manager_->add_dialog_participants(DialogId(request.chat_id_), UserId::get_user_ids(request.user_ids_), std::move(promise)); }