Add pinned posts support

This commit is contained in:
blankie 2023-11-24 00:43:55 +11:00
parent aa0c7806cb
commit e861ab7ba6
Signed by: blankie
GPG Key ID: CC15FC822C7F61F5
6 changed files with 39 additions and 6 deletions

View File

@ -102,6 +102,22 @@ std::optional<Post> MastodonClient::get_post(const std::string& host, const std:
} }
} }
std::vector<Post> MastodonClient::get_pinned_posts(const std::string& host, const std::string& account_id) {
using namespace std::string_literals;
std::string resp = this->_send_request("https://"s + host + "/api/v1/accounts/" + account_id + "/statuses?pinned=true");
std::vector<Post> posts = nlohmann::json::parse(std::move(resp));
for (Post& post : posts) {
post.account.same_server = host == post.account.server;
if (post.reblog) {
post.reblog->account.same_server = host == post.reblog->account.server;
}
}
return posts;
}
std::vector<Post> MastodonClient::get_posts(const std::string& host, const std::string& account_id, PostSortingMethod sorting_method, std::optional<std::string> max_id) { std::vector<Post> MastodonClient::get_posts(const std::string& host, const std::string& account_id, PostSortingMethod sorting_method, std::optional<std::string> max_id) {
using namespace std::string_literals; using namespace std::string_literals;

View File

@ -51,6 +51,7 @@ public:
std::optional<Account> get_account_by_username(const std::string& host, const std::string& username); std::optional<Account> get_account_by_username(const std::string& host, const std::string& username);
std::optional<Post> get_post(const std::string& host, const std::string& id); std::optional<Post> get_post(const std::string& host, const std::string& id);
std::vector<Post> get_pinned_posts(const std::string& host, const std::string& account_id);
std::vector<Post> get_posts(const std::string& host, const std::string& account_id, PostSortingMethod sorting_method, std::optional<std::string> max_id); std::vector<Post> get_posts(const std::string& host, const std::string& account_id, PostSortingMethod sorting_method, std::optional<std::string> max_id);
private: private:

View File

@ -8,3 +8,4 @@
const char fa_retweet[] = R"EOF(<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --><path d="M272 416c17.7 0 32-14.3 32-32s-14.3-32-32-32H160c-17.7 0-32-14.3-32-32V192h32c12.9 0 24.6-7.8 29.6-19.8s2.2-25.7-6.9-34.9l-64-64c-12.5-12.5-32.8-12.5-45.3 0l-64 64c-9.2 9.2-11.9 22.9-6.9 34.9s16.6 19.8 29.6 19.8l32 0 0 128c0 53 43 96 96 96H272zM304 96c-17.7 0-32 14.3-32 32s14.3 32 32 32l112 0c17.7 0 32 14.3 32 32l0 128H416c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 6.9 34.9l64 64c12.5 12.5 32.8 12.5 45.3 0l64-64c9.2-9.2 11.9-22.9 6.9-34.9s-16.6-19.8-29.6-19.8l-32 0V192c0-53-43-96-96-96L304 96z"/></svg>)EOF"; const char fa_retweet[] = R"EOF(<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --><path d="M272 416c17.7 0 32-14.3 32-32s-14.3-32-32-32H160c-17.7 0-32-14.3-32-32V192h32c12.9 0 24.6-7.8 29.6-19.8s2.2-25.7-6.9-34.9l-64-64c-12.5-12.5-32.8-12.5-45.3 0l-64 64c-9.2 9.2-11.9 22.9-6.9 34.9s16.6 19.8 29.6 19.8l32 0 0 128c0 53 43 96 96 96H272zM304 96c-17.7 0-32 14.3-32 32s14.3 32 32 32l112 0c17.7 0 32 14.3 32 32l0 128H416c-12.9 0-24.6 7.8-29.6 19.8s-2.2 25.7 6.9 34.9l64 64c12.5 12.5 32.8 12.5 45.3 0l64-64c9.2-9.2 11.9-22.9 6.9-34.9s-16.6-19.8-29.6-19.8l-32 0V192c0-53-43-96-96-96L304 96z"/></svg>)EOF";
const char fa_reply[] = R"EOF(<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --><path d="M205 34.8c11.5 5.1 19 16.6 19 29.2v64H336c97.2 0 176 78.8 176 176c0 113.3-81.5 163.9-100.2 174.1c-2.5 1.4-5.3 1.9-8.1 1.9c-10.9 0-19.7-8.9-19.7-19.7c0-7.5 4.3-14.4 9.8-19.5c9.4-8.8 22.2-26.4 22.2-56.7c0-53-43-96-96-96H224v64c0 12.6-7.4 24.1-19 29.2s-25 3-34.4-5.4l-160-144C3.9 225.7 0 217.1 0 208s3.9-17.7 10.6-23.8l160-144c9.4-8.5 22.9-10.6 34.4-5.4z"/></svg>)EOF"; const char fa_reply[] = R"EOF(<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --><path d="M205 34.8c11.5 5.1 19 16.6 19 29.2v64H336c97.2 0 176 78.8 176 176c0 113.3-81.5 163.9-100.2 174.1c-2.5 1.4-5.3 1.9-8.1 1.9c-10.9 0-19.7-8.9-19.7-19.7c0-7.5 4.3-14.4 9.8-19.5c9.4-8.8 22.2-26.4 22.2-56.7c0-53-43-96-96-96H224v64c0 12.6-7.4 24.1-19 29.2s-25 3-34.4-5.4l-160-144C3.9 225.7 0 217.1 0 208s3.9-17.7 10.6-23.8l160-144c9.4-8.5 22.9-10.6 34.4-5.4z"/></svg>)EOF";
const char fa_thumbtack[] = R"EOF(<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --><path d="M32 32C32 14.3 46.3 0 64 0H320c17.7 0 32 14.3 32 32s-14.3 32-32 32H290.5l11.4 148.2c36.7 19.9 65.7 53.2 79.5 94.7l1 3c3.3 9.8 1.6 20.5-4.4 28.8s-15.7 13.3-26 13.3H32c-10.3 0-19.9-4.9-26-13.3s-7.7-19.1-4.4-28.8l1-3c13.8-41.5 42.8-74.8 79.5-94.7L93.5 64H64C46.3 64 32 49.7 32 32zM160 384h64v96c0 17.7-14.3 32-32 32s-32-14.3-32-32V384z"/></svg>)EOF";

View File

@ -30,11 +30,14 @@ void user_route(const httplib::Request& req, httplib::Response& res) {
} }
std::optional<Account> account; std::optional<Account> account;
std::vector<Post> posts; std::vector<Post> pinned_posts, posts;
try { try {
account = mastodon_client.get_account_by_username(server, username); account = mastodon_client.get_account_by_username(server, username);
if (account) { if (account) {
posts = mastodon_client.get_posts(server, account->id, sorting_method, std::move(max_id)); if (sorting_method == PostSortingMethod::Posts && !max_id) {
pinned_posts = mastodon_client.get_pinned_posts(server, account->id);
}
posts = mastodon_client.get_posts(server, account->id, sorting_method, max_id);
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
res.status = 500; res.status = 500;
@ -51,14 +54,20 @@ void user_route(const httplib::Request& req, httplib::Response& res) {
Element body("body", { Element body("body", {
user_header(req, server, *account, sorting_method), user_header(req, server, *account, sorting_method),
}); });
body.nodes.reserve(body.nodes.size() + 2 * posts.size() + 1); body.nodes.reserve(body.nodes.size() + 2 * (pinned_posts.size() + posts.size()) + 1);
for (const Post& post : pinned_posts) {
body.nodes.push_back(serialize_post(req, server, post, true));
body.nodes.push_back(Element("hr"));
}
for (const Post& post : posts) { for (const Post& post : posts) {
body.nodes.push_back(serialize_post(req, server, post)); body.nodes.push_back(serialize_post(req, server, post));
body.nodes.push_back(Element("hr")); body.nodes.push_back(Element("hr"));
} }
if (!posts.empty()) { if (!posts.empty()) {
body.nodes.push_back(Element("a", {{"class", "user_page-more_posts"}, {"href", "?max_id="s + posts[posts.size() - 1].id + "#user_posts_nav"}}, {"See more"})); body.nodes.push_back(Element("a", {{"class", "user_page-more_posts"}, {"href", "?max_id="s + posts[posts.size() - 1].id + "#user_posts_nav"}}, {"See more"}));
} else { } else if (max_id) {
body.nodes.push_back(Element("p", {{"class", "user_page-more_posts"}}, {"There are no more posts"})); body.nodes.push_back(Element("p", {{"class", "user_page-more_posts"}}, {"There are no more posts"}));
} }

View File

@ -172,7 +172,7 @@ bool should_send_304(const httplib::Request& req, uint64_t hash) {
return pos != std::string::npos && (pos == 0 || header[pos - 1] != '/'); return pos != std::string::npos && (pos == 0 || header[pos - 1] != '/');
} }
Element serialize_post(const httplib::Request& req, const std::string& server, const Post& post) { Element serialize_post(const httplib::Request& req, const std::string& server, const Post& post, bool pinned) {
using namespace std::string_literals; using namespace std::string_literals;
if (post.reblog) { if (post.reblog) {
@ -181,6 +181,12 @@ Element serialize_post(const httplib::Request& req, const std::string& server, c
preprocess_html(req, post.account.emojis, post.account.display_name + " boosted"), preprocess_html(req, post.account.emojis, post.account.display_name + " boosted"),
}; };
return serialize_post(req, server, *post.reblog, post_status); return serialize_post(req, server, *post.reblog, post_status);
} else if (pinned) {
PostStatus post_status = {
fa_thumbtack,
blankie::html::HTMLString("Pinned post"),
};
return serialize_post(req, server, post, post_status);
} else if (post.in_reply_to_id && post.in_reply_to_account_id && post.account.id == *post.in_reply_to_account_id) { } else if (post.in_reply_to_id && post.in_reply_to_account_id && post.account.id == *post.in_reply_to_account_id) {
PostStatus post_status = { PostStatus post_status = {
fa_reply, fa_reply,

View File

@ -20,7 +20,7 @@ std::string get_origin(const httplib::Request& req);
std::string proxy_mastodon_url(const httplib::Request& req, const std::string& url_str); std::string proxy_mastodon_url(const httplib::Request& req, const std::string& url_str);
bool should_send_304(const httplib::Request& req, uint64_t hash); bool should_send_304(const httplib::Request& req, uint64_t hash);
Element serialize_post(const httplib::Request& req, const std::string& server, const Post& post); Element serialize_post(const httplib::Request& req, const std::string& server, const Post& post, bool pinned = false);
blankie::html::HTMLString preprocess_html(const httplib::Request& req, const std::string& domain_name, const std::vector<Emoji>& emojis, const blankie::html::HTMLString& str); blankie::html::HTMLString preprocess_html(const httplib::Request& req, const std::string& domain_name, const std::vector<Emoji>& emojis, const blankie::html::HTMLString& str);
blankie::html::HTMLString preprocess_html(const httplib::Request& req, const std::vector<Emoji>& emojis, const std::string& str); blankie::html::HTMLString preprocess_html(const httplib::Request& req, const std::vector<Emoji>& emojis, const std::string& str);