Support generating of public links for comment messages.

GitOrigin-RevId: 68d9a0260e60719f129e05d32fcbf756e93fa5d4
This commit is contained in:
levlam 2020-09-14 01:12:24 +03:00
parent ed10f1851c
commit 1cd9f5d8c9
6 changed files with 122 additions and 52 deletions

View File

@ -3681,8 +3681,9 @@ removeNotificationGroup notification_group_id:int32 max_notification_id:int32 =
//@description Returns a public HTTPS link to a message. Available only for messages in supergroups and channels with a username //@description Returns a public HTTPS link to a message. Available only for messages in supergroups and channels with a username
//@chat_id Identifier of the chat to which the message belongs //@chat_id Identifier of the chat to which the message belongs
//@message_id Identifier of the message //@message_id Identifier of the message
//@for_album Pass true if a link for a whole media album should be returned //@for_album Pass true to create a link for a whole media album
getPublicMessageLink chat_id:int53 message_id:int53 for_album:Bool = PublicMessageLink; //@for_comment Pass true to create a link to a message as a channel message comment
getPublicMessageLink chat_id:int53 message_id:int53 for_album:Bool for_comment:Bool = PublicMessageLink;
//@description Returns a private HTTPS link to a message in a chat. Available only for already sent messages in supergroups and channels. The link will work only for members of the chat //@description Returns a private HTTPS link to a message in a chat. Available only for already sent messages in supergroups and channels. The link will work only for members of the chat
//@chat_id Identifier of the chat to which the message belongs //@chat_id Identifier of the chat to which the message belongs

Binary file not shown.

View File

@ -12298,6 +12298,9 @@ std::pair<DialogId, unique_ptr<MessagesManager::Message>> MessagesManager::creat
is_active_message_reply_info(dialog_id, reply_info)) { is_active_message_reply_info(dialog_id, reply_info)) {
top_reply_message_id = message_id; top_reply_message_id = message_id;
} }
if (top_reply_message_id.is_valid() && dialog_type != DialogType::Channel) {
top_reply_message_id = MessageId();
}
bool has_forward_info = message_info.forward_header != nullptr; bool has_forward_info = message_info.forward_header != nullptr;
@ -15306,37 +15309,39 @@ void MessagesManager::get_message_force_from_server(Dialog *d, MessageId message
LOG(INFO) << "Get " << message_id << " in " << d->dialog_id << " using " << to_string(input_message); LOG(INFO) << "Get " << message_id << " in " << d->dialog_id << " using " << to_string(input_message);
auto dialog_type = d->dialog_id.get_type(); auto dialog_type = d->dialog_id.get_type();
auto m = get_message_force(d, message_id, "get_message_force_from_server"); auto m = get_message_force(d, message_id, "get_message_force_from_server");
if (m == nullptr && message_id.is_valid() && message_id.is_server()) { if (m == nullptr) {
if (d->last_new_message_id != MessageId() && message_id > d->last_new_message_id) { if (message_id.is_valid() && message_id.is_server()) {
// message will not be added to the dialog anyway if (d->last_new_message_id != MessageId() && message_id > d->last_new_message_id) {
if (dialog_type == DialogType::Channel) { // message will not be added to the dialog anyway
// so we try to force channel difference first if (dialog_type == DialogType::Channel) {
// so we try to force channel difference first
// replied message can't be older than already added original message, but pinned message can be // replied message can't be older than already added original message, but pinned message can be
LOG_CHECK(input_message == nullptr || input_message->get_id() == telegram_api::inputMessagePinned::ID) LOG_CHECK(input_message == nullptr || input_message->get_id() == telegram_api::inputMessagePinned::ID)
<< to_string(input_message) << " " << d->dialog_id << " " << message_id << " " << d->last_new_message_id << to_string(input_message) << " " << d->dialog_id << " " << message_id << " " << d->last_new_message_id
<< " " << d->last_message_id << " " << d->first_database_message_id << " " << d->last_database_message_id << " " << d->last_message_id << " " << d->first_database_message_id << " " << d->last_database_message_id
<< " " << d->pinned_message_id << " " << d->last_read_all_mentions_message_id << " " << " " << d->pinned_message_id << " " << d->last_read_all_mentions_message_id << " "
<< d->max_unavailable_message_id << " " << d->last_clear_history_message_id << " " << d->order << " " << d->max_unavailable_message_id << " " << d->last_clear_history_message_id << " " << d->order << " "
<< d->deleted_last_message_id << " " << d->max_added_message_id << " " << d->pts << " " << d->deleted_last_message_id << " " << d->max_added_message_id << " " << d->pts << " "
<< d->last_assigned_message_id << " " << d->debug_last_new_message_id << " " << d->last_assigned_message_id << " " << d->debug_last_new_message_id << " "
<< d->debug_first_database_message_id << " " << d->debug_last_database_message_id; << d->debug_first_database_message_id << " " << d->debug_last_database_message_id;
postponed_get_message_requests_[d->dialog_id].emplace_back(message_id, std::move(promise), postponed_get_message_requests_[d->dialog_id].emplace_back(message_id, std::move(promise),
std::move(input_message)); std::move(input_message));
get_channel_difference(d->dialog_id, d->pts, true, "get_message"); get_channel_difference(d->dialog_id, d->pts, true, "get_message");
} else { } else {
promise.set_value(Unit()); promise.set_value(Unit());
}
return;
} }
return;
}
if (d->deleted_message_ids.count(message_id) == 0 && dialog_type != DialogType::SecretChat) { if (d->deleted_message_ids.count(message_id) == 0 && dialog_type != DialogType::SecretChat) {
return get_message_from_server({d->dialog_id, message_id}, std::move(promise), std::move(input_message)); return get_message_from_server({d->dialog_id, message_id}, std::move(promise), std::move(input_message));
} }
} else if (m == nullptr && message_id.is_valid_scheduled() && message_id.is_scheduled_server()) { } else if (message_id.is_valid_scheduled() && message_id.is_scheduled_server()) {
if (d->deleted_scheduled_server_message_ids.count(message_id.get_scheduled_server_message_id()) == 0 && if (d->deleted_scheduled_server_message_ids.count(message_id.get_scheduled_server_message_id()) == 0 &&
dialog_type != DialogType::SecretChat && input_message == nullptr) { dialog_type != DialogType::SecretChat && input_message == nullptr) {
return get_message_from_server({d->dialog_id, message_id}, std::move(promise)); return get_message_from_server({d->dialog_id, message_id}, std::move(promise));
}
} }
} }
@ -15571,42 +15576,95 @@ bool MessagesManager::is_message_edited_recently(FullMessageId full_message_id,
} }
std::pair<string, string> MessagesManager::get_public_message_link(FullMessageId full_message_id, bool for_group, std::pair<string, string> MessagesManager::get_public_message_link(FullMessageId full_message_id, bool for_group,
Promise<Unit> &&promise) { bool &for_comment, Promise<Unit> &&promise) {
auto dialog_id = full_message_id.get_dialog_id(); auto dialog_id = full_message_id.get_dialog_id();
auto d = get_dialog_force(dialog_id); auto d = get_dialog_force(dialog_id);
if (d == nullptr) { if (d == nullptr) {
promise.set_error(Status::Error(6, "Chat not found")); promise.set_error(Status::Error(400, "Chat not found"));
return {}; return {};
} }
if (!have_input_peer(dialog_id, AccessRights::Read)) { if (!have_input_peer(dialog_id, AccessRights::Read)) {
promise.set_error(Status::Error(6, "Can't access the chat")); promise.set_error(Status::Error(400, "Can't access the chat"));
return {}; return {};
} }
if (dialog_id.get_type() != DialogType::Channel || if (dialog_id.get_type() != DialogType::Channel ||
td_->contacts_manager_->get_channel_username(dialog_id.get_channel_id()).empty()) { td_->contacts_manager_->get_channel_username(dialog_id.get_channel_id()).empty()) {
promise.set_error(Status::Error( promise.set_error(Status::Error(
6, "Public message links are available only for messages in supergroups and channel chats with a username")); 400, "Public message links are available only for messages in supergroups and channel chats with a username"));
return {}; return {};
} }
auto *m = get_message_force(d, full_message_id.get_message_id(), "get_public_message_link"); auto *m = get_message_force(d, full_message_id.get_message_id(), "get_public_message_link");
if (m == nullptr) { if (m == nullptr) {
promise.set_error(Status::Error(6, "Message not found")); promise.set_error(Status::Error(400, "Message not found"));
return {}; return {};
} }
if (m->message_id.is_yet_unsent()) { if (m->message_id.is_yet_unsent()) {
promise.set_error(Status::Error(6, "Message is yet unsent")); promise.set_error(Status::Error(400, "Message is yet unsent"));
return {}; return {};
} }
if (m->message_id.is_scheduled()) { if (m->message_id.is_scheduled()) {
promise.set_error(Status::Error(6, "Message is scheduled")); promise.set_error(Status::Error(400, "Message is scheduled"));
return {}; return {};
} }
if (!m->message_id.is_server()) { if (!m->message_id.is_server()) {
promise.set_error(Status::Error(6, "Message is local")); promise.set_error(Status::Error(400, "Message is local"));
return {}; return {};
} }
if (m->media_album_id == 0) {
for_group = true; // default is true
}
string comment_link;
if (!m->top_reply_message_id.is_valid()) {
for_comment = false;
}
if (d->deleted_message_ids.count(m->top_reply_message_id) != 0) {
for_comment = false;
}
if (for_comment) {
CHECK(dialog_id.get_type() == DialogType::Channel); // only channel messages can have top_reply_message_id
auto *top_m = get_message_force(d, m->top_reply_message_id, "get_public_message_link");
if (top_m == nullptr) {
get_message_force_from_server(d, m->top_reply_message_id, std::move(promise));
return {};
}
if (top_m->sender_user_id.is_valid() || top_m->forward_info == nullptr ||
!top_m->forward_info->sender_dialog_id.is_valid() || !top_m->forward_info->message_id.is_valid() ||
DialogId(td_->contacts_manager_->get_channel_linked_channel_id(dialog_id.get_channel_id())) !=
top_m->forward_info->sender_dialog_id) {
for_comment = false;
} else {
auto linked_dialog_id = top_m->forward_info->sender_dialog_id;
auto linked_message_id = top_m->forward_info->message_id;
auto linked_d = get_dialog(linked_dialog_id);
CHECK(linked_d != nullptr);
CHECK(linked_dialog_id.get_type() == DialogType::Channel);
if (!have_input_peer(linked_dialog_id, AccessRights::Read) ||
td_->contacts_manager_->get_channel_username(linked_dialog_id.get_channel_id()).empty() ||
linked_d->deleted_message_ids.count(linked_message_id) != 0) {
for_comment = false;
} else {
auto *linked_m = get_message_force(linked_d, linked_message_id, "get_public_message_link");
if (linked_m == nullptr) {
get_message_force_from_server(linked_d, linked_message_id, std::move(promise));
return {};
}
auto it = public_message_links_[for_group].find({linked_dialog_id, linked_message_id});
if (it == public_message_links_[for_group].end()) {
td_->create_handler<ExportChannelMessageLinkQuery>(std::move(promise))
->send(linked_dialog_id.get_channel_id(), linked_message_id, for_group, false);
return {};
}
comment_link = PSTRING() << it->second.first << (it->second.first.find('?') == string::npos ? '?' : '&')
<< "comment_id=" << m->message_id.get_server_message_id().get();
}
}
}
auto it = public_message_links_[for_group].find(full_message_id); auto it = public_message_links_[for_group].find(full_message_id);
if (it == public_message_links_[for_group].end()) { if (it == public_message_links_[for_group].end()) {
td_->create_handler<ExportChannelMessageLinkQuery>(std::move(promise)) td_->create_handler<ExportChannelMessageLinkQuery>(std::move(promise))
@ -15615,7 +15673,11 @@ std::pair<string, string> MessagesManager::get_public_message_link(FullMessageId
} }
promise.set_value(Unit()); promise.set_value(Unit());
return it->second; if (for_comment) {
return {std::move(comment_link), it->second.second};
} else {
return it->second;
}
} }
void MessagesManager::on_get_public_message_link(FullMessageId full_message_id, bool for_group, string url, void MessagesManager::on_get_public_message_link(FullMessageId full_message_id, bool for_group, string url,
@ -15628,30 +15690,30 @@ string MessagesManager::get_message_link(FullMessageId full_message_id, Promise<
auto dialog_id = full_message_id.get_dialog_id(); auto dialog_id = full_message_id.get_dialog_id();
auto d = get_dialog_force(dialog_id); auto d = get_dialog_force(dialog_id);
if (d == nullptr) { if (d == nullptr) {
promise.set_error(Status::Error(6, "Chat not found")); promise.set_error(Status::Error(400, "Chat not found"));
return {}; return {};
} }
if (!have_input_peer(dialog_id, AccessRights::Read)) { if (!have_input_peer(dialog_id, AccessRights::Read)) {
promise.set_error(Status::Error(6, "Can't access the chat")); promise.set_error(Status::Error(400, "Can't access the chat"));
return {}; return {};
} }
if (dialog_id.get_type() != DialogType::Channel) { if (dialog_id.get_type() != DialogType::Channel) {
promise.set_error( promise.set_error(
Status::Error(6, "Message links are available only for messages in supergroups and channel chats")); Status::Error(400, "Message links are available only for messages in supergroups and channel chats"));
return {}; return {};
} }
auto *m = get_message_force(d, full_message_id.get_message_id(), "get_message_link"); auto *m = get_message_force(d, full_message_id.get_message_id(), "get_message_link");
if (m == nullptr) { if (m == nullptr) {
promise.set_error(Status::Error(6, "Message not found")); promise.set_error(Status::Error(400, "Message not found"));
return {}; return {};
} }
if (m->message_id.is_scheduled()) { if (m->message_id.is_scheduled()) {
promise.set_error(Status::Error(6, "Message is scheduled")); promise.set_error(Status::Error(400, "Message is scheduled"));
return {}; return {};
} }
if (!m->message_id.is_server()) { if (!m->message_id.is_server()) {
promise.set_error(Status::Error(6, "Message is local")); promise.set_error(Status::Error(400, "Message is local"));
return {}; return {};
} }

View File

@ -562,7 +562,7 @@ class MessagesManager : public Actor {
bool is_message_edited_recently(FullMessageId full_message_id, int32 seconds); bool is_message_edited_recently(FullMessageId full_message_id, int32 seconds);
std::pair<string, string> get_public_message_link(FullMessageId full_message_id, bool for_group, std::pair<string, string> get_public_message_link(FullMessageId full_message_id, bool for_group, bool &for_comment,
Promise<Unit> &&promise); Promise<Unit> &&promise);
void on_get_public_message_link(FullMessageId full_message_id, bool for_group, string url, string html); void on_get_public_message_link(FullMessageId full_message_id, bool for_group, string url, string html);

View File

@ -1093,13 +1093,14 @@ class GetMessagesRequest : public RequestOnceActor {
class GetPublicMessageLinkRequest : public RequestActor<> { class GetPublicMessageLinkRequest : public RequestActor<> {
FullMessageId full_message_id_; FullMessageId full_message_id_;
bool for_group_; bool for_group_;
bool for_comment_;
string link_; string link_;
string html_; string html_;
void do_run(Promise<Unit> &&promise) override { void do_run(Promise<Unit> &&promise) override {
std::tie(link_, html_) = std::tie(link_, html_) =
td->messages_manager_->get_public_message_link(full_message_id_, for_group_, std::move(promise)); td->messages_manager_->get_public_message_link(full_message_id_, for_group_, for_comment_, std::move(promise));
} }
void do_send_result() override { void do_send_result() override {
@ -1107,10 +1108,13 @@ class GetPublicMessageLinkRequest : public RequestActor<> {
} }
public: public:
GetPublicMessageLinkRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int64 message_id, bool for_group) GetPublicMessageLinkRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int64 message_id, bool for_group,
bool for_comment)
: RequestActor(std::move(td), request_id) : RequestActor(std::move(td), request_id)
, full_message_id_(DialogId(dialog_id), MessageId(message_id)) , full_message_id_(DialogId(dialog_id), MessageId(message_id))
, for_group_(for_group) { , for_group_(for_group)
, for_comment_(for_comment) {
set_tries(5); // get top message + get linked channel message + get message HTML + get linked channel message link
} }
}; };
@ -5100,7 +5104,8 @@ void Td::on_request(uint64 id, const td_api::getMessages &request) {
void Td::on_request(uint64 id, const td_api::getPublicMessageLink &request) { void Td::on_request(uint64 id, const td_api::getPublicMessageLink &request) {
CHECK_IS_USER(); CHECK_IS_USER();
CREATE_REQUEST(GetPublicMessageLinkRequest, request.chat_id_, request.message_id_, request.for_album_); CREATE_REQUEST(GetPublicMessageLinkRequest, request.chat_id_, request.message_id_, request.for_album_,
request.for_comment_);
} }
void Td::on_request(uint64 id, const td_api::getMessageLink &request) { void Td::on_request(uint64 id, const td_api::getMessageLink &request) {

View File

@ -2615,10 +2615,12 @@ class CliClient final : public Actor {
string chat_id; string chat_id;
string message_id; string message_id;
string for_album; string for_album;
string for_comment;
std::tie(chat_id, args) = split(args); std::tie(chat_id, args) = split(args);
std::tie(message_id, for_album) = split(args); std::tie(message_id, args) = split(args);
std::tie(for_album, for_comment) = split(args);
send_request(td_api::make_object<td_api::getPublicMessageLink>(as_chat_id(chat_id), as_message_id(message_id), send_request(td_api::make_object<td_api::getPublicMessageLink>(as_chat_id(chat_id), as_message_id(message_id),
as_bool(for_album))); as_bool(for_album), as_bool(for_comment)));
} else if (op == "gmlink") { } else if (op == "gmlink") {
string chat_id; string chat_id;
string message_id; string message_id;