Compare commits
11 Commits
f08e235d03
...
61e84a98c7
Author | SHA1 | Date | |
---|---|---|---|
61e84a98c7 | |||
61f289625c | |||
6a12070d0d | |||
03c6816528 | |||
18f4ad9d51 | |||
84adaa934a | |||
579fadfb10 | |||
ff01a00217 | |||
daed17848c | |||
0fb0457dbb | |||
2d5d483790 |
1
cache/mapcache.h
vendored
1
cache/mapcache.h
vendored
@ -4,6 +4,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
/* Thread-Safe Key-Value store */
|
/* Thread-Safe Key-Value store */
|
||||||
template <class T> class MapCache
|
template <class T> class MapCache
|
||||||
|
@ -102,23 +102,27 @@ std::vector<Page> CategoryDaoSqlite::fetchMembers(std::string name, QueryOption
|
|||||||
|
|
||||||
SqliteQueryOption queryOption{o};
|
SqliteQueryOption queryOption{o};
|
||||||
std::string queryoptions =
|
std::string queryoptions =
|
||||||
queryOption.setOrderByColumn("name").setVisibleColumnName("page.visible").setPrependWhere(false).build();
|
queryOption.setOrderByColumn("name").setListedColumnName("page.listed").setPrependWhere(false).build();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto query = *db << "SELECT page.id, page.name AS name, page.title, page.lastrevision, page.visible FROM "
|
auto query =
|
||||||
"categorymember INNER JOIN page ON page.id = "
|
*db
|
||||||
"categorymember.page WHERE category = (SELECT id FROM category WHERE name = ? ) AND " +
|
<< "SELECT page.id, page.name AS name, page.title, page.lastrevision, page.listed, page.feedlisted FROM "
|
||||||
queryoptions
|
"categorymember INNER JOIN page ON page.id = "
|
||||||
<< name;
|
"categorymember.page WHERE category = (SELECT id FROM category WHERE name = ? ) AND " +
|
||||||
query >> [&](unsigned int id, std::string name, std::string title, unsigned int lastrevision, bool visible)
|
queryoptions
|
||||||
|
<< name;
|
||||||
|
query >> [&](unsigned int id, std::string name, std::string title, unsigned int lastrevision, bool listed,
|
||||||
|
bool feedlisted)
|
||||||
{
|
{
|
||||||
Page p;
|
Page p;
|
||||||
p.name = name;
|
p.name = name;
|
||||||
p.pageid = id;
|
p.pageid = id;
|
||||||
p.title = title;
|
p.title = title;
|
||||||
p.current_revision = lastrevision;
|
p.current_revision = lastrevision;
|
||||||
p.listed = visible;
|
p.listed = listed;
|
||||||
|
p.feedlisted = feedlisted;
|
||||||
result.push_back(p);
|
result.push_back(p);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ class PageDao
|
|||||||
virtual void setCategories(std::string pagename, const std::vector<std::string> &catnames) = 0;
|
virtual void setCategories(std::string pagename, const std::vector<std::string> &catnames) = 0;
|
||||||
virtual std::vector<SearchResult> search(std::string query, QueryOption option) = 0;
|
virtual std::vector<SearchResult> search(std::string query, QueryOption option) = 0;
|
||||||
|
|
||||||
|
virtual std::vector<std::string> getChildren(std::string pagename) = 0;
|
||||||
|
|
||||||
virtual ~PageDao()
|
virtual ~PageDao()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -57,8 +57,12 @@ std::optional<Page> PageDaoSqlite::findByTitle(std::string title)
|
|||||||
Page result;
|
Page result;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto ps = *db << "SELECT id, name, title, lastrevision, visible FROM page WHERE title = ?";
|
auto ps =
|
||||||
ps << title >> std::tie(result.pageid, result.name, result.title, result.current_revision, result.listed);
|
*db
|
||||||
|
<< "SELECT id, name, title, lastrevision, listed, feedlisted, (SELECT name FROM page WHERE id = parent) "
|
||||||
|
"FROM page WHERE title = ?";
|
||||||
|
ps << title >> std::tie(result.pageid, result.name, result.title, result.current_revision, result.listed,
|
||||||
|
result.feedlisted, result.parentpage);
|
||||||
}
|
}
|
||||||
catch(const sqlite::errors::no_rows &e)
|
catch(const sqlite::errors::no_rows &e)
|
||||||
{
|
{
|
||||||
@ -78,9 +82,13 @@ std::optional<Page> PageDaoSqlite::find(unsigned int id)
|
|||||||
result.pageid = id;
|
result.pageid = id;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto ps = *db << "SELECT name, title, lastrevision, visible FROM page WHERE id = ?";
|
auto ps =
|
||||||
|
*db
|
||||||
|
<< "SELECT name, title, lastrevision, listed, feedlisted, (SELECT name FROM page WHERE id = parent) FROM "
|
||||||
|
"page WHERE id = ?";
|
||||||
|
|
||||||
ps << id >> std::tie(result.name, result.title, result.current_revision, result.listed);
|
ps << id >> std::tie(result.name, result.title, result.current_revision, result.listed, result.feedlisted,
|
||||||
|
result.parentpage);
|
||||||
}
|
}
|
||||||
catch(const sqlite::errors::no_rows &e)
|
catch(const sqlite::errors::no_rows &e)
|
||||||
{
|
{
|
||||||
@ -118,10 +126,10 @@ void PageDaoSqlite::save(const Page &page)
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
*db << "INSERT OR REPLACE INTO page (id, name, title, lastrevision, visible) VALUES((SELECT id FROM page WHERE "
|
*db << "INSERT OR REPLACE INTO page (id, name, title, lastrevision, listed, feedlisted, parent) VALUES((SELECT "
|
||||||
"name = "
|
"id FROM page WHERE name = ? OR id = ?), ?, ?, ?, ?, ?, (SELECT id FROM page WHERE name = ?))"
|
||||||
"? OR id = ?), ?, ?, ?, ?)"
|
<< page.name << page.pageid << page.name << page.title << page.current_revision << page.listed
|
||||||
<< page.name << page.pageid << page.name << page.title << page.current_revision << page.listed;
|
<< page.feedlisted << page.parentpage;
|
||||||
}
|
}
|
||||||
catch(sqlite::sqlite_exception &e)
|
catch(sqlite::sqlite_exception &e)
|
||||||
{
|
{
|
||||||
@ -137,19 +145,23 @@ std::vector<Page> PageDaoSqlite::getPageList(QueryOption option)
|
|||||||
{
|
{
|
||||||
std::string queryOption = SqliteQueryOption(option)
|
std::string queryOption = SqliteQueryOption(option)
|
||||||
.setOrderByColumn("lower(name)")
|
.setOrderByColumn("lower(name)")
|
||||||
.setVisibleColumnName("visible")
|
.setListedColumnName("listed")
|
||||||
.setPrependWhere(true)
|
.setPrependWhere(true)
|
||||||
.build();
|
.build();
|
||||||
std::string query = "SELECT id, name, title, lastrevision, visible FROM page " + queryOption;
|
std::string query = "SELECT id, name, title, lastrevision, listed, feedlisted, (SELECT name FROM page WHERE "
|
||||||
*db << query >>
|
"id = parent) FROM page " +
|
||||||
[&](unsigned int pageid, std::string name, std::string title, unsigned int current_revision, bool visible)
|
queryOption;
|
||||||
|
*db << query >> [&](unsigned int pageid, std::string name, std::string title, unsigned int current_revision,
|
||||||
|
bool listed, bool feedlisted, std::string parent)
|
||||||
{
|
{
|
||||||
Page tmp;
|
Page tmp;
|
||||||
tmp.pageid = pageid;
|
tmp.pageid = pageid;
|
||||||
tmp.name = name;
|
tmp.name = name;
|
||||||
tmp.title = title;
|
tmp.title = title;
|
||||||
tmp.current_revision = current_revision;
|
tmp.current_revision = current_revision;
|
||||||
tmp.listed = visible;
|
tmp.listed = listed;
|
||||||
|
tmp.feedlisted = feedlisted;
|
||||||
|
tmp.parentpage = parent;
|
||||||
result.push_back(tmp);
|
result.push_back(tmp);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -262,3 +274,11 @@ int PageDaoSqlite::fetchPageId(std::string pagename)
|
|||||||
auto binder = *db << "SELECT id FROM page WHERE name = ?" << pagename;
|
auto binder = *db << "SELECT id FROM page WHERE name = ?" << pagename;
|
||||||
return execInt(binder);
|
return execInt(binder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> PageDaoSqlite::getChildren(std::string pagename)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
auto query = *db << "SELECT name FROM page WHERE parent = (SELECT id FROM page WHERE name = ?)" << pagename;
|
||||||
|
query >> [&](std::string page) { result.push_back(page); };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@ -28,6 +28,8 @@ class PageDaoSqlite : public PageDao, protected SqliteDao
|
|||||||
int fetchPageId(std::string pagename);
|
int fetchPageId(std::string pagename);
|
||||||
std::vector<SearchResult> search(std::string query, QueryOption option) override;
|
std::vector<SearchResult> search(std::string query, QueryOption option) override;
|
||||||
void setCategories(std::string pagename, const std::vector<std::string> &catnames) override;
|
void setCategories(std::string pagename, const std::vector<std::string> &catnames) override;
|
||||||
|
std::vector<std::string> getChildren(std::string pagename) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PAGEDAOSQLITE_H
|
#endif // PAGEDAOSQLITE_H
|
||||||
|
@ -13,7 +13,7 @@ class QueryOption
|
|||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
unsigned int limit = 0;
|
unsigned int limit = 0;
|
||||||
SORT_ORDER order = ASCENDING;
|
SORT_ORDER order = ASCENDING;
|
||||||
bool includeInvisible = true;
|
bool includeUnlisted = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // QUERYOPTION_H
|
#endif // QUERYOPTION_H
|
||||||
|
@ -52,7 +52,7 @@ std::vector<Revision> RevisionDaoSqlite::getAllRevisions(QueryOption &options)
|
|||||||
{
|
{
|
||||||
SqliteQueryOption queryOption{options};
|
SqliteQueryOption queryOption{options};
|
||||||
std::string queryOptionSql = queryOption.setPrependWhere(true)
|
std::string queryOptionSql = queryOption.setPrependWhere(true)
|
||||||
.setVisibleColumnName("page.visible")
|
.setListedColumnName("page.listed")
|
||||||
.setOrderByColumn("creationtime")
|
.setOrderByColumn("creationtime")
|
||||||
.build();
|
.build();
|
||||||
auto query =
|
auto query =
|
||||||
@ -61,7 +61,8 @@ std::vector<Revision> RevisionDaoSqlite::getAllRevisions(QueryOption &options)
|
|||||||
"page.name, revisionid FROM revision INNER JOIN page ON revision.page = page.id " +
|
"page.name, revisionid FROM revision INNER JOIN page ON revision.page = page.id " +
|
||||||
queryOptionSql;
|
queryOptionSql;
|
||||||
query >> [&](std::string author, std::string comment, std::string content, time_t creationtime,
|
query >> [&](std::string author, std::string comment, std::string content, time_t creationtime,
|
||||||
std::string page, unsigned int revisionid) {
|
std::string page, unsigned int revisionid)
|
||||||
|
{
|
||||||
Revision r;
|
Revision r;
|
||||||
r.author = author;
|
r.author = author;
|
||||||
r.comment = comment;
|
r.comment = comment;
|
||||||
@ -91,7 +92,7 @@ std::vector<Revision> RevisionDaoSqlite::getAllRevisionsForPage(std::string page
|
|||||||
{
|
{
|
||||||
SqliteQueryOption queryOption{option};
|
SqliteQueryOption queryOption{option};
|
||||||
std::string queryOptionSql = queryOption.setPrependWhere(false)
|
std::string queryOptionSql = queryOption.setPrependWhere(false)
|
||||||
.setVisibleColumnName("page.visible")
|
.setListedColumnName("page.listed")
|
||||||
.setOrderByColumn("creationtime")
|
.setOrderByColumn("creationtime")
|
||||||
.build();
|
.build();
|
||||||
auto query = *db << "SELECT (SELECT username FROM user WHERE id = author), comment, content, "
|
auto query = *db << "SELECT (SELECT username FROM user WHERE id = author), comment, content, "
|
||||||
@ -101,7 +102,8 @@ std::vector<Revision> RevisionDaoSqlite::getAllRevisionsForPage(std::string page
|
|||||||
<< pagename;
|
<< pagename;
|
||||||
|
|
||||||
query >> [&](std::string author, std::string comment, std::string content, time_t creationtime,
|
query >> [&](std::string author, std::string comment, std::string content, time_t creationtime,
|
||||||
std::string page, unsigned int revisionid) {
|
std::string page, unsigned int revisionid)
|
||||||
|
{
|
||||||
Revision r;
|
Revision r;
|
||||||
r.author = author;
|
r.author = author;
|
||||||
r.comment = comment;
|
r.comment = comment;
|
||||||
@ -129,7 +131,8 @@ std::optional<Revision> RevisionDaoSqlite::getCurrentForPage(std::string pagenam
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto query = *db << "SELECT (SELECT username FROM user WHERE id = author), comment, content, "
|
auto query = *db << "SELECT (SELECT username FROM user WHERE id = author), comment, content, "
|
||||||
"strftime('%s',creationtime), page.name, revisionid FROM revision INNER JOIN page ON revision.page = page.id WHERE page.name = ? AND page.lastrevision = revision.revisionid";
|
"strftime('%s',creationtime), page.name, revisionid FROM revision INNER JOIN page ON "
|
||||||
|
"revision.page = page.id WHERE page.name = ? AND page.lastrevision = revision.revisionid";
|
||||||
query << pagename;
|
query << pagename;
|
||||||
query >>
|
query >>
|
||||||
std::tie(result.author, result.comment, result.content, result.timestamp, result.page, result.revision);
|
std::tie(result.author, result.comment, result.content, result.timestamp, result.page, result.revision);
|
||||||
@ -154,7 +157,8 @@ std::optional<Revision> RevisionDaoSqlite::getRevisionForPage(std::string pagena
|
|||||||
auto query =
|
auto query =
|
||||||
*db
|
*db
|
||||||
<< "SELECT (SELECT username FROM user WHERE id = author), comment, content, strftime('%s',creationtime), "
|
<< "SELECT (SELECT username FROM user WHERE id = author), comment, content, strftime('%s',creationtime), "
|
||||||
"page.name, revisionid FROM revision INNER JOIN page ON revision.page = page.id WHERE page.name = ? AND revisionid = ? ";
|
"page.name, revisionid FROM revision INNER JOIN page ON revision.page = page.id WHERE page.name = ? AND "
|
||||||
|
"revisionid = ? ";
|
||||||
query << pagename << revision;
|
query << pagename << revision;
|
||||||
query >>
|
query >>
|
||||||
std::tie(result.author, result.comment, result.content, result.timestamp, result.page, result.revision);
|
std::tie(result.author, result.comment, result.content, result.timestamp, result.page, result.revision);
|
||||||
|
@ -31,9 +31,9 @@ SqliteQueryOption &SqliteQueryOption::setOrderByColumn(std::string name)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
SqliteQueryOption &SqliteQueryOption::setVisibleColumnName(std::string name)
|
SqliteQueryOption &SqliteQueryOption::setListedColumnName(std::string name)
|
||||||
{
|
{
|
||||||
this->visibleColumnName = name;
|
this->listedColumnName = name;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,9 +50,9 @@ std::string SqliteQueryOption::build()
|
|||||||
{
|
{
|
||||||
result += "WHERE ";
|
result += "WHERE ";
|
||||||
}
|
}
|
||||||
if(!o.includeInvisible && !this->visibleColumnName.empty())
|
if(!o.includeUnlisted && !this->listedColumnName.empty())
|
||||||
{
|
{
|
||||||
result += this->visibleColumnName + " = 1";
|
result += this->listedColumnName + " = 1";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@ class SqliteQueryOption
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
QueryOption o;
|
QueryOption o;
|
||||||
std::string visibleColumnName;
|
std::string listedColumnName;
|
||||||
std::string orderByColumnName;
|
std::string orderByColumnName;
|
||||||
|
|
||||||
bool prependWhere;
|
bool prependWhere;
|
||||||
@ -17,7 +17,7 @@ class SqliteQueryOption
|
|||||||
|
|
||||||
SqliteQueryOption &setOrderByColumn(std::string name);
|
SqliteQueryOption &setOrderByColumn(std::string name);
|
||||||
|
|
||||||
SqliteQueryOption &setVisibleColumnName(std::string name);
|
SqliteQueryOption &setListedColumnName(std::string name);
|
||||||
|
|
||||||
SqliteQueryOption &setPrependWhere(bool b);
|
SqliteQueryOption &setPrependWhere(bool b);
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ std::string DynamicContentPostList::render()
|
|||||||
auto permissionDao = this->database->createPermissionsDao();
|
auto permissionDao = this->database->createPermissionsDao();
|
||||||
|
|
||||||
QueryOption option;
|
QueryOption option;
|
||||||
option.includeInvisible = false;
|
option.includeUnlisted = false;
|
||||||
auto members = categoryDao->fetchMembers(this->argument, 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(const Page &member : members)
|
for(const Page &member : members)
|
||||||
|
73
dynamic/dynamicpostrenderer.cpp
Normal file
73
dynamic/dynamicpostrenderer.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include <chrono>
|
||||||
|
#include "dynamicpostrenderer.h"
|
||||||
|
#include "../parser.h"
|
||||||
|
#include "../utils.h"
|
||||||
|
|
||||||
|
void DynamicPostRenderer::setArgument(std::string argument)
|
||||||
|
{
|
||||||
|
auto splitted = utils::split(argument, '|');
|
||||||
|
this->category = splitted[0];
|
||||||
|
if(splitted.size() >= 2)
|
||||||
|
{
|
||||||
|
this->templatepartname = splitted[1];
|
||||||
|
}
|
||||||
|
if(splitted.size() >= 3)
|
||||||
|
{
|
||||||
|
this->customlinkurl = splitted[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DynamicPostRenderer::linkToPage(std::string page)
|
||||||
|
{
|
||||||
|
if(this->customlinkurl.empty())
|
||||||
|
{
|
||||||
|
return this->urlProvider->page(page);
|
||||||
|
}
|
||||||
|
return utils::strreplace(this->customlinkurl, "{page}", page);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DynamicPostRenderer::render()
|
||||||
|
{
|
||||||
|
auto categoryDao = this->database->createCategoryDao();
|
||||||
|
auto pageDao = this->database->createPageDao();
|
||||||
|
auto revisionDao = this->database->createRevisionDao();
|
||||||
|
auto permissionDao = this->database->createPermissionsDao();
|
||||||
|
|
||||||
|
QueryOption option;
|
||||||
|
option.includeUnlisted = true;
|
||||||
|
auto members = categoryDao->fetchMembers(this->category, option);
|
||||||
|
std::vector<std::pair<std::string, time_t>> pageList;
|
||||||
|
for(const Page &member : members)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
pageList.push_back({member.name, revision->timestamp});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(pageList.begin(), pageList.end(),
|
||||||
|
[](std::pair<std::string, time_t> &a, std::pair<std::string, time_t> &b) { return a.second > b.second; });
|
||||||
|
|
||||||
|
std::string entry = this->templ->loadResolvedPart(this->templatepartname);
|
||||||
|
std::stringstream stream;
|
||||||
|
for(auto &pair : pageList)
|
||||||
|
{
|
||||||
|
std::optional<Revision> revision = revisionDao->getCurrentForPage(pair.first);
|
||||||
|
if(revision)
|
||||||
|
{
|
||||||
|
std::string link = linkToPage(pair.first);
|
||||||
|
Parser parser;
|
||||||
|
|
||||||
|
std::string date = utils::toISODateTime(revision->timestamp);
|
||||||
|
Varreplacer replacer{"{"};
|
||||||
|
replacer.addKeyValue("url", link);
|
||||||
|
replacer.addKeyValue("date", date);
|
||||||
|
replacer.addKeyValue("content", parser.parse(*pageDao, *this->urlProvider,
|
||||||
|
parser.extractFirstTag("content", revision->content)));
|
||||||
|
stream << replacer.parse(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stream.str();
|
||||||
|
}
|
18
dynamic/dynamicpostrenderer.h
Normal file
18
dynamic/dynamicpostrenderer.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef DYNAMICPOSTRENDERER_H
|
||||||
|
#define DYNAMICPOSTRENDERER_H
|
||||||
|
#include "dynamiccontent.h"
|
||||||
|
class DynamicPostRenderer : public DynamicContent
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::string category;
|
||||||
|
std::string customlinkurl;
|
||||||
|
std::string templatepartname = "dynamic/categoryrendererentry";
|
||||||
|
|
||||||
|
public:
|
||||||
|
using DynamicContent::DynamicContent;
|
||||||
|
std::string render() override;
|
||||||
|
void setArgument(std::string argument) override;
|
||||||
|
std::string linkToPage(std::string page);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DYNAMICPOSTRENDERER_H
|
@ -53,7 +53,7 @@ std::string Handler::createPageTitle(std::string title)
|
|||||||
QueryOption Handler::queryOption(const Request &r, SORT_ORDER defaultSort) const
|
QueryOption Handler::queryOption(const Request &r, SORT_ORDER defaultSort) const
|
||||||
{
|
{
|
||||||
QueryOption result;
|
QueryOption result;
|
||||||
result.includeInvisible = false;
|
result.includeUnlisted = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result.limit = utils::toUInt(r.get("limit"));
|
result.limit = utils::toUInt(r.get("limit"));
|
||||||
|
@ -9,7 +9,7 @@ std::vector<HandlerFeedGenerator::EntryRevisionPair> HandlerFeedGenerator::fetch
|
|||||||
|
|
||||||
std::vector<EntryRevisionPair> result;
|
std::vector<EntryRevisionPair> result;
|
||||||
QueryOption option;
|
QueryOption option;
|
||||||
option.includeInvisible = false;
|
option.includeUnlisted = true;
|
||||||
// option.limit = 20;
|
// option.limit = 20;
|
||||||
|
|
||||||
auto comppage = [](const Page &a, const Page &b) { return a.name < b.name; };
|
auto comppage = [](const Page &a, const Page &b) { return a.name < b.name; };
|
||||||
@ -34,12 +34,15 @@ std::vector<HandlerFeedGenerator::EntryRevisionPair> HandlerFeedGenerator::fetch
|
|||||||
}
|
}
|
||||||
for(const Page &member : members)
|
for(const Page &member : members)
|
||||||
{
|
{
|
||||||
Permissions perms = permissionDao->find(member.name, this->userSession->user.login)
|
if(member.feedlisted)
|
||||||
.value_or(this->userSession->user.permissions);
|
|
||||||
if(perms.canRead())
|
|
||||||
{
|
{
|
||||||
auto revision = revisionDao->getRevisionForPage(member.name, 1).value();
|
Permissions perms = permissionDao->find(member.name, this->userSession->user.login)
|
||||||
result.push_back({member, revision});
|
.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(),
|
std::sort(result.begin(), result.end(),
|
||||||
|
@ -76,10 +76,27 @@ Response HandlerPageEdit::handleRequest(PageDao &pageDao, std::string pagename,
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
this->database->beginTransaction();
|
this->database->beginTransaction();
|
||||||
|
|
||||||
std::string visiblecmd = parser.extractCommand("visible", newContent);
|
std::string visiblecmd = parser.extractCommand("visible", newContent);
|
||||||
|
std::string listedcmd = parser.extractCommand("listed", newContent);
|
||||||
|
/* Backwarts compatibility */
|
||||||
|
if(listedcmd.empty())
|
||||||
|
{
|
||||||
|
listedcmd = visiblecmd;
|
||||||
|
}
|
||||||
|
std::string feedlistedcmd = parser.extractCommand("feedlisted", newContent);
|
||||||
|
|
||||||
std::string rename = parser.extractCommand("rename", newContent);
|
std::string rename = parser.extractCommand("rename", newContent);
|
||||||
std::string customtitle = parser.extractCommand("pagetitle", newContent);
|
std::string customtitle = parser.extractCommand("pagetitle", newContent);
|
||||||
|
std::string parentpage = parser.extractCommand("parentpage", newContent);
|
||||||
std::vector<std::string> perms = parser.extractCommands("permissions", newContent);
|
std::vector<std::string> perms = parser.extractCommands("permissions", newContent);
|
||||||
|
|
||||||
|
if(parentpage != "" && !pageDao.find(parentpage))
|
||||||
|
{
|
||||||
|
return this->errorResponse("Invalid parent",
|
||||||
|
"Specified parent page " + parentpage + " does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
Page page;
|
Page page;
|
||||||
std::optional<Page> currentPage = pageDao.find(pagename);
|
std::optional<Page> currentPage = pageDao.find(pagename);
|
||||||
if(currentPage)
|
if(currentPage)
|
||||||
@ -131,9 +148,11 @@ Response HandlerPageEdit::handleRequest(PageDao &pageDao, std::string pagename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
page.current_revision = current_revision;
|
page.current_revision = current_revision;
|
||||||
page.listed = !(visiblecmd == "0");
|
page.listed = !(listedcmd == "0");
|
||||||
|
page.feedlisted = !(feedlistedcmd == "0");
|
||||||
page.name = pagename;
|
page.name = pagename;
|
||||||
page.title = customtitle;
|
page.title = customtitle;
|
||||||
|
page.parentpage = parentpage;
|
||||||
if(page.title.empty())
|
if(page.title.empty())
|
||||||
{
|
{
|
||||||
page.title = page.name;
|
page.title = page.name;
|
||||||
|
@ -15,6 +15,7 @@ class IParser
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
virtual std::string extractFirstTag(std::string tagname, const std::string &content) const = 0;
|
||||||
virtual std::string extractCommand(std::string cmdname, const std::string &content) const = 0;
|
virtual std::string extractCommand(std::string cmdname, const std::string &content) const = 0;
|
||||||
virtual std::vector<std::string> extractCommands(std::string cmdname, const std::string &content) const = 0;
|
virtual std::vector<std::string> extractCommands(std::string cmdname, const std::string &content) const = 0;
|
||||||
|
|
||||||
|
2
page.h
2
page.h
@ -8,7 +8,9 @@ class Page
|
|||||||
Page();
|
Page();
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string title;
|
std::string title;
|
||||||
|
std::string parentpage;
|
||||||
bool listed;
|
bool listed;
|
||||||
|
bool feedlisted;
|
||||||
unsigned int current_revision;
|
unsigned int current_revision;
|
||||||
unsigned int pageid;
|
unsigned int pageid;
|
||||||
};
|
};
|
||||||
|
20
parser.cpp
20
parser.cpp
@ -63,11 +63,10 @@ std::vector<std::string> Parser::extractCategories(const std::string &content) c
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Parser::extractCommand(std::string cmdname, const std::string &content) const
|
std::string Parser::extractFirstTag(std::string tagname, const std::string &content) const
|
||||||
{
|
{
|
||||||
std::string cmd = "[cmd:" + cmdname + "]";
|
std::string cmd = "[" + tagname + "]";
|
||||||
std::string cmdend = "[/cmd:" + cmdname + "]";
|
std::string cmdend = "[/" + tagname + "]";
|
||||||
|
|
||||||
std::string_view view = content;
|
std::string_view view = content;
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
if((pos = view.find(cmd)) != std::string::npos)
|
if((pos = view.find(cmd)) != std::string::npos)
|
||||||
@ -83,6 +82,12 @@ std::string Parser::extractCommand(std::string cmdname, const std::string &conte
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Parser::extractCommand(std::string cmdname, const std::string &content) const
|
||||||
|
{
|
||||||
|
|
||||||
|
return extractFirstTag("cmd:" + cmdname, content);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> Parser::extractCommands(std::string cmdname, const std::string &content) const
|
std::vector<std::string> Parser::extractCommands(std::string cmdname, const std::string &content) const
|
||||||
{
|
{
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
@ -170,7 +175,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|s|li||ul|ol|code|blockquote|img|link|wikilink|h\d|cmd:visible|cmd:rename|cmd:redirect|cmd:pagetitle|cmd:allowinclude|cmd:permissions|category|dynamic:postlist|dynamic:includepage|dynamic:getvar|dynamic:setvar)*?\]((\s|\S)*?)\[/\1])");
|
R"(\[(b|i|u|s|li||ul|ol|code|blockquote|img|link|wikilink|h\d|cmd:visible|cmd:listed|cmd:feedlisted|cmd:rename|cmd:redirect|cmd:pagetitle|cmd:allowinclude|cmd:permissions|cmd:parentpage|content|category|dynamic:postlist|dynamic:includepage|dynamic:getvar|dynamic:setvar)*?\]((\s|\S)*?)\[/\1])");
|
||||||
result = utils::regex_callback_replacer(
|
result = utils::regex_callback_replacer(
|
||||||
tagfinder, content,
|
tagfinder, content,
|
||||||
[&](std::smatch &match)
|
[&](std::smatch &match)
|
||||||
@ -182,6 +187,11 @@ std::string Parser::parse(const PageDao &pagedao, UrlProvider &provider, const s
|
|||||||
{
|
{
|
||||||
content = parse(pagedao, provider, content, callback);
|
content = parse(pagedao, provider, content, callback);
|
||||||
}
|
}
|
||||||
|
/* [content] just helps extracting the actual content of a page, pretty much noop otherwise */
|
||||||
|
if(tag == "content")
|
||||||
|
{
|
||||||
|
return parse(pagedao, provider, content, callback);
|
||||||
|
}
|
||||||
if(std::find(std::begin(justreplace), std::end(justreplace), tag) != std::end(justreplace))
|
if(std::find(std::begin(justreplace), std::end(justreplace), tag) != std::end(justreplace))
|
||||||
{
|
{
|
||||||
return "<" + tag + ">" + content + "</" + tag + ">";
|
return "<" + tag + ">" + content + "</" + tag + ">";
|
||||||
|
1
parser.h
1
parser.h
@ -9,6 +9,7 @@ class Parser : public IParser
|
|||||||
std::string processImage(std::smatch &match) const;
|
std::string processImage(std::smatch &match) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::string extractFirstTag(std::string tagname, const std::string &content) const override;
|
||||||
std::string extractCommand(std::string cmdname, const std::string &content) const override;
|
std::string extractCommand(std::string cmdname, const std::string &content) const override;
|
||||||
std::vector<std::string> extractCommands(std::string cmdname, const std::string &content) const override;
|
std::vector<std::string> extractCommands(std::string cmdname, const std::string &content) const override;
|
||||||
std::vector<Headline> extractHeadlines(const std::string &content) const override;
|
std::vector<Headline> extractHeadlines(const std::string &content) const override;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#include "revisionrenderer.h"
|
#include "revisionrenderer.h"
|
||||||
#include "templatepage.h"
|
#include "templatepage.h"
|
||||||
#include "dynamic/dynamiccontentpostlist.h"
|
#include "dynamic/dynamiccontentpostlist.h"
|
||||||
#include "dynamic/dynamiccontentincludepage.h"
|
#include "dynamic/dynamiccontentincludepage.h"
|
||||||
#include "dynamic/dynamiccontentgetvar.h"
|
#include "dynamic/dynamiccontentgetvar.h"
|
||||||
#include "dynamic/dynamiccontentsetvar.h"
|
#include "dynamic/dynamiccontentsetvar.h"
|
||||||
|
#include "dynamic/dynamicpostrenderer.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "htmllink.h"
|
#include "htmllink.h"
|
||||||
|
|
||||||
@ -17,9 +18,10 @@ std::string RevisionRenderer::dynamicCallback(std::string_view key, std::string_
|
|||||||
}
|
}
|
||||||
if(key == "dynamic:includepage")
|
if(key == "dynamic:includepage")
|
||||||
{
|
{
|
||||||
auto includePage = this->dynamicContentFactory.createDynamicContent<DynamicContentIncludePage>();
|
auto includePage = this->dynamicContentFactory.createDynamicContent<DynamicContentIncludePage>();
|
||||||
includePage->setArgument(std::string(value));
|
includePage->setArgument(std::string(value));
|
||||||
return parser.parseDynamics(includePage->render(), std::bind(&RevisionRenderer::dynamicCallback, this, std::placeholders::_1, std::placeholders::_2));
|
return parser.parseDynamics(includePage->render(), std::bind(&RevisionRenderer::dynamicCallback, this,
|
||||||
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
if(key == "dynamic:setvar")
|
if(key == "dynamic:setvar")
|
||||||
{
|
{
|
||||||
@ -35,6 +37,12 @@ std::string RevisionRenderer::dynamicCallback(std::string_view key, std::string_
|
|||||||
getVar->setArgument(std::string(value));
|
getVar->setArgument(std::string(value));
|
||||||
return getVar->render();
|
return getVar->render();
|
||||||
}
|
}
|
||||||
|
if(key == "dynamic:postrenderer")
|
||||||
|
{
|
||||||
|
auto renderer = this->dynamicContentFactory.createDynamicContent<DynamicPostRenderer>();
|
||||||
|
renderer->setArgument(std::string(value));
|
||||||
|
return renderer->render();
|
||||||
|
}
|
||||||
return std::string{};
|
return std::string{};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +52,8 @@ std::string RevisionRenderer::renderContent(std::string content)
|
|||||||
dynamicVarsMap["createdon"] = utils::toISODate(time(NULL));
|
dynamicVarsMap["createdon"] = utils::toISODate(time(NULL));
|
||||||
dynamicVarsMap["modifydatetime"] = utils::toISODateTime(time(NULL));
|
dynamicVarsMap["modifydatetime"] = utils::toISODateTime(time(NULL));
|
||||||
|
|
||||||
std::string resolvedContent = parser.parseDynamics(content, std::bind(&RevisionRenderer::dynamicCallback, this, std::placeholders::_1, std::placeholders::_2));
|
std::string resolvedContent = parser.parseDynamics(
|
||||||
|
content, std::bind(&RevisionRenderer::dynamicCallback, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
|
||||||
return parser.parse(*this->db->createPageDao(), *this->urlProvider, resolvedContent);
|
return parser.parse(*this->db->createPageDao(), *this->urlProvider, resolvedContent);
|
||||||
}
|
}
|
||||||
@ -55,15 +64,15 @@ std::string RevisionRenderer::renderContent(const Revision &r, std::string_view
|
|||||||
auto firstRevision = revisionDao->getRevisionForPage(r.page, 1);
|
auto firstRevision = revisionDao->getRevisionForPage(r.page, 1);
|
||||||
if(!firstRevision)
|
if(!firstRevision)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Could not get first revision for page, which is odd. Solar flares?");
|
throw std::runtime_error("Could not get first revision for page, which is odd. Solar flares?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dynamicVarsMap["createdon"] = utils::toISODate(firstRevision.value().timestamp);
|
dynamicVarsMap["createdon"] = utils::toISODate(firstRevision.value().timestamp);
|
||||||
dynamicVarsMap["pagetitle"] = customTitle;
|
dynamicVarsMap["pagetitle"] = customTitle;
|
||||||
dynamicVarsMap["modifydatetime"] = utils::toISODateTime(r.timestamp);
|
dynamicVarsMap["modifydatetime"] = utils::toISODateTime(r.timestamp);
|
||||||
|
|
||||||
std::string resolvedContent = parser.parseDynamics(r.content, std::bind(&RevisionRenderer::dynamicCallback, this, std::placeholders::_1, std::placeholders::_2));
|
std::string resolvedContent = parser.parseDynamics(
|
||||||
|
r.content, std::bind(&RevisionRenderer::dynamicCallback, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
|
||||||
return parser.parse(*this->db->createPageDao(), *this->urlProvider, resolvedContent);
|
return parser.parse(*this->db->createPageDao(), *this->urlProvider, resolvedContent);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
CREATE TABLE page(id INTEGER PRIMARY KEY, name varchar(256), title varchar(1024), lastrevision integer, visible integer DEFAULT 1);
|
CREATE TABLE page(id INTEGER PRIMARY KEY, name varchar(256), title varchar(1024), lastrevision integer, listed integer DEFAULT 1, parent integer REFERENCES page(id), feedlisted integer DEFAULT 1);
|
||||||
CREATE TABLE user(id INTEGER PRIMARY KEY,username varchar(64),
|
CREATE TABLE user(id INTEGER PRIMARY KEY,username varchar(64),
|
||||||
password blob, salt blob, permissions integer, enabled integer DEFAULT 1);
|
password blob, salt blob, permissions integer, enabled integer DEFAULT 1);
|
||||||
CREATE TABLE session(id INTEGER PRIMARY KEY, csrf_token varchar(32),
|
CREATE TABLE session(id INTEGER PRIMARY KEY, csrf_token varchar(32),
|
||||||
|
11
template.cpp
11
template.cpp
@ -18,6 +18,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#include <filesystem>
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
#include "varreplacer.h"
|
#include "varreplacer.h"
|
||||||
#include "urlprovider.h"
|
#include "urlprovider.h"
|
||||||
@ -47,9 +48,15 @@ TemplatePage Template::getPage(const std::string &pagename)
|
|||||||
|
|
||||||
std::string Template::getPartPath(std::string_view partname)
|
std::string Template::getPartPath(std::string_view partname)
|
||||||
{
|
{
|
||||||
// TODO: utils::concatPath? C++17 paths?
|
auto absolute_path = std::filesystem::canonical(std::filesystem::path{this->templatepath} / partname);
|
||||||
return this->templatepath + "/" + std::string(partname);
|
std::string result = absolute_path.string();
|
||||||
|
if(result.starts_with(this->templatepath))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Template::loadPartContent(std::string_view partname)
|
std::string Template::loadPartContent(std::string_view partname)
|
||||||
{
|
{
|
||||||
std::string partpath = getPartPath(partname);
|
std::string partpath = getPartPath(partname);
|
||||||
|
Loading…
Reference in New Issue
Block a user