Add poll support
This commit is contained in:
parent
3c28b81405
commit
dc3758004b
16
models.cpp
16
models.cpp
|
@ -71,6 +71,19 @@ void from_json(const json& j, Media& media) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void from_json(const json& j, PollOption& option) {
|
||||||
|
j.at("title").get_to(option.title);
|
||||||
|
j.at("votes_count").get_to(option.votes_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void from_json(const json& j, Poll& poll) {
|
||||||
|
poll.expires_at = parse_rfc3339(j.at("expires_at").get_ref<const std::string&>());
|
||||||
|
j.at("expired").get_to(poll.expired);
|
||||||
|
j.at("voters_count").get_to(poll.voters_count);
|
||||||
|
j.at("options").get_to(poll.options);
|
||||||
|
j.at("emojis").get_to(poll.emojis);
|
||||||
|
}
|
||||||
|
|
||||||
void from_json(const json& j, Post& post) {
|
void from_json(const json& j, Post& post) {
|
||||||
j.at("id").get_to(post.id);
|
j.at("id").get_to(post.id);
|
||||||
post.created_at = parse_rfc3339(j.at("created_at").get_ref<const std::string&>());
|
post.created_at = parse_rfc3339(j.at("created_at").get_ref<const std::string&>());
|
||||||
|
@ -98,6 +111,9 @@ void from_json(const json& j, Post& post) {
|
||||||
j.at("account").get_to(post.account);
|
j.at("account").get_to(post.account);
|
||||||
j.at("media_attachments").get_to(post.media_attachments);
|
j.at("media_attachments").get_to(post.media_attachments);
|
||||||
j.at("emojis").get_to(post.emojis);
|
j.at("emojis").get_to(post.emojis);
|
||||||
|
if (!j.at("poll").is_null()) {
|
||||||
|
post.poll = j["poll"].get<Poll>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void from_json(const json& j, PostContext& context) {
|
void from_json(const json& j, PostContext& context) {
|
||||||
|
|
15
models.h
15
models.h
|
@ -58,6 +58,18 @@ struct Media {
|
||||||
std::optional<std::string> description;
|
std::optional<std::string> description;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PollOption {
|
||||||
|
std::string title;
|
||||||
|
uint64_t votes_count;
|
||||||
|
};
|
||||||
|
struct Poll {
|
||||||
|
time_t expires_at;
|
||||||
|
bool expired;
|
||||||
|
uint64_t voters_count;
|
||||||
|
std::vector<PollOption> options;
|
||||||
|
std::vector<Emoji> emojis;
|
||||||
|
};
|
||||||
|
|
||||||
struct Post {
|
struct Post {
|
||||||
std::string id;
|
std::string id;
|
||||||
time_t created_at;
|
time_t created_at;
|
||||||
|
@ -74,6 +86,7 @@ struct Post {
|
||||||
Account account;
|
Account account;
|
||||||
std::vector<Media> media_attachments;
|
std::vector<Media> media_attachments;
|
||||||
std::vector<Emoji> emojis;
|
std::vector<Emoji> emojis;
|
||||||
|
std::optional<Poll> poll;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PostContext {
|
struct PostContext {
|
||||||
|
@ -85,5 +98,7 @@ void from_json(const nlohmann::json& j, Emoji& emoji);
|
||||||
void from_json(const nlohmann::json& j, AccountField& field);
|
void from_json(const nlohmann::json& j, AccountField& field);
|
||||||
void from_json(const nlohmann::json& j, Account& account);
|
void from_json(const nlohmann::json& j, Account& account);
|
||||||
void from_json(const nlohmann::json& j, Media& media);
|
void from_json(const nlohmann::json& j, Media& media);
|
||||||
|
void from_json(const nlohmann::json& j, PollOption& option);
|
||||||
|
void from_json(const nlohmann::json& j, Poll& poll);
|
||||||
void from_json(const nlohmann::json& j, Post& post);
|
void from_json(const nlohmann::json& j, Post& post);
|
||||||
void from_json(const nlohmann::json& j, PostContext& context);
|
void from_json(const nlohmann::json& j, PostContext& context);
|
||||||
|
|
|
@ -125,6 +125,25 @@ svg {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* POLL */
|
||||||
|
.poll-option {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
.poll-percentage {
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
.poll-bar {
|
||||||
|
height: 0.5em;
|
||||||
|
display: block;
|
||||||
|
background-color: lightgray;
|
||||||
|
border-radius: 10em;
|
||||||
|
margin-top: 0.25em;
|
||||||
|
}
|
||||||
|
.poll-bar[width="0%"] {
|
||||||
|
width: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
/* ERROR PAGE */
|
/* ERROR PAGE */
|
||||||
.error {
|
.error {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -8,6 +8,7 @@ void home_route(const httplib::Request& req, httplib::Response& res) {
|
||||||
Element("ul", {
|
Element("ul", {
|
||||||
Element("li", {Element("a", {{"href", get_origin(req) + "/vt.social/@lina"}}, {"Asahi Lina (朝日リナ) // nullptr::live"})}),
|
Element("li", {Element("a", {{"href", get_origin(req) + "/vt.social/@lina"}}, {"Asahi Lina (朝日リナ) // nullptr::live"})}),
|
||||||
Element("li", {Element("a", {{"href", get_origin(req) + "/vt.social/@LucydiaLuminous/111290028216105435"}}, {"\"I love kids and their creativity. So I was explain…\""})}),
|
Element("li", {Element("a", {{"href", get_origin(req) + "/vt.social/@LucydiaLuminous/111290028216105435"}}, {"\"I love kids and their creativity. So I was explain…\""})}),
|
||||||
|
Element("li", {Element("a", {{"href", get_origin(req) + "/ruby.social/@CoralineAda/109951421922797743"}}, {"\"My partner just said \"I'm starting to think nostal…\""})}),
|
||||||
}),
|
}),
|
||||||
Element("hr"),
|
Element("hr"),
|
||||||
Element("p", {
|
Element("p", {
|
||||||
|
|
|
@ -25,6 +25,7 @@ struct PostStatus {
|
||||||
};
|
};
|
||||||
static Element serialize_post(const httplib::Request& req, const std::string& server, const Post& post, bool main_post, const std::optional<PostStatus>& post_status);
|
static Element serialize_post(const httplib::Request& req, const std::string& server, const Post& post, bool main_post, const std::optional<PostStatus>& post_status);
|
||||||
static inline Element serialize_media(const Media& media);
|
static inline Element serialize_media(const Media& media);
|
||||||
|
static inline Element serialize_poll(const httplib::Request& req, const Poll& poll);
|
||||||
|
|
||||||
class CurlUrlException : public std::exception {
|
class CurlUrlException : public std::exception {
|
||||||
public:
|
public:
|
||||||
|
@ -370,6 +371,7 @@ static Element serialize_post(const httplib::Request& req, const std::string& se
|
||||||
const char* time_badge = post.edited_at < 0 ? "" : " (edited)";
|
const char* time_badge = post.edited_at < 0 ? "" : " (edited)";
|
||||||
|
|
||||||
Element contents("div", {{"class", "post-contents"}}, {preprocess_html(req, server, post.emojis, post.content)});
|
Element contents("div", {{"class", "post-contents"}}, {preprocess_html(req, server, post.emojis, post.content)});
|
||||||
|
|
||||||
Element post_attachments("div", {{"class", "post-attachments"}}, {});
|
Element post_attachments("div", {{"class", "post-attachments"}}, {});
|
||||||
post_attachments.nodes.reserve(post.media_attachments.size());
|
post_attachments.nodes.reserve(post.media_attachments.size());
|
||||||
for (const Media& media : post.media_attachments) {
|
for (const Media& media : post.media_attachments) {
|
||||||
|
@ -377,6 +379,10 @@ static Element serialize_post(const httplib::Request& req, const std::string& se
|
||||||
}
|
}
|
||||||
contents.nodes.push_back(std::move(post_attachments));
|
contents.nodes.push_back(std::move(post_attachments));
|
||||||
|
|
||||||
|
if (post.poll) {
|
||||||
|
contents.nodes.push_back(serialize_poll(req, *post.poll));
|
||||||
|
}
|
||||||
|
|
||||||
if (post.sensitive) {
|
if (post.sensitive) {
|
||||||
std::string spoiler_text = !post.spoiler_text.empty() ? post.spoiler_text : "See more";
|
std::string spoiler_text = !post.spoiler_text.empty() ? post.spoiler_text : "See more";
|
||||||
contents = Element("details", {
|
contents = Element("details", {
|
||||||
|
@ -453,3 +459,37 @@ static inline Element serialize_media(const Media& media) {
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Element serialize_poll(const httplib::Request& req, const Poll& poll) {
|
||||||
|
Element div("div");
|
||||||
|
|
||||||
|
auto pick_form = [](uint64_t count, const char* singular, const char* plural) {
|
||||||
|
return count == 1 ? singular : plural;
|
||||||
|
};
|
||||||
|
|
||||||
|
div.nodes.reserve(poll.options.size() + 1);
|
||||||
|
for (const PollOption& option : poll.options) {
|
||||||
|
std::string percentage = poll.voters_count
|
||||||
|
? std::to_string(option.votes_count * 100 / poll.voters_count) + '%'
|
||||||
|
: "0%";
|
||||||
|
|
||||||
|
div.nodes.push_back(Element("div", {{"class", "poll-option"}, {"title", std::to_string(option.votes_count) + pick_form(option.votes_count, " vote", " votes")}}, {
|
||||||
|
Element("b", {{"class", "poll-percentage"}}, {percentage}), " ", preprocess_html(req, poll.emojis, option.title),
|
||||||
|
Element("object", {{"class", "poll-bar"}, {"width", percentage}}, {}),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Element p("p", {
|
||||||
|
std::to_string(poll.voters_count), " ", pick_form(poll.voters_count, "voter", "voters"),
|
||||||
|
" / ",
|
||||||
|
});
|
||||||
|
if (poll.expired) {
|
||||||
|
p.nodes.push_back("Expired");
|
||||||
|
} else {
|
||||||
|
p.nodes.push_back("Expires in ");
|
||||||
|
p.nodes.push_back(relative_time(current_time(), poll.expires_at));
|
||||||
|
}
|
||||||
|
div.nodes.push_back(std::move(p));
|
||||||
|
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue