From ef1d38462f7b7fa447f9ec8aa5a04f88b0ff2fd9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 23 Dec 2018 00:08:15 +0400 Subject: [PATCH] Simplest polls data export. --- Telegram/Resources/export_html/css/style.css | 3 +- .../export/data/export_data_types.cpp | 48 ++++++++++++++++- .../export/data/export_data_types.h | 16 ++++++ .../export/output/export_output_html.cpp | 52 +++++++++++++++++++ .../export/output/export_output_json.cpp | 23 ++++++++ .../export/output/export_output_text.cpp | 13 +++++ 6 files changed, 153 insertions(+), 2 deletions(-) diff --git a/Telegram/Resources/export_html/css/style.css b/Telegram/Resources/export_html/css/style.css index 74f36842d..52b90fd05 100644 --- a/Telegram/Resources/export_html/css/style.css +++ b/Telegram/Resources/export_html/css/style.css @@ -311,7 +311,8 @@ div.selected { background-position: 12px 12px; background-size: 24px 24px; } -.default .media .title { +.default .media .title, +.default .media_poll .question { padding-top: 4px; font-size: 14px; } diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp index 708fe89a7..6e09160ec 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.cpp +++ b/Telegram/SourceFiles/export/data/export_data_types.cpp @@ -14,6 +14,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include #include +#include +#include +#include namespace App { // Hackish.. QString formatPhone(QString phone); @@ -507,6 +510,49 @@ Invoice ParseInvoice(const MTPDmessageMediaInvoice &data) { return result; } +Poll ParsePoll(const MTPDmessageMediaPoll &data) { + auto result = Poll(); + data.vpoll.match([&](const MTPDpoll &poll) { + result.id = poll.vid.v; + result.question = ParseString(poll.vquestion); + result.closed = poll.is_closed(); + result.answers = ranges::view::all( + poll.vanswers.v + ) | ranges::view::transform([](const MTPPollAnswer &answer) { + return answer.match([](const MTPDpollAnswer &answer) { + auto result = Poll::Answer(); + result.text = ParseString(answer.vtext); + result.option = answer.voption.v; + return result; + }); + }) | ranges::to_vector; + }); + data.vresults.match([&](const MTPDpollResults &results) { + if (results.has_total_voters()) { + result.totalVotes = results.vtotal_voters.v; + } + if (results.has_results()) { + for (const auto &single : results.vresults.v) { + single.match([&](const MTPDpollAnswerVoters &voters) { + const auto &option = voters.voption.v; + const auto i = ranges::find( + result.answers, + voters.voption.v, + &Poll::Answer::option); + if (i == end(result.answers)) { + return; + } + i->votes = voters.vvoters.v; + if (voters.is_chosen()) { + i->my = true; + } + }); + } + } + }); + return result; +} + UserpicsSlice ParseUserpicsSlice( const MTPVector &data, int baseIndex) { @@ -870,7 +916,7 @@ Media ParseMedia( result.content = ParseGeoPoint(data.vgeo); result.ttl = data.vperiod.v; }, [&](const MTPDmessageMediaPoll &data) { - //result.content = ParsePoll(data); // #TODO polls + result.content = ParsePoll(data); }, [](const MTPDmessageMediaEmpty &data) {}); return result; } diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h index 94e530467..8c91246be 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.h +++ b/Telegram/SourceFiles/export/data/export_data_types.h @@ -178,6 +178,21 @@ struct Invoice { int32 receiptMsgId = 0; }; +struct Poll { + struct Answer { + Utf8String text; + QByteArray option; + int votes = 0; + bool my = false; + }; + + uint64 id = 0; + Utf8String question; + std::vector answers; + int totalVotes = 0; + bool closed = false; +}; + struct UserpicsSlice { std::vector list; }; @@ -299,6 +314,7 @@ struct Media { Venue, Game, Invoice, + Poll, UnsupportedMedia> content; TimeId ttl = 0; diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp index 615315d61..535d62a77 100644 --- a/Telegram/SourceFiles/export/output/export_output_html.cpp +++ b/Telegram/SourceFiles/export/output/export_output_html.cpp @@ -621,6 +621,7 @@ private: [[nodiscard]] QByteArray pushPhotoMedia( const Data::Photo &data, const QString &basePath); + [[nodiscard]] QByteArray pushPoll(const Data::Poll &data); File _file; bool _closed = false; @@ -1232,6 +1233,8 @@ QByteArray HtmlWriter::Wrap::pushMedia( } else if (const auto photo = base::get_if(&content)) { Assert(!message.media.ttl); return pushPhotoMedia(*photo, basePath); + } else if (const auto poll = base::get_if(&content)) { + return pushPoll(*poll); } Assert(!content.has_value()); return QByteArray(); @@ -1503,6 +1506,54 @@ QByteArray HtmlWriter::Wrap::pushPhotoMedia( return result; } +QByteArray HtmlWriter::Wrap::pushPoll(const Data::Poll &data) { + using namespace Data; + + auto result = pushDiv("media_wrap clearfix"); + result.append(pushDiv("media_poll")); + result.append(pushDiv("question bold")); + result.append(SerializeString(data.question)); + result.append(popTag()); + result.append(pushDiv("details")); + if (data.closed) { + result.append(SerializeString("Final results")); + } else { + result.append(SerializeString("Anonymous poll")); + } + result.append(popTag()); + const auto votes = [](int count) { + if (count > 1) { + return NumberToString(count) + " votes"; + } else if (count > 0) { + return NumberToString(count) + " vote"; + } + return QByteArray("No votes"); + }; + const auto details = [&](const Poll::Answer &answer) { + if (!answer.votes) { + return QByteArray(""); + } else if (!answer.my) { + return " " + + votes(answer.votes) + + ""; + } + return " " + + votes(answer.votes) + + ", chosen vote"; + }; + for (const auto &answer : data.answers) { + result.append(pushDiv("answer")); + result.append("- " + SerializeString(answer.text) + details(answer)); + result.append(popTag()); + } + result.append(pushDiv("total details ")); + result.append(votes(data.totalVotes)); + result.append(popTag()); + result.append(popTag()); + result.append(popTag()); + return result; +} + MediaData HtmlWriter::Wrap::prepareMediaData( const Data::Message &message, const QString &basePath, @@ -1658,6 +1709,7 @@ MediaData HtmlWriter::Wrap::prepareMediaData( result.title = data.title; result.description = data.description; result.status = Data::FormatMoneyAmount(data.amount, data.currency); + }, [](const Poll &data) { }, [](const UnsupportedMedia &data) { Unexpected("Unsupported message."); }, [](std::nullopt_t) {}); diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp index 5f8421e82..1c448c326 100644 --- a/Telegram/SourceFiles/export/output/export_output_json.cpp +++ b/Telegram/SourceFiles/export/output/export_output_json.cpp @@ -574,6 +574,29 @@ QByteArray SerializeMessage( ? NumberToString(data.receiptMsgId) : QByteArray()) } })); + }, [&](const Poll &data) { + context.nesting.push_back(Context::kObject); + const auto answers = ranges::view::all( + data.answers + ) | ranges::view::transform([&](const Poll::Answer &answer) { + context.nesting.push_back(Context::kArray); + auto result = SerializeObject(context, { + { "text", SerializeString(answer.text) }, + { "voters", NumberToString(answer.votes) }, + { "chosen", answer.my ? "true" : "false" }, + }); + context.nesting.pop_back(); + return result; + }) | ranges::to_vector; + const auto serialized = SerializeArray(context, answers); + context.nesting.pop_back(); + + pushBare("poll", SerializeObject(context, { + { "question", SerializeString(data.question) }, + { "closed", data.closed ? "true" : "false" }, + { "total_voters", NumberToString(data.totalVotes) }, + { "answers", serialized } + })); }, [](const UnsupportedMedia &data) { Unexpected("Unsupported message."); }, [](std::nullopt_t) {}); diff --git a/Telegram/SourceFiles/export/output/export_output_text.cpp b/Telegram/SourceFiles/export/output/export_output_text.cpp index c80cb5315..b5fec1cc3 100644 --- a/Telegram/SourceFiles/export/output/export_output_text.cpp +++ b/Telegram/SourceFiles/export/output/export_output_text.cpp @@ -436,6 +436,19 @@ QByteArray SerializeMessage( ? "ID-" + NumberToString(data.receiptMsgId) : QByteArray()) } })); + }, [&](const Poll &data) { + push("Poll", SerializeKeyValue({ + { "Question", data.question }, + { "Closed", data.closed ? QByteArray("Yes") : QByteArray() }, + { "Votes", NumberToString(data.totalVotes) }, + })); + for (const auto &answer : data.answers) { + push("Answer", SerializeKeyValue({ + { "Text", answer.text }, + { "Votes", NumberToString(answer.votes) }, + { "Chosen", answer.my ? QByteArray("Yes") : QByteArray() } + })); + } }, [](const UnsupportedMedia &data) { Unexpected("Unsupported message."); }, [](std::nullopt_t) {});