Add members filter to searchChatMembers.

GitOrigin-RevId: 8d553d6c73e32446eaa7e6ebb5bdf562458d258d
This commit is contained in:
levlam 2018-07-20 03:00:17 +03:00
parent 28672b750c
commit 15828a2329
10 changed files with 211 additions and 33 deletions

View File

@ -340,6 +340,24 @@ chatMember user_id:int32 inviter_user_id:int32 joined_chat_date:int32 status:Cha
chatMembers total_count:int32 members:vector<chatMember> = ChatMembers; chatMembers total_count:int32 members:vector<chatMember> = ChatMembers;
//@class ChatMembersFilter @description Specifies the kind of chat members to return in searchChatMembers
//@description Returns the creator and administrators
chatMembersFilterAdministrators = ChatMembersFilter;
//@description Returns all chat members, including restricted chat members
chatMembersFilterMembers = ChatMembersFilter;
//@description Returns users under certain restrictions in the chat; can be used only by administrators in a supergroup
chatMembersFilterRestricted = ChatMembersFilter;
//@description Returns users banned from the chat; can be used only by administrators in a supergroup or in a channel
chatMembersFilterBanned = ChatMembersFilter;
//@description Returns bot members of the chat
chatMembersFilterBots = ChatMembersFilter;
//@class SupergroupMembersFilter @description Specifies the kind of chat members to return in getSupergroupMembers //@class SupergroupMembersFilter @description Specifies the kind of chat members to return in getSupergroupMembers
//@description Returns recently active users in reverse chronological order //@description Returns recently active users in reverse chronological order
@ -2724,8 +2742,8 @@ setChatMemberStatus chat_id:int53 user_id:int32 status:ChatMemberStatus = Ok;
//@description Returns information about a single member of a chat @chat_id Chat identifier @user_id User identifier //@description Returns information about a single member of a chat @chat_id Chat identifier @user_id User identifier
getChatMember chat_id:int53 user_id:int32 = ChatMember; getChatMember chat_id:int53 user_id:int32 = ChatMember;
//@description Searches for a specified query in the first name, last name and username of the members of a specified chat. Requires administrator rights in channels @chat_id Chat identifier @query Query to search for @limit The maximum number of users to be returned //@description Searches for a specified query in the first name, last name and username of the members of a specified chat. Requires administrator rights in channels @chat_id Chat identifier @query Query to search for @limit The maximum number of users to be returned The type of users to return. By default, chatMembersFilterMembers
searchChatMembers chat_id:int53 query:string limit:int32 = ChatMembers; searchChatMembers chat_id:int53 query:string limit:int32 filter:ChatMembersFilter = ChatMembers;
//@description Returns a list of users who are administrators of the chat @chat_id Chat identifier //@description Returns a list of users who are administrators of the chat @chat_id Chat identifier
getChatAdministrators chat_id:int53 = Users; getChatAdministrators chat_id:int53 = Users;

Binary file not shown.

View File

@ -8816,6 +8816,7 @@ DialogParticipant ContactsManager::get_chat_participant(ChatId chat_id, UserId u
std::pair<int32, vector<DialogParticipant>> ContactsManager::search_chat_participants(ChatId chat_id, std::pair<int32, vector<DialogParticipant>> ContactsManager::search_chat_participants(ChatId chat_id,
const string &query, int32 limit, const string &query, int32 limit,
DialogParticipantsFilter filter,
bool force, bool force,
Promise<Unit> &&promise) { Promise<Unit> &&promise) {
if (limit < 0) { if (limit < 0) {
@ -8835,7 +8836,31 @@ std::pair<int32, vector<DialogParticipant>> ContactsManager::search_chat_partici
return {}; return {};
} }
auto user_ids = transform(chat_full->participants, [](const auto &participant) { return participant.user_id; }); auto is_dialog_participant_suitable = [this](const DialogParticipant &participant, DialogParticipantsFilter filter) {
switch (filter) {
case DialogParticipantsFilter::Administrators:
return participant.status.is_administrator();
case DialogParticipantsFilter::Members:
return participant.status.is_member(); // should be always true
case DialogParticipantsFilter::Restricted:
return participant.status.is_restricted(); // should be always false
case DialogParticipantsFilter::Banned:
return participant.status.is_banned(); // should be always false
case DialogParticipantsFilter::Bots:
return is_user_bot(participant.user_id);
default:
UNREACHABLE();
return false;
}
};
vector<UserId> user_ids;
for (auto &participant : chat_full->participants) {
if (is_dialog_participant_suitable(participant, filter)) {
user_ids.push_back(participant.user_id);
}
}
int32 total_count; int32 total_count;
std::tie(total_count, user_ids) = search_among_users(user_ids, query, limit); std::tie(total_count, user_ids) = search_among_users(user_ids, query, limit);
return {total_count, transform(user_ids, [&](UserId user_id) { return *get_chat_participant(chat_full, user_id); })}; return {total_count, transform(user_ids, [&](UserId user_id) { return *get_chat_participant(chat_full, user_id); })};
@ -8902,8 +8927,8 @@ DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id,
} }
std::pair<int32, vector<DialogParticipant>> ContactsManager::get_channel_participants( std::pair<int32, vector<DialogParticipant>> ContactsManager::get_channel_participants(
ChannelId channel_id, const tl_object_ptr<td_api::SupergroupMembersFilter> &filter, int32 offset, int32 limit, ChannelId channel_id, const tl_object_ptr<td_api::SupergroupMembersFilter> &filter, const string &additional_query,
int64 &random_id, bool force, Promise<Unit> &&promise) { int32 offset, int32 limit, int32 additional_limit, int64 &random_id, bool force, Promise<Unit> &&promise) {
if (random_id != 0) { if (random_id != 0) {
// request has already been sent before // request has already been sent before
auto it = received_channel_participants_.find(random_id); auto it = received_channel_participants_.find(random_id);
@ -8911,6 +8936,25 @@ std::pair<int32, vector<DialogParticipant>> ContactsManager::get_channel_partici
auto result = std::move(it->second); auto result = std::move(it->second);
received_channel_participants_.erase(it); received_channel_participants_.erase(it);
promise.set_value(Unit()); promise.set_value(Unit());
if (additional_query.empty()) {
return result;
}
auto user_ids = transform(result.second, [](const auto &participant) { return participant.user_id; });
std::pair<int32, vector<UserId>> result_user_ids = search_among_users(user_ids, additional_query, additional_limit);
result.first = result_user_ids.first;
std::unordered_set<UserId, UserIdHash> result_user_ids_set(result_user_ids.second.begin(),
result_user_ids.second.end());
auto all_participants = std::move(result.second);
result.second.clear();
for (auto &participant : all_participants) {
if (result_user_ids_set.count(participant.user_id)) {
result.second.push_back(std::move(participant));
result_user_ids_set.erase(participant.user_id);
}
}
return result; return result;
} }

View File

@ -377,14 +377,16 @@ class ContactsManager : public Actor {
DialogParticipant get_chat_participant(ChatId chat_id, UserId user_id, bool force, Promise<Unit> &&promise); DialogParticipant get_chat_participant(ChatId chat_id, UserId user_id, bool force, Promise<Unit> &&promise);
std::pair<int32, vector<DialogParticipant>> search_chat_participants(ChatId chat_id, const string &query, int32 limit, std::pair<int32, vector<DialogParticipant>> search_chat_participants(ChatId chat_id, const string &query, int32 limit,
bool force, Promise<Unit> &&promise); DialogParticipantsFilter filter, bool force,
Promise<Unit> &&promise);
DialogParticipant get_channel_participant(ChannelId channel_id, UserId user_id, int64 &random_id, bool force, DialogParticipant get_channel_participant(ChannelId channel_id, UserId user_id, int64 &random_id, bool force,
Promise<Unit> &&promise); Promise<Unit> &&promise);
std::pair<int32, vector<DialogParticipant>> get_channel_participants( std::pair<int32, vector<DialogParticipant>> get_channel_participants(
ChannelId channel_id, const tl_object_ptr<td_api::SupergroupMembersFilter> &filter, int32 offset, int32 limit, ChannelId channel_id, const tl_object_ptr<td_api::SupergroupMembersFilter> &filter,
int64 &random_id, bool force, Promise<Unit> &&promise); const string &additional_query, int32 offset, int32 limit, int32 additional_limit, int64 &random_id, bool force,
Promise<Unit> &&promise);
DialogParticipant get_dialog_participant(ChannelId channel_id, DialogParticipant get_dialog_participant(ChannelId channel_id,
tl_object_ptr<telegram_api::ChannelParticipant> &&participant_ptr) const; tl_object_ptr<telegram_api::ChannelParticipant> &&participant_ptr) const;

View File

@ -425,4 +425,25 @@ ChannelParticipantsFilter::ChannelParticipantsFilter(const tl_object_ptr<td_api:
} }
} }
DialogParticipantsFilter get_dialog_participants_filter(const tl_object_ptr<td_api::ChatMembersFilter> &filter) {
if (filter == nullptr) {
return DialogParticipantsFilter::Members;
}
switch (filter->get_id()) {
case td_api::chatMembersFilterAdministrators::ID:
return DialogParticipantsFilter::Administrators;
case td_api::chatMembersFilterMembers::ID:
return DialogParticipantsFilter::Members;
case td_api::chatMembersFilterRestricted::ID:
return DialogParticipantsFilter::Restricted;
case td_api::chatMembersFilterBanned::ID:
return DialogParticipantsFilter::Banned;
case td_api::chatMembersFilterBots::ID:
return DialogParticipantsFilter::Bots;
default:
UNREACHABLE();
return DialogParticipantsFilter::Members;
}
}
} // namespace td } // namespace td

View File

@ -252,6 +252,10 @@ class ChannelParticipantsFilter {
} }
}; };
enum class DialogParticipantsFilter : int32 { Administrators, Members, Restricted, Banned, Bots };
DialogParticipantsFilter get_dialog_participants_filter(const tl_object_ptr<td_api::ChatMembersFilter> &filter);
DialogParticipantStatus get_dialog_participant_status(const tl_object_ptr<td_api::ChatMemberStatus> &status); DialogParticipantStatus get_dialog_participant_status(const tl_object_ptr<td_api::ChatMemberStatus> &status);
DialogParticipantStatus get_dialog_participant_status( DialogParticipantStatus get_dialog_participant_status(

View File

@ -21562,11 +21562,33 @@ DialogParticipant MessagesManager::get_dialog_participant(DialogId dialog_id, Us
return DialogParticipant(); return DialogParticipant();
} }
std::pair<int32, vector<DialogParticipant>> MessagesManager::search_private_chat_participants(UserId my_user_id, std::pair<int32, vector<DialogParticipant>> MessagesManager::search_private_chat_participants(
UserId peer_user_id, UserId my_user_id, UserId peer_user_id, const string &query, int32 limit, DialogParticipantsFilter filter) const {
const string &query, vector<UserId> user_ids;
int32 limit) const { switch (filter) {
auto result = td_->contacts_manager_->search_among_users({my_user_id, peer_user_id}, query, limit); case DialogParticipantsFilter::Administrators:
break;
case DialogParticipantsFilter::Members:
user_ids.push_back(my_user_id);
user_ids.push_back(peer_user_id);
break;
case DialogParticipantsFilter::Restricted:
break;
case DialogParticipantsFilter::Banned:
break;
case DialogParticipantsFilter::Bots:
if (td_->auth_manager_->is_bot()) {
user_ids.push_back(my_user_id);
}
if (td_->contacts_manager_->is_user_bot(peer_user_id)) {
user_ids.push_back(peer_user_id);
}
break;
default:
UNREACHABLE();
}
auto result = td_->contacts_manager_->search_among_users(user_ids, query, limit);
return {result.first, transform(result.second, [&](UserId user_id) { return {result.first, transform(result.second, [&](UserId user_id) {
return DialogParticipant(user_id, user_id == my_user_id ? peer_user_id : my_user_id, 0, return DialogParticipant(user_id, user_id == my_user_id ? peer_user_id : my_user_id, 0,
DialogParticipantStatus::Member()); DialogParticipantStatus::Member());
@ -21574,7 +21596,8 @@ std::pair<int32, vector<DialogParticipant>> MessagesManager::search_private_chat
} }
std::pair<int32, vector<DialogParticipant>> MessagesManager::search_dialog_participants( std::pair<int32, vector<DialogParticipant>> MessagesManager::search_dialog_participants(
DialogId dialog_id, const string &query, int32 limit, int64 &random_id, bool force, Promise<Unit> &&promise) { DialogId dialog_id, const string &query, int32 limit, DialogParticipantsFilter filter, int64 &random_id, bool force,
Promise<Unit> &&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)) { if (!have_dialog_force(dialog_id)) {
promise.set_error(Status::Error(3, "Chat not found")); promise.set_error(Status::Error(3, "Chat not found"));
@ -21589,19 +21612,49 @@ std::pair<int32, vector<DialogParticipant>> MessagesManager::search_dialog_parti
case DialogType::User: case DialogType::User:
promise.set_value(Unit()); promise.set_value(Unit());
return search_private_chat_participants(td_->contacts_manager_->get_my_id("search_dialog_participants"), return search_private_chat_participants(td_->contacts_manager_->get_my_id("search_dialog_participants"),
dialog_id.get_user_id(), query, limit); dialog_id.get_user_id(), query, limit, filter);
case DialogType::Chat: case DialogType::Chat:
return td_->contacts_manager_->search_chat_participants(dialog_id.get_chat_id(), query, limit, force, return td_->contacts_manager_->search_chat_participants(dialog_id.get_chat_id(), query, limit, filter, force,
std::move(promise)); std::move(promise));
case DialogType::Channel: case DialogType::Channel: {
return td_->contacts_manager_->get_channel_participants( tl_object_ptr<td_api::SupergroupMembersFilter> request_filter;
dialog_id.get_channel_id(), td_api::make_object<td_api::supergroupMembersFilterSearch>(query), 0, limit, string additional_query;
random_id, force, std::move(promise)); int32 additional_limit = 0;
switch (filter) {
case DialogParticipantsFilter::Administrators:
request_filter = td_api::make_object<td_api::supergroupMembersFilterAdministrators>();
additional_query = query;
additional_limit = limit;
limit = 100;
break;
case DialogParticipantsFilter::Members:
request_filter = td_api::make_object<td_api::supergroupMembersFilterSearch>(query);
break;
case DialogParticipantsFilter::Restricted:
request_filter = td_api::make_object<td_api::supergroupMembersFilterRestricted>(query);
break;
case DialogParticipantsFilter::Banned:
request_filter = td_api::make_object<td_api::supergroupMembersFilterBanned>(query);
break;
case DialogParticipantsFilter::Bots:
request_filter = td_api::make_object<td_api::supergroupMembersFilterBots>();
additional_query = query;
additional_limit = limit;
limit = 100;
break;
default:
UNREACHABLE();
}
return td_->contacts_manager_->get_channel_participants(dialog_id.get_channel_id(), request_filter,
additional_query, 0, limit, additional_limit, random_id,
force, std::move(promise));
}
case DialogType::SecretChat: { case DialogType::SecretChat: {
promise.set_value(Unit()); promise.set_value(Unit());
auto peer_user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()); auto peer_user_id = td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id());
return search_private_chat_participants(td_->contacts_manager_->get_my_id("search_dialog_participants"), return search_private_chat_participants(td_->contacts_manager_->get_my_id("search_dialog_participants"),
peer_user_id, query, limit); peer_user_id, query, limit, filter);
} }
case DialogType::None: case DialogType::None:
default: default:

View File

@ -1171,7 +1171,8 @@ class MessagesManager : public Actor {
Promise<Unit> &&promise); Promise<Unit> &&promise);
std::pair<int32, vector<DialogParticipant>> search_dialog_participants(DialogId dialog_id, const string &query, std::pair<int32, vector<DialogParticipant>> search_dialog_participants(DialogId dialog_id, const string &query,
int32 limit, int64 &random_id, bool force, int32 limit, DialogParticipantsFilter filter,
int64 &random_id, bool force,
Promise<Unit> &&promise); Promise<Unit> &&promise);
vector<UserId> get_dialog_administrators(DialogId dialog_id, int left_tries, Promise<Unit> &&promise); vector<UserId> get_dialog_administrators(DialogId dialog_id, int left_tries, Promise<Unit> &&promise);
@ -2397,7 +2398,8 @@ class MessagesManager : public Actor {
void update_dialogs_hints_rating(const Dialog *d); void update_dialogs_hints_rating(const Dialog *d);
std::pair<int32, vector<DialogParticipant>> search_private_chat_participants(UserId my_user_id, UserId peer_user_id, std::pair<int32, vector<DialogParticipant>> search_private_chat_participants(UserId my_user_id, UserId peer_user_id,
const string &query, int32 limit) const; const string &query, int32 limit,
DialogParticipantsFilter filter) const;
static unique_ptr<Message> *find_message(unique_ptr<Message> *v, MessageId message_id); static unique_ptr<Message> *find_message(unique_ptr<Message> *v, MessageId message_id);
static const unique_ptr<Message> *find_message(const unique_ptr<Message> *v, MessageId message_id); static const unique_ptr<Message> *find_message(const unique_ptr<Message> *v, MessageId message_id);

View File

@ -6,8 +6,6 @@
// //
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
#include "td/db/binlog/BinlogEvent.h"
#include "td/telegram/net/ConnectionCreator.h" #include "td/telegram/net/ConnectionCreator.h"
#include "td/telegram/net/DcId.h" #include "td/telegram/net/DcId.h"
#include "td/telegram/net/MtprotoHeader.h" #include "td/telegram/net/MtprotoHeader.h"
@ -71,6 +69,8 @@
#include "td/actor/actor.h" #include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h" #include "td/actor/PromiseFuture.h"
#include "td/db/binlog/BinlogEvent.h"
#include "td/mtproto/utils.h" // for create_storer, fetch_result, etc, TODO #include "td/mtproto/utils.h" // for create_storer, fetch_result, etc, TODO
#include "td/utils/buffer.h" #include "td/utils/buffer.h"
@ -1850,12 +1850,13 @@ class SearchChatMembersRequest : public RequestActor<> {
DialogId dialog_id_; DialogId dialog_id_;
string query_; string query_;
int32 limit_; int32 limit_;
DialogParticipantsFilter filter_;
int64 random_id_ = 0; int64 random_id_ = 0;
std::pair<int32, vector<DialogParticipant>> participants_; std::pair<int32, vector<DialogParticipant>> participants_;
void do_run(Promise<Unit> &&promise) override { void do_run(Promise<Unit> &&promise) override {
participants_ = td->messages_manager_->search_dialog_participants(dialog_id_, query_, limit_, random_id_, participants_ = td->messages_manager_->search_dialog_participants(dialog_id_, query_, limit_, filter_, random_id_,
get_tries() < 3, std::move(promise)); get_tries() < 3, std::move(promise));
} }
@ -1871,8 +1872,13 @@ class SearchChatMembersRequest : public RequestActor<> {
} }
public: public:
SearchChatMembersRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, string &&query, int32 limit) SearchChatMembersRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, string &&query, int32 limit,
: RequestActor(std::move(td), request_id), dialog_id_(dialog_id), query_(std::move(query)), limit_(limit) { DialogParticipantsFilter filter)
: RequestActor(std::move(td), request_id)
, dialog_id_(dialog_id)
, query_(std::move(query))
, limit_(limit)
, filter_(filter) {
set_tries(3); set_tries(3);
} }
}; };
@ -2158,8 +2164,8 @@ class GetSupergroupMembersRequest : public RequestActor<> {
std::pair<int32, vector<DialogParticipant>> participants_; std::pair<int32, vector<DialogParticipant>> participants_;
void do_run(Promise<Unit> &&promise) override { void do_run(Promise<Unit> &&promise) override {
participants_ = td->contacts_manager_->get_channel_participants(channel_id_, filter_, offset_, limit_, random_id_, participants_ = td->contacts_manager_->get_channel_participants(channel_id_, filter_, string(), offset_, limit_, -1,
get_tries() < 3, std::move(promise)); random_id_, get_tries() < 3, std::move(promise));
} }
void do_send_result() override { void do_send_result() override {
@ -5476,7 +5482,8 @@ void Td::on_request(uint64 id, const td_api::getChatMember &request) {
void Td::on_request(uint64 id, td_api::searchChatMembers &request) { void Td::on_request(uint64 id, td_api::searchChatMembers &request) {
CLEAN_INPUT_STRING(request.query_); CLEAN_INPUT_STRING(request.query_);
CREATE_REQUEST(SearchChatMembersRequest, request.chat_id_, std::move(request.query_), request.limit_); CREATE_REQUEST(SearchChatMembersRequest, request.chat_id_, std::move(request.query_), request.limit_,
get_dialog_participants_filter(request.filter_));
} }
void Td::on_request(uint64 id, td_api::getChatAdministrators &request) { void Td::on_request(uint64 id, td_api::getChatAdministrators &request) {

View File

@ -923,6 +923,30 @@ class CliClient final : public Actor {
return nullptr; return nullptr;
} }
static tl_object_ptr<td_api::ChatMembersFilter> get_chat_members_filter(MutableSlice filter) {
filter = trim(filter);
to_lower_inplace(filter);
if (filter == "a" || filter == "admin" || filter == "administrators") {
return make_tl_object<td_api::chatMembersFilterAdministrators>();
}
if (filter == "b" || filter == "banned") {
return make_tl_object<td_api::chatMembersFilterBanned>();
}
if (filter == "bot" || filter == "bots") {
return make_tl_object<td_api::chatMembersFilterBots>();
}
if (filter == "m" || filter == "members") {
return make_tl_object<td_api::chatMembersFilterMembers>();
}
if (filter == "r" || filter == "rest" || filter == "restricted") {
return make_tl_object<td_api::chatMembersFilterRestricted>();
}
if (!filter.empty()) {
LOG(ERROR) << "Unsupported chat member filter " << filter;
}
return nullptr;
}
tl_object_ptr<td_api::TopChatCategory> get_top_chat_category(MutableSlice category) { tl_object_ptr<td_api::TopChatCategory> get_top_chat_category(MutableSlice category) {
category = trim(category); category = trim(category);
to_lower_inplace(category); to_lower_inplace(category);
@ -1969,10 +1993,13 @@ class CliClient final : public Actor {
string chat_id; string chat_id;
string limit; string limit;
string query; string query;
string filter;
std::tie(chat_id, args) = split(args); std::tie(chat_id, args) = split(args);
std::tie(limit, query) = split(args); std::tie(limit, args) = split(args);
send_request(make_tl_object<td_api::searchChatMembers>(as_chat_id(chat_id), query, to_integer<int32>(limit))); std::tie(query, filter) = split(args);
send_request(make_tl_object<td_api::searchChatMembers>(as_chat_id(chat_id), query, to_integer<int32>(limit),
get_chat_members_filter(filter)));
} else if (op == "gcm") { } else if (op == "gcm") {
string chat_id; string chat_id;
string user_id; string user_id;