From 954bc416c3c0651ef4ec13a5360247a80a02170a Mon Sep 17 00:00:00 2001 From: Jannik <32801117+code1mountain@users.noreply.github.com> Date: Sat, 2 Jan 2021 12:32:34 +0100 Subject: [PATCH] User only methods (#25) Co-authored-by: code1mountain Co-authored-by: luckydonald --- telegram-bot-api/Client.cpp | 868 ++++++++++++++++++++++++++--- telegram-bot-api/Client.h | 73 ++- telegram-bot-api/ClientManager.cpp | 10 +- 3 files changed, 852 insertions(+), 99 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8058667..8279288 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -33,6 +33,7 @@ #include "td/utils/utf8.h" #include +#include #define CHECK_IS_BOT() \ if (is_user_) { \ @@ -191,25 +192,6 @@ Client::Client(td::ActorShared<> parent, const td::string &bot_token, bool is_us CHECK(is_inited); } -Client::Client(td::ActorShared<> parent, const td::string &bot_token, const td::string &phone_number, bool is_user, - bool is_test_dc, int64 tqueue_id, std::shared_ptr parameters, - td::ActorId stat_actor) - : parent_(std::move(parent)) - , bot_token_(bot_token) - , bot_token_id_("") - , phone_number_(phone_number) - , is_user_(is_user) - , is_test_dc_(is_test_dc) - , tqueue_id_(tqueue_id) - , parameters_(std::move(parameters)) - , stat_actor_(std::move(stat_actor)) { - messages_lru_root_.lru_next = &messages_lru_root_; - messages_lru_root_.lru_prev = &messages_lru_root_; - - static auto is_inited = init_methods(); - CHECK(is_inited); -} - bool Client::init_methods() { methods_.emplace("getme", &Client::process_get_me_query); methods_.emplace("getmycommands", &Client::process_get_my_commands_query); @@ -291,12 +273,30 @@ bool Client::init_methods() { //custom methods methods_.emplace("getmessageinfo", &Client::process_get_message_info_query); - methods_.emplace("getparticipants", &Client::process_get_participants_query); + methods_.emplace("getparticipants", &Client::process_get_chat_members_query); + methods_.emplace("getchatmembers", &Client::process_get_chat_members_query); methods_.emplace("deletemessages", &Client::process_delete_messages_query); methods_.emplace("togglegroupinvites", &Client::process_toggle_group_invites_query); methods_.emplace("ping", &Client::process_ping_query); methods_.emplace("getmemorystats", &Client::process_get_memory_stats_query); + //custom user methods + methods_.emplace("getchats", &Client::process_get_chats_query); + methods_.emplace("getcommonchats", &Client::process_get_common_chats_query); + methods_.emplace("getinactivechats", &Client::process_get_inactive_chats_query); + methods_.emplace("getnearbychats", &Client::process_get_nearby_chats_query); + methods_.emplace("searchpublicchats", &Client::process_search_public_chats_query); + methods_.emplace("votepoll", &Client::process_set_poll_answer_query); + methods_.emplace("joinchat", &Client::process_join_chat_query); + methods_.emplace("addchatmembers", &Client::process_add_chat_member_query); + methods_.emplace("reportchat", &Client::process_report_chat_query); + methods_.emplace("createchat", &Client::process_create_chat_query); + methods_.emplace("searchmessages", &Client::process_search_messages_query); + methods_.emplace("searchchatmessages", &Client::process_search_chat_messages_query); + methods_.emplace("getcallbackqueryanswer", &Client::process_get_callback_query_answer_query); + methods_.emplace("deletechathistory", &Client::process_delete_chat_history_query); + methods_.emplace("getscheduledmessages", &Client::process_get_scheduled_messages_query); + methods_.emplace("editmessagescheduling", &Client::process_edit_message_scheduling_query); return true; } @@ -370,12 +370,16 @@ class Client::JsonUser : public Jsonable { if (user_info != nullptr && !user_info->language_code.empty()) { object("language_code", user_info->language_code); } + + // start custom properties impl if (user_info != nullptr && user_info->is_verified) { object("is_verified", td::JsonBool(user_info->is_verified)); } if (user_info != nullptr && user_info->is_scam) { object("is_scam", td::JsonBool(user_info->is_scam)); } + //end custom properties impl + if (is_bot && full_bot_info_) { object("can_join_groups", td::JsonBool(user_info->can_join_groups)); object("can_read_all_group_messages", td::JsonBool(user_info->can_read_all_group_messages)); @@ -609,8 +613,12 @@ class Client::JsonMessage : public Jsonable { class Client::JsonChat : public Jsonable { public: - JsonChat(int64 chat_id, bool is_full, const Client *client, int64 pinned_message_id = -1) - : chat_id_(chat_id), is_full_(is_full), client_(client), pinned_message_id_(pinned_message_id) { + JsonChat(int64 chat_id, bool is_full, const Client *client, int64 pinned_message_id = -1, int32 distance = -1) + : chat_id_(chat_id) + , is_full_(is_full) + , client_(client) + , pinned_message_id_(pinned_message_id) + , distance_(distance) { } void store(JsonValueScope *scope) const { auto chat_info = client_->get_chat(chat_id_); @@ -629,12 +637,16 @@ class Client::JsonChat : public Jsonable { object("username", user_info->username); } object("type", "private"); + + // start custom properties impl if (user_info->is_verified) { object("is_verified", td::JsonBool(user_info->is_verified)); } if (user_info->is_scam) { object("is_scam", td::JsonBool(user_info->is_scam)); } + // end custom properties impl + if (is_full_) { if (!user_info->bio.empty()) { object("bio", user_info->bio); @@ -680,12 +692,16 @@ class Client::JsonChat : public Jsonable { } else { object("type", "channel"); } + + // start custom properties impl if (supergroup_info->is_verified) { object("is_verified", td::JsonBool(supergroup_info->is_verified)); } if (supergroup_info->is_scam) { object("is_scam", td::JsonBool(supergroup_info->is_scam)); } + // end custom properties impl + if (is_full_) { if (!supergroup_info->description.empty()) { object("description", supergroup_info->description); @@ -737,6 +753,13 @@ class Client::JsonChat : public Jsonable { } } } + + // start custom properties impl + if (distance_ >= 0) { + object("distance", td::JsonInt(distance_)); + } + // end custom properties impl + } private: @@ -744,6 +767,7 @@ class Client::JsonChat : public Jsonable { bool is_full_; const Client *client_; int64 pinned_message_id_; + int32 distance_; }; class Client::JsonMessageSender : public Jsonable { @@ -1532,7 +1556,11 @@ class Client::JsonReplyMarkup : public Jsonable { void Client::JsonMessage::store(JsonValueScope *scope) const { CHECK(message_ != nullptr); auto object = scope->enter_object(); - object("message_id", as_client_message_id(message_->id)); + if (message_->is_scheduled) { + object("message_id", as_scheduled_message_id(message_->id)); + } else { + object("message_id", as_client_message_id(message_->id)); + } if (message_->sender_user_id != 0) { object("from", JsonUser(message_->sender_user_id, client_)); } @@ -1553,6 +1581,12 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { if (message_->forwards != 0) { object("forwards", message_->forwards); } + if (message_->is_scheduled) { + object("is_scheduled", td::JsonBool(message_->is_scheduled)); + } + if (message_->scheduled_at != 0) { + object("scheduled_at", message_->scheduled_at); + } if (message_->initial_send_date > 0) { if (message_->initial_sender_user_id != 0) { object("forward_from", JsonUser(message_->initial_sender_user_id, client_)); @@ -2316,6 +2350,133 @@ class Client::JsonStickerSet : public Jsonable { const Client *client_; }; +// start custom Json objects impl + +class Client::JsonAuthorizationState : public Jsonable { + public: + JsonAuthorizationState(const td_api::AuthorizationState *state, td::string token = "") + : state_(state), token_(token) { + } + + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + if (!token_.empty()) { + object("token", token_); + } + if (state_ == nullptr) { + object("authorization_state", "unknown"); + return; + } + switch (state_->get_id()) { + case td_api::authorizationStateWaitCode::ID: { + object("authorization_state", "wait_code"); + auto state_code = static_cast(state_); + if (state_code != nullptr && state_code->code_info_ != nullptr && state_code->code_info_->timeout_ != 0) { + object("timeout", state_code->code_info_->timeout_); + } + break; + } + case td_api::authorizationStateWaitPassword::ID: { + object("authorization_state", "wait_password"); + auto state_password = static_cast(state_); + if (state_password != nullptr) { + if (!state_password->password_hint_.empty()) { + object("password_hint", state_password->password_hint_); + } + object("has_recovery_email_address", td::JsonBool(state_password->has_recovery_email_address_)); + } + break; + } + case td_api::authorizationStateWaitRegistration::ID: + object("authorization_state", "wait_registration"); + break; + case td_api::authorizationStateReady::ID: + object("authorization_state", "ready"); + break; + + default: + object("authorization_state", "unknown"); + break; + } + } + + private: + const td_api::AuthorizationState *state_; + const td::string token_; +}; + +class Client::JsonCallbackQueryAnswer : public Jsonable { + public: + JsonCallbackQueryAnswer(const td_api::callbackQueryAnswer *answer) : answer_(answer) { + } + + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("text", answer_->text_); + object("show_alert", td::JsonBool(answer_->show_alert_)); + object("url", answer_->url_); + } + + private: + const td_api::callbackQueryAnswer *answer_; +}; + +class Client::JsonChats : public Jsonable { + public: + JsonChats(const object_ptr &chats, const Client *client) : chats_(chats), client_(client) { + } + void store(JsonValueScope *scope) const { + auto array = scope->enter_array(); + for (auto &chat : chats_->chat_ids_) { + array << JsonChat(chat, false, client_); + } + } + + private: + const object_ptr &chats_; + const Client *client_; +}; + +class Client::JsonChatsNearby : public Jsonable { + public: + JsonChatsNearby(const object_ptr &chats_nearby, const Client *client) + : chats_nearby_(chats_nearby), client_(client) { + } + void store(JsonValueScope *scope) const { + auto array = scope->enter_array(); + for (auto &chat : chats_nearby_->users_nearby_) { + array << JsonChat(chat->chat_id_, false, client_, -1, chat->distance_); + } + for (auto &chat : chats_nearby_->supergroups_nearby_) { + array << JsonChat(chat->chat_id_, false, client_, -1, chat->distance_); + } + } + + private: + const object_ptr &chats_nearby_; + const Client *client_; +}; + +class Client::JsonMessagesArray : public Jsonable { + public: + explicit JsonMessagesArray(object_ptr &messages, Client *client) : messages_(messages), client_(client) { + } + void store(JsonValueScope *scope) const { + auto array = scope->enter_array(); + for (auto &message : messages_->messages_) { + auto full_message_id = client_->add_message(std::move(message)); + const MessageInfo *m = client_->get_message(full_message_id.chat_id, full_message_id.message_id); + array << JsonMessage(m, true, "search", client_); + } + } + + private: + object_ptr &messages_; + Client *client_; +}; + +//end custom Json objects impl + class Client::TdOnOkCallback : public TdQueryCallback { public: void on_result(object_ptr result) override { @@ -2334,10 +2495,7 @@ class Client::TdOnAuthorizationCallback : public TdQueryCallback { } void on_result(object_ptr result) override { - bool was_ready = client_->authorization_state_->get_id() != td_api::authorizationStateWaitPhoneNumber::ID && - client_->authorization_state_->get_id() != td_api::authorizationStateWaitCode::ID && - client_->authorization_state_->get_id() != td_api::authorizationStateWaitPassword::ID && - client_->authorization_state_->get_id() != td_api::authorizationStateWaitRegistration::ID; + bool was_ready = client_->authorization_state_->get_id() != td_api::authorizationStateWaitPhoneNumber::ID; if (result->get_id() == td_api::error::ID) { auto error = move_object_as(result); if (error->code_ == 429 || error->code_ >= 500 || (error->code_ != 401 && was_ready)) { @@ -2358,34 +2516,49 @@ class Client::TdOnAuthorizationCallback : public TdQueryCallback { class Client::TdOnAuthorizationQueryCallback : public TdQueryCallback { public: - TdOnAuthorizationQueryCallback(Client *client, PromisedQueryPtr query) : - client_(client), query_(std::move(query)) { + TdOnAuthorizationQueryCallback(Client *client, PromisedQueryPtr query, bool send_token = false) + : client_(client), query_(std::move(query)), send_token_(send_token) { } void on_result(object_ptr result) override { - bool was_ready = client_->authorization_state_->get_id() != td_api::authorizationStateWaitPhoneNumber::ID && - client_->authorization_state_->get_id() != td_api::authorizationStateWaitCode::ID && - client_->authorization_state_->get_id() != td_api::authorizationStateWaitPassword::ID && - client_->authorization_state_->get_id() != td_api::authorizationStateWaitRegistration::ID; + bool was_ready = client_->authorization_state_->get_id() != td_api::authorizationStateWaitPhoneNumber::ID; + bool can_retry = client_->authorization_state_->get_id() == td_api::authorizationStateWaitCode::ID || + client_->authorization_state_->get_id() == td_api::authorizationStateWaitPassword::ID || + client_->authorization_state_->get_id() == td_api::authorizationStateWaitRegistration::ID; if (result->get_id() == td_api::error::ID) { auto error = move_object_as(result); - if (error->code_ == 429 || error->code_ >= 500 || (error->code_ != 401 && was_ready)) { + if (error->code_ == 429 || error->code_ >= 500 || (error->code_ != 401 && was_ready && !client_->is_user_)) { // try again return client_->on_update_authorization_state(); + } else if (error->code_ == 400 && can_retry) { + return fail_query_with_error(std::move(query_), std::move(error)); } fail_query(401, "Unauthorized: Log in failed, logging out due to " + td::oneline(to_string(error)), std::move(query_)); LOG(WARNING) << "Logging out due to " << td::oneline(to_string(error)); client_->log_out(); } else { - answer_query(td::JsonTrue(), std::move(query_)); - client_->on_update_authorization_state(); + if (client_->authorization_state_->get_id() == td_api::authorizationStateWaitRegistration::ID && + !client_->parameters_->allow_users_registration_) { + fail_query(401, + "Unauthorized: It is not allowed to register users with this api. You can enable it with the " + "command line option --allow-users-registration. Logging out", + std::move(query_)); + return client_->log_out(); + } + if (send_token_) { + answer_query(JsonAuthorizationState(client_->authorization_state_.get(), client_->bot_token_), std::move(query_)); + + } else { + answer_query(JsonAuthorizationState(client_->authorization_state_.get()), std::move(query_)); + } } } private: Client *client_; PromisedQueryPtr query_; + bool send_token_; }; class Client::TdOnInitCallback : public TdQueryCallback { @@ -3311,8 +3484,7 @@ class Client::TdOnSendCustomRequestCallback : public TdQueryCallback { class Client::TdOnPingCallback : public TdQueryCallback { public: - explicit TdOnPingCallback(PromisedQueryPtr query) - : query_(std::move(query)) { + explicit TdOnPingCallback(PromisedQueryPtr query) : query_(std::move(query)) { } void on_result(object_ptr result) override { @@ -3322,7 +3494,7 @@ class Client::TdOnPingCallback : public TdQueryCallback { CHECK(result->get_id() == td_api::seconds::ID); auto seconds_ = move_object_as(result); - answer_query(td::VirtuallyJsonableString(std::to_string(seconds_->seconds_)), std::move(query_)); + answer_query(seconds_->seconds_, std::move(query_)); } private: @@ -3349,6 +3521,129 @@ class Client::TdOnGetMemoryStatisticsCallback : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnGetChatsCallback : public TdQueryCallback { + public: + explicit TdOnGetChatsCallback(Client *client, PromisedQueryPtr query) : client_(client), query_(std::move(query)) { + } + + void on_result(object_ptr result) override { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + CHECK(result->get_id() == td_api::chats::ID); + + auto chats = move_object_as(result); + answer_query(JsonChats(chats, client_), std::move(query_)); + } + + private: + const Client *client_; + PromisedQueryPtr query_; +}; + +class Client::TdOnGetChatsNearbyCallback : public TdQueryCallback { + public: + explicit TdOnGetChatsNearbyCallback(Client *client, PromisedQueryPtr query) + : client_(client), query_(std::move(query)) { + } + + void on_result(object_ptr result) override { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + CHECK(result->get_id() == td_api::chatsNearby::ID); + + auto chats_nearby = move_object_as(result); + answer_query(JsonChatsNearby(chats_nearby, client_), std::move(query_)); + } + + private: + const Client *client_; + PromisedQueryPtr query_; +}; + +class Client::TdOnJoinChatCallback : public TdQueryCallback { + public: + explicit TdOnJoinChatCallback(Client *client, PromisedQueryPtr query, int64 chat_id) + : client_(client), query_(std::move(query)), chat_id_(chat_id) { + } + + void on_result(object_ptr result) override { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + CHECK(result->get_id() == td_api::ok::ID); + + answer_query(JsonChat(chat_id_, false, client_), std::move(query_)); + } + + private: + const Client *client_; + PromisedQueryPtr query_; + int64 chat_id_; +}; + +class Client::TdOnReturnChatCallback : public TdQueryCallback { + public: + explicit TdOnReturnChatCallback(Client *client, PromisedQueryPtr query) + : client_(client), query_(std::move(query)) { + } + + void on_result(object_ptr result) override { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + CHECK(result->get_id() == td_api::chat::ID); + + auto chat = move_object_as(result); + answer_query(JsonChat(chat->id_, false, client_), std::move(query_)); + } + + private: + const Client *client_; + PromisedQueryPtr query_; +}; + +class Client::TdOnReturnMessagesCallback : public TdQueryCallback { + public: + explicit TdOnReturnMessagesCallback(Client *client, PromisedQueryPtr query) + : client_(client), query_(std::move(query)) { + } + + void on_result(object_ptr result) override { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + CHECK(result->get_id() == td_api::messages::ID); + + auto messages = move_object_as(result); + answer_query(JsonMessagesArray(messages, client_), std::move(query_)); + } + + private: + Client *client_; + PromisedQueryPtr query_; +}; + +class Client::TdOnGetCallbackQueryAnswerCallback : public TdQueryCallback { + public: + explicit TdOnGetCallbackQueryAnswerCallback(PromisedQueryPtr query) + : query_(std::move(query)) { + } + + void on_result(object_ptr result) override { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + CHECK(result->get_id() == td_api::callbackQueryAnswer::ID); + + auto answer = move_object_as(result); + answer_query(JsonCallbackQueryAnswer(answer.get()), std::move(query_)); + } + + PromisedQueryPtr query_; +}; + //end custom callbacks impl void Client::close() { @@ -4042,8 +4337,8 @@ void Client::on_update_authorization_state() { return send_request(make_object(), std::make_unique(this)); case td_api::authorizationStateWaitPhoneNumber::ID: if (is_user_) { - return send_request(make_object(phone_number_, nullptr), - std::make_unique(this)); + waiting_for_auth_input_ = true; + return loop(); } else { return send_request(make_object(bot_token_), std::make_unique(this)); @@ -5024,8 +5319,8 @@ td::Result> Client::get_input_me return nullptr; } -td_api::object_ptr Client::get_message_send_options(bool disable_notification) { - return make_object(disable_notification, false, nullptr); +td_api::object_ptr Client::get_message_send_options(bool disable_notification, td_api::object_ptr &&scheduling_state) { + return make_object(disable_notification, false, std::move(scheduling_state)); } td::Result>> Client::get_inline_query_results( @@ -6008,9 +6303,9 @@ td::int64 Client::get_message_id(const Query *query, Slice field_name) { } int arg = td::to_integer(s_arg); - if (arg < 0) { - return 0; - } + // if (arg < 0) { + // return 0; + // } return as_tdlib_message_id(arg); } @@ -6057,6 +6352,132 @@ td::int64 Client::extract_yet_unsent_message_query_id(int64 chat_id, int64 messa return query_id; } +// start custom helper methods impl + +td::Result> Client::get_message_scheduling_state( + const Query *query) { + auto send_at = trim(query->arg("send_at")); + if (send_at.empty()) { + return nullptr; + } else if (send_at == "online") { + return make_object(); + } else { + TRY_RESULT(send_at_date, td::to_integer_safe(send_at)); + return make_object(send_at_date); + } +} + +template +td::Result> Client::get_int_array_arg(const Query *query, Slice field_name, bool optional) { + auto input_options = query->arg(field_name); + if (input_options.empty() && optional) { + td::vector array; + return std::move(array); + } + LOG(INFO) << "Parsing JSON object: " << input_options; + auto r_value = json_decode(input_options); + if (r_value.is_error()) { + LOG(INFO) << "Can't parse JSON object: " << r_value.error(); + return Status::Error(400, "Can't parse option_ids JSON object"); + } + + auto value = r_value.move_as_ok(); + if (value.type() != JsonValue::Type::Array) { + return Status::Error(400, "Expected an Array of Integer as options"); + } + + td::vector array; + for (auto &element : value.get_array()) { + if (element.type() != JsonValue::Type::Number) { + return Status::Error(400, "Expected an elements to be of type Integer"); + } + array.push_back(td::to_integer_safe(element.get_number()).move_as_ok()); + } + return std::move(array); +} + +td::int64 Client::get_int64_arg(const Query *query, Slice field_name, int64 default_value, int64 min_value, + int64 max_value) { + auto s_arg = query->arg(field_name); + if (s_arg.empty()) { + return default_value; + } + + return td::clamp(td::to_integer(s_arg), min_value, max_value); +} + +td::Result> Client::get_report_reason(const Query *query, + Slice field_name) { + auto reason = query->arg(field_name); + object_ptr result; + if (reason.empty()) { + return Status::Error(400, "reason is not specified"); + } else if (reason == "child_abuse") { + result = make_object(); + } else if (reason == "copyright") { + result = make_object(); + } else if (reason == "pornography") { + result = make_object(); + } else if (reason == "spam") { + result = make_object(); + } else if (reason == "unrelated_location") { + result = make_object(); + } else if (reason == "violence") { + result = make_object(); + } else { + result = make_object(reason.str()); + } + return std::move(result); +} + +td::Result> Client::get_search_messages_filter(const Query *query, + Slice field_name) { + auto filter = query->arg(field_name); + object_ptr result; + if (filter.empty()) { + result = make_object(); + } else if (filter == "animation") { + result = make_object(); + } else if (filter == "audio") { + result = make_object(); + } else if (filter == "call") { + result = make_object(); + } else if (filter == "chat_photo") { + result = make_object(); + } else if (filter == "document") { + result = make_object(); + } else if (filter == "failed_to_send") { + result = make_object(); + } else if (filter == "mention") { + result = make_object(); + } else if (filter == "missed_call") { + result = make_object(); + } else if (filter == "photo") { + result = make_object(); + } else if (filter == "photo_and_video") { + result = make_object(); + } else if (filter == "pinned") { + result = make_object(); + } else if (filter == "unread_mention") { + result = make_object(); + } else if (filter == "url") { + result = make_object(); + } else if (filter == "video") { + result = make_object(); + } else if (filter == "video_note") { + result = make_object(); + } else if (filter == "voice_and_video_note") { + result = make_object(); + } else if (filter == "voice_note") { + result = make_object(); + } else { + return Status::Error(400, "Filter not valid"); + } + return std::move(result); +} + +// end custom helper methods impl + void Client::on_message_send_succeeded(object_ptr &&message, int64 old_message_id) { auto full_message_id = add_message(std::move(message), true); @@ -6138,9 +6559,11 @@ void Client::on_cmd(PromisedQueryPtr query) { } } if (waiting_for_auth_input_) { - if (query->method() == "authcode") { + if (query->method().empty()) { + return process_auth_phone_number_query(query); + } else if (query->method() == "authcode") { return process_authcode_query(query); - } else if (query->method() == "2fapassword") { + } else if (query->method() == "2fapassword" || query->method() == "authpassword") { return process_2fapassword_query(query); } else if (query->method() == "registeruser" && parameters_->allow_users_registration_) { return process_register_user_query(query); @@ -6529,17 +6952,18 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { // TRY_RESULT(reply_markup, get_reply_markup(query.get())); auto reply_markup = nullptr; TRY_RESULT(input_message_contents, get_input_message_contents(query.get(), "media")); + TRY_RESULT(send_at, get_message_scheduling_state(query.get())); resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), [this, chat_id = chat_id.str(), reply_to_message_id, allow_sending_without_reply, disable_notification, - input_message_contents = std::move(input_message_contents)](object_ptr reply_markup, - PromisedQueryPtr query) mutable { + input_message_contents = std::move(input_message_contents), + send_at = std::move(send_at)](object_ptr reply_markup, PromisedQueryPtr query) mutable { auto on_success = [this, disable_notification, input_message_contents = std::move(input_message_contents), - reply_markup = std::move(reply_markup)](int64 chat_id, int64 reply_to_message_id, - PromisedQueryPtr query) mutable { + reply_markup = std::move(reply_markup), send_at = std::move(send_at)]( + int64 chat_id, int64 reply_to_message_id, PromisedQueryPtr query) mutable { send_request(make_object(chat_id, 0, reply_to_message_id, - get_message_send_options(disable_notification), + get_message_send_options(disable_notification, std::move(send_at)), std::move(input_message_contents)), std::make_unique(this, std::move(query))); }; @@ -7589,51 +8013,47 @@ td::Status Client::process_get_message_info_query(PromisedQueryPtr &query) { return Status::OK(); } -td::Status Client::process_get_participants_query(PromisedQueryPtr &query) { +td::Status Client::process_get_chat_members_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); + td::int32 offset = get_integer_arg(query.get(), "offset", 0); + td::int32 limit = get_integer_arg(query.get(), "limit", 200, 0, 200); - check_chat(chat_id, AccessRights::Read, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { - auto chat_info = get_chat(chat_id); - CHECK(chat_info != nullptr); - td::int32 offset = get_integer_arg(query.get(), "offset", 0); - td::int32 limit = get_integer_arg(query.get(), "limit", 200, 0, 200); - + check_chat( + chat_id, AccessRights::Read, std::move(query), [this, offset, limit](int64 chat_id, PromisedQueryPtr query) { + auto chat_info = get_chat(chat_id); + CHECK(chat_info != nullptr); switch (chat_info->type) { case ChatInfo::Type::Private: - return fail_query(400, "Bad Request: there are no participants in the private chat", std::move(query)); + return fail_query(400, "Bad Request: there are no administrators in the private chat", std::move(query)); case ChatInfo::Type::Group: { - /* auto group_info = get_group_info(chat_info->group_id); CHECK(group_info != nullptr); return send_request(make_object(chat_info->group_id), - std::make_unique(this, true, std::move(query))) - */ - return fail_query(400, "Bad Request: method not available for group chats", std::move(query)); + std::make_unique(this, false, std::move(query))); } case ChatInfo::Type::Supergroup: { td_api::object_ptr filter; - td::string type = "members"; - if (query->has_arg("type")) { - type = td::to_lower(query->arg("type")); - } - - if (type == "members" || type == "participants") { + td::string filter_name = td::to_lower(query->arg("filter")); + auto query_ = query->arg("query"); + if (!query->empty()) { + filter = td_api::make_object(query_.str()); + } else if (filter_name == "members" || filter_name == "participants") { filter = td_api::make_object(); - } else if (type == "banned") { + } else if (filter_name == "banned") { filter = td_api::make_object(); - } else if (type == "restricted") { + } else if (filter_name == "restricted") { filter = td_api::make_object(); - } else if (type == "bots") { + } else if (filter_name == "bots") { filter = td_api::make_object(); - } else if (type == "admins" || type == "administrators") { + } else if (filter_name == "admins" || filter_name == "administrators") { filter = td_api::make_object(); } else { fail_query_with_error(std::move(query), 400, "Invalid member type"); return; } - return send_request( - make_object(chat_info->supergroup_id, std::move(filter), offset, limit), + make_object( + chat_info->supergroup_id, std::move(filter), offset, limit), std::make_unique(this, get_chat_type(chat_id), std::move(query))); } case ChatInfo::Type::Unknown: @@ -7677,11 +8097,10 @@ td::Status Client::process_delete_messages_query(PromisedQueryPtr &query) { ids.push_back(as_tdlib_message_id(i)); } - if (ids.size() != 0) { + if (!ids.empty()) { send_request(make_object(chat_id, std::move(ids), true), - std::make_unique()); + std::make_unique(std::move(query))); } - answer_query(td::JsonTrue(), std::move(query)); }); return Status::OK(); @@ -7693,8 +8112,7 @@ td::Status Client::process_toggle_group_invites_query(PromisedQueryPtr &query) { } td::Status Client::process_ping_query(PromisedQueryPtr &query) { - send_request(make_object(), - std::make_unique(std::move(query))); + send_request(make_object(), std::make_unique(std::move(query))); return Status::OK(); } @@ -7704,8 +8122,254 @@ td::Status Client::process_get_memory_stats_query(PromisedQueryPtr &query) { return Status::OK(); } //end custom methods impl +//start custom user methods impl + +td::Status Client::process_get_chats_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + td::int64 offset_chat_id = get_integer_arg(query.get(), "offset_chat_id", 0); + send_request(make_object(make_object(), LLONG_MAX, offset_chat_id, 100), + std::make_unique(this, std::move(query))); + return Status::OK(); +} + +td::Status Client::process_get_common_chats_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + TRY_RESULT(user_id, get_user_id(query.get())); + td::int64 offset_chat_id = get_integer_arg(query.get(), "offset_chat_id", 0); + + send_request(make_object(user_id, offset_chat_id, 100), + std::make_unique(this, std::move(query))); + return Status::OK(); +} + +td::Status Client::process_get_inactive_chats_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + + send_request(make_object(), + std::make_unique(this, std::move(query))); + return Status::OK(); +} + +td::Status Client::process_get_nearby_chats_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + TRY_RESULT(location, get_location(query.get())); + + send_request(make_object(std::move(location)), + std::make_unique(this, std::move(query))); + return Status::OK(); +} + +td::Status Client::process_search_public_chats_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto query_ = query->arg("query"); + + send_request(make_object(query_.str()), + std::make_unique(this, std::move(query))); + return Status::OK(); +} + +td::Status Client::process_set_poll_answer_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto chat_id = query->arg("chat_id"); + TRY_RESULT(option_ids, get_int_array_arg(query.get(), "option_ids")); + + check_chat(chat_id, AccessRights::Read, std::move(query), + [this, option_ids = std::move(option_ids)](int64 chat_id, PromisedQueryPtr query) mutable { + auto message_id = get_message_id(query.get()); + send_request(make_object(chat_id, message_id, std::move(option_ids)), + std::make_unique(std::move(query))); + }); + + return Status::OK(); +} + +td::Status Client::process_join_chat_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto chat_id = query->arg("chat_id"); + auto invite_link = query->arg("invite_link"); + + if (!chat_id.empty()) { + check_chat(chat_id, AccessRights::Read, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { + send_request(make_object(chat_id), + std::make_unique(this, std::move(query), chat_id)); + }); + } else if (!invite_link.empty()) { + send_request(make_object(invite_link.str()), + std::make_unique(this, std::move(query))); + } else { + fail_query(400, "Bad request: Please specify chat_id or invite_link", std::move(query)); + } + + return Status::OK(); +} + +td::Status Client::process_add_chat_member_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto chat_id = query->arg("chat_id"); + TRY_RESULT(user_id, get_user_id(query.get())) + + check_chat(chat_id, AccessRights::Write, std::move(query), + [this, user_id](int64 chat_id, PromisedQueryPtr query) mutable { + auto chat = get_chat(chat_id); + if (chat->type == ChatInfo::Type::Supergroup) { + std::vector user_ids{user_id}; + send_request(make_object(chat_id, std::move(user_ids)), + std::make_unique(std::move(query))); + } else if (chat->type == ChatInfo::Type::Group) { + send_request(make_object(chat_id, user_id, 0), + std::make_unique(std::move(query))); + } + }); + return Status::OK(); +} + +td::Status Client::process_report_chat_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto chat_id = query->arg("chat_id"); + TRY_RESULT(reason, get_report_reason(query.get())); + TRY_RESULT(message_ids, get_int_array_arg(query.get(), "message_ids", true)); + + check_chat(chat_id, AccessRights::Read, std::move(query), + [this, reason = std::move(reason), message_ids = std::move(message_ids)](int64 chat_id, + PromisedQueryPtr query) mutable { + send_request(make_object(chat_id, std::move(reason), std::move(message_ids)), + std::make_unique(std::move(query))); + }); + return Status::OK(); +} + +td::Status Client::process_create_chat_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto chat_type = query->arg("type"); + auto title = query->arg("title"); + auto description = query->arg("description"); + + if (chat_type == "supergroup") { + send_request(make_object(title.str(), false, description.str(), nullptr), + std::make_unique(this, std::move(query))); + } else if (chat_type == "channel") { + send_request(make_object(title.str(), true, description.str(), nullptr), + std::make_unique(this, std::move(query))); + } else if (chat_type == "group") { + TRY_RESULT(initial_members, get_int_array_arg(query.get(), "user_ids")) + send_request(make_object(std::move(initial_members), title.str()), + std::make_unique(this, std::move(query))); + } else { + return Status::Error(400, "Chat type is not specified"); + } + return Status::OK(); +} + +td::Status Client::process_search_messages_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto query_ = query->arg("query"); + auto offset_date = get_integer_arg(query.get(), "offset_date", 0); + auto offset_chat_id = get_int64_arg(query.get(), "offset_chat_id", 0); + auto offset_message_id = get_int64_arg(query.get(), "offset_message_id", 0); + TRY_RESULT(filter, get_search_messages_filter(query.get())); + auto min_date = get_integer_arg(query.get(), "min_date", 0); + auto max_date = get_integer_arg(query.get(), "max_date", 0); + + send_request(make_object(nullptr, query_.str(), offset_date, offset_chat_id, + offset_message_id, 100, std::move(filter), min_date, max_date), + std::make_unique(this, std::move(query))); + return Status::OK(); +} + +td::Status Client::process_search_chat_messages_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto chat_id = query->arg("chat_id"); + auto query_ = query->arg("query"); + auto sender_user_id = get_integer_arg(query.get(), "sender_user_id", 0); + auto sender = make_object(sender_user_id); + if (sender_user_id == 0) { + sender = nullptr; + } + auto from_message_id = get_int64_arg(query.get(), "from_message_id", 0); + TRY_RESULT(filter, get_search_messages_filter(query.get())); + + check_chat(chat_id, AccessRights::Read, std::move(query), + [this, query_, sender = std::move(sender), from_message_id, filter = std::move(filter)]( + int64 chat_id, PromisedQueryPtr query) mutable { + send_request(make_object(chat_id, query_.str(), std::move(sender), + from_message_id, 0, 100, std::move(filter), 0), + std::make_unique(this, std::move(query))); + }); + return Status::OK(); +} + +td::Status Client::process_get_callback_query_answer_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto chat_id = query->arg("chat_id"); + auto message_id = get_message_id(query.get()); + auto callback_data = query->arg("callback_data"); + auto payload = make_object(callback_data.str()); + check_chat(chat_id, AccessRights::Read, std::move(query), + [this, message_id, payload = std::move(payload)](int64 chat_id, PromisedQueryPtr query) mutable { + send_request(make_object(chat_id, message_id, std::move(payload)), + std::make_unique(std::move(query))); + }); + return Status::OK(); +} + +td::Status Client::process_delete_chat_history_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto chat_id = query->arg("chat_id"); + bool for_everyone = to_bool(query->arg("for_everyone")); + bool remove_from_chat_list = to_bool(query->arg("remove_from_chat_list")); + + check_chat(chat_id, AccessRights::Read, std::move(query), + [this, for_everyone, remove_from_chat_list](int64 chat_id, PromisedQueryPtr query) mutable { + send_request(make_object(chat_id, for_everyone, remove_from_chat_list), + std::make_unique(std::move(query))); + }); + return Status::OK(); +} + +td::Status Client::process_get_scheduled_messages_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto chat_id = query->arg("chat_id"); + check_chat(chat_id, AccessRights::Read, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) mutable { + send_request(make_object(chat_id), + std::make_unique(this, std::move(query))); + }); + return Status::OK(); +} + +td::Status Client::process_edit_message_scheduling_query(PromisedQueryPtr &query) { + CHECK_IS_USER(); + auto chat_id = query->arg("chat_id"); + auto message_id = get_message_id(query.get()); + TRY_RESULT(send_at, get_message_scheduling_state(query.get())); + check_chat(chat_id, AccessRights::Read, std::move(query), + [this, message_id, send_at = std::move(send_at)](int64 chat_id, PromisedQueryPtr query) mutable { + send_request(make_object(chat_id, message_id, std::move(send_at)), + std::make_unique(std::move(query))); + }); + return Status::OK(); +} + +//end custom user methods impl //start custom auth methods impl +void Client::process_auth_phone_number_query(PromisedQueryPtr &query) { + td::MutableSlice r_phone_number = query->arg("phone_number"); + if (r_phone_number.size() < 5 || r_phone_number.size() > 15) { + return fail_query(401, "Unauthorized: invalid phone number specified", std::move(query)); + } + td::int64 phone_number = 0; + for (char const &c : r_phone_number) { + if (isdigit(c)) { + phone_number = phone_number * 10 + (c - 48); + } + } + if (authorization_state_->get_id() != td_api::authorizationStateWaitPhoneNumber::ID) { + return fail_query(400, "Bad Request: currently not waiting for a phone_number", std::move(query)); + } + send_request(make_object(td::to_string(phone_number), nullptr), + std::make_unique(this, std::move(query), true)); +} + void Client::process_authcode_query(PromisedQueryPtr &query) { auto code = query->arg("code"); if (code.empty()) { @@ -7966,16 +8630,22 @@ void Client::do_send_message(object_ptr input_messa return fail_query_with_error(std::move(query), 405, "Method Not Allowed: reply markup not available as user."); } + auto r_send_at = get_message_scheduling_state(query.get()); + if (r_send_at.is_error()) { + return fail_query_with_error(std::move(query), 400, r_send_at.error().message()); + } + auto send_at = r_send_at.move_as_ok(); + resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), [this, chat_id = chat_id.str(), reply_to_message_id, allow_sending_without_reply, disable_notification, - input_message_content = std::move(input_message_content)](object_ptr reply_markup, - PromisedQueryPtr query) mutable { + input_message_content = std::move(input_message_content), + send_at = std::move(send_at)](object_ptr reply_markup, PromisedQueryPtr query) mutable { auto on_success = [this, disable_notification, input_message_content = std::move(input_message_content), - reply_markup = std::move(reply_markup)](int64 chat_id, int64 reply_to_message_id, - PromisedQueryPtr query) mutable { + reply_markup = std::move(reply_markup), send_at = std::move(send_at)]( + int64 chat_id, int64 reply_to_message_id, PromisedQueryPtr query) mutable { send_request(make_object(chat_id, 0, reply_to_message_id, - get_message_send_options(disable_notification), + get_message_send_options(disable_notification, std::move(send_at)), std::move(reply_markup), std::move(input_message_content)), std::make_unique(this, std::move(query))); }; @@ -8179,8 +8849,11 @@ void Client::add_user(std::unordered_map &users, object_ptrlast_name = user->last_name_; user_info->username = user->username_; user_info->language_code = user->language_code_; + + // start custom properties user_info->is_verified = user->is_verified_; user_info->is_scam = user->is_scam_; + //end custom properties user_info->have_access = user->have_access_; @@ -8250,8 +8923,11 @@ void Client::add_supergroup(std::unordered_map &supergrou supergroup_info->status = std::move(supergroup->status_); supergroup_info->is_supergroup = !supergroup->is_channel_; supergroup_info->has_location = supergroup->has_location_; + + // start custom properties supergroup_info->is_verified = supergroup->is_verified_; supergroup_info->is_scam = supergroup->is_scam_; + // end custom properties } void Client::set_supergroup_description(int32 supergroup_id, td::string &&descripton) { @@ -9317,6 +9993,11 @@ Client::FullMessageId Client::add_message(object_ptr &&message, message_info->views = message->interaction_info_->view_count_; message_info->forwards = message->interaction_info_->forward_count_; } + message_info->is_scheduled = message->scheduling_state_!=nullptr; + if (message->scheduling_state_!=nullptr && message->scheduling_state_->get_id() == td_api::messageSchedulingStateSendAtDate::ID) { + auto scheduling_state = move_object_as(message->scheduling_state_); + message_info->scheduled_at = scheduling_state->send_date_; + } message_info->author_signature = std::move(message->author_signature_); @@ -9496,7 +10177,11 @@ td::int32 Client::get_unix_time() const { } td::int64 Client::as_tdlib_message_id(int32 message_id) { - return static_cast(message_id) << 20; + if (message_id >= 0) { + return static_cast(message_id) << 20; + } else { + return static_cast((-message_id) << 3) + 4; + } } td::int32 Client::as_client_message_id(int64 message_id) { @@ -9505,6 +10190,13 @@ td::int32 Client::as_client_message_id(int64 message_id) { return result; } +td::int32 Client::as_scheduled_message_id(int64 message_id) { + // scheduled message ID layout + // |-------30-------|----18---|1|--2-| + // |send_date-2**30 |server_id|1|type| + return -static_cast((message_id >> 3) & ((1 << 18) - 1)); +} + td::int64 Client::get_supergroup_chat_id(int32 supergroup_id) { return static_cast(-1000000000000ll) - static_cast(supergroup_id); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 5e8a7d9..62c2a59 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -41,10 +41,6 @@ class Client : public WebhookActor::Callback { Client(td::ActorShared<> parent, const td::string &bot_token, bool is_user, bool is_test_dc, td::int64 tqueue_id, std::shared_ptr parameters, td::ActorId stat_actor); - Client(td::ActorShared<> parent, const td::string &bot_token, const td::string &phone_number, bool is_user, - bool is_test_dc, td::int64 tqueue_id, std::shared_ptr parameters, - td::ActorId stat_actor); - void send(PromisedQueryPtr query) override; void close(); @@ -157,6 +153,14 @@ class Client : public WebhookActor::Callback { class JsonStickerSet; class JsonCustomJson; + //start custom Json objects + class JsonAuthorizationState; + class JsonCallbackQueryAnswer; + class JsonChats; + class JsonChatsNearby; + class JsonMessagesArray; + //stop custom Json objects + class TdOnOkCallback; class TdOnAuthorizationCallback; class TdOnAuthorizationQueryCallback; @@ -192,6 +196,12 @@ class Client : public WebhookActor::Callback { //start custom callbacks class TdOnPingCallback; class TdOnGetMemoryStatisticsCallback; + class TdOnGetChatsCallback; + class TdOnGetChatsNearbyCallback; + class TdOnJoinChatCallback; + class TdOnReturnChatCallback; + class TdOnReturnMessagesCallback; + class TdOnGetCallbackQueryAnswerCallback; //end custom callbacks void on_get_reply_message(int64 chat_id, object_ptr reply_to_message); @@ -404,7 +414,7 @@ class Client : public WebhookActor::Callback { td::Result>> get_input_message_contents( const Query *query, td::JsonValue &&value) const; - static object_ptr get_message_send_options(bool disable_notification); + static object_ptr get_message_send_options(bool disable_notification, object_ptr &&scheduling_state); static td::Result> get_poll_options(const Query *query); @@ -421,6 +431,24 @@ class Client : public WebhookActor::Callback { static td::Result get_user_id(const Query *query, Slice field_name = Slice("user_id")); int64 extract_yet_unsent_message_query_id(int64 chat_id, int64 message_id, bool *is_reply_to_message_deleted); + + // start custom helper methods + + static td::Result> get_message_scheduling_state(const Query *query); + + template + static td::Result> get_int_array_arg(const Query *query, Slice field_name, bool optional = false); + + static int64 get_int64_arg(const Query *query, Slice field_name, int64 default_value, + int64 min_value = std::numeric_limits::min(), + int64 max_value = std::numeric_limits::max()); + static td::Result> get_report_reason(const Query *query, + Slice field_name = Slice("reason")); + + static td::Result> get_search_messages_filter( + const Query *query, Slice field_name = Slice("filter")); + + // end custom helper methods void on_message_send_succeeded(object_ptr &&message, int64 old_message_id); void on_message_send_failed(int64 chat_id, int64 old_message_id, int64 new_message_id, Status result); @@ -505,13 +533,32 @@ class Client : public WebhookActor::Callback { //custom methods Status process_get_message_info_query(PromisedQueryPtr &query); - Status process_get_participants_query(PromisedQueryPtr &query); + Status process_get_chat_members_query(PromisedQueryPtr &query); Status process_delete_messages_query(PromisedQueryPtr &query); Status process_toggle_group_invites_query(PromisedQueryPtr &query); Status process_ping_query(PromisedQueryPtr &query); Status process_get_memory_stats_query(PromisedQueryPtr &query); + //custom user methods + Status process_get_chats_query(PromisedQueryPtr &query); + Status process_get_common_chats_query(PromisedQueryPtr &query); + Status process_get_inactive_chats_query(PromisedQueryPtr &query); + Status process_get_nearby_chats_query(PromisedQueryPtr &query); + Status process_search_public_chats_query(PromisedQueryPtr &query); + Status process_set_poll_answer_query(PromisedQueryPtr &query); + Status process_join_chat_query(PromisedQueryPtr &query); + Status process_add_chat_member_query(PromisedQueryPtr &query); + Status process_report_chat_query(PromisedQueryPtr &query); + Status process_create_chat_query(PromisedQueryPtr &query); + Status process_search_messages_query(PromisedQueryPtr &query); + Status process_search_chat_messages_query(PromisedQueryPtr &query); + Status process_get_callback_query_answer_query(PromisedQueryPtr &query); + Status process_delete_chat_history_query(PromisedQueryPtr &query); + Status process_get_scheduled_messages_query(PromisedQueryPtr &query); + Status process_edit_message_scheduling_query(PromisedQueryPtr &query); + //custom auth methods + void process_auth_phone_number_query(PromisedQueryPtr &query); void process_authcode_query(PromisedQueryPtr &query); void process_2fapassword_query(PromisedQueryPtr &query); void process_register_user_query(PromisedQueryPtr &query); @@ -579,8 +626,11 @@ class Client : public WebhookActor::Callback { td::string bio; + // start custom properties bool is_verified = false; bool is_scam = false; + // end custom properties + bool have_access = false; bool can_join_groups = false; bool can_read_all_group_messages = false; @@ -617,8 +667,11 @@ class Client : public WebhookActor::Callback { bool is_supergroup = false; bool can_set_sticker_set = false; bool has_location = false; + + // start custom properties bool is_verified = false; bool is_scam = false; + // end custom properties }; static void add_supergroup(std::unordered_map &supergroups, object_ptr &&supergroup); @@ -677,9 +730,14 @@ class Client : public WebhookActor::Callback { object_ptr content; object_ptr reply_markup; + // start custom properties int32 views = 0; int32 forwards = 0; + bool is_scheduled = false; + int32 scheduled_at = 0; + // end custom properties + mutable bool is_reply_to_message_deleted = false; mutable bool is_content_changed = false; }; @@ -762,6 +820,8 @@ class Client : public WebhookActor::Callback { static int32 as_client_message_id(int64 message_id); + static int32 as_scheduled_message_id(int64 message_id); + static int64 get_supergroup_chat_id(int32 supergroup_id); static int64 get_basic_group_chat_id(int32 basic_group_id); @@ -847,7 +907,6 @@ class Client : public WebhookActor::Callback { td::string bot_token_; td::string bot_token_with_dc_; td::string bot_token_id_; - td::string phone_number_; bool is_user_; bool is_test_dc_; int64 tqueue_id_; diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index 18daacc..dc4d7b6 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -145,15 +145,17 @@ void ClientManager::user_login(PromisedQueryPtr query) { auto id = clients_.create(ClientInfo{BotStatActor(stat_.actor_id(&stat_)), user_token, td::ActorOwn()}); auto *client_info = clients_.get(id); auto stat_actor = client_info->stat_.actor_id(&client_info->stat_); - auto client_id = td::create_actor( - PSLICE() << "Client/" << user_token, actor_shared(this, id), user_token, td::to_string(phone_number), - true, query->is_test_dc(), get_tqueue_id(token_hash, query->is_test_dc()), parameters_, std::move(stat_actor)); + auto client_id = td::create_actor(PSLICE() << "Client/" << user_token, actor_shared(this, id), user_token, + true, query->is_test_dc(), get_tqueue_id(token_hash, query->is_test_dc()), + parameters_, std::move(stat_actor)); clients_.get(id)->client_ = std::move(client_id); auto id_it = token_to_id_.end(); std::tie(id_it, std::ignore) = token_to_id_.emplace(user_token, id); + send_closure(client_info->client_, &Client::send, std::move(query)); // will send 429 if the client is already closed + parameters_->shared_data_->user_db_->set(user_token_with_dc, "1"); - answer_query(td::VirtuallyJsonableString(user_token), std::move(query)); + // answer_query(td::VirtuallyJsonableString(user_token), std::move(query)); } bool ClientManager::check_flood_limits(PromisedQueryPtr &query, bool is_user_login) {