#include "handlerfeedgenerator.h" #include "../parser.h" std::vector HandlerFeedGenerator::fetchEntries( std::vector categories) { auto revisionDao = this->database->createRevisionDao(); auto pageDao = this->database->createPageDao(); std::vector result; QueryOption option; option.includeInvisible = false; // option.limit = 20; std::set members; if(categories.empty()) { auto pages = pageDao->getPageList(option); std::copy(pages.begin(), pages.end(), std::inserter(members, members.end())); } else { auto categoryDao = this->database->createCategoryDao(); for(std::string cat : categories) { auto catmembers = categoryDao->fetchMembers(cat, option); std::copy(catmembers.begin(), catmembers.end(), std::inserter(members, members.end())); } } for(const std::string &member : members) { auto page = pageDao->find(member).value(); auto revision = revisionDao->getRevisionForPage(page.name, 1).value(); result.push_back({page, revision}); } std::sort(result.begin(), result.end(), [](EntryRevisionPair &a, EntryRevisionPair &b) { return a.second.timestamp > b.second.timestamp; }); const int maxResults = 20; if(result.size() > maxResults) { result.erase(result.begin() + maxResults - 1, result.end()); } return result; } Response HandlerFeedGenerator::generateAtom(const std::vector &entries, std::string filter) { std::stringstream stream; // don't care about offset for now especially since "%z" does not return what we need exactly (with ':') const std::string dateformat = "%Y-%m-%dT%T"; time_t newestPublished = 0; std::string atomfooter = this->templ->loadResolvedPart("feeds/atomfooter"); auto revisionDao = this->database->createRevisionDao(); auto pageDao = this->database->createPageDao(); if(utils::trim(filter).empty()) { filter = "All pages"; } for(const EntryRevisionPair &entry : entries) { const Page &page = entry.first; const Revision &initialRevision = entry.second; Revision current = revisionDao->getCurrentForPage(page.name).value(); std::string url = this->urlProvider->rootUrl() + this->urlProvider->page(page.name); if(initialRevision.timestamp > newestPublished) { newestPublished = initialRevision.timestamp; } std::string entryPublished = utils::formatLocalDate(initialRevision.timestamp, dateformat) + "Z"; std::string entryurl = this->urlProvider->combine({this->urlProvider->rootUrl(), this->urlProvider->page(page.name)}); TemplatePage atomentry = this->templ->getPage("feeds/atomentry"); atomentry.setVar("entrytitle", utils::html_xss(page.title)); atomentry.setVar("entryurl", utils::html_xss(entryurl)); atomentry.setVar("entryid", utils::html_xss(entryurl)); atomentry.setVar("entrypublished", entryPublished); Parser parser; atomentry.setVar("entrycontent", utils::html_xss(parser.parse(*pageDao, *this->urlProvider, current.content))); stream << atomentry.render(); } stream << atomfooter; TemplatePage atomheader = this->templ->getPage("feeds/atomheader"); atomheader.setVar("subtitle", filter); atomheader.setVar("atomfeeduniqueid", utils::html_xss(this->urlProvider->atomFeed(filter))); atomheader.setVar("atomfeedupdate", utils::formatLocalDate(newestPublished, dateformat) + "Z"); Response result; result.setStatus(200); result.setContentType("application/atom+xml"); result.setBody(atomheader.render() + stream.str()); return result; } Response HandlerFeedGenerator::handleRequest(const Request &r) { Response response; try { std::string type = r.get("type"); std::string categories = r.get("cats"); auto entries = fetchEntries(utils::split(categories, ',')); if(type == "atom") { std::string filter = categories; response = generateAtom(entries, filter); } else { return errorResponse("Invalid feed type", "Unknown feed type, try atom", 400); } } catch(std::runtime_error &e) { Logger::error() << "Error while serving feed: " << e.what(); return errorResponse("Error", "An error occured while trying to serve the feed", 500); } return response; } bool HandlerFeedGenerator::canAccess(const Permissions &perms) { return true; }