Add td_api::getMessageViewers.

This commit is contained in:
levlam 2021-09-03 16:14:03 +03:00
parent 944e8a3c64
commit a4f66c69cb
8 changed files with 191 additions and 0 deletions

View File

@ -4081,6 +4081,9 @@ getMessages chat_id:int53 message_ids:vector<int53> = Messages;
//@description Returns information about a message thread. Can be used only if message.can_get_message_thread == true @chat_id Chat identifier @message_id Identifier of the message
getMessageThread chat_id:int53 message_id:int53 = MessageThreadInfo;
//@description Returns viewers of a recent outgoing message in a basic group or a supergroup chat. For video notes and voice notes only users, opened content of the message, are returned. The method can be called if message.can_get_viewers == true @chat_id Chat identifier @message_id Identifier of the message
getMessageViewers chat_id:int53 message_id:int53 = Users;
//@description Returns information about a file; this is an offline request @file_id Identifier of the file to get
getFile file_id:int32 = File;

View File

@ -14103,6 +14103,14 @@ void ContactsManager::send_get_chat_full_query(ChatId chat_id, Promise<Unit> &&p
get_chat_full_queries_.add_query(chat_id.get(), std::move(send_query), std::move(promise));
}
int32 ContactsManager::get_chat_participant_count(ChatId chat_id) const {
auto c = get_chat(chat_id);
if (c == nullptr) {
return 0;
}
return c->participant_count;
}
bool ContactsManager::get_chat_is_active(ChatId chat_id) const {
auto c = get_chat(chat_id);
if (c == nullptr) {

View File

@ -475,6 +475,7 @@ class ContactsManager final : public Actor {
FileSourceId get_chat_full_file_source_id(ChatId chat_id);
void reload_chat_full(ChatId chat_id, Promise<Unit> &&promise);
int32 get_chat_participant_count(ChatId channel_id) const;
bool get_chat_is_active(ChatId chat_id) const;
ChannelId get_chat_migrated_to_channel_id(ChatId chat_id) const;
DialogParticipantStatus get_chat_status(ChatId chat_id) const;

View File

@ -679,6 +679,37 @@ class UnpinAllMessagesQuery final : public Td::ResultHandler {
}
};
class GetMessageReadParticipantsQuery final : public Td::ResultHandler {
Promise<vector<UserId>> promise_;
DialogId dialog_id_;
public:
explicit GetMessageReadParticipantsQuery(Promise<vector<UserId>> &&promise) : promise_(std::move(promise)) {
}
void send(DialogId dialog_id, MessageId message_id) {
dialog_id_ = dialog_id;
auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
CHECK(input_peer != nullptr);
send_query(G()->net_query_creator().create(telegram_api::messages_getMessageReadParticipants(
std::move(input_peer), message_id.get_server_message_id().get())));
}
void on_result(uint64 id, BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::messages_getMessageReadParticipants>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
promise_.set_value(UserId::get_user_ids(result_ptr.ok()));
}
void on_error(uint64 id, Status status) final {
td->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetMessageReadParticipantsQuery");
promise_.set_error(std::move(status));
}
};
class ExportChannelMessageLinkQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
ChannelId channel_id_;
@ -17067,6 +17098,131 @@ td_api::object_ptr<td_api::messageThreadInfo> MessagesManager::get_message_threa
std::move(messages), std::move(draft_message));
}
Status MessagesManager::can_get_message_viewers(FullMessageId full_message_id) {
auto dialog_id = full_message_id.get_dialog_id();
Dialog *d = get_dialog_force(dialog_id, "get_message_viewers");
if (d == nullptr) {
return Status::Error(400, "Chat not found");
}
auto m = get_message_force(d, full_message_id.get_message_id(), "get_message_viewers");
if (m == nullptr) {
return Status::Error(400, "Message not found");
}
return can_get_message_viewers(dialog_id, m);
}
Status MessagesManager::can_get_message_viewers(DialogId dialog_id, const Message *m) const {
if (!m->is_outgoing) {
return Status::Error(400, "Can't get viewers of incoming messages");
}
if (m->date < G()->unix_time() - 7 * 86400) {
return Status::Error(400, "Message is too old");
}
int32 participant_count = 0;
switch (dialog_id.get_type()) {
case DialogType::User:
return Status::Error(400, "Can't get message viewers in private chats");
case DialogType::Chat:
if (!td_->contacts_manager_->get_chat_is_active(dialog_id.get_chat_id())) {
return Status::Error(400, "Chat is deactivated");
}
participant_count = td_->contacts_manager_->get_chat_participant_count(dialog_id.get_chat_id());
break;
case DialogType::Channel:
if (is_broadcast_channel(dialog_id)) {
return Status::Error(400, "Can't get message viewers in channel chats");
}
participant_count = td_->contacts_manager_->get_channel_participant_count(dialog_id.get_channel_id());
break;
case DialogType::SecretChat:
return Status::Error(400, "Can't get message viewers in secret chats");
case DialogType::None:
default:
UNREACHABLE();
return Status::OK();
}
if (!have_input_peer(dialog_id, AccessRights::Read)) {
return Status::Error(400, "Can't access the chat");
}
if (participant_count == 0) {
return Status::Error(400, "Chat is empty or have unknown number of members");
}
if (participant_count > 50) {
return Status::Error(400, "Chat is too big");
}
if (m->message_id.is_scheduled()) {
return Status::Error(400, "Scheduled messages can't have viewers");
}
if (m->message_id.is_yet_unsent()) {
return Status::Error(400, "Yet unsent messages can't have viewers");
}
if (m->message_id.is_local()) {
return Status::Error(400, "Local messages can't have viewers");
}
CHECK(m->message_id.is_server());
return Status::OK();
}
void MessagesManager::get_message_viewers(FullMessageId full_message_id,
Promise<td_api::object_ptr<td_api::users>> &&promise) {
TRY_STATUS_PROMISE(promise, can_get_message_viewers(full_message_id));
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id = full_message_id.get_dialog_id(),
promise = std::move(promise)](Result<vector<UserId>> result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &MessagesManager::on_get_message_viewers, dialog_id, result.move_as_ok(), false,
std::move(promise));
});
td_->create_handler<GetMessageReadParticipantsQuery>(std::move(query_promise))
->send(full_message_id.get_dialog_id(), full_message_id.get_message_id());
}
void MessagesManager::on_get_message_viewers(DialogId dialog_id, vector<UserId> user_ids, bool is_recursive,
Promise<td_api::object_ptr<td_api::users>> &&promise) {
if (!is_recursive) {
bool need_participant_list = false;
for (auto user_id : user_ids) {
if (!user_id.is_valid()) {
LOG(ERROR) << "Receive invalid " << user_id << " as viewer of a message in " << dialog_id;
continue;
}
if (!td_->contacts_manager_->have_user_force(user_id)) {
need_participant_list = true;
}
}
if (need_participant_list) {
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_id, user_ids = std::move(user_ids),
promise = std::move(promise)](Unit result) mutable {
send_closure(actor_id, &MessagesManager::on_get_message_viewers, dialog_id, std::move(user_ids), true,
std::move(promise));
});
switch (dialog_id.get_type()) {
case DialogType::Chat:
return td_->contacts_manager_->reload_chat_full(dialog_id.get_chat_id(), std::move(query_promise));
case DialogType::Channel:
return td_->contacts_manager_->get_channel_participants(
dialog_id.get_channel_id(), td_api::make_object<td_api::supergroupMembersFilterRecent>(), string(), 0,
200, 200, PromiseCreator::lambda([query_promise = std::move(query_promise)](DialogParticipants) mutable {
query_promise.set_value(Unit());
}));
default:
UNREACHABLE();
return;
}
}
}
promise.set_value(td_->contacts_manager_->get_users_object(-1, user_ids));
}
void MessagesManager::get_dialog_info_full(DialogId dialog_id, Promise<Unit> &&promise, const char *source) {
switch (dialog_id.get_type()) {
case DialogType::User:

View File

@ -578,6 +578,8 @@ class MessagesManager final : public Actor {
DialogId dialog_id, MessageId message_id, DialogId expected_dialog_id,
MessageId expected_message_id, Promise<MessageThreadInfo> promise);
void get_message_viewers(FullMessageId full_message_id, Promise<td_api::object_ptr<td_api::users>> &&promise);
bool is_message_edited_recently(FullMessageId full_message_id, int32 seconds);
bool is_deleted_secret_chat(DialogId dialog_id) const;
@ -1795,6 +1797,10 @@ class MessagesManager final : public Actor {
static Status can_get_media_timestamp_link(DialogId dialog_id, const Message *m);
Status can_get_message_viewers(FullMessageId full_message_id) TD_WARN_UNUSED_RESULT;
Status can_get_message_viewers(DialogId dialog_id, const Message *m) const TD_WARN_UNUSED_RESULT;
void cancel_edit_message_media(DialogId dialog_id, Message *m, Slice error_message);
void on_message_media_edited(DialogId dialog_id, MessageId message_id, FileId file_id, FileId thumbnail_file_id,
@ -2742,6 +2748,9 @@ class MessagesManager final : public Actor {
void on_get_discussion_message(DialogId dialog_id, MessageId message_id, MessageThreadInfo &&message_thread_info,
Promise<MessageThreadInfo> &&promise);
void on_get_message_viewers(DialogId dialog_id, vector<UserId> user_ids, bool is_recursive,
Promise<td_api::object_ptr<td_api::users>> &&promise);
static MessageId get_first_database_message_id_by_index(const Dialog *d, MessageSearchFilter filter);
void on_search_dialog_messages_db_result(int64 random_id, DialogId dialog_id, MessageId from_message_id,

View File

@ -5010,6 +5010,13 @@ void Td::on_request(uint64 id, const td_api::getMessageThread &request) {
CREATE_REQUEST(GetMessageThreadRequest, request.chat_id_, request.message_id_);
}
void Td::on_request(uint64 id, const td_api::getMessageViewers &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
messages_manager_->get_message_viewers({DialogId(request.chat_id_), MessageId(request.message_id_)},
std::move(promise));
}
void Td::on_request(uint64 id, const td_api::getMessageLink &request) {
auto r_message_link =
messages_manager_->get_message_link({DialogId(request.chat_id_), MessageId(request.message_id_)},

View File

@ -516,6 +516,8 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::getMessageThread &request);
void on_request(uint64 id, const td_api::getMessageViewers &request);
void on_request(uint64 id, const td_api::getMessages &request);
void on_request(uint64 id, const td_api::getChatSponsoredMessages &request);

View File

@ -2590,6 +2590,11 @@ class CliClient final : public Actor {
string message_id;
get_args(args, chat_id, message_id);
send_request(td_api::make_object<td_api::getMessageThread>(as_chat_id(chat_id), as_message_id(message_id)));
} else if (op == "gmv") {
string chat_id;
string message_id;
get_args(args, chat_id, message_id);
send_request(td_api::make_object<td_api::getMessageViewers>(as_chat_id(chat_id), as_message_id(message_id)));
} else if (op == "gcpm") {
string chat_id = args;
send_request(td_api::make_object<td_api::getChatPinnedMessage>(as_chat_id(chat_id)));