From f23a562c1b4613a00d53e0be4b20e5b71989df94 Mon Sep 17 00:00:00 2001 From: tastytea Date: Sun, 15 Nov 2020 20:30:42 +0100 Subject: [PATCH] Allow more than 1 screenshot. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * New screenshot naming: branchname-N.extension (the “-N” ist new). * In JSON file: Array of strings instead of string, “screenshots” instead of “screenshot”. * Old format is still supported. --- src/cgi.cpp | 22 +++++++++++++--------- src/files.cpp | 33 +++++++++++++++++++++++++++------ src/generators/html.cpp | 13 +++++++++---- src/generators/rss.cpp | 16 ++++++++++------ src/git.cpp | 13 ++++++++++--- src/json.cpp | 22 +++++++++++++++++++--- src/types.hpp | 2 +- 7 files changed, 89 insertions(+), 32 deletions(-) diff --git a/src/cgi.cpp b/src/cgi.cpp index 9b4b35a..482f51f 100644 --- a/src/cgi.cpp +++ b/src/cgi.cpp @@ -15,12 +15,14 @@ */ #include "cgi.hpp" + #include "files.hpp" #include "fs-compat.hpp" #include "time.hpp" #include #include +#include #include #include @@ -39,6 +41,7 @@ namespace FediBlock::cgi { +using fmt::format; using std::back_inserter; using std::getline; using std::ios; @@ -65,24 +68,25 @@ entry_type parse_formdata() entry.description = cgi("description"); entry.report_time = time::to_string(system_clock::now()); - const auto screenshot = cgi.getFile("screenshot"); - if (screenshot != cgi.getFiles().end()) + for (const auto &screenshot : cgi.getFiles()) { - constexpr size_t size_limit{1024 * 1024 * 2}; // 2 MiB. - if (screenshot->getDataLength() > size_limit) + constexpr size_t size_limit{1024 * 1024 * 1}; + if (screenshot.getDataLength() > size_limit) { - throw runtime_error{"The screenshot is too big. " - "The limit is 2 MiB."}; + throw runtime_error{format("The screenshot “{0:s}” is too big. " + "The limit is {1:.1f} MiB.", + screenshot.getFilename(), + size_limit / 1024 / 1024)}; } - const string filepath{files::get_tmpdir() / screenshot->getFilename()}; + const string filepath{files::get_tmpdir() / screenshot.getFilename()}; ofstream file{filepath, ios::binary}; if (!file.good()) { throw runtime_error{"Could not open temporary file: " + filepath}; } - screenshot->writeToStream(file); - entry.screenshot_filepath = filepath; + screenshot.writeToStream(file); + entry.screenshot_filepaths.push_back(filepath); } return entry; diff --git a/src/files.cpp b/src/files.cpp index feccd97..b4e3254 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -15,12 +15,15 @@ */ #include "files.hpp" + #include "fs-compat.hpp" #include "json.hpp" #include "types.hpp" #include #include // For compatibility with fmt 4. +#include +#include #include #include @@ -29,8 +32,6 @@ #include #include #include -#include -#include namespace FediBlock::files { @@ -184,11 +185,31 @@ vector read_json_files(const bool cache) stringstream ss; ss << file.rdbuf(); auto entry{json::from_json(ss.str())}; - if (!entry.screenshot_filepath.empty()) + if (!entry.screenshot_filepaths.empty()) { - const fs::path sh_path{entry.screenshot_filepath}; - entry.screenshot_filepath = path.stem().string() += - sh_path.extension(); + std::uint8_t counter{0}; + for (auto &screenshot : entry.screenshot_filepaths) + { + ++counter; + const fs::path sh_path{screenshot}; + // clang-format off + const auto compat_path{path.parent_path() /= path.stem() + /= sh_path.extension()}; + // clang-format on + if (entry.screenshot_filepaths.size() == 1 + && fs::exists(compat_path)) + { + // Compatibility for old entries. + screenshot = path.stem().string() += sh_path.extension(); + } + else + { + // clang-format off + screenshot = (path.stem().string() += '-') + += to_string(counter) += sh_path.extension(); + // clang-format on + } + } } entries.push_back(entry); } diff --git a/src/generators/html.cpp b/src/generators/html.cpp index f22f9c6..d505eb6 100644 --- a/src/generators/html.cpp +++ b/src/generators/html.cpp @@ -109,11 +109,16 @@ void write_html(ostream &out, const vector &entries) << "\n"; } out << " \n"; - if (!entry.screenshot_filepath.empty()) + if (!entry.screenshot_filepaths.empty()) { - out << "

Screenshot:
" - << "

)" << '\n'; + out << " Screenshots:
\n" + << "
    \n"; + for (const auto &screenshot : entry.screenshot_filepaths) + { + out << "
  • " + << screenshot << "
  • \n"; + } + out << "
"; } out << " \n"; } diff --git a/src/generators/rss.cpp b/src/generators/rss.cpp index 7b05a13..26c915a 100644 --- a/src/generators/rss.cpp +++ b/src/generators/rss.cpp @@ -165,13 +165,17 @@ void write_rss(ostream &out, const vector &entries, receipt); } tmp_item_description += ""; - if (!entry.screenshot_filepath.empty()) + if (!entry.screenshot_filepaths.empty()) { - tmp_item_description += "

Screenshot:
"; - tmp_item_description += format("" - "

\n", - baseurl, entry.screenshot_filepath); + tmp_item_description += "

Screenshots:
"; + for (const auto &screenshot : entry.screenshot_filepaths) + { + tmp_item_description += format("" + " ", + baseurl, screenshot); + } + tmp_item_description += "

"; } auto item_description{item.append_child("description")}; item_description.append_child(pugi::node_cdata) diff --git a/src/git.cpp b/src/git.cpp index 48ec054..0c2aace 100644 --- a/src/git.cpp +++ b/src/git.cpp @@ -15,6 +15,7 @@ */ #include "git.hpp" + #include "config.hpp" #include "files.hpp" #include "fs-compat.hpp" @@ -153,10 +154,16 @@ void commit(const entry_type &entry) file << json::to_json(entry); file.close(); - if (!entry.screenshot_filepath.empty()) + if (!entry.screenshot_filepaths.empty()) { - const string extension{fs::path(entry.screenshot_filepath).extension()}; - fs::copy(entry.screenshot_filepath, basename + extension); + uint8_t counter{0}; + for (const auto &screenshot : entry.screenshot_filepaths) + { + ++counter; + const string extension{fs::path(screenshot).extension()}; + fs::copy(screenshot, + basename + "-" += to_string(counter) += extension); + } } // Add files. diff --git a/src/json.cpp b/src/json.cpp index 6c2a94b..c182421 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -15,6 +15,7 @@ */ #include "json.hpp" + #include "fs-compat.hpp" #include "types.hpp" @@ -25,13 +26,17 @@ namespace FediBlock::json string to_json(const entry_type &entry) { - const string filename{fs::path(entry.screenshot_filepath).filename()}; + vector filenames; + for (const auto &screenshot : entry.screenshot_filepaths) + { + filenames.push_back(fs::path(screenshot).filename()); + } // clang-format off const nlohmann::json json{{"instance", entry.instance}, {"tags", entry.tags}, {"receipts", entry.receipts}, {"description", entry.description}, - {"screenshot", filename}, + {"screenshots", filenames}, {"report_time", entry.report_time}}; // clang-format on return json.dump(4); @@ -55,7 +60,18 @@ entry_type from_json(const string_view json_string) entry.receipts = json[0].at("receipts").get>(); try { - entry.screenshot_filepath = json[0].at("screenshot").get(); + if (json[0].count("screenshot") == 1) + { + // Compatibility for old entries. + entry.screenshot_filepaths.push_back( + json[0].at("screenshot").get()); + } + else + { + entry.screenshot_filepaths = json[0] + .at("screenshots") + .get>(); + } } #if NLOHMANN_JSON_VERSION_MAJOR >= 3 catch (const nlohmann::detail::out_of_range &) // Ignore missing screenshot. diff --git a/src/types.hpp b/src/types.hpp index 8e3242a..1cb8bc3 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -32,7 +32,7 @@ struct entry_type vector tags; vector receipts; string description; - string screenshot_filepath; + vector screenshot_filepaths; string report_time; };