Support MessageSenders as poll voters.

This commit is contained in:
levlam 2023-04-25 16:41:04 +03:00
parent 48d72677d3
commit 38efb6d673
11 changed files with 124 additions and 82 deletions

View File

@ -497,13 +497,13 @@ webApp short_name:string title:string description:string photo:photo animation:a
//@question Poll question; 1-300 characters
//@options List of poll answer options
//@total_voter_count Total number of voters, participating in the poll
//@recent_voter_user_ids User identifiers of recent voters, if the poll is non-anonymous
//@recent_voter_ids Identifiers of recent voters, if the poll is non-anonymous
//@is_anonymous True, if the poll is anonymous
//@type Type of the poll
//@open_period Amount of time the poll will be active after creation, in seconds
//@close_date Point in time (Unix timestamp) when the poll will automatically be closed
//@is_closed True, if the poll is closed
poll id:int64 question:string options:vector<pollOption> total_voter_count:int32 recent_voter_user_ids:vector<int53> is_anonymous:Bool type:PollType open_period:int32 close_date:int32 is_closed:Bool = Poll;
poll id:int64 question:string options:vector<pollOption> total_voter_count:int32 recent_voter_ids:vector<MessageSender> is_anonymous:Bool type:PollType open_period:int32 close_date:int32 is_closed:Bool = Poll;
//@description Describes a chat background
@ -5692,8 +5692,11 @@ updateNewCustomQuery id:int64 data:string timeout:int32 = Update;
//@description A poll was updated; for bots only @poll New data about the poll
updatePoll poll:poll = Update;
//@description A user changed the answer to a poll; for bots only @poll_id Unique poll identifier @user_id The user, who changed the answer to the poll @option_ids 0-based identifiers of answer options, chosen by the user
updatePollAnswer poll_id:int64 user_id:int53 option_ids:vector<int32> = Update;
//@description A user changed the answer to a poll; for bots only
//@poll_id Unique poll identifier
//@voter_id Identifier of the message sender that changed the answer to the poll
//@option_ids 0-based identifiers of answer options, chosen by the user
updatePollAnswer poll_id:int64 voter_id:MessageSender option_ids:vector<int32> = Update;
//@description User rights changed in a chat; for bots only
//@chat_id Chat identifier
@ -6549,13 +6552,13 @@ getThemeParametersJsonString theme:themeParameters = Text;
//@option_ids 0-based identifiers of answer options, chosen by the user. User can choose more than 1 answer option only is the poll allows multiple answers
setPollAnswer chat_id:int53 message_id:int53 option_ids:vector<int32> = Ok;
//@description Returns users voted for the specified option in a non-anonymous polls. For optimal performance, the number of returned users is chosen by TDLib
//@description Returns message senders voted for the specified option in a non-anonymous polls. For optimal performance, the number of returned users is chosen by TDLib
//@chat_id Identifier of the chat to which the poll belongs
//@message_id Identifier of the message containing the poll
//@option_id 0-based identifier of the answer option
//@offset Number of users to skip in the result; must be non-negative
//@limit The maximum number of users to be returned; must be positive and can't be greater than 50. For optimal performance, the number of returned users is chosen by TDLib and can be smaller than the specified limit, even if the end of the voter list has not been reached
getPollVoters chat_id:int53 message_id:int53 option_id:int32 offset:int32 limit:int32 = Users;
//@offset Number of voters to skip in the result; must be non-negative
//@limit The maximum number of voters to be returned; must be positive and can't be greater than 50. For optimal performance, the number of returned voters is chosen by TDLib and can be smaller than the specified limit, even if the end of the voter list has not been reached
getPollVoters chat_id:int53 message_id:int53 option_id:int32 offset:int32 limit:int32 = MessageSenders;
//@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

View File

@ -3320,7 +3320,7 @@ void set_message_content_poll_answer(Td *td, const MessageContent *content, Full
void get_message_content_poll_voters(Td *td, const MessageContent *content, FullMessageId full_message_id,
int32 option_id, int32 offset, int32 limit,
Promise<std::pair<int32, vector<UserId>>> &&promise) {
Promise<td_api::object_ptr<td_api::messageSenders>> &&promise) {
CHECK(content->get_type() == MessageContentType::Poll);
td->poll_manager_->get_poll_voters(static_cast<const MessagePoll *>(content)->poll_id, full_message_id, option_id,
offset, limit, std::move(promise));

View File

@ -167,7 +167,7 @@ void set_message_content_poll_answer(Td *td, const MessageContent *content, Full
void get_message_content_poll_voters(Td *td, const MessageContent *content, FullMessageId full_message_id,
int32 option_id, int32 offset, int32 limit,
Promise<std::pair<int32, vector<UserId>>> &&promise);
Promise<td_api::object_ptr<td_api::messageSenders>> &&promise);
void stop_message_content_poll(Td *td, const MessageContent *content, FullMessageId full_message_id,
unique_ptr<ReplyMarkup> &&reply_markup, Promise<Unit> &&promise);

View File

@ -7,6 +7,7 @@
#pragma once
#include "td/telegram/MessageReaction.h"
#include "td/telegram/MinChannel.hpp"
#include "td/utils/common.h"
#include "td/utils/tl_helpers.h"

View File

@ -39913,7 +39913,7 @@ void MessagesManager::set_poll_answer(FullMessageId full_message_id, vector<int3
}
void MessagesManager::get_poll_voters(FullMessageId full_message_id, int32 option_id, int32 offset, int32 limit,
Promise<std::pair<int32, vector<UserId>>> &&promise) {
Promise<td_api::object_ptr<td_api::messageSenders>> &&promise) {
auto m = get_message_force(full_message_id, "get_poll_voters");
if (m == nullptr) {
return promise.set_error(Status::Error(400, "Message not found"));

View File

@ -1021,7 +1021,7 @@ class MessagesManager final : public Actor {
void set_poll_answer(FullMessageId full_message_id, vector<int32> &&option_ids, Promise<Unit> &&promise);
void get_poll_voters(FullMessageId full_message_id, int32 option_id, int32 offset, int32 limit,
Promise<std::pair<int32, vector<UserId>>> &&promise);
Promise<td_api::object_ptr<td_api::messageSenders>> &&promise);
void stop_poll(FullMessageId full_message_id, td_api::object_ptr<td_api::ReplyMarkup> &&reply_markup,
Promise<Unit> &&promise);

View File

@ -15,6 +15,7 @@
#include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessageSender.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/misc.h"
#include "td/telegram/PollId.hpp"
@ -380,8 +381,17 @@ void PollManager::on_load_poll_from_database(PollId poll_id, string value) {
if (log_event_parse(*poll, value).is_error()) {
return;
}
for (auto &user_id : poll->recent_voter_user_ids_) {
td_->contacts_manager_->have_user_force(user_id);
for (const auto &recent_voter_min_channel : poll->recent_voter_min_channels_) {
LOG(INFO) << "Add min voted " << recent_voter_min_channel.first;
td_->contacts_manager_->add_min_channel(recent_voter_min_channel.first, recent_voter_min_channel.second);
}
Dependencies dependencies;
for (auto dialog_id : poll->recent_voter_dialog_ids_) {
dependencies.add_message_sender_dependencies(dialog_id);
}
if (!dependencies.resolve_force(td_, "on_load_poll_from_database")) {
poll->recent_voter_dialog_ids_.clear();
poll->recent_voter_min_channels_.clear();
}
if (!poll->is_closed_ && poll->close_date_ != 0) {
if (poll->close_date_ <= G()->server_time()) {
@ -613,10 +623,17 @@ td_api::object_ptr<td_api::poll> PollManager::get_poll_object(PollId poll_id, co
open_period = 0;
close_date = 0;
}
return td_api::make_object<td_api::poll>(
poll_id.get(), poll->question_, std::move(poll_options), total_voter_count,
td_->contacts_manager_->get_user_ids_object(poll->recent_voter_user_ids_, "get_poll_object"), poll->is_anonymous_,
std::move(poll_type), open_period, close_date, poll->is_closed_);
vector<td_api::object_ptr<td_api::MessageSender>> recent_voters;
for (auto dialog_id : poll->recent_voter_dialog_ids_) {
auto recent_voter = get_min_message_sender_object(td_, dialog_id, "get_poll_object");
if (recent_voter != nullptr) {
recent_voters.push_back(std::move(recent_voter));
}
}
return td_api::make_object<td_api::poll>(poll_id.get(), poll->question_, std::move(poll_options), total_voter_count,
std::move(recent_voters), poll->is_anonymous_, std::move(poll_type),
open_period, close_date, poll->is_closed_);
}
telegram_api::object_ptr<telegram_api::pollAnswer> PollManager::get_input_poll_option(const PollOption &poll_option) {
@ -1014,8 +1031,21 @@ PollManager::PollOptionVoters &PollManager::get_poll_option_voters(const Poll *p
return poll_voters[index];
}
td_api::object_ptr<td_api::messageSenders> PollManager::get_poll_voters_object(
int32 total_count, const vector<DialogId> &voter_dialog_ids) const {
auto result = td_api::make_object<td_api::messageSenders>();
result->total_count_ = total_count;
for (auto dialog_id : voter_dialog_ids) {
auto message_sender = get_min_message_sender_object(td_, dialog_id, "get_poll_voters_object");
if (message_sender != nullptr) {
result->senders_.push_back(std::move(message_sender));
}
}
return result;
}
void PollManager::get_poll_voters(PollId poll_id, FullMessageId full_message_id, int32 option_id, int32 offset,
int32 limit, Promise<std::pair<int32, vector<UserId>>> &&promise) {
int32 limit, Promise<td_api::object_ptr<td_api::messageSenders>> &&promise) {
if (is_local_poll_id(poll_id)) {
return promise.set_error(Status::Error(400, "Poll results can't be received"));
}
@ -1040,26 +1070,27 @@ void PollManager::get_poll_voters(PollId poll_id, FullMessageId full_message_id,
auto &voters = get_poll_option_voters(poll, poll_id, option_id);
if (voters.pending_queries_.empty() && voters.was_invalidated_ && offset == 0) {
voters.voter_user_ids_.clear();
voters.voter_dialog_ids_.clear();
voters.next_offset_.clear();
voters.was_invalidated_ = false;
}
auto cur_offset = narrow_cast<int32>(voters.voter_user_ids_.size());
auto cur_offset = narrow_cast<int32>(voters.voter_dialog_ids_.size());
if (offset > cur_offset) {
return promise.set_error(Status::Error(400, "Too big offset specified; voters can be received only consequently"));
}
if (offset < cur_offset) {
vector<UserId> result;
vector<DialogId> result;
for (int32 i = offset; i != cur_offset && i - offset < limit; i++) {
result.push_back(voters.voter_user_ids_[i]);
result.push_back(voters.voter_dialog_ids_[i]);
}
return promise.set_value({max(poll->options_[option_id].voter_count_, cur_offset), std::move(result)});
return promise.set_value(
get_poll_voters_object(max(poll->options_[option_id].voter_count_, cur_offset), std::move(result)));
}
if (poll->options_[option_id].voter_count_ == 0 || (voters.next_offset_.empty() && cur_offset > 0)) {
return promise.set_value({0, vector<UserId>()});
return promise.set_value(get_poll_voters_object(0, vector<DialogId>()));
}
voters.pending_queries_.push_back(std::move(promise));
@ -1122,7 +1153,7 @@ void PollManager::on_get_poll_voters(PollId poll_id, int32 option_id, string off
update_poll_timeout_.set_timeout_in(poll_id.get(), 0.0);
}
vector<UserId> user_ids;
vector<DialogId> dialog_ids;
for (auto &peer_vote : vote_list->votes_) {
DialogId dialog_id;
switch (peer_vote->get_id()) {
@ -1153,25 +1184,23 @@ void PollManager::on_get_poll_voters(PollId poll_id, int32 option_id, string off
UNREACHABLE();
}
if (dialog_id.is_valid()) {
if (dialog_id.get_type() == DialogType::User) {
user_ids.push_back(dialog_id.get_user_id());
}
dialog_ids.push_back(dialog_id);
} else {
LOG(ERROR) << "Receive " << dialog_id << " as voter in " << poll_id;
}
}
append(voters.voter_user_ids_, user_ids);
if (static_cast<int32>(user_ids.size()) > limit) {
user_ids.resize(limit);
append(voters.voter_dialog_ids_, dialog_ids);
if (static_cast<int32>(dialog_ids.size()) > limit) {
dialog_ids.resize(limit);
}
auto known_voter_count = narrow_cast<int32>(voters.voter_user_ids_.size());
auto known_voter_count = narrow_cast<int32>(voters.voter_dialog_ids_.size());
if (voters.next_offset_.empty() && known_voter_count != vote_list->count_) {
// invalidate_poll_option_voters(poll, poll_id, option_id);
voters.was_invalidated_ = true;
}
for (auto &promise : promises) {
promise.set_value({max(vote_list->count_, known_voter_count), vector<UserId>(user_ids)});
promise.set_value(get_poll_voters_object(max(vote_list->count_, known_voter_count), vector<DialogId>(dialog_ids)));
}
}
@ -1772,28 +1801,24 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll
}
}
vector<UserId> recent_voter_user_ids;
vector<DialogId> recent_voter_dialog_ids;
if (!is_bot) {
for (auto &peer_id : poll_results->recent_voters_) {
DialogId dialog_id(peer_id);
if (dialog_id.get_type() != DialogType::User) {
continue;
}
auto user_id = dialog_id.get_user_id();
if (user_id.is_valid()) {
recent_voter_user_ids.push_back(user_id);
if (dialog_id.is_valid()) {
recent_voter_dialog_ids.push_back(dialog_id);
} else {
LOG(ERROR) << "Receive " << user_id << " as recent voter in " << poll_id << " from " << source;
LOG(ERROR) << "Receive " << dialog_id << " as recent voter in " << poll_id << " from " << source;
}
}
}
if (poll->is_anonymous_ && !recent_voter_user_ids.empty()) {
LOG(ERROR) << "Receive anonymous " << poll_id << " with recent voters " << recent_voter_user_ids << " from "
if (poll->is_anonymous_ && !recent_voter_dialog_ids.empty()) {
LOG(ERROR) << "Receive anonymous " << poll_id << " with recent voters " << recent_voter_dialog_ids << " from "
<< source;
recent_voter_user_ids.clear();
recent_voter_dialog_ids.clear();
}
if (recent_voter_user_ids != poll->recent_voter_user_ids_) {
poll->recent_voter_user_ids_ = std::move(recent_voter_user_ids);
if (recent_voter_dialog_ids != poll->recent_voter_dialog_ids_) {
poll->recent_voter_dialog_ids_ = std::move(recent_voter_dialog_ids);
invalidate_poll_voters(poll, poll_id);
is_changed = true;
}
@ -1817,13 +1842,13 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll
return poll_id;
}
void PollManager::on_get_poll_vote(PollId poll_id, UserId user_id, vector<BufferSlice> &&options) {
void PollManager::on_get_poll_vote(PollId poll_id, DialogId dialog_id, vector<BufferSlice> &&options) {
if (!poll_id.is_valid()) {
LOG(ERROR) << "Receive updateMessagePollVote about invalid " << poll_id;
return;
}
if (!user_id.is_valid()) {
LOG(ERROR) << "Receive updateMessagePollVote from invalid " << user_id;
if (!dialog_id.is_valid()) {
LOG(ERROR) << "Receive updateMessagePollVote from invalid " << dialog_id;
return;
}
if (!td_->auth_manager_->is_bot()) {
@ -1840,10 +1865,10 @@ void PollManager::on_get_poll_vote(PollId poll_id, UserId user_id, vector<Buffer
option_ids.push_back(static_cast<int32>(slice[0] - '0'));
}
send_closure(G()->td(), &Td::send_update,
send_closure(
G()->td(), &Td::send_update,
td_api::make_object<td_api::updatePollAnswer>(
poll_id.get(), td_->contacts_manager_->get_user_id_object(user_id, "on_get_poll_vote"),
std::move(option_ids)));
poll_id.get(), get_message_sender_object(td_, dialog_id, "on_get_poll_vote"), std::move(option_ids)));
}
void PollManager::on_binlog_events(vector<BinlogEvent> &&events) {

View File

@ -6,14 +6,15 @@
//
#pragma once
#include "td/telegram/DialogId.h"
#include "td/telegram/FullMessageId.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MinChannel.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/PollId.h"
#include "td/telegram/ReplyMarkup.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
#include "td/actor/actor.h"
#include "td/actor/MultiTimeout.h"
@ -65,7 +66,7 @@ class PollManager final : public Actor {
Promise<Unit> &&promise);
void get_poll_voters(PollId poll_id, FullMessageId full_message_id, int32 option_id, int32 offset, int32 limit,
Promise<std::pair<int32, vector<UserId>>> &&promise);
Promise<td_api::object_ptr<td_api::messageSenders>> &&promise);
void stop_poll(PollId poll_id, FullMessageId full_message_id, unique_ptr<ReplyMarkup> &&reply_markup,
Promise<Unit> &&promise);
@ -81,7 +82,7 @@ class PollManager final : public Actor {
PollId on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll> &&poll_server,
tl_object_ptr<telegram_api::pollResults> &&poll_results, const char *source);
void on_get_poll_vote(PollId poll_id, UserId user_id, vector<BufferSlice> &&options);
void on_get_poll_vote(PollId poll_id, DialogId dialog_id, vector<BufferSlice> &&options);
td_api::object_ptr<td_api::poll> get_poll_object(PollId poll_id) const;
@ -111,7 +112,8 @@ class PollManager final : public Actor {
struct Poll {
string question_;
vector<PollOption> options_;
vector<UserId> recent_voter_user_ids_;
vector<DialogId> recent_voter_dialog_ids_;
vector<std::pair<ChannelId, MinChannel>> recent_voter_min_channels_;
FormattedText explanation_;
int32 total_voter_count_ = 0;
int32 correct_option_id_ = -1;
@ -131,9 +133,9 @@ class PollManager final : public Actor {
};
struct PollOptionVoters {
vector<UserId> voter_user_ids_;
vector<DialogId> voter_dialog_ids_;
string next_offset_;
vector<Promise<std::pair<int32, vector<UserId>>>> pending_queries_;
vector<Promise<td_api::object_ptr<td_api::messageSenders>>> pending_queries_;
bool was_invalidated_ = false; // the list needs to be invalidated when voters are changed
};
@ -209,6 +211,9 @@ class PollManager final : public Actor {
PollOptionVoters &get_poll_option_voters(const Poll *poll, PollId poll_id, int32 option_id);
td_api::object_ptr<td_api::messageSenders> get_poll_voters_object(int32 total_count,
const vector<DialogId> &voter_dialog_ids) const;
void on_get_poll_voters(PollId poll_id, int32 option_id, string offset, int32 limit,
Result<tl_object_ptr<telegram_api::messages_votesList>> &&result);

View File

@ -6,6 +6,7 @@
//
#pragma once
#include "td/telegram/MinChannel.hpp"
#include "td/telegram/PollManager.h"
#include "td/telegram/Version.h"
@ -43,20 +44,23 @@ template <class StorerT>
void PollManager::Poll::store(StorerT &storer) const {
using ::td::store;
bool is_public = !is_anonymous_;
bool has_recent_voters = !recent_voter_user_ids_.empty();
bool has_open_period = open_period_ != 0;
bool has_close_date = close_date_ != 0;
bool has_explanation = !explanation_.text.empty();
bool has_recent_voter_dialog_ids = !recent_voter_dialog_ids_.empty();
bool has_recent_voter_min_channels = !recent_voter_min_channels_.empty();
BEGIN_STORE_FLAGS();
STORE_FLAG(is_closed_);
STORE_FLAG(is_public);
STORE_FLAG(allow_multiple_answers_);
STORE_FLAG(is_quiz_);
STORE_FLAG(has_recent_voters);
STORE_FLAG(false);
STORE_FLAG(has_open_period);
STORE_FLAG(has_close_date);
STORE_FLAG(has_explanation);
STORE_FLAG(is_updated_after_close_);
STORE_FLAG(has_recent_voter_dialog_ids);
STORE_FLAG(has_recent_voter_min_channels);
END_STORE_FLAGS();
store(question_, storer);
@ -65,9 +69,6 @@ void PollManager::Poll::store(StorerT &storer) const {
if (is_quiz_) {
store(correct_option_id_, storer);
}
if (has_recent_voters) {
store(recent_voter_user_ids_, storer);
}
if (has_open_period) {
store(open_period_, storer);
}
@ -77,26 +78,36 @@ void PollManager::Poll::store(StorerT &storer) const {
if (has_explanation) {
store(explanation_, storer);
}
if (has_recent_voter_dialog_ids) {
store(recent_voter_dialog_ids_, storer);
}
if (has_recent_voter_min_channels) {
store(recent_voter_min_channels_, storer);
}
}
template <class ParserT>
void PollManager::Poll::parse(ParserT &parser) {
using ::td::parse;
bool is_public;
bool has_recent_voters;
bool has_recent_voter_user_ids;
bool has_open_period;
bool has_close_date;
bool has_explanation;
bool has_recent_voter_dialog_ids;
bool has_recent_voter_min_channels;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(is_closed_);
PARSE_FLAG(is_public);
PARSE_FLAG(allow_multiple_answers_);
PARSE_FLAG(is_quiz_);
PARSE_FLAG(has_recent_voters);
PARSE_FLAG(has_recent_voter_user_ids);
PARSE_FLAG(has_open_period);
PARSE_FLAG(has_close_date);
PARSE_FLAG(has_explanation);
PARSE_FLAG(is_updated_after_close_);
PARSE_FLAG(has_recent_voter_dialog_ids);
PARSE_FLAG(has_recent_voter_min_channels);
END_PARSE_FLAGS();
is_anonymous_ = !is_public;
@ -109,8 +120,10 @@ void PollManager::Poll::parse(ParserT &parser) {
parser.set_error("Wrong correct_option_id");
}
}
if (has_recent_voters) {
parse(recent_voter_user_ids_, parser);
if (has_recent_voter_user_ids) {
vector<UserId> recent_voter_user_ids;
parse(recent_voter_user_ids, parser);
recent_voter_dialog_ids_ = transform(recent_voter_user_ids, [](UserId user_id) { return DialogId(user_id); });
}
if (has_open_period) {
parse(open_period_, parser);
@ -121,6 +134,12 @@ void PollManager::Poll::parse(ParserT &parser) {
if (has_explanation) {
parse(explanation_, parser);
}
if (has_recent_voter_dialog_ids) {
parse(recent_voter_dialog_ids_, parser);
}
if (has_recent_voter_min_channels) {
parse(recent_voter_min_channels_, parser);
}
}
template <class StorerT>

View File

@ -7839,16 +7839,8 @@ void Td::on_request(uint64 id, td_api::setPollAnswer &request) {
void Td::on_request(uint64 id, td_api::getPollVoters &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda(
[promise = std::move(promise), td = this](Result<std::pair<int32, vector<UserId>>> result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(td->contacts_manager_->get_users_object(result.ok().first, result.ok().second));
}
});
messages_manager_->get_poll_voters({DialogId(request.chat_id_), MessageId(request.message_id_)}, request.option_id_,
request.offset_, request.limit_, std::move(query_promise));
request.offset_, request.limit_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::stopPoll &request) {

View File

@ -2687,10 +2687,7 @@ void UpdatesManager::process_qts_update(tl_object_ptr<telegram_api::Update> &&up
case telegram_api::updateMessagePollVote::ID: {
auto update = move_tl_object_as<telegram_api::updateMessagePollVote>(update_ptr);
DialogId dialog_id(update->peer_);
if (dialog_id.get_type() == DialogType::User) {
td_->poll_manager_->on_get_poll_vote(PollId(update->poll_id_), dialog_id.get_user_id(),
std::move(update->options_));
}
td_->poll_manager_->on_get_poll_vote(PollId(update->poll_id_), dialog_id, std::move(update->options_));
add_qts(qts).set_value(Unit());
break;
}