Add td_api::createChatFilter.

GitOrigin-RevId: 4c3fa89cae21b1db3643cfe7640d8ef1043b99f9
This commit is contained in:
levlam 2020-05-18 22:26:44 +03:00
parent e662e210ef
commit cc77e7e9ca
11 changed files with 283 additions and 14 deletions

View File

@ -3709,6 +3709,9 @@ setChatChatList chat_id:int53 chat_list:ChatList = Ok;
//@description Returns information about a chat filter by its identifier @chat_filter_id Chat filter identifier
getChatFilter chat_filter_id:int32 = ChatFilter;
//@description Creates new chat filter @filter The chat filter
createChatFilter filter:chatFilter = Ok;
//@description Changes the chat title. Supported only for basic groups, supergroups and channels. Requires can_change_info rights. The title will not be changed until the request to the server has been completed
//@chat_id Chat identifier @title New title of the chat; 1-128 characters

Binary file not shown.

View File

@ -143,11 +143,11 @@ void AuthManager::check_bot_token(uint64 query_id, string bot_token) {
}
if (state_ != State::WaitPhoneNumber && state_ != State::Ok) {
// TODO do not allow State::Ok
return on_query_error(query_id, Status::Error(8, "Call to checkAuthenticationBotToken unexpected"));
return on_query_error(query_id, Status::Error(400, "Call to checkAuthenticationBotToken unexpected"));
}
if (!send_code_helper_.phone_number().empty() || was_qr_code_request_) {
return on_query_error(
query_id, Status::Error(8, "Cannot set bot token after authentication beginning. You need to log out first"));
query_id, Status::Error(400, "Cannot set bot token after authentication beginning. You need to log out first"));
}
if (was_check_bot_token_ && bot_token_ != bot_token) {
return on_query_error(query_id, Status::Error(8, "Cannot change bot token. You need to log out first"));

View File

@ -20,12 +20,20 @@ class DialogFilterId {
public:
DialogFilterId() = default;
explicit DialogFilterId(int32 dialog_filter_id) : id(dialog_filter_id) {
explicit constexpr DialogFilterId(int32 dialog_filter_id) : id(dialog_filter_id) {
}
template <class T, typename = std::enable_if_t<std::is_convertible<T, int32>::value>>
DialogFilterId(T dialog_filter_id) = delete;
static constexpr DialogFilterId min() {
return DialogFilterId(static_cast<int32>(2));
}
static constexpr DialogFilterId max() {
return DialogFilterId(static_cast<int32>(255));
}
bool is_valid() const {
// don't check min() and max() for greater future flexibility
return id > 0;
}

View File

@ -48,10 +48,11 @@ InputDialogId::InputDialogId(const tl_object_ptr<telegram_api::InputPeer> &input
LOG(ERROR) << "Receive " << to_string(input_peer);
}
vector<InputDialogId> InputDialogId::get_input_dialog_ids(const vector<tl_object_ptr<telegram_api::InputPeer>> &input_peers) {
vector<InputDialogId> InputDialogId::get_input_dialog_ids(
const vector<tl_object_ptr<telegram_api::InputPeer>> &input_peers) {
vector<InputDialogId> result;
result.reserve(input_peers.size());
for (auto &input_peer:input_peers) {
for (auto &input_peer : input_peers) {
InputDialogId input_dialog_id(input_peer);
if (input_dialog_id.is_valid()) {
result.push_back(input_dialog_id);
@ -60,6 +61,32 @@ vector<InputDialogId> InputDialogId::get_input_dialog_ids(const vector<tl_object
return result;
}
vector<telegram_api::object_ptr<telegram_api::InputDialogPeer>> InputDialogId::get_input_dialog_peers(
const vector<InputDialogId> &input_dialog_ids) {
vector<telegram_api::object_ptr<telegram_api::InputDialogPeer>> result;
result.reserve(input_dialog_ids.size());
for (auto input_dialog_id : input_dialog_ids) {
auto input_peer = input_dialog_id.get_input_peer();
if (input_peer != nullptr) {
result.push_back(telegram_api::make_object<telegram_api::inputDialogPeer>(std::move(input_peer)));
}
}
return result;
}
vector<telegram_api::object_ptr<telegram_api::InputPeer>> InputDialogId::get_input_peers(
const vector<InputDialogId> &input_dialog_ids) {
vector<telegram_api::object_ptr<telegram_api::InputPeer>> result;
result.reserve(input_dialog_ids.size());
for (auto input_dialog_id : input_dialog_ids) {
auto input_peer = input_dialog_id.get_input_peer();
if (input_peer != nullptr) {
result.push_back(std::move(input_peer));
}
}
return result;
}
tl_object_ptr<telegram_api::InputPeer> InputDialogId::get_input_peer() const {
switch (dialog_id.get_type()) {
case DialogType::User:

View File

@ -21,14 +21,19 @@ class InputDialogId {
public:
InputDialogId() = default;
explicit InputDialogId(DialogId dialog_id): dialog_id(dialog_id) {
CHECK(dialog_id.get_type() == DialogType::SecretChat);
explicit InputDialogId(DialogId dialog_id) : dialog_id(dialog_id) {
}
explicit InputDialogId(const tl_object_ptr<telegram_api::InputPeer> &input_peer);
static vector<InputDialogId> get_input_dialog_ids(const vector<tl_object_ptr<telegram_api::InputPeer>> &input_peers);
static vector<telegram_api::object_ptr<telegram_api::InputDialogPeer>> get_input_dialog_peers(
const vector<InputDialogId> &input_dialog_ids);
static vector<telegram_api::object_ptr<telegram_api::InputPeer>> get_input_peers(
const vector<InputDialogId> &input_dialog_ids);
bool operator==(const InputDialogId &other) const {
return dialog_id == other.dialog_id && access_hash == other.access_hash;
}

View File

@ -218,13 +218,10 @@ class GetDialogsQuery : public Td::ResultHandler {
void send(vector<InputDialogId> input_dialog_ids) {
LOG(INFO) << "Send GetDialogsQuery to get " << input_dialog_ids;
CHECK(!input_dialog_ids.empty());
CHECK(input_dialog_ids.size() <= 100);
auto input_dialog_peers = transform(
input_dialog_ids, [](InputDialogId input_dialog_id) -> telegram_api::object_ptr<telegram_api::InputDialogPeer> {
auto input_peer = input_dialog_id.get_input_peer();
CHECK(input_peer != nullptr);
return telegram_api::make_object<telegram_api::inputDialogPeer>(std::move(input_peer));
});
auto input_dialog_peers = InputDialogId::get_input_dialog_peers(input_dialog_ids);
CHECK(input_dialog_peers.size() == input_dialog_ids.size());
send_query(G()->net_query_creator().create(telegram_api::messages_getPeerDialogs(std::move(input_dialog_peers))));
}
@ -428,6 +425,37 @@ class GetScheduledMessagesQuery : public Td::ResultHandler {
}
};
class UpdateDialogFilterQuery : public Td::ResultHandler {
Promise<Unit> promise_;
public:
explicit UpdateDialogFilterQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(DialogFilterId dialog_filter_id, tl_object_ptr<telegram_api::dialogFilter> filter) {
int32 flags = 0;
if (filter != nullptr) {
flags |= telegram_api::messages_updateDialogFilter::FILTER_MASK;
}
send_query(G()->net_query_creator().create(
telegram_api::messages_updateDialogFilter(flags, dialog_filter_id.get(), std::move(filter))));
}
void on_result(uint64 id, BufferSlice packet) override {
auto result_ptr = fetch_result<telegram_api::messages_updateDialogFilter>(packet);
if (result_ptr.is_error()) {
return on_error(id, result_ptr.move_as_error());
}
LOG(INFO) << "Receive result for UpdateDialogFilterQuery: " << result_ptr.ok();
promise_.set_value(Unit());
}
void on_error(uint64 id, Status status) override {
promise_.set_error(std::move(status));
}
};
class UpdateDialogPinnedMessageQuery : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
@ -4775,6 +4803,40 @@ struct MessagesManager::DialogFilter {
template <class ParserT>
void parse(ParserT &parser);
telegram_api::object_ptr<telegram_api::dialogFilter> get_input_dialog_filter() const {
int32 flags = telegram_api::dialogFilter::EMOTICON_MASK;
if (exclude_muted) {
flags |= telegram_api::dialogFilter::EXCLUDE_MUTED_MASK;
}
if (exclude_read) {
flags |= telegram_api::dialogFilter::EXCLUDE_READ_MASK;
}
if (exclude_archived) {
flags |= telegram_api::dialogFilter::EXCLUDE_ARCHIVED_MASK;
}
if (include_contacts) {
flags |= telegram_api::dialogFilter::CONTACTS_MASK;
}
if (include_non_contacts) {
flags |= telegram_api::dialogFilter::NON_CONTACTS_MASK;
}
if (include_bots) {
flags |= telegram_api::dialogFilter::BOTS_MASK;
}
if (include_groups) {
flags |= telegram_api::dialogFilter::GROUPS_MASK;
}
if (include_channels) {
flags |= telegram_api::dialogFilter::BROADCASTS_MASK;
}
return telegram_api::make_object<telegram_api::dialogFilter>(
flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
false /*ignored*/, false /*ignored*/, false /*ignored*/, dialog_filter_id.get(), title, emoji,
InputDialogId::get_input_peers(pinned_dialog_ids), InputDialogId::get_input_peers(included_dialog_ids),
InputDialogId::get_input_peers(excluded_dialog_ids));
}
friend bool operator==(const DialogFilter &lhs, const DialogFilter &rhs) {
return lhs.dialog_filter_id == rhs.dialog_filter_id && lhs.title == rhs.title && lhs.emoji == rhs.emoji &&
lhs.pinned_dialog_ids == rhs.pinned_dialog_ids && lhs.included_dialog_ids == rhs.included_dialog_ids &&
@ -13518,7 +13580,7 @@ void MessagesManager::load_dialogs(vector<DialogId> dialog_ids, Promise<Unit> &&
bool MessagesManager::load_dialog(DialogId dialog_id, int left_tries, Promise<Unit> &&promise) {
if (!dialog_id.is_valid()) {
promise.set_error(Status::Error(6, "Invalid chat identifier"));
promise.set_error(Status::Error(6, "Invalid chat identifier specified"));
return false;
}
@ -13578,6 +13640,10 @@ bool MessagesManager::load_dialog(DialogId dialog_id, int left_tries, Promise<Un
}
void MessagesManager::load_dialog_filter(DialogFilterId dialog_filter_id, bool force, Promise<Unit> &&promise) {
if (!dialog_filter_id.is_valid()) {
return promise.set_error(Status::Error(400, "Invalid chat filter identifier specified"));
}
auto filter = get_dialog_filter(dialog_filter_id);
if (filter == nullptr) {
return promise.set_value(Unit());
@ -13968,6 +14034,8 @@ void MessagesManager::on_get_dialog_filters(Result<vector<tl_object_ptr<telegram
dialog_filter->include_bots = (flags & telegram_api::dialogFilter::BOTS_MASK) != 0;
dialog_filter->include_groups = (flags & telegram_api::dialogFilter::GROUPS_MASK) != 0;
dialog_filter->include_channels = (flags & telegram_api::dialogFilter::BROADCASTS_MASK) != 0;
// TODO add secret chats to the filter
dialog_filters.push_back(std::move(dialog_filter));
}
@ -14896,6 +14964,122 @@ td_api::object_ptr<td_api::messageLinkInfo> MessagesManager::get_message_link_in
return td_api::make_object<td_api::messageLinkInfo>(is_public, dialog_id.get(), std::move(message), for_album);
}
Result<unique_ptr<MessagesManager::DialogFilter>> MessagesManager::create_dialog_filter(
td_api::object_ptr<td_api::chatFilter> filter) {
CHECK(filter != nullptr);
for (auto chat_ids : {&filter->pinned_chat_ids_, &filter->excluded_chat_ids_, &filter->included_chat_ids_}) {
for (auto chat_id : *chat_ids) {
DialogId dialog_id(chat_id);
if (!dialog_id.is_valid()) {
return Status::Error(400, "Invalid chat identifier specified");
}
const Dialog *d = get_dialog_force(dialog_id);
if (d == nullptr) {
return Status::Error(400, "Chat not found");
}
if (!have_input_peer(dialog_id, AccessRights::Read)) {
return Status::Error(6, "Can't access the chat");
}
if (d->order == DEFAULT_ORDER) {
return Status::Error(400, "Chat is not in the chat list");
}
}
}
DialogFilterId dialog_filter_id;
do {
auto min_id = static_cast<int>(DialogFilterId::min().get());
auto max_id = static_cast<int>(DialogFilterId::max().get());
dialog_filter_id = DialogFilterId(static_cast<int32>(Random::fast(min_id, max_id)));
} while (get_dialog_filter(dialog_filter_id) != nullptr);
auto dialog_filter = make_unique<DialogFilter>();
dialog_filter->dialog_filter_id = dialog_filter_id;
std::unordered_set<int64> added_dialog_ids;
auto add_chats = [this, &added_dialog_ids](vector<InputDialogId> &input_dialog_ids, const vector<int64> &chat_ids) {
for (auto &chat_id : chat_ids) {
if (!added_dialog_ids.insert(chat_id).second) {
// do not allow duplicate chat_ids
continue;
}
auto dialog_id = DialogId(chat_id);
auto input_peer = get_input_peer(dialog_id, AccessRights::Read);
if (input_peer == nullptr || input_peer->get_id() == telegram_api::inputPeerSelf::ID) {
input_dialog_ids.push_back(InputDialogId(dialog_id));
} else {
input_dialog_ids.push_back(InputDialogId(input_peer));
}
}
};
add_chats(dialog_filter->pinned_dialog_ids, filter->pinned_chat_ids_);
add_chats(dialog_filter->included_dialog_ids, filter->included_chat_ids_);
add_chats(dialog_filter->excluded_dialog_ids, filter->excluded_chat_ids_);
if (dialog_filter->excluded_dialog_ids.size() > MAX_INCLUDED_FILTER_DIALOGS) {
return Status::Error(400, "Too much excluded chats");
}
if (dialog_filter->included_dialog_ids.size() > MAX_INCLUDED_FILTER_DIALOGS) {
return Status::Error(400, "Too much included chats");
}
if (dialog_filter->pinned_dialog_ids.size() + dialog_filter->included_dialog_ids.size() >
MAX_INCLUDED_FILTER_DIALOGS) {
return Status::Error(400, "Too much pinned chats");
}
dialog_filter->title = std::move(filter->title_);
dialog_filter->emoji = std::move(filter->emoji_);
dialog_filter->exclude_muted = filter->exclude_muted_;
dialog_filter->exclude_read = filter->exclude_read_;
dialog_filter->exclude_archived = filter->exclude_archived_;
dialog_filter->include_contacts = filter->include_contacts_;
dialog_filter->include_non_contacts = filter->include_non_contacts_;
dialog_filter->include_bots = filter->include_bots_;
dialog_filter->include_groups = filter->include_groups_;
dialog_filter->include_channels = filter->include_channels_;
return std::move(dialog_filter);
}
void MessagesManager::create_dialog_filter(td_api::object_ptr<td_api::chatFilter> filter, Promise<Unit> &&promise) {
if (dialog_filters_.size() >= MAX_DIALOG_FILTERS) {
return promise.set_error(Status::Error(400, "Maximum number of chat folders exceeded"));
}
auto r_dialog_filter = create_dialog_filter(std::move(filter));
if (r_dialog_filter.is_error()) {
return promise.set_error(r_dialog_filter.move_as_error());
}
auto dialog_filter = r_dialog_filter.move_as_ok();
CHECK(dialog_filter != nullptr);
auto dialog_filter_id = dialog_filter->dialog_filter_id;
auto input_dialog_filter = dialog_filter->get_input_dialog_filter();
// TODO logevent
// TODO add dialog filter locally
// TODO SequenceDispatcher
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), dialog_filter = std::move(dialog_filter),
promise = std::move(promise)](Result<Unit> result) mutable {
send_closure(actor_id, &MessagesManager::on_create_dialog_filter, std::move(dialog_filter),
result.is_error() ? result.move_as_error() : Status::OK(), std::move(promise));
});
td_->create_handler<UpdateDialogFilterQuery>(std::move(query_promise))
->send(dialog_filter_id, std::move(input_dialog_filter));
}
void MessagesManager::on_create_dialog_filter(unique_ptr<DialogFilter> dialog_filter, Status result,
Promise<Unit> &&promise) {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
// TODO update all changed chat lists and their unread counts
dialog_filters_.push_back(std::move(dialog_filter));
send_update_chat_filters(false);
promise.set_value(Unit());
}
Status MessagesManager::delete_dialog_reply_markup(DialogId dialog_id, MessageId message_id) {
if (td_->auth_manager_->is_bot()) {
return Status::Error(6, "Bots can't delete chat reply markup");

View File

@ -551,6 +551,8 @@ class MessagesManager : public Actor {
td_api::object_ptr<td_api::messageLinkInfo> get_message_link_info_object(const MessageLinkInfo &info) const;
void create_dialog_filter(td_api::object_ptr<td_api::chatFilter> filter, Promise<Unit> &&promise);
Status delete_dialog_reply_markup(DialogId dialog_id, MessageId message_id) TD_WARN_UNUSED_RESULT;
Status set_dialog_draft_message(DialogId dialog_id,
@ -1507,6 +1509,8 @@ class MessagesManager : public Actor {
static constexpr int64 SPONSORED_DIALOG_ORDER = static_cast<int64>(2147483647) << 32;
static constexpr int32 MIN_PINNED_DIALOG_DATE = 2147000000; // some big date
static constexpr int32 MAX_PRIVATE_MESSAGE_TTL = 60; // server side limit
static constexpr int32 MAX_DIALOG_FILTERS = 10; // server side limit
static constexpr int32 MAX_INCLUDED_FILTER_DIALOGS = 100; // server side limit
static constexpr int32 DIALOG_FILTERS_CACHE_TIME = 86400;
static constexpr int32 UPDATE_CHANNEL_TO_LONG_FLAG_HAS_PTS = 1 << 0;
@ -2200,6 +2204,10 @@ class MessagesManager : public Actor {
void update_dialogs_hints(const Dialog *d);
void update_dialogs_hints_rating(const Dialog *d);
Result<unique_ptr<DialogFilter>> create_dialog_filter(td_api::object_ptr<td_api::chatFilter> filter);
void on_create_dialog_filter(unique_ptr<DialogFilter> dialog_filter, Status result, Promise<Unit> &&promise);
DialogFilter *get_dialog_filter(DialogFilterId dialog_filter_id);
const DialogFilter *get_dialog_filter(DialogFilterId dialog_filter_id) const;

View File

@ -5877,6 +5877,17 @@ void Td::on_request(uint64 id, const td_api::getChatFilter &request) {
CREATE_REQUEST(GetChatFilterRequest, request.chat_filter_id_);
}
void Td::on_request(uint64 id, td_api::createChatFilter &request) {
CHECK_IS_USER();
if (request.filter_ == nullptr) {
return send_error_raw(id, 400, "Chat filter must be non-empty");
}
CLEAN_INPUT_STRING(request.filter_->title_);
CLEAN_INPUT_STRING(request.filter_->emoji_);
CREATE_OK_REQUEST_PROMISE();
messages_manager_->create_dialog_filter(std::move(request.filter_), std::move(promise));
}
void Td::on_request(uint64 id, td_api::setChatTitle &request) {
CLEAN_INPUT_STRING(request.title_);
CREATE_OK_REQUEST_PROMISE();

View File

@ -677,6 +677,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::getChatFilter &request);
void on_request(uint64 id, td_api::createChatFilter &request);
void on_request(uint64 id, td_api::setChatTitle &request);
void on_request(uint64 id, const td_api::setChatPhoto &request);

View File

@ -1079,6 +1079,25 @@ class CliClient final : public Actor {
return nullptr;
}
td_api::object_ptr<td_api::chatFilter> as_chat_filter(string filter) const {
string title;
string pinned_chat_ids;
string included_chat_ids;
string excluded_chat_ids;
std::tie(title, filter) = split(filter);
std::tie(pinned_chat_ids, filter) = split(filter);
std::tie(included_chat_ids, filter) = split(filter);
std::tie(excluded_chat_ids, filter) = split(filter);
auto rand_bool = [] {
return Random::fast(0, 1) == 1;
};
return td_api::make_object<td_api::chatFilter>(
title, string(), as_chat_ids(pinned_chat_ids), as_chat_ids(included_chat_ids), as_chat_ids(excluded_chat_ids),
rand_bool(), rand_bool(), rand_bool(), rand_bool(), rand_bool(), rand_bool(), rand_bool(), rand_bool());
}
static td_api::object_ptr<td_api::TopChatCategory> get_top_chat_category(MutableSlice category) {
category = trim(category);
to_lower_inplace(category);
@ -3487,6 +3506,8 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::setChatChatList>(as_chat_id(chat_id), as_chat_list(op)));
} else if (op == "gcf") {
send_request(td_api::make_object<td_api::getChatFilter>(as_chat_filter_id(args)));
} else if (op == "ccf") {
send_request(td_api::make_object<td_api::createChatFilter>(as_chat_filter(args)));
} else if (op == "sct") {
string chat_id;
string title;