indexer.cpp (4602B)
1 #include <algorithm> 2 #include <ctime> 3 #include <format> 4 #include <iomanip> 5 #include <iterator> 6 #include <ostream> 7 #include <sstream> 8 #include <string> 9 10 #include "indexer.hpp" 11 12 #include <hemplate/attribute.hpp> 13 #include <hemplate/classes.hpp> 14 15 #include "article.hpp" 16 17 namespace stamd { 18 19 void Indexer::add(const article_s& article) 20 { 21 m_articles.emplace_back(article); 22 } 23 24 void Indexer::add(categories_t categories) 25 { 26 m_categories.merge(categories); 27 } 28 29 void Indexer::sort() 30 { 31 std::sort(begin(m_articles), 32 end(m_articles), 33 [](const auto& lft, const auto& rht) 34 { return lft->get_date() > rht->get_date(); }); 35 } 36 37 int64_t parse_time(const std::string& date) 38 { 39 std::tm tms = {}; 40 std::stringstream stream(date); 41 stream >> std::get_time(&tms, "%Y-%m-%d"); 42 return std::mktime(&tms); 43 } 44 45 void Indexer::create_index(std::ostream& ost, const std::string& name) 46 { 47 using namespace hemplate; // NOLINT 48 49 const Article index(name, m_options, m_categories); 50 51 index.write_header(ost); 52 ost << html::h1(name); 53 ost << html::ul().set("class", "index"); 54 for (const auto& article : m_articles) 55 { 56 if (article->is_hidden()) continue; 57 58 const auto& filename = article->get_filename(); 59 const auto& title = article->get_title(); 60 const auto& date = article->get_date(); 61 62 ost << html::li() 63 .add(html::span(date + " - ")) 64 .add(html::a(title).set("href", filename)); 65 }; 66 ost << html::ul(); 67 index.write_footer(ost); 68 } 69 70 void Indexer::create_atom(std::ostream& ost, const std::string& name) const 71 { 72 using namespace hemplate; // NOLINT 73 74 const std::string& base_url = m_options.base_url; 75 76 ost << xml(); 77 ost << atom::feed(); 78 ost << atom::title(name); 79 ost << atom::id(base_url); 80 ost << atom::updated(atom::format_time_now()); 81 ost << atom::author().add(atom::name(name)); 82 ost << atom::link(" ", 83 {{"rel", "self"}, {"href", base_url + "blog/atom.xml"}}); 84 ost << atom::link( 85 " ", {{"href", base_url}, {"rel", "alternate"}, {"type", "text/html"}}); 86 87 for (const auto& article : m_articles) 88 { 89 const auto filename = article->get_filename(); 90 const auto title = article->get_title(); 91 const auto date = article->get_date(); 92 const auto summary = article->get("summary").value_or(m_options.summary); 93 94 ost << atom::entry() 95 .add(atom::title(title)) 96 .add(atom::id(base_url + filename)) 97 .add(atom::link(" ").set("href", base_url + filename)) 98 .add(atom::updated(atom::format_time(parse_time((date))))) 99 .add(atom::summary(summary)); 100 } 101 102 ost << atom::feed(); 103 } 104 105 void Indexer::create_rss(std::ostream& ost, const std::string& name) const 106 { 107 using namespace hemplate; // NOLINT 108 109 const std::string& base_url = m_options.base_url; 110 const std::string& description = m_options.description; 111 112 ost << xml(); 113 ost << rss::rss(); 114 ost << rss::channel(); 115 116 ost << rss::title(name); 117 ost << rss::link(base_url); 118 ost << rss::description(description); 119 ost << rss::generator("stamd"); 120 ost << rss::language("en-us"); 121 ost << rss::atomLink().set("href", base_url + "blog/rss.xml"); 122 123 for (const auto& article : m_articles) 124 { 125 const auto filename = article->get_filename(); 126 const auto date = article->get_date(); 127 const auto author = article->get("author").value_or(m_options.author); 128 const auto email = article->get("email").value_or(m_options.email); 129 130 ost << rss::item() 131 .add(rss::title(filename)) 132 .add(rss::link(base_url + filename)) 133 .add(rss::guid(base_url + filename)) 134 .add(rss::pubDate(rss::format_time(parse_time(date)))) 135 .add(rss::author(std::format("{} ({})", email, author))); 136 } 137 138 ost << rss::channel(); 139 ost << rss::rss(); 140 } 141 142 void Indexer::create_sitemap(std::ostream& ost) const 143 { 144 using namespace hemplate; // NOLINT 145 146 static const std::string& base_url = m_options.base_url; 147 148 ost << xml(); 149 ost << sitemap::urlset(); 150 for (const auto& article : m_articles) 151 { 152 const auto& filename = article->get_filename(); 153 const auto& date = article->get_date(); 154 155 ost << sitemap::url() 156 .add(sitemap::loc(base_url + filename)) 157 .add(sitemap::lastmod(date)); 158 } 159 ost << sitemap::urlset(); 160 } 161 162 void Indexer::create_robots(std::ostream& ost) const 163 { 164 static const std::string& base_url = m_options.base_url; 165 166 ost << "User-agent: *"; 167 ost << std::format("Sitemap: {}/sitemap.xml", base_url); 168 } 169 170 } // namespace stamd