比较提交
4 次代码提交
next
...
ba06d04a08
作者 | SHA1 | 提交日期 | |
---|---|---|---|
ba06d04a08 | |||
5bb3f55945 | |||
1ae5495e61 | |||
7bb7600d39 |
@ -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>
|
||||||
|
在新工单中引用
屏蔽一个用户