Add td_api::setPollAnswer.
GitOrigin-RevId: 40c409ea8b4bba6d1ee0137a5cab8dca889d71dd
This commit is contained in:
parent
d22dfb2a0c
commit
b852bd145f
@ -213,7 +213,7 @@ abstract class TlDocumentationGenerator
|
||||
foreach ($info as $name => $value) {
|
||||
if (!$value) {
|
||||
$this->printError("info[$name] for $class_name is empty");
|
||||
} elseif ($value[0] < 'A' || $value[0] > 'Z') {
|
||||
} elseif (($value[0] < 'A' || $value[0] > 'Z') && ($value[0] < '0' || $value[0] > '9')) {
|
||||
$this->printError("info[$name] for $class_name doesn't begins with capital letter");
|
||||
}
|
||||
}
|
||||
|
@ -2906,6 +2906,11 @@ getJsonValue json:string = JsonValue;
|
||||
getJsonString json_value:JsonValue = Text;
|
||||
|
||||
|
||||
//@description Changes user answer to a poll @chat_id Identifier of the chat to which the poll belongs @message_id Identifier of the message containing the poll
|
||||
//@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 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
|
||||
getInlineQueryResults bot_user_id:int32 chat_id:int53 user_location:location query:string offset:string = InlineQueryResults;
|
||||
|
Binary file not shown.
@ -2679,6 +2679,13 @@ void set_message_content_web_page_id(MessageContent *content, WebPageId web_page
|
||||
static_cast<MessageText *>(content)->web_page_id = web_page_id;
|
||||
}
|
||||
|
||||
void set_message_content_poll_answer(Td *td, MessageContent *content, FullMessageId full_message_id,
|
||||
vector<int32> &&option_ids, Promise<Unit> &&promise) {
|
||||
CHECK(content->get_type() == MessageContentType::Poll);
|
||||
td->poll_manager_->set_poll_answer(static_cast<MessagePoll *>(content)->poll_id, full_message_id,
|
||||
std::move(option_ids), 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());
|
||||
|
@ -179,6 +179,9 @@ WebPageId get_message_content_web_page_id(const MessageContent *content);
|
||||
|
||||
void set_message_content_web_page_id(MessageContent *content, WebPageId web_page_id);
|
||||
|
||||
void set_message_content_poll_answer(Td *td, MessageContent *content, FullMessageId full_message_id,
|
||||
vector<int32> &&option_ids, 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);
|
||||
|
@ -24874,12 +24874,32 @@ void MessagesManager::suffix_load_till_message_id(Dialog *d, MessageId message_i
|
||||
suffix_load_add_query(d, std::make_pair(std::move(promise), std::move(condition)));
|
||||
}
|
||||
|
||||
void MessagesManager::set_poll_answer(FullMessageId full_message_id, vector<int32> &&option_ids,
|
||||
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"));
|
||||
}
|
||||
auto message_id = full_message_id.get_message_id();
|
||||
if (!message_id.is_server()) {
|
||||
return promise.set_error(Status::Error(5, "Poll can't be answered"));
|
||||
}
|
||||
|
||||
set_message_content_poll_answer(td_, m->content.get(), full_message_id, std::move(option_ids), std::move(promise));
|
||||
}
|
||||
|
||||
Result<ServerMessageId> MessagesManager::get_invoice_message_id(FullMessageId full_message_id) {
|
||||
auto message = get_message_force(full_message_id);
|
||||
if (message == nullptr) {
|
||||
auto m = get_message_force(full_message_id);
|
||||
if (m == nullptr) {
|
||||
return Status::Error(5, "Message not found");
|
||||
}
|
||||
if (message->content->get_type() != MessageContentType::Invoice) {
|
||||
if (m->content->get_type() != MessageContentType::Invoice) {
|
||||
return Status::Error(5, "Message has no invoice");
|
||||
}
|
||||
auto message_id = full_message_id.get_message_id();
|
||||
@ -24926,11 +24946,11 @@ void MessagesManager::send_payment_form(FullMessageId full_message_id, const str
|
||||
|
||||
void MessagesManager::get_payment_receipt(FullMessageId full_message_id,
|
||||
Promise<tl_object_ptr<td_api::paymentReceipt>> &&promise) {
|
||||
auto message = get_message_force(full_message_id);
|
||||
if (message == nullptr) {
|
||||
auto m = get_message_force(full_message_id);
|
||||
if (m == nullptr) {
|
||||
return promise.set_error(Status::Error(5, "Message not found"));
|
||||
}
|
||||
if (message->content->get_type() != MessageContentType::PaymentSuccessful) {
|
||||
if (m->content->get_type() != MessageContentType::PaymentSuccessful) {
|
||||
return promise.set_error(Status::Error(5, "Message has wrong type"));
|
||||
}
|
||||
auto message_id = full_message_id.get_message_id();
|
||||
|
@ -702,6 +702,8 @@ class MessagesManager : public Actor {
|
||||
|
||||
void on_binlog_events(vector<BinlogEvent> &&events);
|
||||
|
||||
void set_poll_answer(FullMessageId full_message_id, vector<int32> &&option_ids, 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,
|
||||
|
@ -9,9 +9,12 @@
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/MessagesManager.h"
|
||||
#include "td/telegram/net/NetActor.h"
|
||||
#include "td/telegram/PollManager.hpp"
|
||||
#include "td/telegram/SequenceDispatcher.h"
|
||||
#include "td/telegram/TdDb.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/UpdatesManager.h"
|
||||
|
||||
#include "td/db/SqliteKeyValue.h"
|
||||
#include "td/db/SqliteKeyValueAsync.h"
|
||||
@ -20,8 +23,53 @@
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace td {
|
||||
|
||||
class SetPollAnswerQuery : public NetActorOnce {
|
||||
Promise<Unit> promise_;
|
||||
DialogId dialog_id_;
|
||||
|
||||
public:
|
||||
explicit SetPollAnswerQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(FullMessageId full_message_id, vector<BufferSlice> &&options, uint64 generation) {
|
||||
dialog_id_ = full_message_id.get_dialog_id();
|
||||
auto input_peer = td->messages_manager_->get_input_peer(dialog_id_, AccessRights::Read);
|
||||
if (input_peer == nullptr) {
|
||||
LOG(INFO) << "Can't set poll answer, because have no read 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 query = G()->net_query_creator().create(
|
||||
create_storer(telegram_api::messages_sendVote(std::move(input_peer), message_id, std::move(options))));
|
||||
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_sendVote>(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 sendVote result: " << to_string(result);
|
||||
|
||||
td->updates_manager_->on_get_updates(std::move(result));
|
||||
promise_.set_value(Unit());
|
||||
}
|
||||
|
||||
void on_error(uint64 id, Status status) override {
|
||||
td->messages_manager_->on_get_dialog_error(dialog_id_, status, "SetPollAnswerQuery");
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
PollManager::PollManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
||||
}
|
||||
|
||||
@ -130,8 +178,28 @@ td_api::object_ptr<td_api::pollOption> PollManager::get_poll_option_object(const
|
||||
td_api::object_ptr<td_api::poll> PollManager::get_poll_object(PollId poll_id) const {
|
||||
auto poll = get_poll(poll_id);
|
||||
CHECK(poll != nullptr);
|
||||
return td_api::make_object<td_api::poll>(poll->question, transform(poll->options, get_poll_option_object),
|
||||
poll->total_voter_count, poll->is_closed);
|
||||
vector<td_api::object_ptr<td_api::pollOption>> poll_options;
|
||||
auto it = pending_answers_.find(poll_id);
|
||||
int32 voter_count_diff = 0;
|
||||
if (it == pending_answers_.end()) {
|
||||
poll_options = transform(poll->options, get_poll_option_object);
|
||||
} else {
|
||||
auto &chosen_options = it->second.options_;
|
||||
for (auto &poll_option : poll->options) {
|
||||
auto is_chosen =
|
||||
std::find(chosen_options.begin(), chosen_options.end(), poll_option.data) != chosen_options.end();
|
||||
if (poll_option.is_chosen) {
|
||||
voter_count_diff = -1;
|
||||
}
|
||||
poll_options.push_back(
|
||||
td_api::make_object<td_api::pollOption>(poll_option.text, poll_option.voter_count - static_cast<int32>(poll_option.is_chosen) + static_cast<int32>(is_chosen), is_chosen));
|
||||
}
|
||||
if (!chosen_options.empty()) {
|
||||
voter_count_diff++;
|
||||
}
|
||||
}
|
||||
return td_api::make_object<td_api::poll>(poll->question, std::move(poll_options), poll->total_voter_count + voter_count_diff,
|
||||
poll->is_closed);
|
||||
}
|
||||
|
||||
telegram_api::object_ptr<telegram_api::pollAnswer> PollManager::get_input_poll_option(const PollOption &poll_option) {
|
||||
@ -166,6 +234,107 @@ void PollManager::unregister_poll(PollId poll_id, FullMessageId full_message_id)
|
||||
poll_messages_[poll_id].erase(full_message_id);
|
||||
}
|
||||
|
||||
void PollManager::set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<int32> &&option_ids,
|
||||
Promise<Unit> &&promise) {
|
||||
if (option_ids.size() > 1) {
|
||||
return promise.set_error(Status::Error(400, "Can't choose more than 1 option"));
|
||||
}
|
||||
if (is_local_poll_id(poll_id)) {
|
||||
return promise.set_error(Status::Error(5, "Poll can't be answered"));
|
||||
}
|
||||
|
||||
auto poll = get_poll(poll_id);
|
||||
CHECK(poll != nullptr);
|
||||
if (poll->is_closed) {
|
||||
return promise.set_error(Status::Error(400, "Can't answer closed poll"));
|
||||
}
|
||||
vector<string> options;
|
||||
for (auto &option_id : option_ids) {
|
||||
auto index = static_cast<size_t>(option_id);
|
||||
if (index >= poll->options.size()) {
|
||||
return promise.set_error(Status::Error(400, "Invalid option id specified"));
|
||||
}
|
||||
options.push_back(poll->options[index].data);
|
||||
}
|
||||
|
||||
do_set_poll_answer(poll_id, full_message_id, std::move(options), 0, std::move(promise));
|
||||
}
|
||||
|
||||
void PollManager::do_set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<string> &&options,
|
||||
uint64 logevent_id, Promise<Unit> &&promise) {
|
||||
auto &pending_answer = pending_answers_[poll_id];
|
||||
if (!pending_answer.promises_.empty() && pending_answer.options_ == options) {
|
||||
pending_answer.promises_.push_back(std::move(promise));
|
||||
return;
|
||||
}
|
||||
|
||||
if (logevent_id == 0 && G()->parameters().use_message_db) {
|
||||
// TODO add logevent or rewrite pending_answer.logevent_id_
|
||||
}
|
||||
|
||||
if (!pending_answer.promises_.empty()) {
|
||||
auto promises = std::move(pending_answer.promises_);
|
||||
pending_answer.promises_.clear();
|
||||
for (auto &old_promise : promises) {
|
||||
old_promise.set_value(Unit());
|
||||
}
|
||||
}
|
||||
|
||||
vector<BufferSlice> sent_options;
|
||||
for (auto &option : options) {
|
||||
sent_options.emplace_back(option);
|
||||
}
|
||||
|
||||
auto generation = ++current_generation_;
|
||||
|
||||
pending_answer.options_ = std::move(options);
|
||||
pending_answer.promises_.push_back(std::move(promise));
|
||||
pending_answer.generation_ = generation;
|
||||
pending_answer.logevent_id_ = logevent_id;
|
||||
|
||||
notify_on_poll_update(poll_id);
|
||||
|
||||
auto query_promise = PromiseCreator::lambda([poll_id, generation, actor_id = actor_id(this)](Result<Unit> &&result) {
|
||||
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,
|
||||
full_message_id, std::move(sent_options), generation);
|
||||
}
|
||||
|
||||
void PollManager::on_set_poll_answer(PollId poll_id, uint64 generation, Result<Unit> &&result) {
|
||||
if (G()->close_flag() && result.is_error()) {
|
||||
// request will be resent after restart
|
||||
return;
|
||||
}
|
||||
auto it = pending_answers_.find(poll_id);
|
||||
if (it == pending_answers_.end()) {
|
||||
// can happen if this is an answer with mismatched generation and server has ignored invoke-after
|
||||
return;
|
||||
}
|
||||
|
||||
auto &pending_answer = it->second;
|
||||
CHECK(!pending_answer.promises_.empty());
|
||||
if (pending_answer.generation_ != generation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pending_answer.logevent_id_ != 0) {
|
||||
// TODO delete logevent
|
||||
}
|
||||
|
||||
auto promises = std::move(pending_answer.promises_);
|
||||
for (auto &promise : promises) {
|
||||
if (result.is_ok()) {
|
||||
promise.set_value(Unit());
|
||||
} else {
|
||||
promise.set_error(result.error().clone());
|
||||
}
|
||||
}
|
||||
|
||||
pending_answers_.erase(it);
|
||||
}
|
||||
|
||||
void PollManager::close_poll(PollId poll_id) {
|
||||
auto poll = get_poll_editable(poll_id);
|
||||
CHECK(poll != nullptr);
|
||||
|
@ -39,6 +39,9 @@ class PollManager : public Actor {
|
||||
|
||||
void unregister_poll(PollId poll_id, FullMessageId full_message_id);
|
||||
|
||||
void set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<int32> &&option_ids,
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
void close_poll(PollId poll_id);
|
||||
|
||||
tl_object_ptr<telegram_api::InputMedia> get_input_media(PollId poll_id) const;
|
||||
@ -83,7 +86,7 @@ class PollManager : public Actor {
|
||||
|
||||
static bool is_local_poll_id(PollId poll_id);
|
||||
|
||||
static td_api::object_ptr<td_api::pollOption> get_poll_option_object(const PollOption &poll_option);
|
||||
static td_api::object_ptr<td_api::pollOption> PollManager::get_poll_option_object(const PollOption &poll_option);
|
||||
|
||||
static telegram_api::object_ptr<telegram_api::pollAnswer> get_input_poll_option(const PollOption &poll_option);
|
||||
|
||||
@ -107,14 +110,29 @@ class PollManager : public Actor {
|
||||
|
||||
Poll *get_poll_force(PollId poll_id);
|
||||
|
||||
void do_set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<string> &&options, uint64 logevent_id,
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
void on_set_poll_answer(PollId poll_id, uint64 generation, Result<Unit> &&result);
|
||||
|
||||
Td *td_;
|
||||
ActorShared<> parent_;
|
||||
std::unordered_map<PollId, unique_ptr<Poll>, PollIdHash> polls_;
|
||||
|
||||
std::unordered_map<PollId, std::unordered_set<FullMessageId, FullMessageIdHash>, PollIdHash> poll_messages_;
|
||||
|
||||
struct PendingPollAnswer {
|
||||
vector<string> options_;
|
||||
vector<Promise<Unit>> promises_;
|
||||
uint64 generation_ = 0;
|
||||
uint64 logevent_id_ = 0;
|
||||
};
|
||||
std::unordered_map<PollId, PendingPollAnswer, PollIdHash> pending_answers_;
|
||||
|
||||
int64 current_local_poll_id_ = 0;
|
||||
|
||||
uint64 current_generation_ = 0;
|
||||
|
||||
std::unordered_set<PollId, PollIdHash> loaded_from_database_polls_;
|
||||
};
|
||||
|
||||
|
@ -6540,13 +6540,14 @@ void Td::on_request(uint64 id, td_api::setOption &request) {
|
||||
|
||||
return send_error_raw(id, 3, "Option can't be set");
|
||||
}
|
||||
/*
|
||||
void Td::on_request(uint64 id, td_api::setPollAnswers &request) {
|
||||
|
||||
void Td::on_request(uint64 id, td_api::setPollAnswer &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_OK_REQUEST_PROMISE();
|
||||
messages_manager_->set_poll_answers({DialogId(request.chat_id_), MessageId(request.message_id_)}, std::move(request.option_ids_));
|
||||
messages_manager_->set_poll_answer({DialogId(request.chat_id_), MessageId(request.message_id_)},
|
||||
std::move(request.option_ids_), std::move(promise));
|
||||
}
|
||||
*/
|
||||
|
||||
void Td::on_request(uint64 id, td_api::getInlineQueryResults &request) {
|
||||
CHECK_IS_USER();
|
||||
CLEAN_INPUT_STRING(request.query_);
|
||||
|
@ -830,7 +830,7 @@ class Td final : public NetQueryCallback {
|
||||
|
||||
void on_request(uint64 id, td_api::setOption &request);
|
||||
|
||||
// void on_request(uint64 id, td_api::setPollAnswers &request);
|
||||
void on_request(uint64 id, td_api::setPollAnswer &request);
|
||||
|
||||
void on_request(uint64 id, td_api::getInlineQueryResults &request);
|
||||
|
||||
|
@ -3212,6 +3212,15 @@ class CliClient final : public Actor {
|
||||
|
||||
std::tie(chat_id, user_ids) = split(args);
|
||||
send_request(make_tl_object<td_api::addChatMembers>(as_chat_id(chat_id), as_user_ids(user_ids, ',')));
|
||||
} else if (op == "spolla") {
|
||||
string chat_id;
|
||||
string message_id;
|
||||
string option_ids;
|
||||
|
||||
std::tie(chat_id, args) = split(args);
|
||||
std::tie(message_id, option_ids) = split(args);
|
||||
send_request(make_tl_object<td_api::setPollAnswer>(as_chat_id(chat_id), as_message_id(message_id),
|
||||
to_integers<int32>(option_ids)));
|
||||
} else {
|
||||
op_not_found_count++;
|
||||
}
|
||||
|
Reference in New Issue
Block a user