4 次程式碼提交

共有 13 個檔案被更改,包括 79 行新增27 行删除

查看文件

@ -11,9 +11,15 @@ class DynamicContent
Database *database; Database *database;
UrlProvider *urlProvider; UrlProvider *urlProvider;
std::string argument;
public: public:
DynamicContent(Template &templ, Database &database, UrlProvider &urlProvider); DynamicContent(Template &templ, Database &database, UrlProvider &urlProvider);
virtual std::string render() = 0; virtual std::string render() = 0;
virtual void setArgument(std::string argument)
{
this->argument = argument;
}
virtual ~DynamicContent() virtual ~DynamicContent()
{ {
} }

查看文件

@ -0,0 +1,14 @@
#include "dynamiccontentincludepage.h"
#include "../parser.h"
std::string DynamicContentIncludePage::render()
{
auto revisionDao = this->database->createRevisionDao();
auto rev = revisionDao->getCurrentForPage(this->argument);
if(rev)
{
Parser parser;
auto result = parser.parse(*this->database->createPageDao(), *this->urlProvider, rev->content);
return result;
}
return {};
}

查看文件

@ -0,0 +1,12 @@
#ifndef DYNAMICCONTENTINCLUDEPAGE_H
#define DYNAMICCONTENTINCLUDEPAGE_H
#include "dynamiccontent.h"
class DynamicContentIncludePage : public DynamicContent
{
public:
using DynamicContent::DynamicContent;
std::string render();
};
#endif // DYNAMICCONTENTINCLUDEPAGE_H

查看文件

@ -1,11 +1,6 @@
#include <chrono> #include <chrono>
#include "dynamiccontentpostlist.h" #include "dynamiccontentpostlist.h"
void DynamicContentPostList::setCategory(std::string catname)
{
this->catname = catname;
}
std::string DynamicContentPostList::render() std::string DynamicContentPostList::render()
{ {
auto categoryDao = this->database->createCategoryDao(); auto categoryDao = this->database->createCategoryDao();
@ -13,7 +8,7 @@ std::string DynamicContentPostList::render()
auto revisionDao = this->database->createRevisionDao(); auto revisionDao = this->database->createRevisionDao();
QueryOption option; QueryOption option;
option.includeInvisible = false; option.includeInvisible = false;
auto members = categoryDao->fetchMembers(this->catname, option); auto members = categoryDao->fetchMembers(this->argument, option);
std::vector<std::pair<std::string, time_t>> pageList; std::vector<std::pair<std::string, time_t>> pageList;
for(std::string &member : members) for(std::string &member : members)
{ {

查看文件

@ -4,12 +4,8 @@
#include "dynamiccontent.h" #include "dynamiccontent.h"
class DynamicContentPostList : public DynamicContent class DynamicContentPostList : public DynamicContent
{ {
private:
std::string catname;
public: public:
using DynamicContent::DynamicContent; using DynamicContent::DynamicContent;
void setCategory(std::string catname);
std::string render() override; std::string render() override;
}; };

查看文件

@ -21,6 +21,10 @@ std::vector<HandlerFeedGenerator::EntryRevisionPair> HandlerFeedGenerator::fetch
auto categoryDao = this->database->createCategoryDao(); auto categoryDao = this->database->createCategoryDao();
for(std::string cat : categories) for(std::string cat : categories)
{ {
if(!categoryDao->find(cat))
{
throw std::runtime_error("No such category");
}
auto catmembers = categoryDao->fetchMembers(cat, option); auto catmembers = categoryDao->fetchMembers(cat, option);
std::copy(catmembers.begin(), catmembers.end(), std::inserter(members, members.end())); std::copy(catmembers.begin(), catmembers.end(), std::inserter(members, members.end()));
} }
@ -43,7 +47,7 @@ std::vector<HandlerFeedGenerator::EntryRevisionPair> HandlerFeedGenerator::fetch
return result; return result;
} }
Response HandlerFeedGenerator::generateAtom(const std::vector<HandlerFeedGenerator::EntryRevisionPair> &entries, std::string HandlerFeedGenerator::generateAtom(const std::vector<HandlerFeedGenerator::EntryRevisionPair> &entries,
std::string filter) std::string filter)
{ {
@ -56,9 +60,10 @@ Response HandlerFeedGenerator::generateAtom(const std::vector<HandlerFeedGenerat
auto revisionDao = this->database->createRevisionDao(); auto revisionDao = this->database->createRevisionDao();
auto pageDao = this->database->createPageDao(); auto pageDao = this->database->createPageDao();
std::string subtitle = filter;
if(utils::trim(filter).empty()) if(utils::trim(filter).empty())
{ {
filter = "All pages"; subtitle = "All pages";
} }
for(const EntryRevisionPair &entry : entries) for(const EntryRevisionPair &entry : entries)
@ -72,6 +77,7 @@ Response HandlerFeedGenerator::generateAtom(const std::vector<HandlerFeedGenerat
newestPublished = initialRevision.timestamp; newestPublished = initialRevision.timestamp;
} }
std::string entryPublished = utils::formatLocalDate(initialRevision.timestamp, dateformat) + "Z"; std::string entryPublished = utils::formatLocalDate(initialRevision.timestamp, dateformat) + "Z";
std::string entryUpdated = utils::formatLocalDate(current.timestamp, dateformat) + "Z";
std::string entryurl = std::string entryurl =
this->urlProvider->combine({this->urlProvider->rootUrl(), this->urlProvider->page(page.name)}); this->urlProvider->combine({this->urlProvider->rootUrl(), this->urlProvider->page(page.name)});
TemplatePage atomentry = this->templ->getPage("feeds/atomentry"); TemplatePage atomentry = this->templ->getPage("feeds/atomentry");
@ -79,21 +85,19 @@ Response HandlerFeedGenerator::generateAtom(const std::vector<HandlerFeedGenerat
atomentry.setVar("entryurl", utils::html_xss(entryurl)); atomentry.setVar("entryurl", utils::html_xss(entryurl));
atomentry.setVar("entryid", utils::html_xss(entryurl)); atomentry.setVar("entryid", utils::html_xss(entryurl));
atomentry.setVar("entrypublished", entryPublished); atomentry.setVar("entrypublished", entryPublished);
atomentry.setVar("entryupdated", entryUpdated);
Parser parser; Parser parser;
atomentry.setVar("entrycontent", utils::html_xss(parser.parse(*pageDao, *this->urlProvider, current.content))); atomentry.setVar("entrycontent", utils::html_xss(parser.parse(*pageDao, *this->urlProvider, current.content)));
stream << atomentry.render(); stream << atomentry.render();
} }
stream << atomfooter; stream << atomfooter;
TemplatePage atomheader = this->templ->getPage("feeds/atomheader"); TemplatePage atomheader = this->templ->getPage("feeds/atomheader");
atomheader.setVar("subtitle", filter); atomheader.setVar("subtitle", subtitle);
atomheader.setVar("atomfeeduniqueid", utils::html_xss(this->urlProvider->atomFeed(filter))); 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"); atomheader.setVar("atomfeedupdate", utils::formatLocalDate(newestPublished, dateformat) + "Z");
return atomheader.render() + stream.str();
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 HandlerFeedGenerator::handleRequest(const Request &r)
@ -103,12 +107,26 @@ Response HandlerFeedGenerator::handleRequest(const Request &r)
{ {
std::string type = r.get("type"); std::string type = r.get("type");
std::string categories = r.get("cats"); std::string categories = r.get("cats");
auto entries = fetchEntries(utils::split(categories, ','));
if(type == "atom") if(type == "atom")
{ {
std::string filter = categories; std::string filter = categories;
response = generateAtom(entries, filter); 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 else
{ {

查看文件

@ -9,7 +9,7 @@ class HandlerFeedGenerator : public Handler
protected: protected:
std::vector<EntryRevisionPair> fetchEntries(std::vector<std::string> categories); std::vector<EntryRevisionPair> fetchEntries(std::vector<std::string> categories);
Response generateAtom(const std::vector<EntryRevisionPair> &entries, std::string atomtitle); std::string generateAtom(const std::vector<EntryRevisionPair> &entries, std::string atomtitle);
Response generateRss(const std::vector<EntryRevisionPair> &entries); Response generateRss(const std::vector<EntryRevisionPair> &entries);
public: public:

查看文件

@ -45,6 +45,7 @@ Response HandlerPageDelete::handleRequest(PageDao &pageDao, std::string pagename
{ {
pageDao.deletePage(pagename); pageDao.deletePage(pagename);
this->cache->removePrefix("page:"); // TODO: overkill? this->cache->removePrefix("page:"); // TODO: overkill?
this->cache->removePrefix("feed:");
return Response::redirectTemporarily(this->urlProvider->index()); return Response::redirectTemporarily(this->urlProvider->index());
} }
TemplatePage delPage = this->templ->getPage("page_deletion"); TemplatePage delPage = this->templ->getPage("page_deletion");

查看文件

@ -101,6 +101,7 @@ Response HandlerPageEdit::handleRequest(PageDao &pageDao, std::string pagename,
pageDao.setCategories(pagename, cats); pageDao.setCategories(pagename, cats);
this->database->commitTransaction(); this->database->commitTransaction();
this->cache->removePrefix("page:"); // TODO: overkill? this->cache->removePrefix("page:"); // TODO: overkill?
this->cache->removePrefix("feed:");
} }
catch(const DatabaseException &e) catch(const DatabaseException &e)
{ {

查看文件

@ -24,6 +24,7 @@ SOFTWARE.
#include "../parser.h" #include "../parser.h"
#include "../htmllink.h" #include "../htmllink.h"
#include "../dynamic/dynamiccontentpostlist.h" #include "../dynamic/dynamiccontentpostlist.h"
#include "../dynamic/dynamiccontentincludepage.h"
bool HandlerPageView::canAccess(std::string page) bool HandlerPageView::canAccess(std::string page)
{ {
return effectivePermissions(page).canRead(); return effectivePermissions(page).canRead();
@ -142,9 +143,15 @@ Response HandlerPageView::handleRequest(PageDao &pageDao, std::string pagename,
if(key == "dynamic:postlist") if(key == "dynamic:postlist")
{ {
std::shared_ptr<DynamicContentPostList> postlist = createDynamic<DynamicContentPostList>(); std::shared_ptr<DynamicContentPostList> postlist = createDynamic<DynamicContentPostList>();
postlist->setCategory(std::string(value)); postlist->setArgument(std::string(value));
return postlist->render(); return postlist->render();
} }
if(key == "dynamic:includepage")
{
std::shared_ptr<DynamicContentIncludePage> includePage = createDynamic<DynamicContentIncludePage>();
includePage->setArgument(std::string(value));
return includePage->render();
}
return std::string{}; return std::string{};
}; };
if(revisionid > 0) if(revisionid > 0)

查看文件

@ -122,7 +122,7 @@ std::string Parser::parse(const PageDao &pagedao, UrlProvider &provider, const s
std::string result; std::string result;
// we don't care about commands, but we nevertheless replace them with empty strings // we don't care about commands, but we nevertheless replace them with empty strings
std::regex tagfinder( std::regex tagfinder(
R"(\[(b|i|u|li||ul|ol|link|wikilink|h\d|cmd:rename|cmd:redirect|cmd:pagetitle|category|dynamic:postlist)*?\]((\s|\S)*?)\[/\1])"); R"(\[(b|i|u|li||ul|ol|link|wikilink|h\d|cmd:rename|cmd:redirect|cmd:pagetitle|category|dynamic:postlist|dynamic:includepage)*?\]((\s|\S)*?)\[/\1])");
result = utils::regex_callback_replacer( result = utils::regex_callback_replacer(
tagfinder, content, tagfinder, content,
[&](std::smatch &match) [&](std::smatch &match)

查看文件

@ -3,5 +3,6 @@
<link href="{qswiki:var:entryurl}"/> <link href="{qswiki:var:entryurl}"/>
<id>{qswiki:var:entryid}</id> <id>{qswiki:var:entryid}</id>
<published>{qswiki:var:entrypublished}</published> <published>{qswiki:var:entrypublished}</published>
<updated>{qswiki:var:entryupdated}</updated>
<content type="html">{qswiki:var:entrycontent}</content> <content type="html">{qswiki:var:entrycontent}</content>
</entry> </entry>

查看文件

@ -5,4 +5,5 @@
</author> </author>
<title>{qswiki:config:wikiname} - {qswiki:var:subtitle}</title> <title>{qswiki:config:wikiname} - {qswiki:var:subtitle}</title>
<id>{qswiki:var:atomfeeduniqueid}</id> <id>{qswiki:var:atomfeeduniqueid}</id>
<link rel="self" href="{qswiki:var:atomselflink}"/>
<updated>{qswiki:var:atomfeedupdate}</updated> <updated>{qswiki:var:atomfeedupdate}</updated>