Add td_api::stopPoll.

GitOrigin-RevId: f2d9b5d42e267b9d06591450d69efb323639bb66
This commit is contained in:
levlam 2019-02-22 18:09:55 +03:00
parent 272608a5fb
commit 168add9006
13 changed files with 223 additions and 24 deletions

View File

@ -2910,6 +2910,10 @@ getJsonString json_value:JsonValue = Text;
//@option_ids 0-based identifiers of options, chosen by the user. Currently user can't choose more than 1 option
setPollAnswer chat_id:int53 message_id:int53 option_ids:vector<int32> = Ok;
//@description Stops a poll. A poll in a message can be stopped when the message has can_be_edited flag set
//@chat_id Identifier of the chat to which the poll belongs @message_id Identifier of the message containing the poll
stopPoll chat_id:int53 message_id:int53 = Ok;
//@description Sends an inline query to a bot and returns its results. Returns an error with code 502 if the bot fails to answer the query before the query timeout expires @bot_user_id The identifier of the target bot
//@chat_id Identifier of the chat, where the query was sent @user_location Location of the user, only if needed @query Text of the query @offset Offset of the first entry to return

Binary file not shown.

View File

@ -2667,6 +2667,15 @@ int32 get_message_content_live_location_period(const MessageContent *content) {
}
}
bool get_message_content_poll_is_closed(const Td *td, const MessageContent *content) {
switch (content->get_type()) {
case MessageContentType::Poll:
return td->poll_manager_->get_poll_is_closed(static_cast<const MessagePoll *>(content)->poll_id);
default:
return true;
}
}
WebPageId get_message_content_web_page_id(const MessageContent *content) {
if (content->get_type() == MessageContentType::Text) {
return static_cast<const MessageText *>(content)->web_page_id;
@ -2686,6 +2695,12 @@ void set_message_content_poll_answer(Td *td, MessageContent *content, FullMessag
std::move(option_ids), std::move(promise));
}
void stop_message_content_poll(Td *td, MessageContent *content, FullMessageId full_message_id,
Promise<Unit> &&promise) {
CHECK(content->get_type() == MessageContentType::Poll);
td->poll_manager_->stop_poll(static_cast<MessagePoll *>(content)->poll_id, full_message_id, std::move(promise));
}
static void merge_location_access_hash(const Location &first, const Location &second) {
if (second.get_access_hash() != 0) {
first.set_access_hash(second.get_access_hash());
@ -4790,7 +4805,7 @@ void update_failed_to_send_message_content(Td *td, unique_ptr<MessageContent> &c
}
case MessageContentType::Poll: {
const MessagePoll *message_poll = static_cast<const MessagePoll *>(content.get());
td->poll_manager_->close_poll(message_poll->poll_id);
td->poll_manager_->stop_local_poll(message_poll->poll_id);
break;
}
default:

View File

@ -175,6 +175,8 @@ UserId get_message_content_deleted_user_id(const MessageContent *content);
int32 get_message_content_live_location_period(const MessageContent *content);
bool get_message_content_poll_is_closed(const Td *td, const MessageContent *content);
WebPageId get_message_content_web_page_id(const MessageContent *content);
void set_message_content_web_page_id(MessageContent *content, WebPageId web_page_id);
@ -182,6 +184,8 @@ void set_message_content_web_page_id(MessageContent *content, WebPageId web_page
void set_message_content_poll_answer(Td *td, MessageContent *content, FullMessageId full_message_id,
vector<int32> &&option_ids, Promise<Unit> &&promise);
void stop_message_content_poll(Td *td, MessageContent *content, FullMessageId full_message_id, Promise<Unit> &&promise);
void merge_message_contents(Td *td, const MessageContent *old_content, MessageContent *new_content,
bool need_message_changed_warning, DialogId dialog_id, bool need_merge_files,
bool &is_content_changed, bool &need_update);

View File

@ -2241,11 +2241,6 @@ class EditMessageActor : public NetActorOnce {
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for editMessage: " << to_string(ptr);
if (ptr->get_id() == telegram_api::updateShortSentMessage::ID) {
LOG(ERROR) << "Receive updateShortSentMessage in edit message";
return on_error(id, Status::Error(500, "Unsupported result was returned from the server"));
}
td->updates_manager_->on_get_updates(std::move(ptr));
promise_.set_value(Unit());
@ -5020,10 +5015,13 @@ bool MessagesManager::update_message_views(DialogId dialog_id, Message *m, int32
}
void MessagesManager::on_update_message_content(FullMessageId full_message_id) {
const Message *m = get_message(full_message_id);
const Dialog *d = get_dialog(full_message_id.get_dialog_id());
CHECK(d != nullptr);
const Message *m = get_message(d, full_message_id.get_message_id());
CHECK(m != nullptr);
send_update_message_content(full_message_id.get_dialog_id(), m->message_id, m->content.get(), m->date,
m->is_content_secret, "on_update_message_content");
on_message_changed(d, m, true, "on_update_message_content");
}
bool MessagesManager::update_message_contains_unread_mention(Dialog *d, Message *m, bool contains_unread_mention,
@ -16190,8 +16188,11 @@ bool MessagesManager::can_edit_message(DialogId dialog_id, const Message *m, boo
return false;
}
auto content_type = m->content->get_type();
DialogId my_dialog_id(my_id);
bool has_edit_time_limit = !(is_bot && m->is_outgoing) && dialog_id != my_dialog_id;
bool has_edit_time_limit = !(is_bot && m->is_outgoing) && dialog_id != my_dialog_id &&
content_type != MessageContentType::Poll &&
content_type != MessageContentType::LiveLocation;
switch (dialog_id.get_type()) {
case DialogType::User:
@ -16234,13 +16235,15 @@ bool MessagesManager::can_edit_message(DialogId dialog_id, const Message *m, boo
return false;
}
if (has_edit_time_limit) {
const int32 DEFAULT_EDIT_TIME_LIMIT = 2 * 86400;
int32 edit_time_limit = G()->shared_config().get_option_integer("edit_time_limit", DEFAULT_EDIT_TIME_LIMIT);
if (has_edit_time_limit && G()->unix_time_cached() - m->date >= edit_time_limit + (is_editing ? 300 : 0)) {
if (G()->unix_time_cached() - m->date - (is_editing ? 300 : 0) >= edit_time_limit) {
return false;
}
}
switch (m->content->get_type()) {
switch (content_type) {
case MessageContentType::Animation:
case MessageContentType::Audio:
case MessageContentType::Document:
@ -16257,9 +16260,15 @@ bool MessagesManager::can_edit_message(DialogId dialog_id, const Message *m, boo
}
return G()->unix_time_cached() - m->date < get_message_content_live_location_period(m->content.get());
}
case MessageContentType::Poll: {
if (is_bot && only_reply_markup) {
// there is no caption to edit, but bot can edit inline reply_markup
return true;
}
return !get_message_content_poll_is_closed(td_, m->content.get());
}
case MessageContentType::Contact:
case MessageContentType::Location:
case MessageContentType::Poll:
case MessageContentType::Sticker:
case MessageContentType::Venue:
case MessageContentType::VideoNote:
@ -24922,6 +24931,24 @@ void MessagesManager::set_poll_answer(FullMessageId full_message_id, vector<int3
set_message_content_poll_answer(td_, m->content.get(), full_message_id, std::move(option_ids), std::move(promise));
}
void MessagesManager::stop_poll(FullMessageId full_message_id, Promise<Unit> &&promise) {
auto m = get_message_force(full_message_id);
if (m == nullptr) {
return promise.set_error(Status::Error(5, "Message not found"));
}
if (!have_input_peer(full_message_id.get_dialog_id(), AccessRights::Read)) {
return promise.set_error(Status::Error(3, "Can't access the chat"));
}
if (m->content->get_type() != MessageContentType::Poll) {
return promise.set_error(Status::Error(5, "Message is not a poll"));
}
if (!can_edit_message(full_message_id.get_dialog_id(), m, true)) {
return promise.set_error(Status::Error(5, "Poll can't be stopped"));
}
stop_message_content_poll(td_, m->content.get(), full_message_id, std::move(promise));
}
Result<ServerMessageId> MessagesManager::get_invoice_message_id(FullMessageId full_message_id) {
auto m = get_message_force(full_message_id);
if (m == nullptr) {

View File

@ -707,6 +707,8 @@ class MessagesManager : public Actor {
void set_poll_answer(FullMessageId full_message_id, vector<int32> &&option_ids, Promise<Unit> &&promise);
void stop_poll(FullMessageId full_message_id, Promise<Unit> &&promise);
void get_payment_form(FullMessageId full_message_id, Promise<tl_object_ptr<td_api::paymentForm>> &&promise);
void validate_order_info(FullMessageId full_message_id, tl_object_ptr<td_api::orderInfo> order_info, bool allow_save,

View File

@ -6,8 +6,10 @@
//
#include "td/telegram/PollManager.h"
#include "td/telegram/AuthManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/logevent/LogEventHelper.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/net/NetActor.h"
#include "td/telegram/PollId.hpp"
@ -31,12 +33,12 @@
namespace td {
class SetPollAnswerQuery : public NetActorOnce {
class SetPollAnswerActor : public NetActorOnce {
Promise<Unit> promise_;
DialogId dialog_id_;
public:
explicit SetPollAnswerQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
explicit SetPollAnswerActor(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(FullMessageId full_message_id, vector<BufferSlice> &&options, uint64 generation, NetQueryRef *query_ref) {
@ -70,7 +72,57 @@ class SetPollAnswerQuery : public NetActorOnce {
}
void on_error(uint64 id, Status status) override {
td->messages_manager_->on_get_dialog_error(dialog_id_, status, "SetPollAnswerQuery");
td->messages_manager_->on_get_dialog_error(dialog_id_, status, "SetPollAnswerActor");
promise_.set_error(std::move(status));
}
};
class StopPollActor : public NetActorOnce {
Promise<Unit> promise_;
DialogId dialog_id_;
public:
explicit StopPollActor(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(FullMessageId full_message_id) {
dialog_id_ = full_message_id.get_dialog_id();
auto input_peer = td->messages_manager_->get_input_peer(dialog_id_, AccessRights::Edit);
if (input_peer == nullptr) {
LOG(INFO) << "Can't close poll, because have no edit access to " << dialog_id_;
return on_error(0, Status::Error(400, "Can't access the chat"));
}
auto message_id = full_message_id.get_message_id().get_server_message_id().get();
auto poll = telegram_api::make_object<telegram_api::poll>();
poll->flags_ |= telegram_api::poll::CLOSED_MASK;
auto input_media = telegram_api::make_object<telegram_api::inputMediaPoll>(std::move(poll));
auto query = G()->net_query_creator().create(create_storer(telegram_api::messages_editMessage(
telegram_api::messages_editMessage::MEDIA_MASK, false /*ignored*/, std::move(input_peer), message_id, string(),
std::move(input_media), nullptr, vector<tl_object_ptr<telegram_api::MessageEntity>>())));
auto sequence_id = -1;
send_closure(td->messages_manager_->sequence_dispatcher_, &MultiSequenceDispatcher::send_with_callback,
std::move(query), actor_shared(this), sequence_id);
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::messages_editMessage>(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 stopPoll: " << to_string(result);
td->updates_manager_->on_get_updates(std::move(result));
promise_.set_value(Unit());
}
void on_error(uint64 id, Status status) override {
if (!td->auth_manager_->is_bot() && status.message() == "MESSAGE_NOT_MODIFIED") {
return promise_.set_value(Unit());
}
td->messages_manager_->on_get_dialog_error(dialog_id_, status, "StopPollActor");
promise_.set_error(std::move(status));
}
};
@ -241,6 +293,12 @@ void PollManager::unregister_poll(PollId poll_id, FullMessageId full_message_id)
poll_messages_[poll_id].erase(full_message_id);
}
bool PollManager::get_poll_is_closed(PollId poll_id) const {
auto poll = get_poll(poll_id);
CHECK(poll != nullptr);
return poll->is_closed;
}
void PollManager::set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<int32> &&option_ids,
Promise<Unit> &&promise) {
if (option_ids.size() > 1) {
@ -346,7 +404,7 @@ void PollManager::do_set_poll_answer(PollId poll_id, FullMessageId full_message_
send_closure(actor_id, &PollManager::on_set_poll_answer, poll_id, generation, std::move(result));
});
send_closure(td_->create_net_actor<SetPollAnswerQuery>(std::move(query_promise)), &SetPollAnswerQuery::send,
send_closure(td_->create_net_actor<SetPollAnswerActor>(std::move(query_promise)), &SetPollAnswerActor::send,
full_message_id, std::move(sent_options), generation, &pending_answer.query_ref_);
}
@ -384,7 +442,60 @@ void PollManager::on_set_poll_answer(PollId poll_id, uint64 generation, Result<U
pending_answers_.erase(it);
}
void PollManager::close_poll(PollId poll_id) {
void PollManager::stop_poll(PollId poll_id, FullMessageId full_message_id, Promise<Unit> &&promise) {
if (is_local_poll_id(poll_id)) {
LOG(ERROR) << "Receive local " << poll_id << " from " << full_message_id << " in stop_poll";
stop_local_poll(poll_id);
promise.set_value(Unit());
return;
}
auto poll = get_poll_editable(poll_id);
CHECK(poll != nullptr);
if (poll->is_closed) {
promise.set_value(Unit());
return;
}
poll->is_closed = true;
notify_on_poll_update(poll_id);
save_poll(poll, poll_id);
do_stop_poll(poll_id, full_message_id, 0, std::move(promise));
}
class PollManager::StopPollLogEvent {
public:
PollId poll_id_;
FullMessageId full_message_id_;
template <class StorerT>
void store(StorerT &storer) const {
td::store(poll_id_, storer);
td::store(full_message_id_, storer);
}
template <class ParserT>
void parse(ParserT &parser) {
td::parse(poll_id_, parser);
td::parse(full_message_id_, parser);
}
};
void PollManager::do_stop_poll(PollId poll_id, FullMessageId full_message_id, uint64 logevent_id,
Promise<Unit> &&promise) {
if (logevent_id == 0 && G()->parameters().use_message_db) {
StopPollLogEvent logevent{poll_id, full_message_id};
auto storer = LogEventStorerImpl<StopPollLogEvent>(logevent);
logevent_id = binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::StopPoll, storer);
}
auto new_promise = get_erase_logevent_promise(logevent_id, std::move(promise));
send_closure(td_->create_net_actor<StopPollActor>(std::move(new_promise)), &StopPollActor::send, full_message_id);
}
void PollManager::stop_local_poll(PollId poll_id) {
CHECK(is_local_poll_id(poll_id));
auto poll = get_poll_editable(poll_id);
CHECK(poll != nullptr);
if (poll->is_closed) {
@ -393,10 +504,6 @@ void PollManager::close_poll(PollId poll_id) {
poll->is_closed = true;
notify_on_poll_update(poll_id);
if (!is_local_poll_id(poll_id)) {
// TODO send poll close request to the server + LogEvent
save_poll(poll, poll_id);
}
}
tl_object_ptr<telegram_api::InputMedia> PollManager::get_input_media(PollId poll_id) const {
@ -530,6 +637,24 @@ void PollManager::on_binlog_events(vector<BinlogEvent> &&events) {
Auto());
break;
}
case LogEvent::HandlerType::StopPoll: {
if (!G()->parameters().use_message_db) {
binlog_erase(G()->td_db()->get_binlog(), event.id_);
break;
}
StopPollLogEvent log_event;
log_event_parse(log_event, event.data_).ensure();
auto dialog_id = log_event.full_message_id_.get_dialog_id();
Dependencies dependencies;
td_->messages_manager_->add_dialog_dependencies(dependencies, dialog_id);
td_->messages_manager_->resolve_dependencies_force(dependencies);
do_stop_poll(log_event.poll_id_, log_event.full_message_id_, event.id_, Auto());
break;
}
default:
LOG(FATAL) << "Unsupported logevent type " << event.type_;
}

View File

@ -42,10 +42,14 @@ class PollManager : public Actor {
void unregister_poll(PollId poll_id, FullMessageId full_message_id);
bool get_poll_is_closed(PollId poll_id) const;
void set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<int32> &&option_ids,
Promise<Unit> &&promise);
void close_poll(PollId poll_id);
void stop_poll(PollId poll_id, FullMessageId full_message_id, Promise<Unit> &&promise);
void stop_local_poll(PollId poll_id);
tl_object_ptr<telegram_api::InputMedia> get_input_media(PollId poll_id) const;
@ -88,6 +92,7 @@ class PollManager : public Actor {
};
class SetPollAnswerLogEvent;
class StopPollLogEvent;
void tear_down() override;
@ -122,6 +127,8 @@ class PollManager : public Actor {
void on_set_poll_answer(PollId poll_id, uint64 generation, Result<Unit> &&result);
void do_stop_poll(PollId poll_id, FullMessageId full_message_id, uint64 logevent_id, Promise<Unit> &&promise);
Td *td_;
ActorShared<> parent_;
std::unordered_map<PollId, unique_ptr<Poll>, PollIdHash> polls_;

View File

@ -6550,6 +6550,11 @@ void Td::on_request(uint64 id, td_api::setPollAnswer &request) {
std::move(request.option_ids_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::stopPoll &request) {
CREATE_OK_REQUEST_PROMISE();
messages_manager_->stop_poll({DialogId(request.chat_id_), MessageId(request.message_id_)}, std::move(promise));
}
void Td::on_request(uint64 id, td_api::getInlineQueryResults &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.query_);

View File

@ -832,6 +832,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, td_api::setPollAnswer &request);
void on_request(uint64 id, const td_api::stopPoll &request);
void on_request(uint64 id, td_api::getInlineQueryResults &request);
void on_request(uint64 id, td_api::answerInlineQuery &request);

View File

@ -76,6 +76,7 @@ Status init_binlog(Binlog &binlog, string path, BinlogKeyValue<Binlog> &binlog_p
events.web_page_events.push_back(event.clone());
break;
case LogEvent::HandlerType::SetPollAnswer:
case LogEvent::HandlerType::StopPoll:
events.to_poll_manager.push_back(event.clone());
break;
case LogEvent::HandlerType::SendMessage:

View File

@ -3233,6 +3233,12 @@ class CliClient final : public Actor {
std::tie(message_id, option_ids) = split(args);
send_request(td_api::make_object<td_api::setPollAnswer>(as_chat_id(chat_id), as_message_id(message_id),
to_integers<int32>(option_ids)));
} else if (op == "stoppoll") {
string chat_id;
string message_id;
std::tie(chat_id, message_id) = split(args);
send_request(td_api::make_object<td_api::stopPoll>(as_chat_id(chat_id), as_message_id(message_id)));
} else {
op_not_found_count++;
}

View File

@ -70,6 +70,7 @@ class LogEvent {
SecretChatInfos = 5,
WebPages = 0x10,
SetPollAnswer = 0x20,
StopPoll = 0x21,
SendMessage = 0x100,
DeleteMessage = 0x101,
DeleteMessagesFromServer = 0x102,