diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index dc226d9d1..1346e9e4b 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -566,6 +566,12 @@ chatInviteLinks total_count:int32 invite_links:vector = ChatInvi //@is_public True, if the chat is a public supergroup or channel, i.e. it has a username or it is a location-based supergroup chatInviteLinkInfo chat_id:int53 accessible_for:int32 type:ChatType title:string photo:chatPhotoInfo member_count:int32 member_user_ids:vector is_public:Bool = ChatInviteLinkInfo; +//@description Describes a user joined a chat by an invite link @user_id User identifier @joined_chat_date Point in time (Unix timestamp) when the user joined the chat +chatInviteLinkUser user_id:int32 joined_chat_date:int32 = ChatInviteLinkUser; + +//@description Contains a list of users joined a chat by an invite link @total_count Approximate total count of users found @users List of users, joined a chat by an invite link +chatInviteLinkUsers total_count:int32 users:vector = ChatInviteLinkUsers; + //@description Represents a basic group of 0-200 users (must be upgraded to a supergroup to accommodate more than 200 users) //@id Group identifier @@ -4368,10 +4374,14 @@ createChatInviteLink chat_id:int53 expire_date:int32 usage_limit:int32 is_perman //@is_revoked True, if the link is revoked editChatInviteLink chat_id:int53 invite_link:string expire_date:int32 usage_limit:int32 is_revoked:Bool = ChatInviteLink; -//@description Returns exported invite links for a chat @chat_id Chat identifier @administrator_user_id If not 0, only invite links created by the specified administrator will be returned +//@description Returns exported invite links for a chat. Requires administrator privileges and can_invite_users right @chat_id Chat identifier @administrator_user_id If not 0, only invite links created by the specified administrator will be returned //@offset_invite_link Invite link starting after which to return invite links; use empty string to get results from the beginning @limit Maximum number of invite links to return getChatInviteLinks chat_id:int53 administrator_user_id:int32 offset_invite_link:string limit:int32 = ChatInviteLinks; +//@description Returns users joined a chat by an invite link. Requires administrator privileges and can_invite_users right @chat_id Chat identifier @invite_link Invite link for which to return users +//@offset_user A user from which to return next users; use null to get results from the beginning @limit Maximum number of users to return +getChatInviteLinkUsers chat_id:int53 invite_link:string offset_user:chatInviteLinkUser limit:int32 = ChatInviteLinkUsers; + //@description Checks the validity of an invite link for a chat and returns information about the corresponding chat @invite_link Invite link to be checked; must begin with "https://t.me/joinchat/", "https://telegram.me/joinchat/", or "https://telegram.dog/joinchat/" checkChatInviteLink invite_link:string = ChatInviteLinkInfo; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index ee686f866..45a58fda1 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 3a3f34d7b..bcb37513a 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -1708,6 +1708,67 @@ class GetExportedChatInvitesQuery : public Td::ResultHandler { } }; +class GetChatInviteImportersQuery : public Td::ResultHandler { + Promise> promise_; + DialogId dialog_id_; + + public: + explicit GetChatInviteImportersQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send(DialogId dialog_id, const string &invite_link, int32 offset_date, UserId offset_user_id, int32 limit) { + dialog_id_ = dialog_id; + auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); + if (input_peer == nullptr) { + return on_error(0, Status::Error(400, "Can't access the chat")); + } + + auto input_user = td->contacts_manager_->get_input_user(offset_user_id); + if (input_user == nullptr) { + input_user = make_tl_object(); + } + + send_query(G()->net_query_creator().create(telegram_api::messages_getChatInviteImporters( + std::move(input_peer), invite_link, offset_date, std::move(input_user), limit))); + } + + 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 result = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetChatInviteImportersQuery: " << to_string(result); + + td->contacts_manager_->on_get_users(std::move(result->users_), "GetChatInviteImportersQuery"); + + int32 total_count = result->count_; + if (total_count < static_cast(result->importers_.size())) { + LOG(ERROR) << "Receive wrong total count of invite link users " << total_count << " in " << dialog_id_; + total_count = static_cast(result->importers_.size()); + } + vector> invite_link_users; + for (auto &importer : result->importers_) { + UserId user_id(importer->user_id_); + if (!user_id.is_valid()) { + LOG(ERROR) << "Receive invalid invite link " << user_id << " in " << dialog_id_; + total_count--; + continue; + } + invite_link_users.push_back(td_api::make_object( + td->contacts_manager_->get_user_id_object(user_id, "chatInviteLinkUser"), importer->date_)); + } + promise_.set_value(td_api::make_object(total_count, std::move(invite_link_users))); + } + + void on_error(uint64 id, Status status) override { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetChatInviteImportersQuery"); + promise_.set_error(std::move(status)); + } +}; + class CheckDialogInviteLinkQuery : public Td::ResultHandler { Promise promise_; string invite_link_; @@ -6704,6 +6765,27 @@ void ContactsManager::get_dialog_invite_links(DialogId dialog_id, UserId adminis ->send(dialog_id, administrator_user_id, offset_invite_link, limit); } +void ContactsManager::get_dialog_invite_link_users(DialogId dialog_id, const string &invite_link, + td_api::object_ptr offset_user, + int32 limit, + Promise> &&promise) { + TRY_STATUS_PROMISE(promise, can_manage_dialog_invite_links(dialog_id)); + + if (limit <= 0) { + return promise.set_error(Status::Error(400, "Parameter limit must be positive")); + } + + UserId offset_user_id; + int32 offset_date = 0; + if (offset_user != nullptr) { + offset_user_id = UserId(offset_user->user_id_); + offset_date = offset_user->joined_chat_date_; + } + + td_->create_handler(std::move(promise)) + ->send(dialog_id, invite_link, offset_date, offset_user_id, limit); +} + void ContactsManager::check_dialog_invite_link(const string &invite_link, Promise &&promise) const { if (invite_link_infos_.count(invite_link) > 0) { return promise.set_value(Unit()); diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index af9323224..6395c98b7 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -396,6 +396,10 @@ class ContactsManager : public Actor { void get_dialog_invite_links(DialogId dialog_id, UserId administrator_user_id, const string &offset_invite_link, int32 limit, Promise> &&promise); + void get_dialog_invite_link_users(DialogId dialog_id, const string &invite_link, + td_api::object_ptr offset_user, int32 limit, + Promise> &&promise); + void check_dialog_invite_link(const string &invite_link, Promise &&promise) const; void import_dialog_invite_link(const string &invite_link, Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index d280ba6d4..52e8eb44e 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6295,6 +6295,13 @@ void Td::on_request(uint64 id, td_api::getChatInviteLinks &request) { request.offset_invite_link_, request.limit_, std::move(promise)); } +void Td::on_request(uint64 id, td_api::getChatInviteLinkUsers &request) { + CREATE_REQUEST_PROMISE(); + CLEAN_INPUT_STRING(request.invite_link_); + contacts_manager_->get_dialog_invite_link_users(DialogId(request.chat_id_), request.invite_link_, + std::move(request.offset_user_), request.limit_, std::move(promise)); +} + void Td::on_request(uint64 id, td_api::checkChatInviteLink &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.invite_link_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 775bcb868..1f9e8f21d 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -792,6 +792,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::getChatInviteLinks &request); + void on_request(uint64 id, td_api::getChatInviteLinkUsers &request); + void on_request(uint64 id, td_api::checkChatInviteLink &request); void on_request(uint64 id, td_api::joinChatByInviteLink &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index b413a4f6f..0b7efc4e3 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2706,6 +2706,16 @@ class CliClient final : public Actor { get_args(args, chat_id, administrator_user_id, offset_invite_link, limit); send_request(td_api::make_object( as_chat_id(chat_id), as_user_id(administrator_user_id), offset_invite_link, as_limit(limit))); + } else if (op == "gcilu") { + string chat_id; + string invite_link; + string offset_user_id; + int32 offset_date; + string limit; + get_args(args, chat_id, invite_link, offset_user_id, offset_date, limit); + send_request(td_api::make_object( + as_chat_id(chat_id), invite_link, + td_api::make_object(as_user_id(offset_user_id), offset_date), as_limit(limit))); } else if (op == "ccil") { send_request(td_api::make_object(args)); } else if (op == "jcbil") {