diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2021-10-14 18:41:55 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2021-10-14 18:41:55 +0200 |
commit | 51d9d23c99d77edad03e6425f3ab35a390156117 (patch) | |
tree | 82b632c2aac22c3d79f43e427f311a46591f30ca /src/content/blog | |
parent | f0f4b8a4d139a855ad15f9d79190edf6320eba51 (diff) |
Blog Metadata parsing, validationa and templating.
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
Diffstat (limited to 'src/content/blog')
-rw-r--r-- | src/content/blog/Blog.cpp | 138 | ||||
-rw-r--r-- | src/content/blog/Blog.hpp | 28 |
2 files changed, 157 insertions, 9 deletions
diff --git a/src/content/blog/Blog.cpp b/src/content/blog/Blog.cpp index b473bf3..1893cc5 100644 --- a/src/content/blog/Blog.cpp +++ b/src/content/blog/Blog.cpp @@ -1,11 +1,13 @@ #include "Blog.hpp" +#include <filesystem> + Blog::Blog(std::string uriBasePath, std::string mainTemplatePath, std::string blogPath) : Content(), m_UriBasePath(uriBasePath), m_MainTemplatePath(mainTemplatePath), m_BlogPath(blogPath), - m_BlogEntries("", blogPath) + m_BlogContents("", blogPath) { m_Redirections.push_back(uriBasePath + "/"); m_Redirections.push_back(uriBasePath + "/index.html"); @@ -13,25 +15,48 @@ Blog::Blog(std::string uriBasePath, std::string mainTemplatePath, std::string bl bool Blog::Init() { - std::cout << "Blog entries path: " << m_BlogPath << std::endl; + bool retval = true; + std::cout << "Blog entries path: " << m_BlogPath << std::endl; std::vector<std::string> extensions = {"json"}; - if (m_BlogEntriesMetadata.Scan(m_BlogPath, extensions, false) == false) + Filesystem fs; + if (fs.Scan(m_BlogPath, extensions, false) == false) { return false; } - m_BlogEntries.Init(); + for (auto const & jfile : fs.GetFiles()) + { + auto const json_metadata = inja::json::parse(jfile.second.data); + BlogEntry be = + std::make_shared<struct blog_entry>(jfile.first, + std::string(std::filesystem::path(jfile.first).stem()) + ".md"); + if (Blog::ValidateAndSetMetdadata(json_metadata, be) == false) + { + std::cerr << "Blog Metadata validation failed." << std::endl; + retval = false; + } + m_BlogEntriesSortedByDate.push_back(be); - return true; + m_Redirections.push_back(std::filesystem::path(jfile.first).stem()); + } + + m_BlogContents.Init(); + + if (retval == false) + { + return false; + } + + return ValidateEntries(); } void Blog::Shutdown() { std::cout << "Blog module shutdown" << std::endl; - m_BlogEntries.Shutdown(); + m_BlogContents.Shutdown(); } bool Blog::Render(RequestResponse & rr, RenderData & rd, std::string & out) @@ -40,7 +65,15 @@ bool Blog::Render(RequestResponse & rr, RenderData & rd, std::string & out) (void)rd; (void)out; - rd["blah"] = "Yooooh!"; + if (rr.GetUriPath() == m_UriBasePath || rr.GetUriPath() == m_UriBasePath + "/" || + rr.GetUriPath() == m_UriBasePath + "/index.html") + { + GenerateBlogListing(rd["blog_listing"]); + } + else + { + rd["blog_content"] = "bla"; + } return true; } @@ -59,3 +92,94 @@ Redirections const & Blog::GetRedirections() const { return m_Redirections; } + +bool Blog::ValidateAndSetMetdadata(BlogMetadata const & blogMetadata, BlogEntry & blogEntry) +{ + bool retval = true; + std::function<bool(BlogMetadata const &, std::string const)> validateMetadata = + [blogEntry](BlogMetadata const & bm, std::string const tname) { + if (bm.find(tname) == bm.cend()) + { + std::cerr << "Metadata validation: JSON key '" << tname << "' missing in " + << blogEntry->metadata_filename << std::endl; + return false; + } + return true; + }; + std::function<bool(std::string const &, std::time_t &)> parseDateTime = [](std::string const & timeStr, + std::time_t & time) { + std::tm tm = {}; + std::stringstream ss(timeStr); + ss >> std::get_time(&tm, "%d.%m.%y %H:%M"); + time = std::mktime(&tm); + if (time <= 0) + { + std::cerr << "Metadata validation: Invalid time string '" << timeStr + << "', format required: '%d.%m.%y %H:%M'" << std::endl; + return false; + } + return true; + }; + + if (validateMetadata(blogMetadata, "createDate") == false || + parseDateTime(blogMetadata["createDate"], blogEntry->createDate) == false) + { + retval = false; + } + + if (validateMetadata(blogMetadata, "publishDate") == false || + parseDateTime(blogMetadata["publishDate"], blogEntry->publishDate) == false) + { + retval = false; + } + + if (validateMetadata(blogMetadata, "published") == false) + { + retval = false; + } + blogEntry->published = blogMetadata["published"]; + + return retval; +} + +bool Blog::ValidateEntries() const +{ + bool retval = true; + + for (auto const & e : m_BlogEntriesSortedByDate) + { + if (m_BlogContents.HasMarkdownFile(e->content_filename) == false) + { + std::cerr << "Blog entry metadata " << e->metadata_filename << " exists, but markdown file " + << e->content_filename << " not." << std::endl; + retval = false; + } + } + for (auto const & m : m_BlogContents.GetMarkdowns()) + { + if (std::any_of(m_BlogEntriesSortedByDate.cbegin(), + m_BlogEntriesSortedByDate.cend(), + [m](BlogEntry const & be) { return m.first == be->content_filename; }) == false) + { + std::cerr << "Blog entry markdown " << m.first << " exists, but metadata not." << std::endl; + retval = false; + } + } + + return retval; +} + +void Blog::GenerateBlogListing(RenderData & rd) const +{ + for (auto const & e : m_BlogEntriesSortedByDate) + { + RenderData re; + re["metadata_filename"] = e->metadata_filename; + re["content_filename"] = e->content_filename; + re["createDate"] = e->createDate; + re["publishDate"] = e->publishDate; + re["published"] = e->published; + + rd += re; + } +} diff --git a/src/content/blog/Blog.hpp b/src/content/blog/Blog.hpp index 970c7fd..a0e35b1 100644 --- a/src/content/blog/Blog.hpp +++ b/src/content/blog/Blog.hpp @@ -1,10 +1,30 @@ #ifndef BLOG_H #define BLOG_H 1 +#include <inja/inja.hpp> + #include "../../Content.hpp" #include "../../Filesystem.hpp" #include "../markdown/Markdown.hpp" +struct blog_entry +{ + explicit blog_entry(std::string const & metadata_filename, std::string const & content_filename) + : metadata_filename(metadata_filename), content_filename(content_filename) + { + } + + std::string const metadata_filename; + std::string const content_filename; + std::time_t createDate; + std::time_t publishDate; + bool published; +}; + +using BlogMetadata = inja::json; +using BlogEntry = std::shared_ptr<struct blog_entry>; +using BlogEntries = std::vector<BlogEntry>; + class Blog : public Content { public: @@ -18,13 +38,17 @@ public: std::string const & GetMainTemplate() const; Redirections const & GetRedirections() const; + static bool ValidateAndSetMetdadata(BlogMetadata const & blogMetadata, BlogEntry & blogEntry); + bool ValidateEntries() const; + void GenerateBlogListing(RenderData & rd) const; + private: std::string m_UriBasePath; std::string m_MainTemplatePath; std::string m_BlogPath; Redirections m_Redirections; - Filesystem m_BlogEntriesMetadata; - Markdown m_BlogEntries; + Markdown m_BlogContents; + BlogEntries m_BlogEntriesSortedByDate; }; #endif |