Make universal offline getMessageLink method.

GitOrigin-RevId: 523db9044cfb2d41076ac98974d4a00f0740e2a6
This commit is contained in:
levlam 2020-09-20 22:07:27 +03:00
parent 8f4e9b2ed4
commit 2afbf38c33
7 changed files with 60 additions and 205 deletions

View File

@ -2732,8 +2732,8 @@ chatReportReasonUnrelatedLocation = ChatReportReason;
chatReportReasonCustom text:string = ChatReportReason; chatReportReasonCustom text:string = ChatReportReason;
//@description Contains a public HTTPS link to a message in a supergroup or channel with a username @link Message link @html HTML-code for embedding the message; may be empty if unknown //@description Contains an HTTPS link to a message in a supergroup or channel @link Message link @is_public True, if the link will work for non-members of the chat
publicMessageLink link:string html:string = PublicMessageLink; messageLink link:string is_public:Bool = MessageLink;
//@description Contains information about a link to a message in a chat //@description Contains information about a link to a message in a chat
//@is_public True, if the link is a public link for a message in a chat //@is_public True, if the link is a public link for a message in a chat
@ -3688,19 +3688,12 @@ removeNotification notification_group_id:int32 notification_id:int32 = Ok;
removeNotificationGroup notification_group_id:int32 max_notification_id:int32 = Ok; removeNotificationGroup notification_group_id:int32 max_notification_id:int32 = Ok;
//@description Returns a public HTTPS link to a message. Available only for messages in supergroups and channels with a username //@description Returns an HTTPS link to a message in a chat. Available only for already sent messages in supergroups and channels. This is an offline request
//@chat_id Identifier of the chat to which the message belongs
//@message_id Identifier of the message
//@for_album Pass true to create a link for the whole media album
//@for_comment Pass true to create a link to the message as a channel post comment, or from a message thread. The channel or the discussion supergroup must have a username
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
//@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 to create a link for the whole media album //@for_album Pass true to create a link for the whole media album
//@for_comment Pass true to create a link to the message as a channel post comment, or from a message thread //@for_comment Pass true to create a link to the message as a channel post comment, or from a message thread
getMessageLink chat_id:int53 message_id:int53 for_album:Bool for_comment:Bool = HttpUrl; getMessageLink chat_id:int53 message_id:int53 for_album:Bool for_comment:Bool = MessageLink;
//@description Returns an HTML code for embedding the message. Available only for messages in supergroups and channels with a username //@description Returns an HTML code for embedding the 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

Binary file not shown.

View File

@ -16039,40 +16039,32 @@ bool MessagesManager::is_message_edited_recently(FullMessageId full_message_id,
return m->edit_date >= G()->unix_time() - seconds; return m->edit_date >= G()->unix_time() - seconds;
} }
std::pair<string, string> MessagesManager::get_public_message_link(FullMessageId full_message_id, bool for_group, Result<std::pair<string, bool>> MessagesManager::get_message_link(FullMessageId full_message_id, bool for_group,
bool for_comment, Promise<Unit> &&promise) { bool for_comment) {
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(400, "Chat not found")); return Status::Error(400, "Chat not found");
return {};
} }
if (!have_input_peer(dialog_id, AccessRights::Read)) { if (!have_input_peer(dialog_id, AccessRights::Read)) {
promise.set_error(Status::Error(400, "Can't access the chat")); return Status::Error(400, "Can't access the chat");
return {};
} }
if (dialog_id.get_type() != DialogType::Channel) { if (dialog_id.get_type() != DialogType::Channel) {
promise.set_error( return Status::Error(400, "Public message links are available only for messages in supergroups and channel chats");
Status::Error(400, "Public message links are available only for messages in supergroups and channel chats"));
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_message_link");
if (m == nullptr) { if (m == nullptr) {
promise.set_error(Status::Error(400, "Message not found")); return Status::Error(400, "Message not found");
return {};
} }
if (m->message_id.is_yet_unsent()) { if (m->message_id.is_yet_unsent()) {
promise.set_error(Status::Error(400, "Message is yet unsent")); return Status::Error(400, "Message is yet unsent");
return {};
} }
if (m->message_id.is_scheduled()) { if (m->message_id.is_scheduled()) {
promise.set_error(Status::Error(400, "Message is scheduled")); return Status::Error(400, "Message is scheduled");
return {};
} }
if (!m->message_id.is_server()) { if (!m->message_id.is_server()) {
promise.set_error(Status::Error(400, "Message is local")); return Status::Error(400, "Message is local");
return {};
} }
if (m->media_album_id == 0) { if (m->media_album_id == 0) {
@ -16085,14 +16077,17 @@ std::pair<string, string> MessagesManager::get_public_message_link(FullMessageId
if (d->deleted_message_ids.count(m->top_reply_message_id) != 0) { if (d->deleted_message_ids.count(m->top_reply_message_id) != 0) {
for_comment = false; for_comment = false;
} }
string comment_link; if (for_comment && is_broadcast_channel(dialog_id)) {
for_comment = false;
}
td_->create_handler<ExportChannelMessageLinkQuery>(Promise<Unit>())
->send(dialog_id.get_channel_id(), m->message_id, for_group, true);
auto t_me = G()->shared_config().get_option_string("t_me_url", "https://t.me/");
if (for_comment) { if (for_comment) {
auto *top_m = get_message_force(d, m->top_reply_message_id, "get_public_message_link"); auto *top_m = get_message_force(d, m->top_reply_message_id, "get_public_message_link");
if (top_m == nullptr) { if (top_m != nullptr && !top_m->sender_user_id.is_valid() && top_m->forward_info != 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() && 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())) == DialogId(td_->contacts_manager_->get_channel_linked_channel_id(dialog_id.get_channel_id())) ==
top_m->forward_info->sender_dialog_id) { top_m->forward_info->sender_dialog_id) {
@ -16101,103 +16096,26 @@ std::pair<string, string> MessagesManager::get_public_message_link(FullMessageId
auto linked_d = get_dialog(linked_dialog_id); auto linked_d = get_dialog(linked_dialog_id);
CHECK(linked_d != nullptr); CHECK(linked_d != nullptr);
CHECK(linked_dialog_id.get_type() == DialogType::Channel); CHECK(linked_dialog_id.get_type() == DialogType::Channel);
auto channel_username = td_->contacts_manager_->get_channel_username(linked_dialog_id.get_channel_id());
if (linked_message_id.is_server() && have_input_peer(linked_dialog_id, AccessRights::Read) &&
!channel_username.empty() && linked_d->deleted_message_ids.count(linked_message_id) == 0) {
auto *linked_m = get_message_force(linked_d, linked_message_id, "get_public_message_link"); auto *linked_m = get_message_force(linked_d, linked_message_id, "get_public_message_link");
if (linked_m == nullptr) { auto channel_username = td_->contacts_manager_->get_channel_username(linked_dialog_id.get_channel_id());
get_message_force_from_server(linked_d, linked_message_id, std::move(promise)); if (linked_m != nullptr && linked_message_id.is_server() &&
return {}; have_input_peer(linked_dialog_id, AccessRights::Read) && !channel_username.empty() &&
linked_d->deleted_message_ids.count(linked_message_id) == 0) {
return std::make_pair(
PSTRING() << t_me << channel_username << '/' << linked_message_id.get_server_message_id().get()
<< "?comment=" << m->message_id.get_server_message_id().get() << (for_group ? "" : "&single"),
true);
}
}
} }
comment_link = PSTRING() << G()->shared_config().get_option_string("t_me_url", "https://t.me/") auto dialog_username = td_->contacts_manager_->get_channel_username(dialog_id.get_channel_id());
<< channel_username << '/' << linked_message_id.get_server_message_id().get() if (m->content->get_type() == MessageContentType::VideoNote && is_broadcast_channel(dialog_id) &&
<< "?comment=" << m->message_id.get_server_message_id().get() !dialog_username.empty()) {
<< (for_group ? "" : "&single"); return std::make_pair(
PSTRING() << "https://telesco.pe/" << dialog_username << '/' << m->message_id.get_server_message_id().get(),
true);
} }
}
}
if (comment_link.empty() && td_->contacts_manager_->get_channel_username(dialog_id.get_channel_id()).empty()) {
promise.set_error(
Status::Error(400, "Public message links are available only for messages in chats with a username"));
return {};
}
auto &links = public_message_links_[for_group][dialog_id].links_;
auto it = links.find(m->message_id);
if (it == links.end()) {
td_->create_handler<ExportChannelMessageLinkQuery>(std::move(promise))
->send(dialog_id.get_channel_id(), m->message_id, for_group, false);
return {};
}
if (for_comment && comment_link.empty()) {
comment_link = PSTRING() << it->second.first << (it->second.first.find('?') == string::npos ? '?' : '&')
<< "thread=" << m->top_reply_message_id.get_server_message_id().get();
}
promise.set_value(Unit());
if (!comment_link.empty()) {
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,
string html) {
LOG_IF(ERROR, url.empty() && html.empty()) << "Receive empty public link for " << full_message_id;
public_message_links_[for_group][full_message_id.get_dialog_id()].links_[full_message_id.get_message_id()] = {
std::move(url), std::move(html)};
}
string MessagesManager::get_message_link(FullMessageId full_message_id, bool for_group, bool for_comment,
Promise<Unit> &&promise) {
auto dialog_id = full_message_id.get_dialog_id();
auto d = get_dialog_force(dialog_id);
if (d == nullptr) {
promise.set_error(Status::Error(400, "Chat not found"));
return {};
}
if (!have_input_peer(dialog_id, AccessRights::Read)) {
promise.set_error(Status::Error(400, "Can't access the chat"));
return {};
}
if (dialog_id.get_type() != DialogType::Channel) {
promise.set_error(
Status::Error(400, "Message links are available only for messages in supergroups and channel chats"));
return {};
}
auto *m = get_message_force(d, full_message_id.get_message_id(), "get_message_link");
if (m == nullptr) {
promise.set_error(Status::Error(400, "Message not found"));
return {};
}
if (m->message_id.is_scheduled()) {
promise.set_error(Status::Error(400, "Message is scheduled"));
return {};
}
if (!m->message_id.is_server()) {
promise.set_error(Status::Error(400, "Message is local"));
return {};
}
if (m->media_album_id == 0) {
for_group = true; // default is true
}
if (!m->top_reply_message_id.is_valid() || !m->top_reply_message_id.is_server()) {
for_comment = false;
}
if (d->deleted_message_ids.count(m->top_reply_message_id) != 0) {
for_comment = false;
}
td_->create_handler<ExportChannelMessageLinkQuery>(Promise<Unit>())
->send(dialog_id.get_channel_id(), m->message_id, for_group, true);
promise.set_value(Unit());
string args; string args;
if (for_comment) { if (for_comment) {
@ -16208,8 +16126,13 @@ string MessagesManager::get_message_link(FullMessageId full_message_id, bool for
args += "single"; args += "single";
} }
return PSTRING() << G()->shared_config().get_option_string("t_me_url", "https://t.me/") << "c/" bool is_public = !dialog_username.empty();
<< dialog_id.get_channel_id().get() << "/" << m->message_id.get_server_message_id().get() << args; if (!is_public) {
dialog_username = PSTRING() << "c/" << dialog_id.get_channel_id().get();
}
return std::make_pair(PSTRING() << G()->shared_config().get_option_string("t_me_url", "https://t.me/")
<< dialog_username << '/' << m->message_id.get_server_message_id().get() << args,
is_public);
} }
string MessagesManager::get_message_embedding_code(FullMessageId full_message_id, bool for_group, string MessagesManager::get_message_embedding_code(FullMessageId full_message_id, bool for_group,
@ -16265,6 +16188,13 @@ string MessagesManager::get_message_embedding_code(FullMessageId full_message_id
return it->second.second; return it->second.second;
} }
void MessagesManager::on_get_public_message_link(FullMessageId full_message_id, bool for_group, string url,
string html) {
LOG_IF(ERROR, url.empty() && html.empty()) << "Receive empty public link for " << full_message_id;
public_message_links_[for_group][full_message_id.get_dialog_id()].links_[full_message_id.get_message_id()] = {
std::move(url), std::move(html)};
}
Result<MessagesManager::MessageLinkInfo> MessagesManager::get_message_link_info(Slice url) { Result<MessagesManager::MessageLinkInfo> MessagesManager::get_message_link_info(Slice url) {
if (url.empty()) { if (url.empty()) {
return Status::Error("URL must be non-empty"); return Status::Error("URL must be non-empty");

View File

@ -586,15 +586,12 @@ 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, bool for_comment, Result<std::pair<string, bool>> get_message_link(FullMessageId full_message_id, bool for_group, bool for_comment);
Promise<Unit> &&promise);
string get_message_embedding_code(FullMessageId full_message_id, bool for_group, Promise<Unit> &&promise); string get_message_embedding_code(FullMessageId full_message_id, bool for_group, 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);
string get_message_link(FullMessageId full_message_id, bool for_group, bool for_comment, Promise<Unit> &&promise);
struct MessageLinkInfo { struct MessageLinkInfo {
string username; string username;
// or // or

View File

@ -1112,59 +1112,6 @@ class GetMessagesRequest : public RequestOnceActor {
} }
}; };
class GetPublicMessageLinkRequest : public RequestActor<> {
FullMessageId full_message_id_;
bool for_group_;
bool for_comment_;
string link_;
string html_;
void do_run(Promise<Unit> &&promise) override {
std::tie(link_, html_) =
td->messages_manager_->get_public_message_link(full_message_id_, for_group_, for_comment_, std::move(promise));
}
void do_send_result() override {
send_result(make_tl_object<td_api::publicMessageLink>(link_, html_));
}
public:
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)
, full_message_id_(DialogId(dialog_id), MessageId(message_id))
, 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
}
};
class GetMessageLinkRequest : public RequestActor<> {
FullMessageId full_message_id_;
bool for_group_;
bool for_comment_;
string link_;
void do_run(Promise<Unit> &&promise) override {
link_ = td->messages_manager_->get_message_link(full_message_id_, for_group_, for_comment_, std::move(promise));
}
void do_send_result() override {
send_result(td_api::make_object<td_api::httpUrl>(link_));
}
public:
GetMessageLinkRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id, int64 message_id, bool for_group,
bool for_comment)
: RequestActor(std::move(td), request_id)
, full_message_id_(DialogId(dialog_id), MessageId(message_id))
, for_group_(for_group)
, for_comment_(for_comment) {
}
};
class GetMessageEmbeddingCodeRequest : public RequestActor<> { class GetMessageEmbeddingCodeRequest : public RequestActor<> {
FullMessageId full_message_id_; FullMessageId full_message_id_;
bool for_group_; bool for_group_;
@ -5159,16 +5106,16 @@ void Td::on_request(uint64 id, const td_api::getMessages &request) {
CREATE_REQUEST(GetMessagesRequest, request.chat_id_, request.message_ids_); CREATE_REQUEST(GetMessagesRequest, request.chat_id_, request.message_ids_);
} }
void Td::on_request(uint64 id, const td_api::getPublicMessageLink &request) {
CHECK_IS_USER();
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) {
CHECK_IS_USER(); CHECK_IS_USER();
CREATE_REQUEST(GetMessageLinkRequest, request.chat_id_, request.message_id_, request.for_album_, auto r_message_link = messages_manager_->get_message_link(
request.for_comment_); {DialogId(request.chat_id_), MessageId(request.message_id_)}, request.for_album_, request.for_comment_);
if (r_message_link.is_error()) {
send_closure(actor_id(this), &Td::send_error, id, r_message_link.move_as_error());
} else {
send_closure(actor_id(this), &Td::send_result, id,
td_api::make_object<td_api::messageLink>(r_message_link.ok().first, r_message_link.ok().second));
}
} }
void Td::on_request(uint64 id, const td_api::getMessageEmbeddingCode &request) { void Td::on_request(uint64 id, const td_api::getMessageEmbeddingCode &request) {

View File

@ -496,8 +496,6 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::getMessages &request); void on_request(uint64 id, const td_api::getMessages &request);
void on_request(uint64 id, const td_api::getPublicMessageLink &request);
void on_request(uint64 id, const td_api::getMessageLink &request); void on_request(uint64 id, const td_api::getMessageLink &request);
void on_request(uint64 id, const td_api::getMessageEmbeddingCode &request); void on_request(uint64 id, const td_api::getMessageEmbeddingCode &request);

View File

@ -2613,16 +2613,6 @@ class CliClient final : public Actor {
string message_ids; string message_ids;
std::tie(chat_id, message_ids) = split(args); std::tie(chat_id, message_ids) = split(args);
send_request(td_api::make_object<td_api::getMessages>(as_chat_id(chat_id), as_message_ids(message_ids))); send_request(td_api::make_object<td_api::getMessages>(as_chat_id(chat_id), as_message_ids(message_ids)));
} else if (op == "gpml") {
string chat_id;
string message_id;
string for_album;
string for_comment;
std::tie(chat_id, args) = 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),
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;