Any small change on a page "updates" the feed, which is misleading to clients. May need "minor edit" or something. For now, get rid of it.
		
			
				
	
	
		
			158 lignes
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			158 lignes
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "handlerfeedgenerator.h"
 | |
| #include "../revisionrenderer.h"
 | |
| std::vector<HandlerFeedGenerator::EntryRevisionPair> HandlerFeedGenerator::fetchEntries(
 | |
| 	std::vector<std::string> categories)
 | |
| {
 | |
| 	auto revisionDao = this->database->createRevisionDao();
 | |
| 	auto pageDao = this->database->createPageDao();
 | |
| 	auto permissionDao = this->database->createPermissionsDao();
 | |
| 
 | |
| 	std::vector<EntryRevisionPair> result;
 | |
| 	QueryOption option;
 | |
| 	option.includeUnlisted = true;
 | |
| 	// option.limit = 20;
 | |
| 
 | |
| 	auto comppage = [](const Page &a, const Page &b) { return a.name < b.name; };
 | |
| 	std::set<Page, decltype(comppage)> members(comppage);
 | |
| 	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)
 | |
| 		{
 | |
| 			if(!categoryDao->find(cat))
 | |
| 			{
 | |
| 				throw std::runtime_error("No such category");
 | |
| 			}
 | |
| 			auto catmembers = categoryDao->fetchMembers(cat, option);
 | |
| 			std::copy(catmembers.begin(), catmembers.end(), std::inserter(members, members.end()));
 | |
| 		}
 | |
| 	}
 | |
| 	for(const Page &member : members)
 | |
| 	{
 | |
| 		if(member.feedlisted)
 | |
| 		{
 | |
| 			Permissions perms = permissionDao->find(member.name, this->userSession->user.login)
 | |
| 									.value_or(this->userSession->user.permissions);
 | |
| 			if(perms.canRead())
 | |
| 			{
 | |
| 				auto revision = revisionDao->getRevisionForPage(member.name, 1).value();
 | |
| 				result.push_back({member, 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;
 | |
| }
 | |
| 
 | |
| std::string HandlerFeedGenerator::generateAtom(const std::vector<HandlerFeedGenerator::EntryRevisionPair> &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();
 | |
| 
 | |
| 	std::string subtitle = filter;
 | |
| 	if(utils::trim(filter).empty())
 | |
| 	{
 | |
| 		subtitle = "All pages";
 | |
| 	}
 | |
| 
 | |
| 	RevisionRenderer revisionRenderer{*this->templ, *this->database, *this->urlProvider, *this->userSession};
 | |
| 
 | |
| 	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", page.title);
 | |
| 		atomentry.setVar("entryurl", utils::html_xss(entryurl));
 | |
| 		atomentry.setVar("entryid", utils::html_xss(entryurl));
 | |
| 		atomentry.setVar("entrypublished", entryPublished);
 | |
| 		atomentry.setVar("entryupdated", entryPublished);
 | |
| 		atomentry.setVar("entrycontent", utils::html_xss(revisionRenderer.renderContent(current, page.title)));
 | |
| 		stream << atomentry.render();
 | |
| 	}
 | |
| 	stream << atomfooter;
 | |
| 	TemplatePage atomheader = this->templ->getPage("feeds/atomheader");
 | |
| 	atomheader.setVar("subtitle", subtitle);
 | |
| 	std::string selflink = utils::html_xss(this->urlProvider->atomFeed(filter));
 | |
| 	atomheader.setVar("atomfeeduniqueid", selflink);
 | |
| 	atomheader.setVar("atomselflink", selflink);
 | |
| 	atomheader.setVar("atomfeedupdate", utils::formatLocalDate(newestPublished, dateformat) + "Z");
 | |
| 	return atomheader.render() + stream.str();
 | |
| }
 | |
| 
 | |
| Response HandlerFeedGenerator::handleRequest(const Request &r)
 | |
| {
 | |
| 	Response response;
 | |
| 	try
 | |
| 	{
 | |
| 		std::string type = r.get("type");
 | |
| 		std::string categories = r.get("cats");
 | |
| 		if(type == "atom")
 | |
| 		{
 | |
| 			std::string filter = categories;
 | |
| 			Response result;
 | |
| 			result.setStatus(200);
 | |
| 			result.setContentType("application/atom+xml");
 | |
| 			std::string cacheKey = "feed:atom:" + filter;
 | |
| 			auto cached = this->cache->get(cacheKey);
 | |
| 			if(cached)
 | |
| 			{
 | |
| 				result.setBody(cached.value());
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				auto entries = fetchEntries(utils::split(categories, ','));
 | |
| 				std::string feed = generateAtom(entries, filter);
 | |
| 				result.setBody(feed);
 | |
| 				this->cache->put(cacheKey, feed);
 | |
| 			}
 | |
| 			response = result;
 | |
| 		}
 | |
| 		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;
 | |
| }
 |