Archived
1
0
This repository has been archived on 2023-08-12. You can view files and clone it, but cannot push or open issues or pull requests.
nntpchan/contrib/backends/nntpchan-daemon/libnntpchan/template_engine.cpp

167 lines
4.6 KiB
C++
Raw Normal View History

2017-10-11 18:48:27 +05:00
#include <nntpchan/template_engine.hpp>
#include <nntpchan/sanitize.hpp>
2017-10-13 16:58:41 +05:00
#include <mstch/mstch.hpp>
2017-10-11 18:48:27 +05:00
#include <iostream>
2017-10-13 16:58:41 +05:00
#include <sstream>
namespace nntpchan
{
2017-10-13 16:58:41 +05:00
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
namespace mustache = mstch;
static mustache::map post_to_map(const nntpchan::model::Post & post)
{
mustache::map m;
mustache::array attachments;
mustache::map h;
for (const auto & att : nntpchan::model::GetAttachments(post))
{
mustache::map a;
a["filename"] = nntpchan::model::GetFilename(att);
a["hexdigest"] = nntpchan::model::GetHexDigest(att);
a["thumbnail"] = nntpchan::model::GetThumbnail(att);
attachments.push_back(a);
}
for (const auto & item : nntpchan::model::GetHeader(post))
{
mustache::array vals;
for(const auto & v : item.second)
vals.push_back(v);
h[item.first] = vals;
}
m["attachments"] = attachments;
m["message"] = nntpchan::model::GetBody(post);
m["header"] = h;
return m;
}
static mustache::map thread_to_map(const nntpchan::model::Thread & t)
{
mustache::map thread;
mustache::array posts;
for(const auto & post : t)
{
posts.push_back(post_to_map(post));
}
auto & opHeader = nntpchan::model::GetHeader(t[0]);
thread["title"] = nntpchan::model::HeaderIFind(opHeader, "subject", "None")[0];
thread["posts"] = posts;
return thread;
}
struct MustacheTemplateEngine : public TemplateEngine
{
struct Impl
{
2017-10-11 18:48:27 +05:00
2017-10-13 16:58:41 +05:00
Impl(const std::map<std::string, std::string> & partials) : m_partials(partials) {}
2017-10-11 18:48:27 +05:00
bool ParseTemplate(const FileHandle_ptr & in)
{
2017-10-13 16:58:41 +05:00
std::stringstream str;
std::string line;
while(std::getline(*in, line))
str << line << "\n";
m_tmplString = str.str();
return in->eof();
2017-10-11 18:48:27 +05:00
}
bool RenderFile(const Args_t & args, const FileHandle_ptr & out)
{
2017-10-13 16:58:41 +05:00
mustache::map obj;
for (const auto & item : args)
{
std::visit(overloaded {
[&obj, item](const nntpchan::model::Model & m) {
std::visit(overloaded {
[&obj, item](const nntpchan::model::BoardPage & p) {
mustache::array threads;
for (const auto & thread : p)
{
threads.push_back(thread_to_map(thread));
}
obj[item.first] = threads;
},
[&obj, item](const nntpchan::model::Thread & t) {
obj[item.first] = thread_to_map(t);
}
}, m);
}
,[&obj, item](const std::string & str) {
obj[item.first] = str;
}
}, item.second);
}
std::string str = mustache::render(m_tmplString, obj);
out->write(str.c_str(), str.size());
out->flush();
return !out->fail();
}
2017-10-11 18:48:27 +05:00
2017-10-13 16:58:41 +05:00
std::string m_tmplString;
const std::map<std::string, std::string> & m_partials;
};
2017-10-11 18:48:27 +05:00
virtual bool WriteTemplate(const fs::path & fpath, const Args_t & args, const FileHandle_ptr & out)
{
2017-10-11 18:48:27 +05:00
auto templFile = OpenFile(fpath, eRead);
if(!templFile)
{
std::clog << "no such template at " << fpath << std::endl;
return false;
}
2017-10-13 16:58:41 +05:00
std::map<std::string, std::string> partials;
if(!LoadPartials(fpath.parent_path(), partials))
{
std::clog << "failed to load partials" << std::endl;
return false;
}
Impl impl(partials);
if(impl.ParseTemplate(templFile))
{
return impl.RenderFile(args, out);
}
2017-10-11 18:48:27 +05:00
std::clog << "failed to parse template " << fpath << std::endl;
return false;
}
2017-10-13 16:58:41 +05:00
bool LoadPartials(fs::path dir, std::map<std::string, std::string> & partials)
{
const auto partial_files = { "header", "footer" };
for(const auto & fname : partial_files)
{
auto file = OpenFile(dir / fs::path(fname + std::string(".html")), eRead);
if(!file) {
std::clog << "no such partial: " << fname << std::endl;
return false;
}
std::string line;
std::stringstream input;
while(std::getline(*file, line))
input << line << "\n";
partials[fname] = input.str();
}
return true;
}
};
TemplateEngine * CreateTemplateEngine(const std::string & dialect)
{
auto d = ToLower(dialect);
if(d == "mustache")
return new MustacheTemplateEngine;
else
return nullptr;
}
}