Support forum topic creation.

This commit is contained in:
levlam 2022-10-25 16:10:15 +03:00
parent 83a2a786ef
commit eadf411679
9 changed files with 221 additions and 0 deletions

View File

@ -5291,6 +5291,10 @@ editInlineMessageReplyMarkup inline_message_id:string reply_markup:ReplyMarkup =
editMessageSchedulingState chat_id:int53 message_id:int53 scheduling_state:MessageSchedulingState = Ok;
//@description Creates a topic in a forum supergroup chat; requires can_manage_topics rights in the supergroup @chat_id Identifier of the chat @title Title of the topic @icon Icon of the topic. Icon color must be one of 0x6FB9F0, 0xFFD67E, 0xCB86DB, 0x8EEE98, 0xFF93B2, or 0xFB6F5F. Icon custom emoji can be added only by Telegram Premium users
createForumTopic chat_id:int53 title:string icon:forumTopicIcon = ForumTopicInfo;
//@description Returns information about a emoji reaction. Returns a 404 error if the reaction is not found @emoji Text representation of the reaction
getEmojiReaction emoji:string = EmojiReaction;

View File

@ -35,6 +35,17 @@ class ForumTopicInfo {
explicit ForumTopicInfo(const tl_object_ptr<telegram_api::ForumTopic> &forum_topic_ptr);
ForumTopicInfo(MessageId top_thread_message_id, string title, ForumTopicIcon icon, int32 creation_date,
DialogId creator_dialog_id, bool is_outgoing, bool is_closed)
: top_thread_message_id_(top_thread_message_id)
, title_(std::move(title))
, icon_(std::move(icon))
, creation_date_(creation_date)
, creator_dialog_id_(creator_dialog_id)
, is_outgoing_(is_outgoing)
, is_closed_(is_closed) {
}
bool is_empty() const {
return !top_thread_message_id_.is_valid();
}

View File

@ -6,10 +6,92 @@
//
#include "td/telegram/ForumTopicManager.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/CustomEmojiId.h"
#include "td/telegram/Global.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/misc.h"
#include "td/telegram/Td.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UpdatesManager.h"
#include "td/utils/buffer.h"
#include "td/utils/Random.h"
namespace td {
class CreateForumTopicQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::forumTopicInfo>> promise_;
ChannelId channel_id_;
DialogId creator_dialog_id_;
int64 random_id_;
public:
explicit CreateForumTopicQuery(Promise<td_api::object_ptr<td_api::forumTopicInfo>> &&promise)
: promise_(std::move(promise)) {
}
void send(ChannelId channel_id, const string &title, int32 icon_color, CustomEmojiId icon_custom_emoji_id) {
channel_id_ = channel_id;
creator_dialog_id_ = DialogId(td_->contacts_manager_->get_my_id());
int32 flags = 0;
if (icon_color != -1) {
flags |= telegram_api::channels_createForumTopic::ICON_COLOR_MASK;
}
if (icon_custom_emoji_id.is_valid()) {
flags |= telegram_api::channels_createForumTopic::ICON_EMOJI_ID_MASK;
}
do {
random_id_ = Random::secure_int64();
} while (random_id_ == 0);
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
CHECK(input_channel != nullptr);
send_query(G()->net_query_creator().create(
telegram_api::channels_createForumTopic(flags, std::move(input_channel), title, icon_color,
icon_custom_emoji_id.get(), random_id_, nullptr),
{{channel_id}}));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::channels_createForumTopic>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(INFO) << "Receive result for CreateForumTopicQuery: " << to_string(ptr);
auto message = UpdatesManager::get_message_by_random_id(ptr.get(), DialogId(channel_id_), random_id_);
if (message == nullptr || message->get_id() != telegram_api::messageService::ID) {
LOG(ERROR) << "Receive invalid result for CreateForumTopicQuery: " << to_string(ptr);
return promise_.set_error(Status::Error(400, "Invalid result received"));
}
auto service_message = static_cast<const telegram_api::messageService *>(message);
if (service_message->action_->get_id() != telegram_api::messageActionTopicCreate::ID) {
LOG(ERROR) << "Receive invalid result for CreateForumTopicQuery: " << to_string(ptr);
return promise_.set_error(Status::Error(400, "Invalid result received"));
}
auto action = static_cast<const telegram_api::messageActionTopicCreate *>(service_message->action_.get());
ForumTopicInfo forum_topic_info(MessageId(ServerMessageId(service_message->id_)), action->title_,
ForumTopicIcon(action->icon_color_, action->icon_emoji_id_), service_message->date_,
creator_dialog_id_, true, false);
td_->updates_manager_->on_get_updates(
std::move(ptr), PromiseCreator::lambda([forum_topic_info = std::move(forum_topic_info),
promise = std::move(promise_)](Unit result) mutable {
send_closure(G()->forum_topic_manager(), &ForumTopicManager::on_forum_topic_created,
std::move(forum_topic_info), std::move(promise));
}));
}
void on_error(Status status) final {
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "CreateForumTopicQuery");
promise_.set_error(std::move(status));
}
};
ForumTopicManager::ForumTopicManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
}
@ -19,4 +101,51 @@ void ForumTopicManager::tear_down() {
parent_.reset();
}
void ForumTopicManager::create_forum_topic(DialogId dialog_id, string &&title,
td_api::object_ptr<td_api::forumTopicIcon> &&icon,
Promise<td_api::object_ptr<td_api::forumTopicInfo>> &&promise) {
TRY_STATUS_PROMISE(promise, is_forum(dialog_id));
auto channel_id = dialog_id.get_channel_id();
if (!td_->contacts_manager_->get_channel_permissions(channel_id).can_create_topics()) {
return promise.set_error(Status::Error(400, "Not enough rights to create a topic"));
}
auto new_title = clean_name(std::move(title), MAX_FORUM_TOPIC_TITLE_LENGTH);
if (new_title.empty()) {
return promise.set_error(Status::Error(400, "Title must be non-empty"));
}
int32 icon_color = -1;
CustomEmojiId icon_custom_emoji_id;
if (icon != nullptr) {
icon_color = icon->color_;
if (icon_color < 0 || icon_color > 0xFFFFFF) {
return promise.set_error(Status::Error(400, "Invalid icon color specified"));
}
icon_custom_emoji_id = CustomEmojiId(icon->custom_emoji_id_);
}
td_->create_handler<CreateForumTopicQuery>(std::move(promise))
->send(channel_id, new_title, icon_color, icon_custom_emoji_id);
}
void ForumTopicManager::on_forum_topic_created(ForumTopicInfo &&forum_topic_info,
Promise<td_api::object_ptr<td_api::forumTopicInfo>> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
promise.set_value(forum_topic_info.get_forum_topic_info_object(td_));
}
Status ForumTopicManager::is_forum(DialogId dialog_id) {
if (!td_->messages_manager_->have_dialog_force(dialog_id, "ForumTopicManager::is_forum")) {
return Status::Error(400, "Chat not found");
}
if (dialog_id.get_type() != DialogType::Channel ||
!td_->contacts_manager_->is_forum_channel(dialog_id.get_channel_id())) {
return Status::Error(400, "The chat is not a forum");
}
return Status::OK();
}
} // namespace td

View File

@ -6,6 +6,10 @@
//
#pragma once
#include "td/telegram/DialogId.h"
#include "td/telegram/ForumTopicInfo.h"
#include "td/telegram/td_api.h"
#include "td/actor/actor.h"
#include "td/utils/common.h"
@ -24,9 +28,19 @@ class ForumTopicManager final : public Actor {
ForumTopicManager &operator=(ForumTopicManager &&) = delete;
~ForumTopicManager() final;
void create_forum_topic(DialogId dialog_id, string &&title, td_api::object_ptr<td_api::forumTopicIcon> &&icon,
Promise<td_api::object_ptr<td_api::forumTopicInfo>> &&promise);
void on_forum_topic_created(ForumTopicInfo &&forum_topic_info,
Promise<td_api::object_ptr<td_api::forumTopicInfo>> &&promise);
private:
static constexpr size_t MAX_FORUM_TOPIC_TITLE_LENGTH = 128; // server side limit for forum topic title
void tear_down() final;
Status is_forum(DialogId dialog_id);
Td *td_;
ActorShared<> parent_;
};

View File

@ -5509,6 +5509,14 @@ void Td::on_request(uint64 id, td_api::editMessageSchedulingState &request) {
std::move(request.scheduling_state_), std::move(promise));
}
void Td::on_request(uint64 id, td_api::createForumTopic &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.title_);
CREATE_REQUEST_PROMISE();
forum_topic_manager_->create_forum_topic(DialogId(request.chat_id_), std::move(request.title_),
std::move(request.icon_), std::move(promise));
}
void Td::on_request(uint64 id, td_api::setGameScore &request) {
CHECK_IS_BOT();
CREATE_REQUEST_PROMISE();

View File

@ -730,6 +730,8 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::editMessageSchedulingState &request);
void on_request(uint64 id, td_api::createForumTopic &request);
void on_request(uint64 id, td_api::setGameScore &request);
void on_request(uint64 id, td_api::setInlineGameScore &request);

View File

@ -1155,6 +1155,49 @@ FlatHashSet<int64> UpdatesManager::get_sent_messages_random_ids(const telegram_a
return random_ids;
}
const telegram_api::Message *UpdatesManager::get_message_by_random_id(const telegram_api::Updates *updates_ptr,
DialogId dialog_id, int64 random_id) {
auto updates = get_updates(updates_ptr);
if (updates == nullptr) {
return nullptr;
}
int32 message_id = 0;
for (auto &update : *updates) {
if (update->get_id() == telegram_api::updateMessageID::ID) {
auto update_message_id = static_cast<const telegram_api::updateMessageID *>(update.get());
if (update_message_id->random_id_ == random_id) {
if (message_id != 0 || update_message_id->id_ == 0) {
return nullptr;
}
message_id = update_message_id->id_;
}
}
}
if (message_id == 0) {
return nullptr;
}
const telegram_api::Message *result = nullptr;
FullMessageId full_message_id(dialog_id, MessageId(ServerMessageId(message_id)));
for (auto &update : *updates) {
auto constructor_id = update->get_id();
const tl_object_ptr<telegram_api::Message> *message = nullptr;
if (constructor_id == telegram_api::updateNewMessage::ID) {
message = &static_cast<const telegram_api::updateNewMessage *>(update.get())->message_;
} else if (constructor_id == telegram_api::updateNewChannelMessage::ID) {
message = &static_cast<const telegram_api::updateNewChannelMessage *>(update.get())->message_;
}
if (message != nullptr && MessagesManager::get_full_message_id(*message, false) == full_message_id) {
if (result != nullptr) {
return nullptr;
}
result = message->get();
}
}
return result;
}
vector<const tl_object_ptr<telegram_api::Message> *> UpdatesManager::get_new_messages(
const telegram_api::Updates *updates_ptr) {
vector<const tl_object_ptr<telegram_api::Message> *> messages;

View File

@ -103,6 +103,9 @@ class UpdatesManager final : public Actor {
static FlatHashSet<int64> get_sent_messages_random_ids(const telegram_api::Updates *updates_ptr);
static const telegram_api::Message *get_message_by_random_id(const telegram_api::Updates *updates_ptr,
DialogId dialog_id, int64 random_id);
static vector<const tl_object_ptr<telegram_api::Message> *> get_new_messages(
const telegram_api::Updates *updates_ptr);

View File

@ -3842,6 +3842,13 @@ class CliClient final : public Actor {
get_args(args, chat_id, message_id, date);
send_request(td_api::make_object<td_api::editMessageSchedulingState>(chat_id, message_id,
as_message_scheduling_state(date)));
} else if (op == "cft") {
ChatId chat_id;
string title;
int32 icon_color;
get_args(args, chat_id, title, icon_color);
send_request(td_api::make_object<td_api::createForumTopic>(
chat_id, title, td_api::make_object<td_api::forumTopicIcon>(icon_color, 0)));
} else if (op == "gallm") {
send_request(td_api::make_object<td_api::getActiveLiveLocationMessages>());
} else if (op == "sbsm") {