Add td_api::setMessageReaction.

This commit is contained in:
levlam 2022-01-21 20:39:55 +03:00
parent ebb78d3c1b
commit ce19ad822b
11 changed files with 166 additions and 18 deletions

View File

@ -4587,6 +4587,12 @@ editInlineMessageReplyMarkup inline_message_id:string reply_markup:ReplyMarkup =
editMessageSchedulingState chat_id:int53 message_id:int53 scheduling_state:MessageSchedulingState = Ok; editMessageSchedulingState chat_id:int53 message_id:int53 scheduling_state:MessageSchedulingState = Ok;
//@description Changes chosen reaction for a message
//@chat_id Identifier of the chat to which the message belongs
//@message_id Identifier of the message
//@reaction Text representation of the chosen reaction, or an empty string to remove reaction
setMessageReaction chat_id:int53 message_id:int53 reaction:string = Ok;
//@description Returns reactions chosen for a message, along with their source //@description Returns reactions chosen for a message, along with their source
//@chat_id Identifier of the chat to which the message belongs //@chat_id Identifier of the chat to which the message belongs
//@message_id Identifier of the message //@message_id Identifier of the message

View File

@ -5649,6 +5649,10 @@ bool is_unsent_animated_emoji_click(Td *td, DialogId dialog_id, const DialogActi
return !td->stickers_manager_->is_sent_animated_emoji_click(dialog_id, remove_emoji_modifiers(emoji)); return !td->stickers_manager_->is_sent_animated_emoji_click(dialog_id, remove_emoji_modifiers(emoji));
} }
bool is_active_reaction(Td *td, const string &reaction) {
return td->stickers_manager_->is_active_reaction(reaction);
}
void on_dialog_used(TopDialogCategory category, DialogId dialog_id, int32 date) { void on_dialog_used(TopDialogCategory category, DialogId dialog_id, int32 date) {
send_closure(G()->top_dialog_manager(), &TopDialogManager::on_dialog_used, category, dialog_id, date); send_closure(G()->top_dialog_manager(), &TopDialogManager::on_dialog_used, category, dialog_id, date);
} }

View File

@ -248,6 +248,8 @@ void on_sent_message_content(Td *td, const MessageContent *content);
bool is_unsent_animated_emoji_click(Td *td, DialogId dialog_id, const DialogAction &action); bool is_unsent_animated_emoji_click(Td *td, DialogId dialog_id, const DialogAction &action);
bool is_active_reaction(Td *td, const string &reaction);
void on_dialog_used(TopDialogCategory category, DialogId dialog_id, int32 date); void on_dialog_used(TopDialogCategory category, DialogId dialog_id, int32 date);
void update_used_hashtags(Td *td, const MessageContent *content); void update_used_hashtags(Td *td, const MessageContent *content);

View File

@ -9,6 +9,7 @@
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/MessagesManager.h" #include "td/telegram/MessagesManager.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
#include "td/telegram/UpdatesManager.h"
#include "td/utils/algorithm.h" #include "td/utils/algorithm.h"
#include "td/utils/buffer.h" #include "td/utils/buffer.h"
@ -18,6 +19,50 @@
namespace td { namespace td {
class SendReactionQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
MessageId message_id_;
public:
explicit SendReactionQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(FullMessageId full_message_id, string reaction) {
dialog_id_ = full_message_id.get_dialog_id();
message_id_ = full_message_id.get_message_id();
auto input_peer = td_->messages_manager_->get_input_peer(dialog_id_, AccessRights::Read);
if (input_peer == nullptr) {
return on_error(Status::Error(400, "Can't access the chat"));
}
int32 flags = 0;
if (!reaction.empty()) {
flags |= telegram_api::messages_sendReaction::REACTION_MASK;
}
send_query(G()->net_query_creator().create(telegram_api::messages_sendReaction(
flags, std::move(input_peer), message_id_.get_server_message_id().get(), reaction)));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::messages_sendReaction>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for SendReactionQuery: " << to_string(ptr);
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
}
void on_error(Status status) final {
td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendReactionQuery");
promise_.set_error(std::move(status));
}
};
class GetMessageReactionsListQuery final : public Td::ResultHandler { class GetMessageReactionsListQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::chosenReactions>> promise_; Promise<td_api::object_ptr<td_api::chosenReactions>> promise_;
DialogId dialog_id_; DialogId dialog_id_;
@ -95,6 +140,19 @@ class GetMessageReactionsListQuery final : public Td::ResultHandler {
} }
}; };
void MessageReaction::set_is_chosen(bool is_chosen, DialogId chooser_dialog_id) {
if (is_chosen_ == is_chosen) {
return;
}
is_chosen_ = is_chosen;
if (chooser_dialog_id.is_valid()) {
choose_count_ += is_chosen_ ? 1 : -1;
// TODO update recent_chooser_dialog_ids_, but only if not broadcast
}
}
td_api::object_ptr<td_api::messageReaction> MessageReaction::get_message_reaction_object(Td *td) const { td_api::object_ptr<td_api::messageReaction> MessageReaction::get_message_reaction_object(Td *td) const {
CHECK(!is_empty()); CHECK(!is_empty());
@ -250,13 +308,17 @@ bool MessageReactions::need_update_message_reactions(const MessageReactions *old
return true; return true;
} }
// has_pending_reaction_ and old_chosen_reaction_ don't affect visible state // has_pending_reaction_ doesn't affect visible state
// compare all other fields // compare all other fields
return old_reactions->reactions_ != new_reactions->reactions_ || old_reactions->is_min_ != new_reactions->is_min_ || return old_reactions->reactions_ != new_reactions->reactions_ || old_reactions->is_min_ != new_reactions->is_min_ ||
old_reactions->can_see_all_choosers_ != new_reactions->can_see_all_choosers_ || old_reactions->can_see_all_choosers_ != new_reactions->can_see_all_choosers_ ||
old_reactions->need_polling_ != new_reactions->need_polling_; old_reactions->need_polling_ != new_reactions->need_polling_;
} }
void set_message_reaction(Td *td, FullMessageId full_message_id, string reaction, Promise<Unit> &&promise) {
td->create_handler<SendReactionQuery>(std::move(promise))->send(full_message_id, std::move(reaction));
}
void get_message_chosen_reactions(Td *td, FullMessageId full_message_id, string reaction, string offset, int32 limit, void get_message_chosen_reactions(Td *td, FullMessageId full_message_id, string reaction, string offset, int32 limit,
Promise<td_api::object_ptr<td_api::chosenReactions>> &&promise) { Promise<td_api::object_ptr<td_api::chosenReactions>> &&promise) {
if (!td->messages_manager_->have_message_force(full_message_id, "get_message_chosen_reactions")) { if (!td->messages_manager_->have_message_force(full_message_id, "get_message_chosen_reactions")) {
@ -264,7 +326,8 @@ void get_message_chosen_reactions(Td *td, FullMessageId full_message_id, string
} }
auto message_id = full_message_id.get_message_id(); auto message_id = full_message_id.get_message_id();
if (!message_id.is_valid() || !message_id.is_server()) { if (full_message_id.get_dialog_id().get_type() == DialogType::SecretChat || !message_id.is_valid() ||
!message_id.is_server()) {
return promise.set_value(td_api::make_object<td_api::chosenReactions>(0, Auto(), string())); return promise.set_value(td_api::make_object<td_api::chosenReactions>(0, Auto(), string()));
} }

View File

@ -41,7 +41,7 @@ class MessageReaction {
MessageReaction() = default; MessageReaction() = default;
MessageReaction(string &&reaction, int32 choose_count, bool is_chosen, vector<DialogId> &&recent_chooser_dialog_ids, MessageReaction(string reaction, int32 choose_count, bool is_chosen, vector<DialogId> &&recent_chooser_dialog_ids,
vector<std::pair<ChannelId, MinChannel>> &&recent_chooser_min_channels) vector<std::pair<ChannelId, MinChannel>> &&recent_chooser_min_channels)
: reaction_(std::move(reaction)) : reaction_(std::move(reaction))
, choose_count_(choose_count) , choose_count_(choose_count)
@ -62,9 +62,7 @@ class MessageReaction {
return is_chosen_; return is_chosen_;
} }
void set_is_chosen(bool is_chosen) { void set_is_chosen(bool is_chosen, DialogId chooser_dialog_id = DialogId());
is_chosen_ = is_chosen;
}
const vector<DialogId> &get_recent_chooser_dialog_ids() const { const vector<DialogId> &get_recent_chooser_dialog_ids() const {
return recent_chooser_dialog_ids_; return recent_chooser_dialog_ids_;
@ -97,7 +95,6 @@ struct MessageReactions {
bool need_polling_ = true; bool need_polling_ = true;
bool can_see_all_choosers_ = false; bool can_see_all_choosers_ = false;
bool has_pending_reaction_ = false; bool has_pending_reaction_ = false;
string old_chosen_reaction_;
MessageReactions() = default; MessageReactions() = default;
@ -117,6 +114,8 @@ struct MessageReactions {
void parse(ParserT &parser); void parse(ParserT &parser);
}; };
void set_message_reaction(Td *td, FullMessageId full_message_id, string reaction, Promise<Unit> &&promise);
void get_message_chosen_reactions(Td *td, FullMessageId full_message_id, string reaction, string offset, int32 limit, void get_message_chosen_reactions(Td *td, FullMessageId full_message_id, string reaction, string offset, int32 limit,
Promise<td_api::object_ptr<td_api::chosenReactions>> &&promise); Promise<td_api::object_ptr<td_api::chosenReactions>> &&promise);

View File

@ -56,41 +56,31 @@ void MessageReaction::parse(ParserT &parser) {
template <class StorerT> template <class StorerT>
void MessageReactions::store(StorerT &storer) const { void MessageReactions::store(StorerT &storer) const {
bool has_reactions = !reactions_.empty(); bool has_reactions = !reactions_.empty();
bool has_old_chosen_reaction = !old_chosen_reaction_.empty();
BEGIN_STORE_FLAGS(); BEGIN_STORE_FLAGS();
STORE_FLAG(is_min_); STORE_FLAG(is_min_);
STORE_FLAG(need_polling_); STORE_FLAG(need_polling_);
STORE_FLAG(can_see_all_choosers_); STORE_FLAG(can_see_all_choosers_);
STORE_FLAG(has_pending_reaction_); STORE_FLAG(has_pending_reaction_);
STORE_FLAG(has_reactions); STORE_FLAG(has_reactions);
STORE_FLAG(has_old_chosen_reaction);
END_STORE_FLAGS(); END_STORE_FLAGS();
if (has_reactions) { if (has_reactions) {
td::store(reactions_, storer); td::store(reactions_, storer);
} }
if (has_old_chosen_reaction) {
td::store(old_chosen_reaction_, storer);
}
} }
template <class ParserT> template <class ParserT>
void MessageReactions::parse(ParserT &parser) { void MessageReactions::parse(ParserT &parser) {
bool has_reactions; bool has_reactions;
bool has_old_chosen_reaction;
BEGIN_PARSE_FLAGS(); BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_min_); PARSE_FLAG(is_min_);
PARSE_FLAG(need_polling_); PARSE_FLAG(need_polling_);
PARSE_FLAG(can_see_all_choosers_); PARSE_FLAG(can_see_all_choosers_);
PARSE_FLAG(has_pending_reaction_); PARSE_FLAG(has_pending_reaction_);
PARSE_FLAG(has_reactions); PARSE_FLAG(has_reactions);
PARSE_FLAG(has_old_chosen_reaction);
END_PARSE_FLAGS(); END_PARSE_FLAGS();
if (has_reactions) { if (has_reactions) {
td::parse(reactions_, parser); td::parse(reactions_, parser);
} }
if (has_old_chosen_reaction) {
td::parse(old_chosen_reaction_, parser);
}
} }
} // namespace td } // namespace td

View File

@ -23720,6 +23720,72 @@ void MessagesManager::on_get_scheduled_messages_from_database(DialogId dialog_id
} }
} }
void MessagesManager::set_message_reaction(FullMessageId full_message_id, string reaction, Promise<Unit> &&promise) {
auto dialog_id = full_message_id.get_dialog_id();
Dialog *d = get_dialog_force(dialog_id, "set_message_reaction");
if (d == nullptr) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
Message *m = get_message_force(d, full_message_id.get_message_id(), "set_message_reaction");
if (m == nullptr) {
return promise.set_error(Status::Error(400, "Message not found"));
}
if (full_message_id.get_dialog_id().get_type() == DialogType::SecretChat || !m->message_id.is_valid() ||
!m->message_id.is_server()) {
return promise.set_error(Status::Error(400, "Message can't have reactions"));
}
if (!reaction.empty() && !is_active_reaction(td_, reaction)) {
return promise.set_error(Status::Error(400, "Invalid reaction specified"));
}
if (m->reactions == nullptr) {
if (reaction.empty()) {
return promise.set_value(Unit());
}
m->reactions = make_unique<MessageReactions>();
}
bool is_found = false;
for (auto it = m->reactions->reactions_.begin(); it != m->reactions->reactions_.end();) {
auto &message_reaction = *it;
if (message_reaction.is_chosen()) {
if (message_reaction.get_reaction() == reaction) {
return promise.set_value(Unit());
}
message_reaction.set_is_chosen(false);
if (message_reaction.is_empty()) {
it = m->reactions->reactions_.erase(it);
continue;
}
} else {
if (message_reaction.get_reaction() == reaction) {
message_reaction.set_is_chosen(true);
is_found = true;
}
}
++it;
}
// m->reactions->has_pending_reaction_ = true;
if (!is_found && !reaction.empty()) {
// TODO place to the correct position
vector<DialogId> recent_chooser_dialog_ids;
if (!is_broadcast_channel(dialog_id)) {
recent_chooser_dialog_ids.push_back(get_my_dialog_id());
}
m->reactions->reactions_.emplace_back(reaction, 1, true, std::move(recent_chooser_dialog_ids), Auto());
}
send_update_message_interaction_info(dialog_id, m);
on_message_changed(d, m, true, "set_message_reaction");
::td::set_message_reaction(td_, full_message_id, std::move(reaction), std::move(promise));
}
void MessagesManager::get_message_public_forwards(FullMessageId full_message_id, string offset, int32 limit, void MessagesManager::get_message_public_forwards(FullMessageId full_message_id, string offset, int32 limit,
Promise<td_api::object_ptr<td_api::foundMessages>> &&promise) { Promise<td_api::object_ptr<td_api::foundMessages>> &&promise) {
auto dc_id_promise = PromiseCreator::lambda([actor_id = actor_id(this), full_message_id, offset = std::move(offset), auto dc_id_promise = PromiseCreator::lambda([actor_id = actor_id(this), full_message_id, offset = std::move(offset),

View File

@ -780,6 +780,8 @@ class MessagesManager final : public Actor {
vector<MessageId> get_dialog_scheduled_messages(DialogId dialog_id, bool force, bool ignore_result, vector<MessageId> get_dialog_scheduled_messages(DialogId dialog_id, bool force, bool ignore_result,
Promise<Unit> &&promise); Promise<Unit> &&promise);
void set_message_reaction(FullMessageId full_message_id, string reaction, Promise<Unit> &&promise);
void get_message_public_forwards(FullMessageId full_message_id, string offset, int32 limit, void get_message_public_forwards(FullMessageId full_message_id, string offset, int32 limit,
Promise<td_api::object_ptr<td_api::foundMessages>> &&promise); Promise<td_api::object_ptr<td_api::foundMessages>> &&promise);

View File

@ -5244,10 +5244,18 @@ void Td::on_request(uint64 id, const td_api::getChatScheduledMessages &request)
CREATE_REQUEST(GetChatScheduledMessagesRequest, request.chat_id_); CREATE_REQUEST(GetChatScheduledMessagesRequest, request.chat_id_);
} }
void Td::on_request(uint64 id, td_api::setMessageReaction &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.reaction_);
CREATE_OK_REQUEST_PROMISE();
messages_manager_->set_message_reaction({DialogId(request.chat_id_), MessageId(request.message_id_)},
std::move(request.reaction_), std::move(promise));
}
void Td::on_request(uint64 id, td_api::getMessageChosenReactions &request) { void Td::on_request(uint64 id, td_api::getMessageChosenReactions &request) {
CHECK_IS_USER(); CHECK_IS_USER();
CLEAN_INPUT_STRING(request.offset_);
CLEAN_INPUT_STRING(request.reaction_); CLEAN_INPUT_STRING(request.reaction_);
CLEAN_INPUT_STRING(request.offset_);
CREATE_REQUEST_PROMISE(); CREATE_REQUEST_PROMISE();
get_message_chosen_reactions(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, get_message_chosen_reactions(this, {DialogId(request.chat_id_), MessageId(request.message_id_)},
std::move(request.reaction_), std::move(request.offset_), request.limit_, std::move(request.reaction_), std::move(request.offset_), request.limit_,

View File

@ -645,6 +645,8 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::getChatScheduledMessages &request); void on_request(uint64 id, const td_api::getChatScheduledMessages &request);
void on_request(uint64 id, td_api::setMessageReaction &request);
void on_request(uint64 id, td_api::getMessageChosenReactions &request); void on_request(uint64 id, td_api::getMessageChosenReactions &request);
void on_request(uint64 id, td_api::getMessagePublicForwards &request); void on_request(uint64 id, td_api::getMessagePublicForwards &request);

View File

@ -2058,6 +2058,12 @@ class CliClient final : public Actor {
ChatId chat_id; ChatId chat_id;
get_args(args, chat_id); get_args(args, chat_id);
send_request(td_api::make_object<td_api::getChatScheduledMessages>(chat_id)); send_request(td_api::make_object<td_api::getChatScheduledMessages>(chat_id));
} else if (op == "react") {
ChatId chat_id;
MessageId message_id;
string reaction;
get_args(args, chat_id, message_id, reaction);
send_request(td_api::make_object<td_api::setMessageReaction>(chat_id, message_id, reaction));
} else if (op == "gmcr") { } else if (op == "gmcr") {
ChatId chat_id; ChatId chat_id;
MessageId message_id; MessageId message_id;