diff options
author | Roland Reichwein <mail@reichwein.it> | 2020-04-22 19:29:37 +0200 |
---|---|---|
committer | Roland Reichwein <mail@reichwein.it> | 2020-04-22 19:29:37 +0200 |
commit | 1560d0efec6876ef8e820c5ec72bea6098f99870 (patch) | |
tree | 0eff46f0e3ea201b087b34110cb21c10748a1105 | |
parent | ef7ed9034bebe80a429112930ab0481c8aa66c95 (diff) |
weblog (wip)
-rw-r--r-- | plugins/weblog/weblog.cpp | 73 |
1 files changed, 63 insertions, 10 deletions
diff --git a/plugins/weblog/weblog.cpp b/plugins/weblog/weblog.cpp index 0c0ffcd..38d6dec 100644 --- a/plugins/weblog/weblog.cpp +++ b/plugins/weblog/weblog.cpp @@ -1,6 +1,8 @@ #include "weblog.h" #include <boost/algorithm/string/predicate.hpp> +#include <boost/property_tree/ptree.hpp> +#include <boost/property_tree/xml_parser.hpp> #include <algorithm> #include <filesystem> @@ -10,6 +12,7 @@ using namespace std::string_literals; namespace fs = std::filesystem; +namespace pt = boost::property_tree; namespace { @@ -82,6 +85,12 @@ namespace { return (rel_target.size() == 0 || rel_target == "/"); } + bool is_index_file(std::string& rel_target, fs::path& path) + { + // must be top-level file, recognized as mime_type() + return rel_target.find("/") == rel_target.npos && mime_type(path) != "application/text"; + } + bool is_article_page(std::string& rel_target, fs::path& path) { return (rel_target.size() >= 2 && rel_target.back() == '/' && fs::is_directory(path)); @@ -146,9 +155,12 @@ namespace { std::vector<ArticleInfo> result; for (auto& year_entry: fs::directory_iterator(path)) { - for (auto& entry: fs::directory_iterator(year_entry.path())) { - auto metaData{getMetaData(entry.path())}; - result.emplace_back(ArticleInfo{entry.path(), metaData.at("Subject"), metaData.at("Date")}); + std::string year_entry_filename{year_entry.path().filename().string()}; + if (fs::is_directory(year_entry)) { + for (auto& entry: fs::directory_iterator(year_entry.path())) { + auto metaData{getMetaData(entry.path())}; + result.emplace_back(ArticleInfo{entry.path(), metaData.at("Subject"), metaData.at("Date")}); + } } } @@ -159,19 +171,60 @@ namespace { return {result.begin(), result.begin() + size}; } + // returns plain text of string (xml elements removed) + std::string plainText(const std::string& text) + { + pt::ptree tree; + + std::istringstream ss{text}; + //pt::read_xml(ss, tree, pt::xml_parser::no_comments | pt::xml_parser::trim_whitespace); + + //std::cout << "DEBUG: " << tree.get<std::string>("file") << std::endl; + + return text; + } + + // returns teaser of article in plain text + std::string shortVersion(const fs::path& path) + { + std::string article {getFile(path / article_filename)}; + size_t pos0 {article.find("\n\n")}; + if (pos0 == article.npos) + return ""; + + article = "<file>" + article.substr(pos0 + 2) + "</file>"; + + article = plainText(article); + + size_t pos1 {article.find(".")}; + + size_t num {std::min(static_cast<size_t>(1000), pos1) + 1}; + + return article.substr(0, num); + } + std::string generateIndexPage(fs::path& path, std::function<std::string(const std::string& key)>& GetRequestParam, std::function<plugin_interface_setter_type>& SetResponseHeader) { try { - std::string result{"<html><body><h1>"s + GetRequestParam("WEBLOG_NAME") + "</h1>"s}; + std::string result{"<!DOCTYPE html><html><head><meta charset=\"utf-8\"/></head><body><h1>"s + GetRequestParam("WEBLOG_NAME") + "</h1>"s}; fs::path link{ GetRequestParam("rel_target")}; auto list{getArticleList(path)}; for (const auto& article: list) { - result += "<h2><a href=\"" + (link / article.path.filename()).string() + "/\">"s + article.subject + "</a></h2>"s + article.date + "<br/>"s; + std::string linkstart{"<a href=\"" + (link / article.path.filename()).string() + "/\">"}; + std::string linkend{"</a>"}; + result += "<h2>"s + linkstart + article.subject + linkend + "</h2>"s + article.date + "<br/>"s; + + auto sv{shortVersion(article.path)}; + if (sv.size()) { + result += sv + " "s + linkstart + "more..." + linkend; + } } + result += "<br/><br/><br/>"; + result += "<a href=\"impressum.html\">Impressum</a>"; result += "</body></html>"; return result; } catch (const std::exception& ex) { @@ -191,7 +244,7 @@ namespace { if (pos == data.npos) throw std::runtime_error("Error parsing article"); - std::string result { "<html><body><h1>"s + metaData.at("Subject") + "</h1>"s + metaData.at("Date") + "<br/><br/>"s + data.substr(pos + 2) + "</body></html>"s}; + std::string result { "<!DOCTYPE html><html><head><meta charset=\"utf-8\"/></head><body><h1>"s + metaData.at("Subject") + "</h1>"s + metaData.at("Date") + "<br/><br/>"s + data.substr(pos + 2) + "</body></html>"s}; return result; } catch (const std::exception& ex) { @@ -199,7 +252,7 @@ namespace { } } - std::string generateArticleFile(fs::path& path, std::function<plugin_interface_setter_type>& SetResponseHeader) + std::string generateStaticFile(fs::path& path, std::function<plugin_interface_setter_type>& SetResponseHeader) { try { SetResponseHeader("content_type", mime_type(path)); @@ -247,7 +300,7 @@ std::string weblog_plugin::generate_page( // Build the path to the requested file std::string doc_root{GetRequestParam("doc_root")}; - if (rel_target.size() >= 4 && std::for_each(rel_target.begin(), rel_target.begin() + 4, isdigit)) { + if (rel_target.size() >= 4 && std::all_of(rel_target.begin(), rel_target.begin() + 4, isdigit)) { rel_target = rel_target.substr(0, 4) + "/" + rel_target; } fs::path path {fs::path{doc_root} / rel_target}; @@ -265,8 +318,8 @@ std::string weblog_plugin::generate_page( if (is_article_page(rel_target, path)) return generateArticlePage(path, SetResponseHeader); - if (is_article_file(rel_target, path)) - return generateArticleFile(path, SetResponseHeader); + if (is_index_file(rel_target, path) || is_article_file(rel_target, path)) + return generateStaticFile(path, SetResponseHeader); return HttpStatus("404", "Bad path specification: "s + rel_target, SetResponseHeader); |