diff --git a/client.cpp b/client.cpp index e8504a2..b3caf21 100644 --- a/client.cpp +++ b/client.cpp @@ -102,6 +102,22 @@ std::optional MastodonClient::get_post(const std::string& host, const std: } } +std::vector 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 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 MastodonClient::get_posts(const std::string& host, const std::string& account_id, PostSortingMethod sorting_method, std::optional max_id) { using namespace std::string_literals; diff --git a/client.h b/client.h index 0ea2b28..27703ea 100644 --- a/client.h +++ b/client.h @@ -51,6 +51,7 @@ public: std::optional get_account_by_username(const std::string& host, const std::string& username); std::optional get_post(const std::string& host, const std::string& id); + std::vector get_pinned_posts(const std::string& host, const std::string& account_id); std::vector get_posts(const std::string& host, const std::string& account_id, PostSortingMethod sorting_method, std::optional max_id); private: diff --git a/font_awesome.h b/font_awesome.h index ec65ce5..38725e5 100644 --- a/font_awesome.h +++ b/font_awesome.h @@ -8,3 +8,4 @@ const char fa_retweet[] = R"EOF()EOF"; const char fa_reply[] = R"EOF()EOF"; +const char fa_thumbtack[] = R"EOF()EOF"; diff --git a/routes/user.cpp b/routes/user.cpp index 3abc3c9..7dd8f7e 100644 --- a/routes/user.cpp +++ b/routes/user.cpp @@ -30,11 +30,14 @@ void user_route(const httplib::Request& req, httplib::Response& res) { } std::optional account; - std::vector posts; + std::vector pinned_posts, posts; try { account = mastodon_client.get_account_by_username(server, username); 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) { res.status = 500; @@ -51,14 +54,20 @@ void user_route(const httplib::Request& req, httplib::Response& res) { Element body("body", { 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) { body.nodes.push_back(serialize_post(req, server, post)); body.nodes.push_back(Element("hr")); } + 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"})); - } else { + } else if (max_id) { body.nodes.push_back(Element("p", {{"class", "user_page-more_posts"}}, {"There are no more posts"})); } diff --git a/servehelper.cpp b/servehelper.cpp index c083bbb..41059ab 100644 --- a/servehelper.cpp +++ b/servehelper.cpp @@ -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] != '/'); } -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; 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"), }; 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) { PostStatus post_status = { fa_reply, diff --git a/servehelper.h b/servehelper.h index 5a77ce1..fe48e40 100644 --- a/servehelper.h +++ b/servehelper.h @@ -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); 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& emojis, const blankie::html::HTMLString& str); blankie::html::HTMLString preprocess_html(const httplib::Request& req, const std::vector& emojis, const std::string& str);