Let's make (git) history!
This commit is contained in:
當前提交
3bfebfe8a8
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
*.o
|
||||
*.d
|
||||
*.out
|
||||
*.gch
|
||||
*.user
|
||||
qswiki
|
||||
wikiqs*
|
||||
data/*
|
||||
gtest*
|
||||
cgi-bin/*
|
20
LICENCE
Normal file
20
LICENCE
Normal file
@ -0,0 +1,20 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
59
Makefile
Normal file
59
Makefile
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
|
||||
CXXFLAGS=-std=c++17 -O0 -g -pg -no-pie -pipe -MMD -Wall -Wextra
|
||||
RELEASE_CXXFLAGS=-std=c++17 -O3 -pipe -MMD -Wall -Wextra
|
||||
LDFLAGS=-lsqlite3 -lpthread -lcrypto -lstdc++fs
|
||||
|
||||
#currently default g++ versions in most distros do not usually support c++17 well enough
|
||||
CXX=g++-8.2.0
|
||||
|
||||
|
||||
SOURCES=$(wildcard *.cpp)
|
||||
SOURCES+=$(wildcard gateway/*.cpp)
|
||||
SOURCES+=$(wildcard handlers/*.cpp)
|
||||
SOURCES+=$(wildcard database/*.cpp)
|
||||
SOURCES+=$(wildcard cache/*.cpp)
|
||||
|
||||
HEADERS=$(wildcard *.h)
|
||||
HEADERS+=$(wildcard gateway/*.h)
|
||||
HEADERS+=$(wildcard handlers/*.h)
|
||||
HEADERS+=$(wildcard database/*.h)
|
||||
HEADERS+=$(wildcard cache/*.h)
|
||||
|
||||
|
||||
OBJECTS=$(patsubst %.cpp, %.o, $(SOURCES))
|
||||
WIKIOBJECTS=$(filter-out test.o, $(OBJECTS))
|
||||
TESTOBJECTS=$(filter-out qswiki.o, $(OBJECTS))
|
||||
DEPENDS = ${WIKIOBJECTS:.o=.d}
|
||||
-include ${DEPENDS}
|
||||
|
||||
# Points to the root of Google Test, relative to where this file is.
|
||||
# Remember to tweak this if you move this file.
|
||||
GTEST_DIR = /home/data/SOURCES/gtest/googletest
|
||||
|
||||
GTESTS_TESTDIR = ./tests/
|
||||
|
||||
GTEST_CXXFLAGS=-std=c++17 -isystem $(GTEST_DIR)/include -I$(GTEST_DIR) -g -O0 -pipe -Wall -Wextra
|
||||
GTEST_LDFLAGS=-lsqlite3 -g -O0 -lpthread -lcrypto -lstdc++fs
|
||||
GTEST_OBJECTS=$(filter-out qswiki.o, $(WIKIOBJECTS))
|
||||
|
||||
.DEFAULT_GOAL := qswiki
|
||||
|
||||
release: CXXFLAGS=$(RELEASE_CXXFLAGS)
|
||||
release: qswiki
|
||||
qswiki: $(WIKIOBJECTS)
|
||||
$(CXX) $(WIKIOBJECTS) ${LDFLAGS} -I database/hdr -o qswiki
|
||||
|
||||
test: $(TESTOBJECTS)
|
||||
$(CXX) $(TESTOBJECTS) ${LDFLAGS} -o test
|
||||
|
||||
gtest: $(GTESTS_TESTDIR)/*.cpp $(GTEST_OBJECTS)
|
||||
$(CXX) -o gtest $(GTESTS_TESTDIR)/*.cpp $(GTEST_OBJECTS) $(GTEST_CXXFLAGS) $(GTEST_DIR)/src/gtest_main.cc $(GTEST_DIR)/src/gtest-all.cc $(GTEST_LDFLAGS)
|
||||
|
||||
%.o:%.cpp
|
||||
$(CXX) ${CXXFLAGS} ${LDFLAGS} -I database/hdr -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS) $(DEPENDS)
|
||||
|
||||
|
77
README.md
Normal file
77
README.md
Normal file
@ -0,0 +1,77 @@
|
||||
# qswiki
|
||||
|
||||
About
|
||||
====
|
||||
qswiki is a wiki software, intended for small wikis. Originally
|
||||
implemented in C, it's now written in C++.
|
||||
|
||||
History
|
||||
====
|
||||
A couple of years ago, I wanted to setup a personal wiki on my raspberry
|
||||
pi. However, the distribution I used back then did not have a PHP package
|
||||
for ARM. So I decided I would write one in C. Yes, that's an odd way
|
||||
to approach the problem and indeed, I may have had too much time back
|
||||
then. Also, I wanted to see how it's like to write a "web app" in C
|
||||
and wanted to sharpen my C a little bit.
|
||||
|
||||
Of course, it's pretty straightforward at first. No really. Just use CGI.
|
||||
And indeed, that's probably more than enough. Then I decided to play
|
||||
around and started using FastCGI (with the official library from now
|
||||
defunct fastcgi.com) and created a multi-threaded version. It initially
|
||||
used a "pile of files database", but that became too painful, so then
|
||||
I started using sqlite.
|
||||
|
||||
C++
|
||||
---
|
||||
Eventually the code became unmaintainable. Initially, I wanted something
|
||||
quick. I did not care about memory leaks (as it was CGI initially).
|
||||
After FastCGI, they became an issue. In the end, the task of avoiding
|
||||
memory leaks became too annoying. And of course, C does not include any
|
||||
"batteries" and while I could manage, this too was another good reason.
|
||||
|
||||
Overall, I am just continuing the experiment with C++17 now. It's not
|
||||
nearly as bad as you would expect perhaps. Some things are surprisingly
|
||||
convenient even. Still, the standard library is lacking and
|
||||
I would hope for a some better built-in Unicode support in the future.
|
||||
|
||||
Features
|
||||
========
|
||||
To be fair, at this point it doesn't even have a "diff" between revisions
|
||||
yet and does not have features that make you prefer it over other wikis.
|
||||
|
||||
- CGI
|
||||
- HTTP server using the header only library cpp-httplib. It's more
|
||||
portable and more "future-proof" than FastCGI (since the official website
|
||||
disappeared, the library's future appears to be uncertain).
|
||||
- Support for user accounts. Passwords are stored using PBKDF2.
|
||||
sqlite database, but not too much of an effort to add other types of
|
||||
storage backends. sqlite is using the great header only library
|
||||
sqlite_modern_cpp
|
||||
- Relatively fine-grained permission system.
|
||||
- Categories
|
||||
- Templates
|
||||
- FTS search
|
||||
- Caching
|
||||
|
||||
Security
|
||||
========
|
||||
The most reasonable way would have been to add some sort sandboxing
|
||||
support right away, but this is lacking so far. As for "web security",
|
||||
all POST requests are centrally protected against CSRF attacks and all
|
||||
input is escaped against XSS attacks.
|
||||
|
||||
Building
|
||||
========
|
||||
Dependencies:
|
||||
- cpp-httplib: https://github.com/yhirose/cpp-httplib
|
||||
- SqliteModernCpp: https://github.com/SqliteModernCpp
|
||||
|
||||
Given the fact those are header-only libraries, they are already
|
||||
included here, so you only need to run:
|
||||
|
||||
```make release```
|
||||
|
||||
|
||||
Setup
|
||||
=====
|
||||
To be written
|
8
TODO
Normal file
8
TODO
Normal file
@ -0,0 +1,8 @@
|
||||
search: allow all chars (filter sqlite match syntax)
|
||||
diff
|
||||
Redirection,Rename
|
||||
UI for permission system.
|
||||
user administration
|
||||
user registration
|
||||
more caching
|
||||
not all config values take effect yet.
|
62
cache/fscache.cpp
vendored
Normal file
62
cache/fscache.cpp
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include "fscache.h"
|
||||
#include "../logger.h"
|
||||
|
||||
FsCache::FsCache(std::string path)
|
||||
{
|
||||
if(!std::filesystem::exists(path))
|
||||
{
|
||||
throw std::runtime_error{"Directory does not exist"};
|
||||
}
|
||||
this->path = path;
|
||||
}
|
||||
|
||||
std::string FsCache::getFilePath(std::string_view path) const
|
||||
{
|
||||
std::filesystem::path ps{path};
|
||||
std::string name = ps.filename();
|
||||
return std::filesystem::path{this->path} / name;
|
||||
}
|
||||
std::optional<std::string> FsCache::get(std::string_view key) const
|
||||
{
|
||||
std::string path = getFilePath(key);
|
||||
if(std::filesystem::exists(path))
|
||||
{
|
||||
return utils::readCompleteFile(path);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void FsCache::put(std::string_view key, std::string val)
|
||||
{
|
||||
std::string path = std::filesystem::path{this->path} / key;
|
||||
std::fstream f1;
|
||||
f1.open(path, std::ios::out);
|
||||
f1 << val;
|
||||
}
|
||||
|
||||
void FsCache::remove(std::string_view key)
|
||||
{
|
||||
std::filesystem::remove_all(std::filesystem::path{this->path} / key);
|
||||
}
|
||||
|
||||
void FsCache::removePrefix(std::string_view prefix)
|
||||
{
|
||||
// TODO: lock dir
|
||||
for(auto &entry : std::filesystem::directory_iterator(std::filesystem::path{this->path}))
|
||||
{
|
||||
if(static_cast<std::string>(entry.path().filename()).find(prefix) == 0)
|
||||
{
|
||||
std::filesystem::remove_all(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FsCache::clear()
|
||||
{
|
||||
for(auto &entry : std::filesystem::directory_iterator(std::filesystem::path{this->path}))
|
||||
{
|
||||
std::filesystem::remove_all(entry);
|
||||
}
|
||||
}
|
23
cache/fscache.h
vendored
Normal file
23
cache/fscache.h
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef FSCACHE_H
|
||||
#define FSCACHE_H
|
||||
#include "icache.h"
|
||||
class FsCache : public ICache
|
||||
{
|
||||
private:
|
||||
std::string path;
|
||||
std::string getFilePath(std::string_view path) const;
|
||||
|
||||
public:
|
||||
FsCache(std::string directory);
|
||||
std::optional<std::string> get(std::string_view key) const;
|
||||
void put(std::string_view key, std::string val);
|
||||
void remove(std::string_view key);
|
||||
void removePrefix(std::string_view prefix);
|
||||
void clear();
|
||||
using ICache::ICache;
|
||||
~FsCache()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // FSCACHE_H
|
20
cache/icache.h
vendored
Normal file
20
cache/icache.h
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef ICACHE_H
|
||||
#define ICACHE_H
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <optional>
|
||||
#include "../utils.h"
|
||||
class ICache
|
||||
{
|
||||
public:
|
||||
virtual std::optional<std::string> get(std::string_view key) const = 0;
|
||||
virtual void put(std::string_view key, std::string val) = 0;
|
||||
virtual void remove(std::string_view key) = 0;
|
||||
virtual void removePrefix(std::string_view prefix) = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual ~ICache()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // ICACHE_H
|
25
category.cpp
Normal file
25
category.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "category.h"
|
||||
|
||||
Category::Category()
|
||||
{
|
||||
}
|
13
category.h
Normal file
13
category.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef CATEGORY_H
|
||||
#define CATEGORY_H
|
||||
|
||||
#include <string>
|
||||
class Category
|
||||
{
|
||||
public:
|
||||
Category();
|
||||
unsigned int id;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
#endif // CATEGORY_H
|
122
config.cpp
Normal file
122
config.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "permissions.h"
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
std::string Config::required(const std::string &key)
|
||||
{
|
||||
auto it = this->configmap.find(key);
|
||||
if(it != this->configmap.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
throw std::runtime_error("Required config key " + key + " not found");
|
||||
}
|
||||
|
||||
std::string Config::optional(const std::string &key, std::string defaultvalue)
|
||||
{
|
||||
auto it = this->configmap.find(key);
|
||||
if(it != this->configmap.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return defaultvalue;
|
||||
}
|
||||
|
||||
int Config::optional(const std::string &key, int defaultvalue)
|
||||
{
|
||||
auto it = this->configmap.find(key);
|
||||
if(it != this->configmap.end())
|
||||
{
|
||||
std::string str = it->second;
|
||||
return std::stoi(str);
|
||||
}
|
||||
return defaultvalue;
|
||||
}
|
||||
|
||||
Config::Config(const std::map<std::string, std::string> &map)
|
||||
{
|
||||
|
||||
this->configmap = map;
|
||||
this->wikipath = optional("wikipath", "/");
|
||||
this->anon_username = optional("anon_username", "anonymouse");
|
||||
this->wikiname = required("wikiname");
|
||||
this->logfile = required("logfile");
|
||||
this->templatepath = required("templatepath");
|
||||
this->linkallcats = required("linkallcats");
|
||||
this->linkallpages = required("linkallpages");
|
||||
this->linkcategory = required("linkcategory");
|
||||
this->linkdelete = required("linkdelete");
|
||||
this->linkedit = required("linkedit");
|
||||
this->linkhistory = required("linkhistory");
|
||||
this->linkindex = required("linkindex");
|
||||
this->linklogout = required("linklogout");
|
||||
this->linkpage = required("linkpage");
|
||||
this->linkrecent = required("linkrecent");
|
||||
this->linkrevision = required("linkrevision");
|
||||
this->linksettings = required("linksettings");
|
||||
this->linkshere = required("linkshere");
|
||||
this->loginurl = required("loginurl");
|
||||
this->linkrecentsort = required("linkrecentsort");
|
||||
this->linkhistorysort = required("linkhistorysort");
|
||||
this->actionurl = required("actionurl");
|
||||
this->settingsurl = required("settingsurl");
|
||||
this->deletionurl = required("deletionurl");
|
||||
this->adminregisterurl = required("adminregisterurl");
|
||||
this->userchangepwurl = required("userchangepwurl");
|
||||
this->connectionstring = required("connectionstring");
|
||||
|
||||
this->max_pagename_length = optional("max_pagename_length", 256);
|
||||
this->session_max_lifetime = optional("session_max_lifetime", 3600);
|
||||
this->query_limit = optional("query_limit", 200);
|
||||
this->threadscount = optional("threadscount", 1);
|
||||
|
||||
this->anon_permissions = Permissions(required("anon_permissions"));
|
||||
|
||||
this->templateprefix = "{wikiqs:";
|
||||
}
|
||||
|
||||
ConfigReader::ConfigReader(const std::string &file)
|
||||
{
|
||||
this->path = file;
|
||||
}
|
||||
|
||||
Config ConfigReader::readConfig()
|
||||
{
|
||||
std::fstream f1(path, std::fstream::in);
|
||||
std::string line;
|
||||
std::map<std::string, std::string> configmap;
|
||||
while(getline(f1, line))
|
||||
{
|
||||
if(isspace(line[0]) || line[0] == '#')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
std::stringstream s(line);
|
||||
std::string key;
|
||||
std::string value;
|
||||
s >> key >> value;
|
||||
|
||||
configmap.insert(std::make_pair(std::move(key), std::move(value)));
|
||||
}
|
||||
return Config(configmap);
|
||||
}
|
72
config.h
Normal file
72
config.h
Normal file
@ -0,0 +1,72 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include "permissions.h"
|
||||
#include "utils.h"
|
||||
class Config
|
||||
{
|
||||
private:
|
||||
std::map<std::string, std::string> configmap;
|
||||
std::string required(const std::string &key);
|
||||
|
||||
std::string optional(const std::string &key, std::string defaultvalue = "");
|
||||
int optional(const std::string &key, int defaulvalue);
|
||||
|
||||
public:
|
||||
Config(const std::map<std::string, std::string> &map);
|
||||
// TODO: these could be references!?
|
||||
std::string wikiname;
|
||||
std::string wikipath;
|
||||
std::string templatepath;
|
||||
std::string templateprefix;
|
||||
std::string logfile;
|
||||
std::string anon_username;
|
||||
std::string linkindex;
|
||||
std::string linkrecent;
|
||||
std::string linkallpages;
|
||||
std::string linkallcats;
|
||||
std::string linkshere;
|
||||
std::string linkpage;
|
||||
std::string linkrevision;
|
||||
std::string linkhistory;
|
||||
std::string linkedit;
|
||||
std::string linksettings;
|
||||
std::string linkdelete;
|
||||
std::string linklogout;
|
||||
std::string linkcategory;
|
||||
std::string loginurl;
|
||||
std::string linkrecentsort;
|
||||
std::string actionurl;
|
||||
std::string settingsurl;
|
||||
std::string deletionurl;
|
||||
std::string linkhistorysort;
|
||||
std::string adminregisterurl;
|
||||
std::string userchangepwurl;
|
||||
std::string connectionstring;
|
||||
|
||||
int query_limit;
|
||||
int session_max_lifetime;
|
||||
int max_pagename_length;
|
||||
int threadscount;
|
||||
Permissions anon_permissions;
|
||||
|
||||
std::string getConfig(const std::string &key) const
|
||||
{
|
||||
return utils::getKeyOrEmpty(configmap, key);
|
||||
}
|
||||
};
|
||||
|
||||
class ConfigReader
|
||||
{
|
||||
private:
|
||||
std::string path;
|
||||
|
||||
public:
|
||||
ConfigReader(const std::string &file);
|
||||
Config readConfig();
|
||||
};
|
||||
|
||||
#endif // CONFIG_H
|
28
cookie.cpp
Normal file
28
cookie.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "cookie.h"
|
||||
|
||||
Cookie::Cookie(const std::string &key, const std::string &val, int expireSeconds)
|
||||
{
|
||||
this->key = key;
|
||||
this->value = val;
|
||||
this->expires = expireSeconds;
|
||||
}
|
20
cookie.h
Normal file
20
cookie.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef COOKIE_H
|
||||
#define COOKIE_H
|
||||
|
||||
#include <string>
|
||||
class Cookie
|
||||
{
|
||||
public:
|
||||
std::string key;
|
||||
std::string value;
|
||||
int expires;
|
||||
|
||||
Cookie(const std::string &key, const std::string &val, int expireSeconds = 0);
|
||||
|
||||
std::string createHeaderValue() const
|
||||
{
|
||||
return key + "=" + value + "; path=/; HttpOnly";
|
||||
}
|
||||
};
|
||||
|
||||
#endif // COOKIE_H
|
25
database/categorydao.cpp
Normal file
25
database/categorydao.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "categorydao.h"
|
||||
|
||||
CategoryDao::CategoryDao()
|
||||
{
|
||||
}
|
20
database/categorydao.h
Normal file
20
database/categorydao.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef CATEGORYDAO_H
|
||||
#define CATEGORYDAO_H
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include "queryoption.h"
|
||||
#include "../category.h"
|
||||
|
||||
class CategoryDao
|
||||
{
|
||||
public:
|
||||
CategoryDao();
|
||||
virtual void save(const Category &c) = 0;
|
||||
virtual std::vector<std::string> fetchList(QueryOption o) = 0;
|
||||
virtual std::optional<Category> find(std::string name) = 0;
|
||||
virtual void deleteCategory(std::string name) = 0;
|
||||
virtual std::vector<std::string> fetchMembers(std::string name, QueryOption o) = 0;
|
||||
};
|
||||
|
||||
#endif // CATEGORYDAO_H
|
122
database/categorydaosqlite.cpp
Normal file
122
database/categorydaosqlite.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "categorydaosqlite.h"
|
||||
#include "sqlitequeryoption.h"
|
||||
CategoryDaoSqlite::CategoryDaoSqlite()
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<Category> CategoryDaoSqlite::find(std::string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
Category result;
|
||||
*db << "SELECT id, name FROM category WHERE name = ?" << name >> std::tie(result.id, result.name);
|
||||
return result;
|
||||
}
|
||||
catch(const sqlite::exceptions::no_rows &e)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
||||
|
||||
void CategoryDaoSqlite::save(const Category &c)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
*db << "INSERT OR IGNORE INTO category (id, name) VALUES (SELECT id FROM category WHERE lower(name) = "
|
||||
"lower(?), lower(?)"
|
||||
<< c.name << c.name;
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
||||
|
||||
void CategoryDaoSqlite::deleteCategory(std::string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
*db << "BEGIN";
|
||||
*db << "DELETE FROM categorymember WHERE catid = (SELECT id FROM category WHERE name = ?)" << name;
|
||||
*db << "DELETE FROM category WHERE name = ?" << name;
|
||||
*db << "COMMIT;";
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> CategoryDaoSqlite::fetchList(QueryOption o)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
try
|
||||
{
|
||||
auto queryoption = SqliteQueryOption(o).setPrependWhere(true).setOrderByColumn("name").build();
|
||||
*db << "SELECT name FROM category " + queryoption >> [&](std::string n) { result.push_back(n); };
|
||||
}
|
||||
catch(const sqlite::exceptions::no_rows &e)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
catch(const sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
std::vector<std::string> CategoryDaoSqlite::fetchMembers(std::string name, QueryOption o)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
SqliteQueryOption queryOption{o};
|
||||
std::string queryoptions =
|
||||
queryOption.setOrderByColumn("name").setVisibleColumnName("page.visible").setPrependWhere(false).build();
|
||||
|
||||
try
|
||||
{
|
||||
auto query = *db << "SELECT page.name AS name FROM categorymember INNER JOIN page ON page.id = "
|
||||
"categorymember.page WHERE category = (SELECT id FROM category WHERE name = ? ) AND " +
|
||||
queryoptions
|
||||
<< name;
|
||||
query >> [&](std::string p) { result.push_back(p); };
|
||||
}
|
||||
catch(const sqlite::exceptions::no_rows &e)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
18
database/categorydaosqlite.h
Normal file
18
database/categorydaosqlite.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef CATEGORYDAOSQLITE_H
|
||||
#define CATEGORYDAOSQLITE_H
|
||||
|
||||
#include "categorydao.h"
|
||||
#include "sqlitedao.h"
|
||||
class CategoryDaoSqlite : public CategoryDao, protected SqliteDao
|
||||
{
|
||||
public:
|
||||
CategoryDaoSqlite();
|
||||
std::vector<std::string> fetchList(QueryOption o) override;
|
||||
std::vector<std::string> fetchMembers(std::string name, QueryOption o) override;
|
||||
void save(const Category &c) override;
|
||||
void deleteCategory(std::string name) override;
|
||||
std::optional<Category> find(std::string name) override;
|
||||
using SqliteDao::SqliteDao;
|
||||
};
|
||||
|
||||
#endif // CATEGORYDAOSQLITE_H
|
40
database/database.h
Normal file
40
database/database.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef DATABASE_H
|
||||
#define DATABASE_H
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "../user.h"
|
||||
#include "../request.h"
|
||||
#include "../response.h"
|
||||
#include "pagedao.h"
|
||||
#include "revisiondao.h"
|
||||
#include "sessiondao.h"
|
||||
#include "userdao.h"
|
||||
#include "categorydao.h"
|
||||
class Database
|
||||
{
|
||||
private:
|
||||
std::string connnectionstring;
|
||||
|
||||
public:
|
||||
Database()
|
||||
{
|
||||
}
|
||||
Database(std::string connstring)
|
||||
{
|
||||
this->connnectionstring = connstring;
|
||||
}
|
||||
|
||||
virtual void beginTransaction() = 0;
|
||||
virtual void rollbackTransaction() = 0;
|
||||
virtual void commitTransaction() = 0;
|
||||
virtual std::unique_ptr<PageDao> createPageDao() const = 0;
|
||||
virtual std::unique_ptr<RevisionDao> createRevisionDao() const = 0;
|
||||
virtual std::unique_ptr<SessionDao> createSessionDao() const = 0;
|
||||
virtual std::unique_ptr<UserDao> createUserDao() const = 0;
|
||||
virtual std::unique_ptr<CategoryDao> createCategoryDao() const = 0;
|
||||
virtual ~Database()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
26
database/databasefactory.cpp
Normal file
26
database/databasefactory.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "databasefactory.h"
|
||||
#include "sqlite.h"
|
||||
std::unique_ptr<Database> createDatabase(const Config &o)
|
||||
{
|
||||
return std::make_unique<Sqlite>(o.connectionstring);
|
||||
}
|
7
database/databasefactory.h
Normal file
7
database/databasefactory.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef DATABASEFACTORY_H
|
||||
#define DATABASEFACTORY_H
|
||||
#include "../config.h"
|
||||
#include "database.h"
|
||||
|
||||
std::unique_ptr<Database> createDatabase(const Config &o);
|
||||
#endif // DATABASEFACTORY_H
|
15
database/exceptions.h
Normal file
15
database/exceptions.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef EXCEPTIONS_H
|
||||
#define EXCEPTIONS_H
|
||||
#include <stdexcept>
|
||||
|
||||
class DatabaseException : public std::runtime_error
|
||||
{
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
class DatabaseQueryException : public DatabaseException
|
||||
{
|
||||
using DatabaseException::DatabaseException;
|
||||
};
|
||||
|
||||
#endif // EXCEPTIONS_H
|
1160
database/hdr/sqlite_modern_cpp.h
Normal file
1160
database/hdr/sqlite_modern_cpp.h
Normal file
文件差異過大導致無法顯示
Load Diff
100
database/hdr/sqlite_modern_cpp/errors.h
Normal file
100
database/hdr/sqlite_modern_cpp/errors.h
Normal file
@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
namespace sqlite
|
||||
{
|
||||
|
||||
class sqlite_exception : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
sqlite_exception(const char *msg, std::string sql, int code = -1) : runtime_error(msg), code(code), sql(sql)
|
||||
{
|
||||
}
|
||||
sqlite_exception(int code, std::string sql) : runtime_error(sqlite3_errstr(code)), code(code), sql(sql)
|
||||
{
|
||||
}
|
||||
int get_code() const
|
||||
{
|
||||
return code & 0xFF;
|
||||
}
|
||||
int get_extended_code() const
|
||||
{
|
||||
return code;
|
||||
}
|
||||
std::string get_sql() const
|
||||
{
|
||||
return sql;
|
||||
}
|
||||
|
||||
private:
|
||||
int code;
|
||||
std::string sql;
|
||||
};
|
||||
|
||||
namespace errors
|
||||
{
|
||||
// One more or less trivial derived error class for each SQLITE error.
|
||||
// Note the following are not errors so have no classes:
|
||||
// SQLITE_OK, SQLITE_NOTICE, SQLITE_WARNING, SQLITE_ROW, SQLITE_DONE
|
||||
//
|
||||
// Note these names are exact matches to the names of the SQLITE error codes.
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME, name, derived) \
|
||||
class name : public sqlite_exception \
|
||||
{ \
|
||||
using sqlite_exception::sqlite_exception; \
|
||||
}; \
|
||||
derived
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE, SUB, base, sub) \
|
||||
class base##_##sub : public base \
|
||||
{ \
|
||||
using base::base; \
|
||||
};
|
||||
#include "lists/error_codes.h"
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE
|
||||
|
||||
// Some additional errors are here for the C++ interface
|
||||
class more_rows : public sqlite_exception
|
||||
{
|
||||
using sqlite_exception::sqlite_exception;
|
||||
};
|
||||
class no_rows : public sqlite_exception
|
||||
{
|
||||
using sqlite_exception::sqlite_exception;
|
||||
};
|
||||
class more_statements : public sqlite_exception
|
||||
{
|
||||
using sqlite_exception::sqlite_exception;
|
||||
}; // Prepared statements can only contain one statement
|
||||
class invalid_utf16 : public sqlite_exception
|
||||
{
|
||||
using sqlite_exception::sqlite_exception;
|
||||
};
|
||||
|
||||
static void throw_sqlite_error(const int &error_code, const std::string &sql = "")
|
||||
{
|
||||
switch(error_code & 0xFF)
|
||||
{
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME, name, derived) \
|
||||
case SQLITE_##NAME: \
|
||||
switch(error_code) \
|
||||
{ \
|
||||
derived default : throw name(error_code, sql); \
|
||||
}
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE, SUB, base, sub) \
|
||||
case SQLITE_##BASE##_##SUB: \
|
||||
throw base##_##sub(error_code, sql);
|
||||
#include "lists/error_codes.h"
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE
|
||||
default:
|
||||
throw sqlite_exception(error_code, sql);
|
||||
}
|
||||
}
|
||||
} // namespace errors
|
||||
namespace exceptions = errors;
|
||||
} // namespace sqlite
|
90
database/hdr/sqlite_modern_cpp/lists/error_codes.h
Normal file
90
database/hdr/sqlite_modern_cpp/lists/error_codes.h
Normal file
@ -0,0 +1,90 @@
|
||||
#if SQLITE_VERSION_NUMBER < 3010000
|
||||
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27 << 8))
|
||||
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28 << 8))
|
||||
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1 << 8))
|
||||
#endif
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(ERROR, error, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(INTERNAL, internal, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(PERM, perm, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(ABORT, abort, SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(ABORT, ROLLBACK, abort, rollback))
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(BUSY, busy,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BUSY, RECOVERY, busy, recovery)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BUSY, SNAPSHOT, busy, snapshot))
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(LOCKED, locked,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(LOCKED, SHAREDCACHE, locked, sharedcache))
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(NOMEM, nomem, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(READONLY, readonly, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(INTERRUPT, interrupt, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(
|
||||
IOERR, ioerr,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, READ, ioerr, read) SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(
|
||||
IOERR, SHORT_READ, ioerr,
|
||||
short_read) SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, WRITE, ioerr,
|
||||
write) SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, FSYNC,
|
||||
ioerr, fsync)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, DIR_FSYNC, ioerr, dir_fsync) SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(
|
||||
IOERR, TRUNCATE, ioerr,
|
||||
truncate) SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, FSTAT, ioerr,
|
||||
fstat) SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, UNLOCK,
|
||||
ioerr, unlock)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, RDLOCK, ioerr, rdlock) SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(
|
||||
IOERR, DELETE, ioerr, delete) SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, BLOCKED, ioerr, blocked)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, NOMEM, ioerr, nomem) SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(
|
||||
IOERR, ACCESS, ioerr, access) SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, CHECKRESERVEDLOCK, ioerr,
|
||||
checkreservedlock)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, LOCK, ioerr, lock)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, CLOSE, ioerr, close)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, DIR_CLOSE, ioerr, dir_close)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, SHMOPEN, ioerr, shmopen)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, SHMSIZE, ioerr, shmsize)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, SHMLOCK, ioerr, shmlock)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, SHMMAP, ioerr, shmmap)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, SEEK, ioerr, seek)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, DELETE_NOENT, ioerr,
|
||||
delete_noent)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, MMAP, ioerr, mmap)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, GETTEMPPATH,
|
||||
ioerr, gettemppath)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, CONVPATH,
|
||||
ioerr, convpath)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR, VNODE,
|
||||
ioerr, vnode)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(
|
||||
IOERR, AUTH, ioerr, auth))
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(CORRUPT, corrupt, SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CORRUPT, VTAB, corrupt, vtab))
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(NOTFOUND, notfound, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(FULL, full, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(CANTOPEN, cantopen,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN, NOTEMPDIR, cantopen, notempdir)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN, ISDIR, cantopen, isdir)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN, FULLPATH, cantopen, fullpath)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN, CONVPATH, cantopen, convpath))
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(PROTOCOL, protocol, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(EMPTY, empty, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(SCHEMA, schema, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(TOOBIG, toobig, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(
|
||||
CONSTRAINT, constraint,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT, CHECK, constraint, check)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT, COMMITHOOK, constraint, commithook)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT, FOREIGNKEY, constraint, foreignkey)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT, FUNCTION, constraint, function)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT, NOTNULL, constraint, notnull)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT, PRIMARYKEY, constraint, primarykey)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT, TRIGGER, constraint, trigger)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT, UNIQUE, constraint, unique)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT, VTAB, constraint, vtab)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT, ROWID, constraint, rowid))
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(MISMATCH, mismatch, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(MISUSE, misuse, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(NOLFS, nolfs, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(AUTH, auth, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(FORMAT, format, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(RANGE, range, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(NOTADB, notadb, )
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(NOTICE, notice,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(NOTICE, RECOVER_WAL, notice, recover_wal)
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(NOTICE, RECOVER_ROLLBACK, notice,
|
||||
recover_rollback))
|
||||
SQLITE_MODERN_CPP_ERROR_CODE(WARNING, warning,
|
||||
SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(WARNING, AUTOINDEX, warning, autoindex))
|
124
database/hdr/sqlite_modern_cpp/log.h
Normal file
124
database/hdr/sqlite_modern_cpp/log.h
Normal file
@ -0,0 +1,124 @@
|
||||
#include "errors.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace sqlite
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <class> using void_t = void;
|
||||
template <class T, class = void> struct is_callable : std::false_type
|
||||
{
|
||||
};
|
||||
template <class Functor, class... Arguments>
|
||||
struct is_callable<Functor(Arguments...), void_t<decltype(std::declval<Functor>()(std::declval<Arguments>()...))>>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
template <class Functor, class... Functors> class FunctorOverload : public Functor, public FunctorOverload<Functors...>
|
||||
{
|
||||
public:
|
||||
template <class Functor1, class... Remaining>
|
||||
FunctorOverload(Functor1 &&functor, Remaining &&...remaining)
|
||||
: Functor(std::forward<Functor1>(functor)), FunctorOverload<Functors...>(std::forward<Remaining>(remaining)...)
|
||||
{
|
||||
}
|
||||
using Functor::operator();
|
||||
using FunctorOverload<Functors...>::operator();
|
||||
};
|
||||
template <class Functor> class FunctorOverload<Functor> : public Functor
|
||||
{
|
||||
public:
|
||||
template <class Functor1> FunctorOverload(Functor1 &&functor) : Functor(std::forward<Functor1>(functor))
|
||||
{
|
||||
}
|
||||
using Functor::operator();
|
||||
};
|
||||
template <class Functor> class WrapIntoFunctor : public Functor
|
||||
{
|
||||
public:
|
||||
template <class Functor1> WrapIntoFunctor(Functor1 &&functor) : Functor(std::forward<Functor1>(functor))
|
||||
{
|
||||
}
|
||||
using Functor::operator();
|
||||
};
|
||||
template <class ReturnType, class... Arguments> class WrapIntoFunctor<ReturnType (*)(Arguments...)>
|
||||
{
|
||||
ReturnType (*ptr)(Arguments...);
|
||||
|
||||
public:
|
||||
WrapIntoFunctor(ReturnType (*ptr)(Arguments...)) : ptr(ptr)
|
||||
{
|
||||
}
|
||||
ReturnType operator()(Arguments... arguments)
|
||||
{
|
||||
return (*ptr)(std::forward<Arguments>(arguments)...);
|
||||
}
|
||||
};
|
||||
inline void store_error_log_data_pointer(std::shared_ptr<void> ptr)
|
||||
{
|
||||
static std::shared_ptr<void> stored;
|
||||
stored = std::move(ptr);
|
||||
}
|
||||
template <class T> std::shared_ptr<typename std::decay<T>::type> make_shared_inferred(T &&t)
|
||||
{
|
||||
return std::make_shared<typename std::decay<T>::type>(std::forward<T>(t));
|
||||
}
|
||||
} // namespace detail
|
||||
template <class Handler>
|
||||
typename std::enable_if<!detail::is_callable<Handler(const sqlite_exception &)>::value>::type error_log(
|
||||
Handler &&handler);
|
||||
template <class Handler>
|
||||
typename std::enable_if<detail::is_callable<Handler(const sqlite_exception &)>::value>::type error_log(
|
||||
Handler &&handler);
|
||||
template <class... Handler> typename std::enable_if<sizeof...(Handler) >= 2>::type error_log(Handler &&...handler)
|
||||
{
|
||||
return error_log(detail::FunctorOverload<detail::WrapIntoFunctor<typename std::decay<Handler>::type>...>(
|
||||
std::forward<Handler>(handler)...));
|
||||
}
|
||||
template <class Handler>
|
||||
typename std::enable_if<!detail::is_callable<Handler(const sqlite_exception &)>::value>::type error_log(
|
||||
Handler &&handler)
|
||||
{
|
||||
return error_log(std::forward<Handler>(handler), [](const sqlite_exception &) {});
|
||||
}
|
||||
template <class Handler>
|
||||
typename std::enable_if<detail::is_callable<Handler(const sqlite_exception &)>::value>::type error_log(
|
||||
Handler &&handler)
|
||||
{
|
||||
auto ptr = detail::make_shared_inferred(
|
||||
[handler = std::forward<Handler>(handler)](int error_code, const char *errstr) mutable {
|
||||
switch(error_code & 0xFF)
|
||||
{
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME, name, derived) \
|
||||
case SQLITE_##NAME: \
|
||||
switch(error_code) \
|
||||
{ \
|
||||
derived default : handler(errors::name(errstr, "", error_code)); \
|
||||
}; \
|
||||
break;
|
||||
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE, SUB, base, sub) \
|
||||
case SQLITE_##BASE##_##SUB: \
|
||||
handler(errors::base##_##sub(errstr, "", error_code)); \
|
||||
break;
|
||||
#include "lists/error_codes.h"
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
|
||||
#undef SQLITE_MODERN_CPP_ERROR_CODE
|
||||
default:
|
||||
handler(sqlite_exception(errstr, "", error_code));
|
||||
}
|
||||
});
|
||||
|
||||
sqlite3_config(
|
||||
SQLITE_CONFIG_LOG,
|
||||
(void (*)(void *, int, const char *))[](void *functor, int error_code, const char *errstr) {
|
||||
(*static_cast<decltype(ptr.get())>(functor))(error_code, errstr);
|
||||
},
|
||||
ptr.get());
|
||||
detail::store_error_log_data_pointer(std::move(ptr));
|
||||
}
|
||||
} // namespace sqlite
|
53
database/hdr/sqlite_modern_cpp/sqlcipher.h
Normal file
53
database/hdr/sqlite_modern_cpp/sqlcipher.h
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SQLITE_HAS_CODEC
|
||||
#define SQLITE_HAS_CODEC
|
||||
#endif
|
||||
|
||||
#include "../sqlite_modern_cpp.h"
|
||||
|
||||
namespace sqlite
|
||||
{
|
||||
struct sqlcipher_config : public sqlite_config
|
||||
{
|
||||
std::string key;
|
||||
};
|
||||
|
||||
class sqlcipher_database : public database
|
||||
{
|
||||
public:
|
||||
sqlcipher_database(std::string db, const sqlcipher_config &config) : database(db, config)
|
||||
{
|
||||
set_key(config.key);
|
||||
}
|
||||
|
||||
sqlcipher_database(std::u16string db, const sqlcipher_config &config) : database(db, config)
|
||||
{
|
||||
set_key(config.key);
|
||||
}
|
||||
|
||||
void set_key(const std::string &key)
|
||||
{
|
||||
if(auto ret = sqlite3_key(_db.get(), key.data(), key.size()))
|
||||
errors::throw_sqlite_error(ret);
|
||||
}
|
||||
|
||||
void set_key(const std::string &key, const std::string &db_name)
|
||||
{
|
||||
if(auto ret = sqlite3_key_v2(_db.get(), db_name.c_str(), key.data(), key.size()))
|
||||
errors::throw_sqlite_error(ret);
|
||||
}
|
||||
|
||||
void rekey(const std::string &new_key)
|
||||
{
|
||||
if(auto ret = sqlite3_rekey(_db.get(), new_key.data(), new_key.size()))
|
||||
errors::throw_sqlite_error(ret);
|
||||
}
|
||||
|
||||
void rekey(const std::string &new_key, const std::string &db_name)
|
||||
{
|
||||
if(auto ret = sqlite3_rekey_v2(_db.get(), db_name.c_str(), new_key.data(), new_key.size()))
|
||||
errors::throw_sqlite_error(ret);
|
||||
}
|
||||
};
|
||||
} // namespace sqlite
|
40
database/hdr/sqlite_modern_cpp/utility/function_traits.h
Normal file
40
database/hdr/sqlite_modern_cpp/utility/function_traits.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace sqlite
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
|
||||
template <typename> struct function_traits;
|
||||
|
||||
template <typename Function>
|
||||
struct function_traits : public function_traits<decltype(&std::remove_reference<Function>::type::operator())>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename ClassType, typename ReturnType, typename... Arguments>
|
||||
struct function_traits<ReturnType (ClassType::*)(Arguments...) const> : function_traits<ReturnType (*)(Arguments...)>
|
||||
{
|
||||
};
|
||||
|
||||
/* support the non-const operator ()
|
||||
* this will work with user defined functors */
|
||||
template <typename ClassType, typename ReturnType, typename... Arguments>
|
||||
struct function_traits<ReturnType (ClassType::*)(Arguments...)> : function_traits<ReturnType (*)(Arguments...)>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename ReturnType, typename... Arguments> struct function_traits<ReturnType (*)(Arguments...)>
|
||||
{
|
||||
typedef ReturnType result_type;
|
||||
|
||||
template <std::size_t Index> using argument = typename std::tuple_element<Index, std::tuple<Arguments...>>::type;
|
||||
|
||||
static const std::size_t arity = sizeof...(Arguments);
|
||||
};
|
||||
|
||||
} // namespace utility
|
||||
} // namespace sqlite
|
34
database/hdr/sqlite_modern_cpp/utility/uncaught_exceptions.h
Normal file
34
database/hdr/sqlite_modern_cpp/utility/uncaught_exceptions.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
|
||||
namespace sqlite
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
#ifdef __cpp_lib_uncaught_exceptions
|
||||
class UncaughtExceptionDetector
|
||||
{
|
||||
public:
|
||||
operator bool()
|
||||
{
|
||||
return count != std::uncaught_exceptions();
|
||||
}
|
||||
|
||||
private:
|
||||
int count = std::uncaught_exceptions();
|
||||
};
|
||||
#else
|
||||
class UncaughtExceptionDetector
|
||||
{
|
||||
public:
|
||||
operator bool()
|
||||
{
|
||||
return std::uncaught_exception();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
} // namespace utility
|
||||
} // namespace sqlite
|
45
database/hdr/sqlite_modern_cpp/utility/utf16_utf8.h
Normal file
45
database/hdr/sqlite_modern_cpp/utility/utf16_utf8.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../errors.h"
|
||||
|
||||
namespace sqlite
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
inline std::string utf16_to_utf8(const std::u16string &input)
|
||||
{
|
||||
struct : std::codecvt<char16_t, char, std::mbstate_t>
|
||||
{
|
||||
} codecvt;
|
||||
std::mbstate_t state{};
|
||||
std::string result((std::max)(input.size() * 3 / 2, std::size_t(4)), '\0');
|
||||
const char16_t *remaining_input = input.data();
|
||||
std::size_t produced_output = 0;
|
||||
while(true)
|
||||
{
|
||||
char *used_output;
|
||||
switch(codecvt.out(state, remaining_input, &input[input.size()], remaining_input, &result[produced_output],
|
||||
&result[result.size() - 1] + 1, used_output))
|
||||
{
|
||||
case std::codecvt_base::ok:
|
||||
result.resize(used_output - result.data());
|
||||
return result;
|
||||
case std::codecvt_base::noconv:
|
||||
// This should be unreachable
|
||||
case std::codecvt_base::error:
|
||||
throw errors::invalid_utf16("Invalid UTF-16 input", "");
|
||||
case std::codecvt_base::partial:
|
||||
if(used_output == result.data() + produced_output)
|
||||
throw errors::invalid_utf16("Unexpected end of input", "");
|
||||
produced_output = used_output - result.data();
|
||||
result.resize(result.size() +
|
||||
(std::max)((&input[input.size()] - remaining_input) * 3 / 2, std::ptrdiff_t(4)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace utility
|
||||
} // namespace sqlite
|
230
database/hdr/sqlite_modern_cpp/utility/variant.h
Normal file
230
database/hdr/sqlite_modern_cpp/utility/variant.h
Normal file
@ -0,0 +1,230 @@
|
||||
#pragma once
|
||||
|
||||
#include "../errors.h"
|
||||
#include <sqlite3.h>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
namespace sqlite::utility
|
||||
{
|
||||
template <typename... Options> struct VariantFirstNullable
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
template <typename T, typename... Options> struct VariantFirstNullable<T, Options...>
|
||||
{
|
||||
using type = typename VariantFirstNullable<Options...>::type;
|
||||
};
|
||||
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
||||
template <typename T, typename... Options> struct VariantFirstNullable<std::optional<T>, Options...>
|
||||
{
|
||||
using type = std::optional<T>;
|
||||
};
|
||||
#endif
|
||||
template <typename T, typename... Options> struct VariantFirstNullable<std::unique_ptr<T>, Options...>
|
||||
{
|
||||
using type = std::unique_ptr<T>;
|
||||
};
|
||||
template <typename... Options> struct VariantFirstNullable<std::nullptr_t, Options...>
|
||||
{
|
||||
using type = std::nullptr_t;
|
||||
};
|
||||
template <typename Callback, typename... Options> inline void variant_select_null(Callback &&callback)
|
||||
{
|
||||
if constexpr(std::is_same_v<typename VariantFirstNullable<Options...>::type, void>)
|
||||
{
|
||||
throw errors::mismatch("NULL is unsupported by this variant.", "", SQLITE_MISMATCH);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::forward<Callback>(callback)(typename VariantFirstNullable<Options...>::type());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Options> struct VariantFirstIntegerable
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
template <typename T, typename... Options> struct VariantFirstIntegerable<T, Options...>
|
||||
{
|
||||
using type = typename VariantFirstIntegerable<Options...>::type;
|
||||
};
|
||||
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
||||
template <typename T, typename... Options> struct VariantFirstIntegerable<std::optional<T>, Options...>
|
||||
{
|
||||
using type = std::conditional_t<std::is_same_v<typename VariantFirstIntegerable<T, Options...>::type, T>,
|
||||
std::optional<T>, typename VariantFirstIntegerable<Options...>::type>;
|
||||
};
|
||||
#endif
|
||||
template <typename T, typename... Options>
|
||||
struct VariantFirstIntegerable<
|
||||
std::enable_if_t<std::is_same_v<typename VariantFirstIntegerable<T, Options...>::type, T>>, std::unique_ptr<T>,
|
||||
Options...>
|
||||
{
|
||||
using type = std::conditional_t<std::is_same_v<typename VariantFirstIntegerable<T, Options...>::type, T>,
|
||||
std::unique_ptr<T>, typename VariantFirstIntegerable<Options...>::type>;
|
||||
};
|
||||
template <typename... Options> struct VariantFirstIntegerable<int, Options...>
|
||||
{
|
||||
using type = int;
|
||||
};
|
||||
template <typename... Options> struct VariantFirstIntegerable<sqlite_int64, Options...>
|
||||
{
|
||||
using type = sqlite_int64;
|
||||
};
|
||||
template <typename Callback, typename... Options> inline auto variant_select_integer(Callback &&callback)
|
||||
{
|
||||
if constexpr(std::is_same_v<typename VariantFirstIntegerable<Options...>::type, void>)
|
||||
{
|
||||
throw errors::mismatch("Integer is unsupported by this variant.", "", SQLITE_MISMATCH);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::forward<Callback>(callback)(typename VariantFirstIntegerable<Options...>::type());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Options> struct VariantFirstFloatable
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
template <typename T, typename... Options> struct VariantFirstFloatable<T, Options...>
|
||||
{
|
||||
using type = typename VariantFirstFloatable<Options...>::type;
|
||||
};
|
||||
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
||||
template <typename T, typename... Options> struct VariantFirstFloatable<std::optional<T>, Options...>
|
||||
{
|
||||
using type = std::conditional_t<std::is_same_v<typename VariantFirstFloatable<T, Options...>::type, T>,
|
||||
std::optional<T>, typename VariantFirstFloatable<Options...>::type>;
|
||||
};
|
||||
#endif
|
||||
template <typename T, typename... Options> struct VariantFirstFloatable<std::unique_ptr<T>, Options...>
|
||||
{
|
||||
using type = std::conditional_t<std::is_same_v<typename VariantFirstFloatable<T, Options...>::type, T>,
|
||||
std::unique_ptr<T>, typename VariantFirstFloatable<Options...>::type>;
|
||||
};
|
||||
template <typename... Options> struct VariantFirstFloatable<float, Options...>
|
||||
{
|
||||
using type = float;
|
||||
};
|
||||
template <typename... Options> struct VariantFirstFloatable<double, Options...>
|
||||
{
|
||||
using type = double;
|
||||
};
|
||||
template <typename Callback, typename... Options> inline auto variant_select_float(Callback &&callback)
|
||||
{
|
||||
if constexpr(std::is_same_v<typename VariantFirstFloatable<Options...>::type, void>)
|
||||
{
|
||||
throw errors::mismatch("Real is unsupported by this variant.", "", SQLITE_MISMATCH);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::forward<Callback>(callback)(typename VariantFirstFloatable<Options...>::type());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Options> struct VariantFirstTextable
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
template <typename T, typename... Options> struct VariantFirstTextable<T, Options...>
|
||||
{
|
||||
using type = typename VariantFirstTextable<void, Options...>::type;
|
||||
};
|
||||
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
||||
template <typename T, typename... Options> struct VariantFirstTextable<std::optional<T>, Options...>
|
||||
{
|
||||
using type = std::conditional_t<std::is_same_v<typename VariantFirstTextable<T, Options...>::type, T>,
|
||||
std::optional<T>, typename VariantFirstTextable<Options...>::type>;
|
||||
};
|
||||
#endif
|
||||
template <typename T, typename... Options> struct VariantFirstTextable<std::unique_ptr<T>, Options...>
|
||||
{
|
||||
using type = std::conditional_t<std::is_same_v<typename VariantFirstTextable<T, Options...>::type, T>,
|
||||
std::unique_ptr<T>, typename VariantFirstTextable<Options...>::type>;
|
||||
};
|
||||
template <typename... Options> struct VariantFirstTextable<std::string, Options...>
|
||||
{
|
||||
using type = std::string;
|
||||
};
|
||||
template <typename... Options> struct VariantFirstTextable<std::u16string, Options...>
|
||||
{
|
||||
using type = std::u16string;
|
||||
};
|
||||
template <typename Callback, typename... Options> inline void variant_select_text(Callback &&callback)
|
||||
{
|
||||
if constexpr(std::is_same_v<typename VariantFirstTextable<Options...>::type, void>)
|
||||
{
|
||||
throw errors::mismatch("Text is unsupported by this variant.", "", SQLITE_MISMATCH);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::forward<Callback>(callback)(typename VariantFirstTextable<Options...>::type());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Options> struct VariantFirstBlobable
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
template <typename T, typename... Options> struct VariantFirstBlobable<T, Options...>
|
||||
{
|
||||
using type = typename VariantFirstBlobable<Options...>::type;
|
||||
};
|
||||
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
|
||||
template <typename T, typename... Options> struct VariantFirstBlobable<std::optional<T>, Options...>
|
||||
{
|
||||
using type = std::conditional_t<std::is_same_v<typename VariantFirstBlobable<T, Options...>::type, T>,
|
||||
std::optional<T>, typename VariantFirstBlobable<Options...>::type>;
|
||||
};
|
||||
#endif
|
||||
template <typename T, typename... Options> struct VariantFirstBlobable<std::unique_ptr<T>, Options...>
|
||||
{
|
||||
using type = std::conditional_t<std::is_same_v<typename VariantFirstBlobable<T, Options...>::type, T>,
|
||||
std::unique_ptr<T>, typename VariantFirstBlobable<Options...>::type>;
|
||||
};
|
||||
template <typename T, typename A, typename... Options>
|
||||
struct VariantFirstBlobable<std::enable_if_t<std::is_pod_v<T>>, std::vector<T, A>, Options...>
|
||||
{
|
||||
using type = std::vector<T, A>;
|
||||
};
|
||||
template <typename Callback, typename... Options> inline auto variant_select_blob(Callback &&callback)
|
||||
{
|
||||
if constexpr(std::is_same_v<typename VariantFirstBlobable<Options...>::type, void>)
|
||||
{
|
||||
throw errors::mismatch("Blob is unsupported by this variant.", "", SQLITE_MISMATCH);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::forward<Callback>(callback)(typename VariantFirstBlobable<Options...>::type());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Options> inline auto variant_select(int type)
|
||||
{
|
||||
return [type](auto &&callback) {
|
||||
using Callback = decltype(callback);
|
||||
switch(type)
|
||||
{
|
||||
case SQLITE_NULL:
|
||||
variant_select_null<Callback, Options...>(std::forward<Callback>(callback));
|
||||
break;
|
||||
case SQLITE_INTEGER:
|
||||
variant_select_integer<Callback, Options...>(std::forward<Callback>(callback));
|
||||
break;
|
||||
case SQLITE_FLOAT:
|
||||
variant_select_float<Callback, Options...>(std::forward<Callback>(callback));
|
||||
break;
|
||||
case SQLITE_TEXT:
|
||||
variant_select_text<Callback, Options...>(std::forward<Callback>(callback));
|
||||
break;
|
||||
case SQLITE_BLOB:
|
||||
variant_select_blob<Callback, Options...>(std::forward<Callback>(callback));
|
||||
break;
|
||||
default:;
|
||||
/* assert(false); */
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace sqlite::utility
|
25
database/pagedao.cpp
Normal file
25
database/pagedao.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "pagedao.h"
|
||||
|
||||
PageDao::PageDao()
|
||||
{
|
||||
}
|
30
database/pagedao.h
Normal file
30
database/pagedao.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef PAGEDAO_H
|
||||
#define PAGEDAO_H
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include "queryoption.h"
|
||||
#include "../page.h"
|
||||
#include "../searchresult.h"
|
||||
class PageDao
|
||||
{
|
||||
public:
|
||||
PageDao();
|
||||
virtual bool exists(std::string page) const = 0;
|
||||
virtual bool exists(int id) const = 0;
|
||||
virtual std::optional<Page> find(std::string name) = 0;
|
||||
virtual std::optional<Page> find(int id) = 0;
|
||||
virtual std::vector<std::string> getPageList(QueryOption option) = 0;
|
||||
virtual std::vector<std::string> fetchCategories(std::string pagename, QueryOption option) = 0;
|
||||
virtual void deletePage(std::string page) = 0;
|
||||
virtual void save(const Page &page) = 0;
|
||||
// TODO: this may not be the correct place for this.
|
||||
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 ~PageDao()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // PAGEDAO_H
|
207
database/pagedaosqlite.cpp
Normal file
207
database/pagedaosqlite.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include <sqlite_modern_cpp/errors.h>
|
||||
#include "pagedaosqlite.h"
|
||||
#include "exceptions.h"
|
||||
#include "sqlitequeryoption.h"
|
||||
#include "../logger.h"
|
||||
|
||||
/* TODO: copied from C version mostly, review whether access to table other than page is ok */
|
||||
|
||||
bool PageDaoSqlite::exists(int id) const
|
||||
{
|
||||
auto binder = *db << "SELECT 1 from page WHERE id = ?" << id;
|
||||
return execBool(binder);
|
||||
}
|
||||
|
||||
bool PageDaoSqlite::exists(std::string name) const
|
||||
{
|
||||
auto binder = *db << "SELECT 1 FROM page WHERE name = ?" << name;
|
||||
return execBool(binder);
|
||||
}
|
||||
|
||||
std::optional<Page> PageDaoSqlite::find(std::string name)
|
||||
{
|
||||
int pageid = fetchPageId(name);
|
||||
return find(pageid);
|
||||
}
|
||||
|
||||
std::optional<Page> PageDaoSqlite::find(int id)
|
||||
{
|
||||
Page result;
|
||||
try
|
||||
{
|
||||
auto ps = *db << "SELECT name, lastrevision, visible FROM page WHERE id = ?";
|
||||
|
||||
ps << id >> std::tie(result.name, result.current_revision, result.listed);
|
||||
}
|
||||
catch(const sqlite::errors::no_rows &e)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PageDaoSqlite::deletePage(std::string page)
|
||||
{
|
||||
int pageId = this->fetchPageId(page);
|
||||
// TODO on delete cascade is better most certainly
|
||||
try
|
||||
{
|
||||
*db << "BEGIN;";
|
||||
*db << "DELETE FROM revision WHERE page = ?;" << pageId;
|
||||
*db << "DELETE FROM categorymember WHERE page = ?;" << pageId;
|
||||
*db << "DELETE FROM permissions WHERE page = ?;" << pageId;
|
||||
*db << "DELETE FROM page WHERE id =?;" << pageId;
|
||||
*db << "COMMIT;";
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
||||
|
||||
void PageDaoSqlite::save(const Page &page)
|
||||
{
|
||||
try
|
||||
{
|
||||
*db << "INSERT INTO page (name, lastrevision, visible) VALUES(?, ?, ?)" << page.name << page.current_revision
|
||||
<< page.listed;
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
||||
std::vector<std::string> PageDaoSqlite::getPageList(QueryOption option)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
std::string queryOption = SqliteQueryOption(option)
|
||||
.setOrderByColumn("lower(name)")
|
||||
.setVisibleColumnName("visible")
|
||||
.setPrependWhere(true)
|
||||
.build();
|
||||
std::string query = "SELECT name FROM page " + queryOption;
|
||||
|
||||
*db << query >> [&](std::string name) { result.push_back(name); };
|
||||
}
|
||||
catch(const sqlite::errors::no_rows &e)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> PageDaoSqlite::fetchCategories(std::string pagename, QueryOption option)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
try
|
||||
{
|
||||
auto query = *db << "SELECT name FROM categorymember INNNER JOIN category ON category = category.id WHERE page "
|
||||
"= (SELECT id FROM page WHERE name = ?)"
|
||||
<< pagename;
|
||||
query << " AND " << SqliteQueryOption(option).setPrependWhere(false).setOrderByColumn("name").build();
|
||||
query >> [&](std::string pagename) { result.push_back(pagename); };
|
||||
}
|
||||
catch(const sqlite::exceptions::no_rows &e)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<SearchResult> PageDaoSqlite::search(std::string name, QueryOption option)
|
||||
{
|
||||
|
||||
std::vector<SearchResult> result;
|
||||
try
|
||||
{
|
||||
std::string qo = SqliteQueryOption(option).setPrependWhere(false).setOrderByColumn("rank").build();
|
||||
// TODO: what is passed here, simple gets thrown to the MATCH operator without escaping or anything and this is
|
||||
// suboptimal
|
||||
auto query =
|
||||
*db << "SELECT page.name FROM search INNER JOIN page ON search.page = page.id WHERE search MATCH ? "
|
||||
<< name;
|
||||
query >> [&](std::string pagename) {
|
||||
SearchResult sresult;
|
||||
sresult.pagename = pagename;
|
||||
sresult.query = name;
|
||||
result.push_back(sresult);
|
||||
};
|
||||
}
|
||||
catch(const sqlite::exceptions::no_rows &e)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void PageDaoSqlite::setCategories(std::string pagename, const std::vector<std::string> &catnames)
|
||||
{
|
||||
try
|
||||
{
|
||||
int pageid = fetchPageId(pagename);
|
||||
*db << "savepoint setcategories;";
|
||||
*db << "DELETE FROM categorymember WHERE page = ?" << pageid;
|
||||
for(const std::string &cat : catnames)
|
||||
{
|
||||
*db << "INSERT OR IGNORE INTO category (id, name) VALUES( (SELECT id FROM category WHERE lower(name) = "
|
||||
"lower(?)), lower(?))"
|
||||
<< cat << cat;
|
||||
*db << "INSERT INTO categorymember (category, page) VALUES ( (SELECT ID FROM category WHERE lower(name) = "
|
||||
"lower(?)), ?)"
|
||||
<< cat << pageid;
|
||||
}
|
||||
*db << "release setcategories;";
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
||||
|
||||
int PageDaoSqlite::fetchPageId(std::string pagename)
|
||||
{
|
||||
auto binder = *db << "SELECT id FROM page WHERE name = ?" << pagename;
|
||||
return execInt(binder);
|
||||
}
|
29
database/pagedaosqlite.h
Normal file
29
database/pagedaosqlite.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef PAGEDAOSQLITE_H
|
||||
#define PAGEDAOSQLITE_H
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <sqlite3.h>
|
||||
#include "../page.h"
|
||||
#include "pagedao.h"
|
||||
#include "sqlitedao.h"
|
||||
class PageDaoSqlite : public PageDao, protected SqliteDao
|
||||
{
|
||||
public:
|
||||
PageDaoSqlite()
|
||||
{
|
||||
}
|
||||
void deletePage(std::string page) override;
|
||||
bool exists(int id) const override;
|
||||
bool exists(std::string name) const override;
|
||||
void save(const Page &page) override;
|
||||
std::optional<Page> find(std::string name) override;
|
||||
std::optional<Page> find(int id) override;
|
||||
std::vector<std::string> getPageList(QueryOption option) override;
|
||||
std::vector<std::string> fetchCategories(std::string pagename, QueryOption option) override;
|
||||
using SqliteDao::SqliteDao;
|
||||
int fetchPageId(std::string pagename);
|
||||
std::vector<SearchResult> search(std::string query, QueryOption option) override;
|
||||
void setCategories(std::string pagename, const std::vector<std::string> &catnames) override;
|
||||
};
|
||||
|
||||
#endif // PAGEDAOSQLITE_H
|
25
database/permissionsdao.cpp
Normal file
25
database/permissionsdao.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "permissionsdao.h"
|
||||
|
||||
PermissionsDao::PermissionsDao()
|
||||
{
|
||||
}
|
12
database/permissionsdao.h
Normal file
12
database/permissionsdao.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef PERMISSIONSDAO_H
|
||||
#define PERMISSIONSDAO_H
|
||||
#include "../permissions.h"
|
||||
#include "../user.h"
|
||||
class PermissionsDao
|
||||
{
|
||||
public:
|
||||
PermissionsDao();
|
||||
virtual Permissions find(std::string pagename, std::string username) = 0;
|
||||
};
|
||||
|
||||
#endif // PERMISSIONSDAO_H
|
31
database/permissionsdaosqlite.cpp
Normal file
31
database/permissionsdaosqlite.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "permissionsdaosqlite.h"
|
||||
|
||||
PermissionsDaoSqlite::PermissionsDaoSqlite()
|
||||
{
|
||||
}
|
||||
|
||||
Permissions PermissionsDaoSqlite::find(std::string pagename, std::string username)
|
||||
{
|
||||
/* auto query = *db << "SELECT COALESCE( (SELECT permissions FROM permissions WHERE page = ? AND userid = ?),
|
||||
(SELECT permissions FROM user WHERE ID = ?))"; exec*/
|
||||
}
|
15
database/permissionsdaosqlite.h
Normal file
15
database/permissionsdaosqlite.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef PERMISSIONSDAOSQLITE_H
|
||||
#define PERMISSIONSDAOSQLITE_H
|
||||
#include "permissionsdao.h"
|
||||
#include "sqlitedao.h"
|
||||
|
||||
class PermissionsDaoSqlite : public PermissionsDao, protected SqliteDao
|
||||
{
|
||||
public:
|
||||
PermissionsDaoSqlite();
|
||||
|
||||
Permissions find(std::string pagename, std::string username) override;
|
||||
using SqliteDao::SqliteDao;
|
||||
};
|
||||
|
||||
#endif // PERMISSIONSDAOSQLITE_H
|
21
database/queryoption.cpp
Normal file
21
database/queryoption.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "queryoption.h"
|
19
database/queryoption.h
Normal file
19
database/queryoption.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef QUERYOPTION_H
|
||||
#define QUERYOPTION_H
|
||||
|
||||
enum SORT_ORDER
|
||||
{
|
||||
ASCENDING = 0,
|
||||
DESCENDING
|
||||
};
|
||||
|
||||
class QueryOption
|
||||
{
|
||||
public:
|
||||
unsigned int offset = 0;
|
||||
unsigned int limit = 0;
|
||||
SORT_ORDER order = ASCENDING;
|
||||
bool includeInvisible = true;
|
||||
};
|
||||
|
||||
#endif // QUERYOPTION_H
|
21
database/revisiondao.cpp
Normal file
21
database/revisiondao.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "revisiondao.h"
|
23
database/revisiondao.h
Normal file
23
database/revisiondao.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef REVISIONDAO_H
|
||||
#define REVISIONDAO_H
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include "../revision.h"
|
||||
#include "queryoption.h"
|
||||
class RevisionDao
|
||||
{
|
||||
public:
|
||||
virtual void save(const Revision &revision) = 0;
|
||||
virtual std::vector<Revision> getAllRevisions(QueryOption &options) = 0;
|
||||
virtual std::vector<Revision> getAllRevisionsForPage(std::string pagename, QueryOption &option) = 0;
|
||||
virtual std::optional<Revision> getCurrentForPage(std::string pagename) = 0;
|
||||
virtual std::optional<Revision> getRevisionForPage(std::string pagnename, unsigned int revision) = 0;
|
||||
virtual unsigned int countTotalRevisions() = 0;
|
||||
virtual unsigned int countTotalRevisions(std::string pagename) = 0;
|
||||
|
||||
virtual ~RevisionDao()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // REVISIONDAO_H
|
174
database/revisiondaosqlite.cpp
Normal file
174
database/revisiondaosqlite.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "revisiondaosqlite.h"
|
||||
#include "exceptions.h"
|
||||
#include "sqlitequeryoption.h"
|
||||
#include "../utils.h"
|
||||
RevisionDaoSqlite::RevisionDaoSqlite()
|
||||
{
|
||||
}
|
||||
|
||||
void RevisionDaoSqlite::save(const Revision &revision)
|
||||
{
|
||||
try
|
||||
{
|
||||
*db << "savepoint revisionsubmit;";
|
||||
*db << "INSERT INTO revision(author, comment, content, creationtime, page, revisionid) VALUES((SELECT id FROM "
|
||||
"user WHERE username = ?), ?, ?, DATETIME(), (SELECT id FROM page WHERE name = ?), (SELECT "
|
||||
"lastrevision+1 FROM page WHERE id = (SELECT id FROM page WHERE name = ?)));"
|
||||
<< revision.author << revision.comment << revision.content << revision.page << revision.page;
|
||||
*db << "UPDATE page SET lastrevision=lastrevision+1 WHERE name = ?; " << revision.page;
|
||||
*db << "release revisionsubmit;";
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Revision> RevisionDaoSqlite::getAllRevisions(QueryOption &options)
|
||||
{
|
||||
std::vector<Revision> result;
|
||||
|
||||
try
|
||||
{
|
||||
SqliteQueryOption queryOption{options};
|
||||
std::string queryOptionSql = queryOption.setPrependWhere(true).setOrderByColumn("id").build();
|
||||
|
||||
auto query = *db << "SELECT author, comment, content, strftime('%s',creationtime), (SELECT name FROM page "
|
||||
"WHERE page.id = page ), revisionid FROM revision " +
|
||||
queryOptionSql;
|
||||
query >> [&](std::string author, std::string comment, std::string content, time_t creationtime,
|
||||
std::string page, unsigned int revisionid) {
|
||||
Revision r;
|
||||
r.author = author;
|
||||
r.comment = comment;
|
||||
r.content = content;
|
||||
r.timestamp = creationtime;
|
||||
r.page = page;
|
||||
r.revision = revisionid;
|
||||
result.push_back(r);
|
||||
};
|
||||
}
|
||||
catch(const sqlite::errors::no_rows &e)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Revision> RevisionDaoSqlite::getAllRevisionsForPage(std::string pagename, QueryOption &option)
|
||||
{
|
||||
std::vector<Revision> result;
|
||||
|
||||
try
|
||||
{
|
||||
SqliteQueryOption queryOption{option};
|
||||
std::string queryOptionSql = queryOption.setPrependWhere(false).setOrderByColumn("id").build();
|
||||
|
||||
auto query = *db << "SELECT (SELECT username FROM user WHERE id = author), comment, content, "
|
||||
"strftime('%s',creationtime), (SELECT name FROM page WHERE page.id = page ), revisionid "
|
||||
"FROM revision WHERE page = (SELECT id FROM page WHERE name = ?) " +
|
||||
queryOptionSql
|
||||
<< pagename;
|
||||
|
||||
query >> [&](std::string author, std::string comment, std::string content, time_t creationtime,
|
||||
std::string page, unsigned int revisionid) {
|
||||
Revision r;
|
||||
r.author = author;
|
||||
r.comment = comment;
|
||||
r.content = content;
|
||||
r.timestamp = creationtime;
|
||||
r.page = page;
|
||||
r.revision = revisionid;
|
||||
result.push_back(r);
|
||||
};
|
||||
}
|
||||
catch(const sqlite::errors::no_rows &e)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<Revision> RevisionDaoSqlite::getCurrentForPage(std::string pagename)
|
||||
{
|
||||
Revision result;
|
||||
try
|
||||
{
|
||||
auto query = *db << "SELECT (SELECT username FROM user WHERE id = author), comment, content, "
|
||||
"strftime('%s',creationtime), page, revisionid FROM revision WHERE page = (SELECT id FROM "
|
||||
"page WHERE name = ? ) AND revisionid = (SELECT lastrevision FROM page WHERE name = ?)";
|
||||
query << pagename << pagename;
|
||||
query >>
|
||||
std::tie(result.author, result.comment, result.content, result.timestamp, result.page, result.revision);
|
||||
}
|
||||
catch(const sqlite::errors::no_rows &e)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<Revision> RevisionDaoSqlite::getRevisionForPage(std::string pagename, unsigned int revision)
|
||||
{
|
||||
Revision result;
|
||||
|
||||
try
|
||||
{
|
||||
auto query =
|
||||
*db
|
||||
<< "SELECT (SELECT username FROM user WHERE id = author), comment, content, strftime('%s',creationtime), "
|
||||
"page, revisionid FROM revision WHERE page = (SELECT id FROM page WHERE name = ? ) AND revisionid = ?";
|
||||
query << pagename << revision;
|
||||
query >>
|
||||
std::tie(result.author, result.comment, result.content, result.timestamp, result.page, result.revision);
|
||||
}
|
||||
catch(const sqlite::exceptions::no_rows &e)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int RevisionDaoSqlite::countTotalRevisions()
|
||||
{
|
||||
auto query = *db << "SELECT COUNT(ROWID) FROM revision";
|
||||
return static_cast<unsigned int>(execInt(query));
|
||||
}
|
||||
|
||||
unsigned int RevisionDaoSqlite::countTotalRevisions(std::string page)
|
||||
{
|
||||
auto query = *db << "SELECT COUNT(ROWID) FROM revision WHERE page = (SELECT id FROM page WHERE name = ?)" << page;
|
||||
return static_cast<unsigned int>(execInt(query));
|
||||
}
|
21
database/revisiondaosqlite.h
Normal file
21
database/revisiondaosqlite.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef REVISIONDAOSQLITE_H
|
||||
#define REVISIONDAOSQLITE_H
|
||||
#include <sqlite3.h>
|
||||
#include "revisiondao.h"
|
||||
#include "sqlitedao.h"
|
||||
|
||||
class RevisionDaoSqlite : public RevisionDao, protected SqliteDao
|
||||
{
|
||||
public:
|
||||
RevisionDaoSqlite();
|
||||
void save(const Revision &revision) override;
|
||||
std::vector<Revision> getAllRevisions(QueryOption &options) override;
|
||||
std::vector<Revision> getAllRevisionsForPage(std::string pagename, QueryOption &option) override;
|
||||
std::optional<Revision> getCurrentForPage(std::string pagename) override;
|
||||
std::optional<Revision> getRevisionForPage(std::string pagnename, unsigned int revision) override;
|
||||
unsigned int countTotalRevisions() override;
|
||||
unsigned int countTotalRevisions(std::string pagename) override;
|
||||
using SqliteDao::SqliteDao;
|
||||
};
|
||||
|
||||
#endif // REVISIONDAOSQLITE_H
|
25
database/sessiondao.cpp
Normal file
25
database/sessiondao.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "sessiondao.h"
|
||||
|
||||
SessionDao::SessionDao()
|
||||
{
|
||||
}
|
18
database/sessiondao.h
Normal file
18
database/sessiondao.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef SESSIONDAO_H
|
||||
#define SESSIONDAO_H
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include "../session.h"
|
||||
class SessionDao
|
||||
{
|
||||
public:
|
||||
SessionDao();
|
||||
virtual void save(const Session &session) = 0;
|
||||
virtual std::optional<Session> find(std::string token) = 0;
|
||||
virtual void deleteSession(std::string token) = 0;
|
||||
virtual ~SessionDao()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SESSIONDAO_H
|
94
database/sessiondaosqlite.cpp
Normal file
94
database/sessiondaosqlite.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "sessiondaosqlite.h"
|
||||
#include "userdaosqlite.h"
|
||||
|
||||
void SessionDaoSqlite::save(const Session &session)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: we do not store creationtime
|
||||
auto q = *db << "INSERT OR REPLACE INTO session(id, token, csrf_token, creationtime, userid) VALUES((SELECT id "
|
||||
"FROM session WHERE token = ?), ?, ?, DATETIME(), (SELECT id FROM user WHERE username = ?))";
|
||||
q << session.token << session.token << session.csrf_token << session.user.login;
|
||||
q.execute();
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
||||
|
||||
void SessionDaoSqlite::deleteSession(std::string token)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto stmt = *db << "DELETE FROM session WHERE token = ?" << token;
|
||||
stmt.execute();
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Session> SessionDaoSqlite::find(std::string token)
|
||||
{
|
||||
Session result;
|
||||
|
||||
try
|
||||
{
|
||||
std::string username;
|
||||
auto q = *db << "SELECT userid, token, csrf_token, strftime('%s', creationtime) FROM session WHERE token = ?"
|
||||
<< token;
|
||||
int userid;
|
||||
q >> std::tie(userid, result.token, result.csrf_token, result.creation_time);
|
||||
|
||||
if(userid > -1)
|
||||
{
|
||||
UserDaoSqlite userDao{this->db};
|
||||
auto u = userDao.find(userid);
|
||||
if(u)
|
||||
{
|
||||
result.user = *u;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error() << "Session for non existent user";
|
||||
throw DatabaseQueryException("Session for non existent user");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.user = User::Anonymous();
|
||||
}
|
||||
result.loggedIn = userid != -1;
|
||||
}
|
||||
catch(const sqlite::exceptions::no_rows &e)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
return result;
|
||||
}
|
17
database/sessiondaosqlite.h
Normal file
17
database/sessiondaosqlite.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef SESSIONDAOSQLITE_H
|
||||
#define SESSIONDAOSQLITE_H
|
||||
#include "sessiondao.h"
|
||||
#include "../session.h"
|
||||
#include "sqlitedao.h"
|
||||
|
||||
class SessionDaoSqlite : public SessionDao, protected SqliteDao
|
||||
{
|
||||
public:
|
||||
SessionDaoSqlite();
|
||||
void save(const Session &session) override;
|
||||
std::optional<Session> find(std::string token) override;
|
||||
void deleteSession(std::string token) override;
|
||||
using SqliteDao::SqliteDao;
|
||||
};
|
||||
|
||||
#endif // SESSIONDAOSQLITE_H
|
86
database/sqlite.cpp
Normal file
86
database/sqlite.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "sqlite.h"
|
||||
#include "../logger.h"
|
||||
#include "pagedaosqlite.h"
|
||||
#include "revisiondaosqlite.h"
|
||||
#include "sessiondaosqlite.h"
|
||||
#include "userdaosqlite.h"
|
||||
#include "categorydaosqlite.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
Sqlite::Sqlite(std::string path) : Database(path)
|
||||
{
|
||||
this->db = std::make_shared<sqlite::database>(path);
|
||||
|
||||
*db << "PRAGMA journal_mode=WAL;";
|
||||
}
|
||||
|
||||
std::unique_ptr<RevisionDao> Sqlite::createRevisionDao() const
|
||||
{
|
||||
return create<RevisionDaoSqlite>();
|
||||
}
|
||||
|
||||
std::unique_ptr<PageDao> Sqlite::createPageDao() const
|
||||
{
|
||||
return create<PageDaoSqlite>();
|
||||
}
|
||||
|
||||
std::unique_ptr<UserDao> Sqlite::createUserDao() const
|
||||
{
|
||||
return create<UserDaoSqlite>();
|
||||
}
|
||||
|
||||
std::unique_ptr<SessionDao> Sqlite::createSessionDao() const
|
||||
{
|
||||
return create<SessionDaoSqlite>();
|
||||
}
|
||||
|
||||
std::unique_ptr<CategoryDao> Sqlite::createCategoryDao() const
|
||||
{
|
||||
return create<CategoryDaoSqlite>();
|
||||
}
|
||||
void Sqlite::beginTransaction()
|
||||
{
|
||||
if(!inTransaction)
|
||||
{
|
||||
*db << "begin;";
|
||||
inTransaction = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Sqlite::rollbackTransaction()
|
||||
{
|
||||
if(inTransaction)
|
||||
{
|
||||
*db << "rollback;";
|
||||
inTransaction = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Sqlite::commitTransaction()
|
||||
{
|
||||
if(inTransaction)
|
||||
{
|
||||
*db << "commit;";
|
||||
inTransaction = false;
|
||||
}
|
||||
}
|
31
database/sqlite.h
Normal file
31
database/sqlite.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef SQLITE_H
|
||||
#define SQLITE_H
|
||||
#include <string>
|
||||
#include <sqlite3.h>
|
||||
#include <sqlite_modern_cpp.h>
|
||||
#include "database.h"
|
||||
|
||||
class Sqlite : public Database
|
||||
{
|
||||
private:
|
||||
bool inTransaction = false;
|
||||
std::shared_ptr<sqlite::database> db;
|
||||
|
||||
template <class T> std::unique_ptr<T> create() const
|
||||
{
|
||||
return std::make_unique<T>(db);
|
||||
}
|
||||
|
||||
public:
|
||||
Sqlite(std::string path);
|
||||
std::unique_ptr<PageDao> createPageDao() const;
|
||||
std::unique_ptr<RevisionDao> createRevisionDao() const;
|
||||
std::unique_ptr<UserDao> createUserDao() const;
|
||||
std::unique_ptr<SessionDao> createSessionDao() const;
|
||||
std::unique_ptr<CategoryDao> createCategoryDao() const;
|
||||
void beginTransaction();
|
||||
void commitTransaction();
|
||||
void rollbackTransaction();
|
||||
};
|
||||
|
||||
#endif // SQLITE_H
|
51
database/sqlitedao.cpp
Normal file
51
database/sqlitedao.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "sqlitedao.h"
|
||||
|
||||
bool SqliteDao::execBool(sqlite::database_binder &binder) const
|
||||
{
|
||||
bool result;
|
||||
try
|
||||
{
|
||||
bool result;
|
||||
binder >> result;
|
||||
return result;
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
// TODO: well, we may want to check whether rows have found or not and thus log this here
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int SqliteDao::execInt(sqlite::database_binder &binder) const
|
||||
{
|
||||
try
|
||||
{
|
||||
int result;
|
||||
binder >> result;
|
||||
return result;
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
42
database/sqlitedao.h
Normal file
42
database/sqlitedao.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef SQLITEDAO_H
|
||||
#define SQLITEDAO_H
|
||||
#include <string_view>
|
||||
#include <sqlite3.h>
|
||||
#include <stdarg.h>
|
||||
#include <sqlite_modern_cpp.h>
|
||||
#include <sqlite_modern_cpp/errors.h>
|
||||
#include "queryoption.h"
|
||||
#include "exceptions.h"
|
||||
#include "../logger.h"
|
||||
|
||||
class SqliteDao
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<sqlite::database> db;
|
||||
|
||||
public:
|
||||
SqliteDao()
|
||||
{
|
||||
}
|
||||
|
||||
SqliteDao(std::shared_ptr<sqlite::database> db)
|
||||
{
|
||||
this->db = db;
|
||||
}
|
||||
void setDb(std::shared_ptr<sqlite::database> db)
|
||||
{
|
||||
this->db = db;
|
||||
}
|
||||
|
||||
inline void throwFrom(const sqlite::sqlite_exception &e) const
|
||||
{
|
||||
std::string msg = "Sqlite Error: " + std::to_string(e.get_code()) + " SQL: " + e.get_sql();
|
||||
Logger::error() << msg << " Extended code: " << e.get_extended_code();
|
||||
throw DatabaseQueryException(msg);
|
||||
}
|
||||
|
||||
bool execBool(sqlite::database_binder &binder) const;
|
||||
int execInt(sqlite::database_binder &binder) const;
|
||||
};
|
||||
|
||||
#endif // SQLITEDAO_H
|
72
database/sqlitequeryoption.cpp
Normal file
72
database/sqlitequeryoption.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "sqlitequeryoption.h"
|
||||
|
||||
SqliteQueryOption::SqliteQueryOption(const QueryOption &o)
|
||||
{
|
||||
this->o = o;
|
||||
}
|
||||
|
||||
SqliteQueryOption &SqliteQueryOption::setOrderByColumn(std::string name)
|
||||
{
|
||||
this->orderByColumnName = name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SqliteQueryOption &SqliteQueryOption::setVisibleColumnName(std::string name)
|
||||
{
|
||||
this->visibleColumnName = name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SqliteQueryOption &SqliteQueryOption::setPrependWhere(bool b)
|
||||
{
|
||||
this->prependWhere = b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string SqliteQueryOption::build()
|
||||
{
|
||||
std::string result;
|
||||
if(!o.includeInvisible && !this->visibleColumnName.empty())
|
||||
{
|
||||
if(this->prependWhere)
|
||||
{
|
||||
result += "WHERE ";
|
||||
}
|
||||
result += this->visibleColumnName + " = 1";
|
||||
}
|
||||
|
||||
result += " ORDER BY " + orderByColumnName;
|
||||
if(o.order == ASCENDING)
|
||||
{
|
||||
result += " ASC";
|
||||
}
|
||||
else
|
||||
{
|
||||
result += " DESC";
|
||||
}
|
||||
// TODO: limits for offset?
|
||||
if(o.limit > 0)
|
||||
result += " LIMIT " + std::to_string(o.limit) + " OFFSET " + std::to_string(o.offset);
|
||||
|
||||
return result;
|
||||
}
|
27
database/sqlitequeryoption.h
Normal file
27
database/sqlitequeryoption.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef SQLITEQUERYOPTION_H
|
||||
#define SQLITEQUERYOPTION_H
|
||||
#include <string>
|
||||
#include "queryoption.h"
|
||||
|
||||
class SqliteQueryOption
|
||||
{
|
||||
private:
|
||||
QueryOption o;
|
||||
std::string visibleColumnName;
|
||||
std::string orderByColumnName;
|
||||
|
||||
bool prependWhere;
|
||||
|
||||
public:
|
||||
SqliteQueryOption(const QueryOption &o);
|
||||
|
||||
SqliteQueryOption &setOrderByColumn(std::string name);
|
||||
|
||||
SqliteQueryOption &setVisibleColumnName(std::string name);
|
||||
|
||||
SqliteQueryOption &setPrependWhere(bool b);
|
||||
|
||||
std::string build();
|
||||
};
|
||||
|
||||
#endif // SQLITEQUERYOPTION_H
|
25
database/userdao.cpp
Normal file
25
database/userdao.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "userdao.h"
|
||||
|
||||
UserDao::UserDao()
|
||||
{
|
||||
}
|
18
database/userdao.h
Normal file
18
database/userdao.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef USERDAO_H
|
||||
#define USERDAO_H
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include "../user.h"
|
||||
class UserDao
|
||||
{
|
||||
public:
|
||||
UserDao();
|
||||
virtual bool exists(std::string username) = 0;
|
||||
virtual std::optional<User> find(std::string username) = 0;
|
||||
virtual std::optional<User> find(int id) = 0;
|
||||
virtual void deleteUser(std::string username) = 0;
|
||||
virtual void save(const User &u) = 0;
|
||||
virtual ~UserDao(){};
|
||||
};
|
||||
|
||||
#endif // USERDAO_H
|
91
database/userdaosqlite.cpp
Normal file
91
database/userdaosqlite.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include <sqlite3.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
#include "userdaosqlite.h"
|
||||
|
||||
UserDaoSqlite::UserDaoSqlite()
|
||||
{
|
||||
}
|
||||
|
||||
bool UserDaoSqlite::exists(std::string username)
|
||||
{
|
||||
auto prep = *db << "SELECT 1 FROM user WHERE username = ?" << username;
|
||||
return execBool(prep);
|
||||
}
|
||||
|
||||
std::optional<User> UserDaoSqlite::find(std::string username)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
User user;
|
||||
auto stmt = *db << "SELECT username, password, salt, permissions FROM user WHERE username = ?" << username;
|
||||
|
||||
int perms = 0;
|
||||
stmt >> std::tie(user.login, user.password, user.salt, perms);
|
||||
user.permissions = Permissions{perms};
|
||||
|
||||
return std::move(user);
|
||||
}
|
||||
catch(const sqlite::errors::no_rows &e)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<User> UserDaoSqlite::find(int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
User user;
|
||||
auto stmt = *db << "SELECT username, password, salt, permissions FROM user WHERE id = ?" << id;
|
||||
|
||||
int perms = 0;
|
||||
stmt >> std::tie(user.login, user.password, user.salt, perms);
|
||||
user.permissions = Permissions{perms};
|
||||
|
||||
return std::move(user);
|
||||
}
|
||||
catch(const sqlite::errors::no_rows &e)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
catch(sqlite::sqlite_exception &e)
|
||||
{
|
||||
throwFrom(e);
|
||||
}
|
||||
}
|
||||
|
||||
void UserDaoSqlite::deleteUser(std::string username)
|
||||
{
|
||||
// What to do with the contributions of the user?
|
||||
}
|
||||
|
||||
void UserDaoSqlite::save(const User &u)
|
||||
{
|
||||
}
|
22
database/userdaosqlite.h
Normal file
22
database/userdaosqlite.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef USERDAOSQLITE_H
|
||||
#define USERDAOSQLITE_H
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include "userdao.h"
|
||||
#include "sqlitedao.h"
|
||||
|
||||
class UserDaoSqlite : public UserDao, protected SqliteDao
|
||||
{
|
||||
public:
|
||||
bool exists(std::string username);
|
||||
std::optional<User> find(std::string username);
|
||||
std::optional<User> find(int id);
|
||||
|
||||
void deleteUser(std::string username);
|
||||
void save(const User &u);
|
||||
using SqliteDao::SqliteDao;
|
||||
UserDaoSqlite();
|
||||
};
|
||||
|
||||
#endif // USERDAOSQLITE_H
|
109
gateway/cgi.cpp
Normal file
109
gateway/cgi.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "cgi.h"
|
||||
#include "../utils.h"
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
Cgi::Cgi(const Config &c)
|
||||
{
|
||||
this->config = &c;
|
||||
}
|
||||
|
||||
bool Cgi::keepReading()
|
||||
{
|
||||
return !this->responseSent;
|
||||
}
|
||||
|
||||
Request Cgi::readRequest()
|
||||
{
|
||||
|
||||
std::string request_uri = utils::getenv("REQUEST_URI");
|
||||
if(request_uri == "")
|
||||
{
|
||||
throw std::runtime_error("REQUEST_URI is empty");
|
||||
}
|
||||
|
||||
Request result{request_uri};
|
||||
|
||||
std::string method = utils::getenv("REQUEST_METHOD");
|
||||
if(method == "POST")
|
||||
{
|
||||
std::string content_type = utils::getenv("CONTENT_TYPE");
|
||||
if(content_type != "application/x-www-form-urlencoded")
|
||||
{
|
||||
throw "invalid content_type";
|
||||
}
|
||||
std::string content_length = utils::getenv("CONTENT_LENGTH");
|
||||
int cl = std::stoi(content_length);
|
||||
std::unique_ptr<char[]> ptr(new char[cl + 1]);
|
||||
std::cin.get(ptr.get(), cl + 1);
|
||||
|
||||
std::string post_data{ptr.get()};
|
||||
}
|
||||
|
||||
result.initCookies(utils::getenv("HTTP_COOKIE"));
|
||||
result.setIp(utils::getenv("REMOTE_ADDR"));
|
||||
result.setUseragent(utils::getenv("HTTP_USER_AGENT"));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Cgi::work(RequestWorker &worker)
|
||||
{
|
||||
while(this->keepReading())
|
||||
{
|
||||
Request req = readRequest();
|
||||
sendResponse(worker.processRequest(req));
|
||||
}
|
||||
}
|
||||
|
||||
void Cgi::sendResponse(const Response &r)
|
||||
{
|
||||
std::cout << "Status: " << r.getStatus() << "\r\n";
|
||||
std::cout << "Content-Type: " << r.getContentType() << "\r\n";
|
||||
for(auto header : r.getResponseHeaders())
|
||||
{
|
||||
std::string key = header.first;
|
||||
std::string second = header.second;
|
||||
if(key.back() != ':')
|
||||
{
|
||||
std::cout << key << ":" << second << "\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << key << second << "\r\n";
|
||||
}
|
||||
}
|
||||
for(const Cookie &c : r.getCookies())
|
||||
{
|
||||
std::cout << "Set-Cookie: " << c.createHeaderValue() << "\r\n";
|
||||
}
|
||||
std::cout << "\r\n";
|
||||
std::cout << r.getBody();
|
||||
std::cout.flush();
|
||||
this->responseSent = true;
|
||||
}
|
||||
|
||||
Cgi::~Cgi()
|
||||
{
|
||||
}
|
22
gateway/cgi.h
Normal file
22
gateway/cgi.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef CGI_H
|
||||
#define CGI_H
|
||||
|
||||
#include "gatewayinterface.h"
|
||||
#include "../requestworker.h"
|
||||
class Cgi : public GatewayInterface
|
||||
{
|
||||
private:
|
||||
bool responseSent = false;
|
||||
const Config *config;
|
||||
Request readRequest();
|
||||
void sendResponse(const Response &r);
|
||||
|
||||
public:
|
||||
Cgi(const Config &c);
|
||||
bool keepReading() override;
|
||||
void work(RequestWorker &worker) override;
|
||||
|
||||
~Cgi();
|
||||
};
|
||||
|
||||
#endif // CGI_H
|
28
gateway/gatewayfactory.cpp
Normal file
28
gateway/gatewayfactory.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "gatewayfactory.h"
|
||||
#include "cgi.h"
|
||||
#include "httpgateway.h"
|
||||
|
||||
std::unique_ptr<GatewayInterface> createGateway(const Config &c)
|
||||
{
|
||||
return std::make_unique<HttpGateway>(c);
|
||||
}
|
8
gateway/gatewayfactory.h
Normal file
8
gateway/gatewayfactory.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef GATEWAYFACTORY_H
|
||||
#define GATEWAYFACTORY_H
|
||||
#include <memory>
|
||||
#include "../config.h"
|
||||
#include "gatewayinterface.h"
|
||||
std::unique_ptr<GatewayInterface> createGateway(const Config &c);
|
||||
|
||||
#endif // GATEWAYFACTORY_H
|
25
gateway/gatewayinterface.cpp
Normal file
25
gateway/gatewayinterface.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "gatewayinterface.h"
|
||||
|
||||
GatewayInterface::GatewayInterface()
|
||||
{
|
||||
}
|
18
gateway/gatewayinterface.h
Normal file
18
gateway/gatewayinterface.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef GATEWAYINTERFACE_H
|
||||
#define GATEWAYINTERFACE_H
|
||||
#include "../request.h"
|
||||
#include "../response.h"
|
||||
#include "../config.h"
|
||||
#include "../requestworker.h"
|
||||
class GatewayInterface
|
||||
{
|
||||
public:
|
||||
GatewayInterface();
|
||||
virtual bool keepReading() = 0;
|
||||
virtual void work(RequestWorker &worker) = 0;
|
||||
virtual ~GatewayInterface()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // GATEWAYINTERFACE_H
|
93
gateway/httpgateway.cpp
Normal file
93
gateway/httpgateway.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "httpgateway.h"
|
||||
#include "../logger.h"
|
||||
HttpGateway::HttpGateway(const Config &config)
|
||||
{
|
||||
}
|
||||
|
||||
bool HttpGateway::keepReading()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Request HttpGateway::convertRequest(httplib::Request request)
|
||||
{
|
||||
Request result;
|
||||
result.setRequestMethod(request.method);
|
||||
result.setUrl(request.target);
|
||||
|
||||
// TODO: this eats resources, where perhaps it does not need to. move it to request?
|
||||
for(auto &it : request.params)
|
||||
{
|
||||
it.second = utils::html_xss(std::string{it.second});
|
||||
}
|
||||
if(request.method == "GET")
|
||||
{
|
||||
result.setGetVars(request.params);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.initGetMap(request.target);
|
||||
result.setPostVars(request.params);
|
||||
}
|
||||
|
||||
if(request.has_header("COOKIE"))
|
||||
{
|
||||
result.initCookies(request.get_header_value("COOKIE"));
|
||||
}
|
||||
result.setIp(request.get_header_value("REMOTE_ADDR"));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
httplib::Response HttpGateway::convertResponse(Response response)
|
||||
{
|
||||
httplib::Response result;
|
||||
result.set_content(response.getBody(), response.getContentType().c_str());
|
||||
result.status = response.getStatus();
|
||||
for(auto &header : response.getResponseHeaders())
|
||||
{
|
||||
result.set_header(header.first.c_str(), header.second.c_str());
|
||||
}
|
||||
|
||||
for(const Cookie &cookie : response.getCookies())
|
||||
{
|
||||
result.set_header("Set-Cookie", cookie.createHeaderValue().c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void HttpGateway::work(RequestWorker &worker)
|
||||
{
|
||||
httplib::Server server;
|
||||
|
||||
auto handler = [&](const httplib::Request &req, httplib::Response &res) {
|
||||
Request wikiRequest = convertRequest(req);
|
||||
Logger::debug() << "httpgateway: received request " << wikiRequest;
|
||||
Response wikiresponse = worker.processRequest(wikiRequest);
|
||||
|
||||
res = convertResponse(wikiresponse);
|
||||
};
|
||||
server.Get("/(.*)", handler);
|
||||
server.Post("/(.*)", handler);
|
||||
server.listen("localhost", 1234);
|
||||
}
|
22
gateway/httpgateway.h
Normal file
22
gateway/httpgateway.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef HTTPGATEWAY_H
|
||||
#define HTTPGATEWAY_H
|
||||
#include "httplib.h"
|
||||
#include "gatewayinterface.h"
|
||||
#include "../requestworker.h"
|
||||
#include "../request.h"
|
||||
#include "../response.h"
|
||||
#include "../utils.h"
|
||||
class HttpGateway : public GatewayInterface
|
||||
{
|
||||
private:
|
||||
Response convertResponse(httplib::Response response);
|
||||
httplib::Response convertResponse(Response response);
|
||||
Request convertRequest(httplib::Request request);
|
||||
// void worker(const httplib::Request& req, httplib::Response& res);
|
||||
public:
|
||||
HttpGateway(const Config &config);
|
||||
bool keepReading() override;
|
||||
void work(RequestWorker &worker) override;
|
||||
};
|
||||
|
||||
#endif // HTTPGATEWAY_H
|
2665
gateway/httplib.h
Normal file
2665
gateway/httplib.h
Normal file
文件差異過大導致無法顯示
Load Diff
76
handlers/handler.cpp
Normal file
76
handlers/handler.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handler.h"
|
||||
|
||||
void Handler::setGeneralVars(TemplatePage &page)
|
||||
{
|
||||
if(userSession->loggedIn)
|
||||
{
|
||||
page.setVar("loginstatus", "Logged in as " + userSession->user.login);
|
||||
}
|
||||
else
|
||||
{
|
||||
page.setVar("loginstatus", "not logged in");
|
||||
}
|
||||
page.setVar("csrf_token", utils::toString(this->userSession->csrf_token));
|
||||
}
|
||||
Response Handler::errorResponse(std::string errortitle, std::string errormessage, int status)
|
||||
{
|
||||
TemplatePage &error = this->templ->getPage("error");
|
||||
error.setVar("errortitle", errortitle);
|
||||
error.setVar("errormessage", errormessage);
|
||||
// TODO: log?
|
||||
setGeneralVars(error);
|
||||
return {status, error.render()};
|
||||
}
|
||||
|
||||
QueryOption Handler::queryOption(const Request &r) const
|
||||
{
|
||||
QueryOption result;
|
||||
result.includeInvisible = false;
|
||||
try
|
||||
{
|
||||
result.limit = utils::toUInt(r.get("limit"));
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
result.limit = 0;
|
||||
}
|
||||
try
|
||||
{
|
||||
result.offset = utils::toUInt(r.get("offset"));
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
result.offset = 0;
|
||||
}
|
||||
std::string order = r.get("sort");
|
||||
if(order == "0")
|
||||
{
|
||||
result.order = ASCENDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.order = DESCENDING;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
40
handlers/handler.h
Normal file
40
handlers/handler.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef HANDLER_H
|
||||
#define HANDLER_H
|
||||
|
||||
#include "../response.h"
|
||||
#include "../request.h"
|
||||
#include "../template.h"
|
||||
#include "../database/database.h"
|
||||
#include "../urlprovider.h"
|
||||
#include "../database/queryoption.h"
|
||||
#include "../logger.h"
|
||||
#include "../cache/icache.h"
|
||||
class Handler
|
||||
{
|
||||
protected:
|
||||
ICache *cache;
|
||||
Template *templ;
|
||||
Database *database;
|
||||
Session *userSession;
|
||||
UrlProvider *urlProvider;
|
||||
|
||||
QueryOption queryOption(const Request &r) const;
|
||||
|
||||
public:
|
||||
Handler(Template &templ, Database &db, Session &userSession, UrlProvider &provider, ICache &cache)
|
||||
{
|
||||
this->templ = &templ;
|
||||
this->database = &db;
|
||||
this->userSession = &userSession;
|
||||
this->urlProvider = &provider;
|
||||
this->cache = &cache;
|
||||
}
|
||||
virtual Response handle(const Request &r) = 0;
|
||||
void setGeneralVars(TemplatePage &page);
|
||||
virtual ~Handler()
|
||||
{
|
||||
}
|
||||
Response errorResponse(std::string errortitle, std::string errormessage, int status = 200);
|
||||
};
|
||||
|
||||
#endif // HANDLER_H
|
45
handlers/handlerallcategories.cpp
Normal file
45
handlers/handlerallcategories.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlerallcategories.h"
|
||||
#include "../urlprovider.h"
|
||||
#include "../logger.h"
|
||||
Response HandlerAllCategories::handle(const Request &r)
|
||||
{
|
||||
auto categoryDao = this->database->createCategoryDao();
|
||||
QueryOption qo = queryOption(r);
|
||||
auto resultList = categoryDao->fetchList(qo);
|
||||
if(resultList.size() == 0)
|
||||
{
|
||||
return errorResponse(
|
||||
"No categories",
|
||||
"This wiki does not have any categories defined yet or your query options did not yield any results");
|
||||
}
|
||||
TemplatePage &searchPage = this->templ->getPage("allcategories");
|
||||
std::string body =
|
||||
this->templ->renderSearch(resultList, [&](std::string str) { return this->urlProvider->category(str); });
|
||||
searchPage.setVar("categorylist", body);
|
||||
setGeneralVars(searchPage);
|
||||
|
||||
Response response;
|
||||
response.setBody(searchPage.render());
|
||||
response.setStatus(200);
|
||||
return response;
|
||||
}
|
14
handlers/handlerallcategories.h
Normal file
14
handlers/handlerallcategories.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef HANDLERALLCATEGORIES_H
|
||||
#define HANDLERALLCATEGORIES_H
|
||||
|
||||
#include "handler.h"
|
||||
|
||||
class HandlerAllCategories : public Handler
|
||||
{
|
||||
public:
|
||||
HandlerAllCategories();
|
||||
using Handler::Handler;
|
||||
Response handle(const Request &r) override;
|
||||
};
|
||||
|
||||
#endif // HANDLERALLCATEGORIES_H
|
48
handlers/handlerallpages.cpp
Normal file
48
handlers/handlerallpages.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlerallpages.h"
|
||||
|
||||
Response HandlerAllPages::handle(const Request &r)
|
||||
{
|
||||
try
|
||||
{
|
||||
Response response;
|
||||
auto pageDao = this->database->createPageDao();
|
||||
QueryOption qo = queryOption(r);
|
||||
auto resultList = pageDao->getPageList(qo);
|
||||
if(resultList.size() == 0)
|
||||
{
|
||||
return errorResponse("No pages", "This wiki does not have any pages yet");
|
||||
}
|
||||
TemplatePage &searchPage = this->templ->getPage("allpages");
|
||||
std::string body = this->templ->renderSearch(resultList);
|
||||
searchPage.setVar("pagelist", body);
|
||||
setGeneralVars(searchPage);
|
||||
response.setBody(searchPage.render());
|
||||
response.setStatus(200);
|
||||
return response;
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
Logger::error() << "Error during allpages Handler" << e.what();
|
||||
return errorResponse("Error", "An unknown error occured");
|
||||
}
|
||||
}
|
13
handlers/handlerallpages.h
Normal file
13
handlers/handlerallpages.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef HANDLERALLPAGES_H
|
||||
#define HANDLERALLPAGES_H
|
||||
|
||||
#include "handler.h"
|
||||
class HandlerAllPages : public Handler
|
||||
{
|
||||
public:
|
||||
HandlerAllPages();
|
||||
using Handler::Handler;
|
||||
Response handle(const Request &r) override;
|
||||
};
|
||||
|
||||
#endif // HANDLERALLPAGES_H
|
50
handlers/handlercategory.cpp
Normal file
50
handlers/handlercategory.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlercategory.h"
|
||||
|
||||
Response HandlerCategory::handle(const Request &r)
|
||||
{
|
||||
try
|
||||
{
|
||||
Response response;
|
||||
std::string categoryname = r.get("category");
|
||||
auto categoryDao = this->database->createCategoryDao();
|
||||
if(!categoryDao->find(categoryname))
|
||||
{
|
||||
return this->errorResponse("No such category", "A category with the provided name does not exist", 404);
|
||||
}
|
||||
QueryOption qo = queryOption(r);
|
||||
auto resultList = categoryDao->fetchMembers(categoryname, qo);
|
||||
TemplatePage &searchPage = this->templ->getPage("show_category");
|
||||
std::string body = this->templ->renderSearch(resultList);
|
||||
searchPage.setVar("pagelist", body);
|
||||
searchPage.setVar("categoryname", categoryname);
|
||||
setGeneralVars(searchPage);
|
||||
response.setBody(searchPage.render());
|
||||
response.setStatus(200);
|
||||
return response;
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
Logger::error() << "Error during category Handler" << e.what();
|
||||
return errorResponse("Error", "An unknown error occured");
|
||||
}
|
||||
}
|
13
handlers/handlercategory.h
Normal file
13
handlers/handlercategory.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef HANDLERCATEGORY_H
|
||||
#define HANDLERCATEGORY_H
|
||||
#include "handler.h"
|
||||
|
||||
class HandlerCategory : public Handler
|
||||
{
|
||||
public:
|
||||
HandlerCategory();
|
||||
using Handler::Handler;
|
||||
Response handle(const Request &r) override;
|
||||
};
|
||||
|
||||
#endif // HANDLERCATEGORY_H
|
30
handlers/handlerdefault.cpp
Normal file
30
handlers/handlerdefault.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlerdefault.h"
|
||||
|
||||
Response HandlerDefault::handle(const Request &r)
|
||||
{
|
||||
return Response::redirectTemporarily(this->urlProvider->index());
|
||||
}
|
||||
|
||||
HandlerDefault::~HandlerDefault()
|
||||
{
|
||||
}
|
13
handlers/handlerdefault.h
Normal file
13
handlers/handlerdefault.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef HANDLERDEFAULT_H
|
||||
#define HANDLERDEFAULT_H
|
||||
|
||||
#include "handler.h"
|
||||
class HandlerDefault : public Handler
|
||||
{
|
||||
public:
|
||||
Response handle(const Request &r) override;
|
||||
~HandlerDefault() override;
|
||||
using Handler::Handler;
|
||||
};
|
||||
|
||||
#endif // HANDLERDEFAULT_H
|
102
handlers/handlerfactory.cpp
Normal file
102
handlers/handlerfactory.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlerfactory.h"
|
||||
#include "handler.h"
|
||||
#include "handlerdefault.h"
|
||||
#include "handlerpageview.h"
|
||||
#include "handlerinvalidaction.h"
|
||||
#include "handlerlogin.h"
|
||||
#include "handlerpageedit.h"
|
||||
#include "handlersearch.h"
|
||||
#include "handlerallpages.h"
|
||||
#include "handlerallcategories.h"
|
||||
#include "handlercategory.h"
|
||||
#include "handlerhistory.h"
|
||||
#include "handlerpagedelete.h"
|
||||
class Factory
|
||||
{
|
||||
Template &templ;
|
||||
Database &db;
|
||||
Session &userSession;
|
||||
UrlProvider &urlProvider;
|
||||
ICache &cache;
|
||||
|
||||
public:
|
||||
Factory(Template &templ, Database &db, Session &usersession, UrlProvider &urlprovider, ICache &cache)
|
||||
: templ(templ), db(db), userSession(usersession), urlProvider(urlprovider), cache(cache)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T> inline std::unique_ptr<T> produce()
|
||||
{
|
||||
return std::make_unique<T>(templ, db, userSession, urlProvider, cache);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<Handler> createHandler(const std::string &action, Template &templ, Database &db, Session &usersession,
|
||||
UrlProvider &urlprovider, ICache &cache)
|
||||
{
|
||||
|
||||
Factory producer(templ, db, usersession, urlprovider, cache);
|
||||
|
||||
if(action == "" || action == "index")
|
||||
{
|
||||
return producer.produce<HandlerDefault>();
|
||||
}
|
||||
if(action == "show")
|
||||
{
|
||||
return producer.produce<HandlerPageView>();
|
||||
}
|
||||
if(action == "edit")
|
||||
{
|
||||
return producer.produce<HandlerPageEdit>();
|
||||
}
|
||||
if(action == "login")
|
||||
{
|
||||
return producer.produce<HandlerLogin>();
|
||||
}
|
||||
if(action == "search")
|
||||
{
|
||||
return producer.produce<HandlerSearch>();
|
||||
}
|
||||
if(action == "delete")
|
||||
{
|
||||
return producer.produce<HandlerPageDelete>();
|
||||
}
|
||||
if(action == "allpages")
|
||||
{
|
||||
return producer.produce<HandlerAllPages>();
|
||||
}
|
||||
if(action == "allcategories")
|
||||
{
|
||||
return producer.produce<HandlerAllCategories>();
|
||||
}
|
||||
if(action == "showcat")
|
||||
{
|
||||
return producer.produce<HandlerCategory>();
|
||||
}
|
||||
if(action == "recent")
|
||||
{
|
||||
return producer.produce<HandlerHistory>();
|
||||
}
|
||||
|
||||
return producer.produce<HandlerInvalidAction>();
|
||||
}
|
9
handlers/handlerfactory.h
Normal file
9
handlers/handlerfactory.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef HANDLERFACTORY_H
|
||||
#define HANDLERFACTORY_H
|
||||
#include <memory>
|
||||
#include "handler.h"
|
||||
#include "../template.h"
|
||||
|
||||
std::unique_ptr<Handler> createHandler(const std::string &action, Template &templ, Database &db, Session &usersession,
|
||||
UrlProvider &urlprovider, ICache &cache);
|
||||
#endif // HANDLERFACTORY_H
|
104
handlers/handlerhistory.cpp
Normal file
104
handlers/handlerhistory.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlerhistory.h"
|
||||
#include "handler.h"
|
||||
#include "../htmllink.h"
|
||||
#include "../logger.h"
|
||||
#include "../database/exceptions.h"
|
||||
Response HandlerHistory::handle(const Request &r)
|
||||
{
|
||||
QueryOption qo = queryOption(r);
|
||||
std::string page = r.get("page");
|
||||
|
||||
unsigned int count = 0;
|
||||
std::vector<Revision> resultList;
|
||||
auto revisionDao = this->database->createRevisionDao();
|
||||
|
||||
auto makeSortedLink = [&](unsigned int limit, unsigned int offset, unsigned int order) {
|
||||
if(!page.empty())
|
||||
{
|
||||
return this->urlProvider->pageHistorySort(page, limit, offset, order);
|
||||
}
|
||||
return this->urlProvider->recentSorted(limit, offset, order);
|
||||
};
|
||||
std::string templatename = "recentchanges";
|
||||
try
|
||||
{
|
||||
if(!page.empty())
|
||||
{
|
||||
auto pageDao = this->database->createPageDao();
|
||||
if(!pageDao->exists(page))
|
||||
{
|
||||
return errorResponse("No such page", "No such page exists to show history for", 404);
|
||||
}
|
||||
count = revisionDao->countTotalRevisions(page);
|
||||
resultList = revisionDao->getAllRevisionsForPage(page, qo);
|
||||
templatename = "page_history";
|
||||
}
|
||||
else
|
||||
{
|
||||
count = revisionDao->countTotalRevisions();
|
||||
if(count == 0)
|
||||
{
|
||||
return errorResponse("No revisions", "This wiki does not have any pages with revisions yet");
|
||||
}
|
||||
resultList = revisionDao->getAllRevisions(qo);
|
||||
}
|
||||
}
|
||||
catch(const DatabaseException &e)
|
||||
{
|
||||
Logger::error() << "DatabaseException in handlerhistory: " << e.what();
|
||||
return errorResponse("Database error", "While trying to fetch revision list, a database error occured");
|
||||
}
|
||||
TemplatePage historyPage = this->templ->getPage(templatename);
|
||||
setGeneralVars(historyPage);
|
||||
|
||||
if((qo.offset + (unsigned int)resultList.size()) < count)
|
||||
{
|
||||
HtmlLink link;
|
||||
link.href = makeSortedLink(qo.limit, qo.offset + qo.limit, qo.order);
|
||||
link.innervalue = "Next page";
|
||||
|
||||
historyPage.setVar("nextpage", link.render());
|
||||
}
|
||||
|
||||
unsigned int prevoffset = qo.offset - qo.limit;
|
||||
if(prevoffset > count)
|
||||
{
|
||||
prevoffset = 0;
|
||||
}
|
||||
if(qo.offset > 0 && qo.offset < count)
|
||||
{
|
||||
HtmlLink link;
|
||||
link.href = makeSortedLink(qo.limit, prevoffset, qo.order);
|
||||
link.innervalue = "Previous page";
|
||||
|
||||
historyPage.setVar("prevpage", link.render());
|
||||
}
|
||||
|
||||
unsigned int neworder = (qo.order == DESCENDING) ? ASCENDING : DESCENDING;
|
||||
historyPage.setVar("linkrecentsort", makeSortedLink(qo.limit, qo.offset, neworder));
|
||||
historyPage.setVar("revisionlist", this->templ->renderRevisionList(resultList, page.empty()));
|
||||
Response response;
|
||||
response.setBody(historyPage.render());
|
||||
response.setStatus(200);
|
||||
return response;
|
||||
}
|
14
handlers/handlerhistory.h
Normal file
14
handlers/handlerhistory.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef HANDLERHISTORY_H
|
||||
#define HANDLERHISTORY_H
|
||||
#include "handler.h"
|
||||
|
||||
class HandlerHistory : public Handler
|
||||
{
|
||||
|
||||
public:
|
||||
HandlerHistory();
|
||||
using Handler::Handler;
|
||||
Response handle(const Request &r) override;
|
||||
};
|
||||
|
||||
#endif // HANDLERHISTORY_H
|
26
handlers/handlerinvalidaction.cpp
Normal file
26
handlers/handlerinvalidaction.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlerinvalidaction.h"
|
||||
|
||||
Response HandlerInvalidAction::handle(const Request &r)
|
||||
{
|
||||
return errorResponse("Invalid action", "No action defined for this action");
|
||||
}
|
15
handlers/handlerinvalidaction.h
Normal file
15
handlers/handlerinvalidaction.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef HANDLERINVALIDACTION_H
|
||||
#define HANDLERINVALIDACTION_H
|
||||
#include "handler.h"
|
||||
|
||||
class HandlerInvalidAction : public Handler
|
||||
{
|
||||
public:
|
||||
Response handle(const Request &r) override;
|
||||
~HandlerInvalidAction() override
|
||||
{
|
||||
}
|
||||
using Handler::Handler;
|
||||
};
|
||||
|
||||
#endif // HANDLERINVALIDACTION_H
|
118
handlers/handlerlogin.cpp
Normal file
118
handlers/handlerlogin.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include <openssl/evp.h>
|
||||
#include "handlerlogin.h"
|
||||
#include "../logger.h"
|
||||
struct LoginFail
|
||||
{
|
||||
unsigned int count;
|
||||
time_t lastfail;
|
||||
};
|
||||
static std::map<std::string, LoginFail> loginFails;
|
||||
|
||||
// TODO: make configurable
|
||||
bool HandlerLogin::isBanned(std::string ip)
|
||||
{
|
||||
if(utils::hasKey(loginFails, ip))
|
||||
{
|
||||
LoginFail &fl = loginFails[ip];
|
||||
return fl.count > 5 && (time(nullptr) - fl.lastfail) < 1200;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HandlerLogin::incFailureCount(std::string ip)
|
||||
{
|
||||
LoginFail &fl = loginFails[ip];
|
||||
fl.count += 1;
|
||||
fl.lastfail = time(nullptr);
|
||||
}
|
||||
|
||||
std::vector<char> HandlerLogin::pbkdf5(std::string password, const std::vector<char> &salt)
|
||||
{
|
||||
unsigned char hash[32];
|
||||
const EVP_MD *sha256 = EVP_sha256();
|
||||
const unsigned char *rawsalt = reinterpret_cast<const unsigned char *>(salt.data());
|
||||
PKCS5_PBKDF2_HMAC(password.c_str(), password.size(), rawsalt, salt.size(), 300000, sha256, sizeof(hash), hash);
|
||||
|
||||
std::vector<char> result;
|
||||
|
||||
for(size_t i = 0; i < sizeof(hash); i++)
|
||||
{
|
||||
|
||||
result.push_back(static_cast<char>(hash[i]));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Response HandlerLogin::handle(const Request &r)
|
||||
{
|
||||
auto createErrorReesponse = [&]() {
|
||||
return errorResponse("Login error", "The supplied credenetials are incorrect");
|
||||
};
|
||||
|
||||
if(isBanned(r.getIp()))
|
||||
{
|
||||
return errorResponse("Banned", "You have been banned for too many login attempts. Try again later");
|
||||
}
|
||||
if(r.param("submit") == "1")
|
||||
{
|
||||
std::string password = r.post("password");
|
||||
std::string username = r.post("user");
|
||||
|
||||
auto userDao = this->database->createUserDao();
|
||||
std::optional<User> user = userDao->find(username);
|
||||
if(!user)
|
||||
{
|
||||
return createErrorReesponse();
|
||||
}
|
||||
|
||||
auto hashresult = pbkdf5(password, user.value().salt);
|
||||
// TODO: timing attack
|
||||
if(hashresult == user.value().password)
|
||||
{
|
||||
loginFails.erase(r.getIp());
|
||||
Response r = Response::redirectTemporarily(urlProvider->index());
|
||||
*(this->userSession) = Session(user.value());
|
||||
return r;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: only if wanted by config
|
||||
incFailureCount(r.getIp());
|
||||
return createErrorReesponse();
|
||||
}
|
||||
|
||||
// auto pbkdf5 = pbkdf5(password, user->)
|
||||
}
|
||||
std::string page = r.get("page");
|
||||
if(page.empty())
|
||||
page = "index";
|
||||
|
||||
TemplatePage &loginTemplatePage = this->templ->getPage("login");
|
||||
setGeneralVars(loginTemplatePage);
|
||||
loginTemplatePage.setVar("loginurl", urlProvider->login(page));
|
||||
Response result;
|
||||
result.setStatus(200);
|
||||
result.setBody(loginTemplatePage.render());
|
||||
return result;
|
||||
}
|
22
handlers/handlerlogin.h
Normal file
22
handlers/handlerlogin.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef HANDLERLOGIN_H
|
||||
#define HANDLERLOGIN_H
|
||||
#include <vector>
|
||||
#include "handler.h"
|
||||
|
||||
class HandlerLogin : public Handler
|
||||
{
|
||||
private:
|
||||
bool isBanned(std::string ip);
|
||||
void incFailureCount(std::string ip);
|
||||
std::vector<char> pbkdf5(std::string password, const std::vector<char> &salt);
|
||||
|
||||
public:
|
||||
HandlerLogin();
|
||||
Response handle(const Request &r) override;
|
||||
~HandlerLogin() override
|
||||
{
|
||||
}
|
||||
using Handler::Handler;
|
||||
};
|
||||
|
||||
#endif // HANDERLOGIN_H
|
90
handlers/handlerpage.cpp
Normal file
90
handlers/handlerpage.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlerpage.h"
|
||||
|
||||
Response HandlerPage::handle(const Request &r)
|
||||
{
|
||||
std::string pagename = r.get("page");
|
||||
auto pageDao = this->database->createPageDao();
|
||||
if(pagename.empty())
|
||||
{
|
||||
return errorResponse("No page given", "No page given to request");
|
||||
}
|
||||
|
||||
if(pageMustExist() && !pageDao->exists(pagename))
|
||||
{
|
||||
std::string createlink = this->urlProvider->editPage(pagename);
|
||||
return errorResponse(
|
||||
"Page not found",
|
||||
"The requested page was not found. Do you want to <a href=\"" + createlink + "\">create</a> it?", 404);
|
||||
}
|
||||
|
||||
if(!canAccess(pagename))
|
||||
{
|
||||
return errorResponse("Permission denied", accessErrorMessage());
|
||||
}
|
||||
|
||||
return this->handleRequest(*pageDao, pagename, r);
|
||||
}
|
||||
|
||||
std::string HandlerPage::accessErrorMessage()
|
||||
{
|
||||
return "You don't have permission to access this page";
|
||||
}
|
||||
|
||||
bool HandlerPage::pageMustExist()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandlerPage::setPageVars(TemplatePage &page, std::string pagename)
|
||||
{
|
||||
setGeneralVars(page);
|
||||
|
||||
if(!pagename.empty())
|
||||
{
|
||||
std::string headerlinks;
|
||||
TemplatePage &headerlink = this->templ->getPage("_headerlink");
|
||||
auto addHeaderLink = [&headerlinks, &headerlink](std::string href, std::string value) {
|
||||
headerlink.setVar("href", href);
|
||||
headerlink.setVar("value", value);
|
||||
headerlinks += headerlink.render();
|
||||
};
|
||||
Permissions &perms = this->userSession->user.permissions;
|
||||
|
||||
if(perms.canEdit())
|
||||
{
|
||||
addHeaderLink(this->urlProvider->editPage(pagename), "Edit");
|
||||
addHeaderLink(this->urlProvider->pageSettings(pagename), "Page settings");
|
||||
}
|
||||
if(perms.canDelete())
|
||||
{
|
||||
addHeaderLink(this->urlProvider->pageDelete(pagename), "Delete");
|
||||
}
|
||||
if(perms.canSeePageHistory())
|
||||
{
|
||||
addHeaderLink(this->urlProvider->pageHistory(pagename), "Show history");
|
||||
}
|
||||
|
||||
page.setVar("headerlinks", headerlinks);
|
||||
page.setVar("page", pagename);
|
||||
}
|
||||
}
|
23
handlers/handlerpage.h
Normal file
23
handlers/handlerpage.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef HANDLERPAGE_H
|
||||
#define HANDLERPAGE_H
|
||||
#include "handler.h"
|
||||
|
||||
class HandlerPage : public Handler
|
||||
{
|
||||
protected:
|
||||
virtual bool canAccess(std::string page) = 0;
|
||||
virtual bool pageMustExist();
|
||||
virtual std::string accessErrorMessage();
|
||||
|
||||
public:
|
||||
Response handle(const Request &r) override;
|
||||
virtual Response handleRequest(PageDao &pageDao, std::string pagename, const Request &r) = 0;
|
||||
~HandlerPage() override
|
||||
{
|
||||
}
|
||||
using Handler::Handler;
|
||||
|
||||
void setPageVars(TemplatePage &page, std::string pagename);
|
||||
};
|
||||
|
||||
#endif // HANDLERPAGE_H
|
47
handlers/handlerpagedelete.cpp
Normal file
47
handlers/handlerpagedelete.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlerpagedelete.h"
|
||||
#include "../database/exceptions.h"
|
||||
|
||||
Response HandlerPageDelete::handleRequest(PageDao &pageDao, std::string pagename, const Request &r)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if(r.getRequestMethod() == "POST")
|
||||
{
|
||||
pageDao.deletePage(pagename);
|
||||
this->cache->removePrefix("page:"); // TODO: overkill?
|
||||
return Response::redirectTemporarily(this->urlProvider->index());
|
||||
}
|
||||
TemplatePage delPage = this->templ->getPage("page_deletion");
|
||||
delPage.setVar("deletionurl", this->urlProvider->pageDelete(pagename));
|
||||
setPageVars(delPage, pagename);
|
||||
Response r;
|
||||
r.setBody(delPage.render());
|
||||
return r;
|
||||
}
|
||||
catch(const DatabaseException &e)
|
||||
{
|
||||
Logger::debug() << "Error delete page: " << e.what();
|
||||
return errorResponse("Database error", "A database error occured while trying to delete this page");
|
||||
}
|
||||
}
|
27
handlers/handlerpagedelete.h
Normal file
27
handlers/handlerpagedelete.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef HANDLERPAGEDELETE_H
|
||||
#define HANDLERPAGEDELETE_H
|
||||
#include "handlerpage.h"
|
||||
|
||||
class HandlerPageDelete : public HandlerPage
|
||||
{
|
||||
bool pageMustExist() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canAccess(std::string page) override
|
||||
{
|
||||
return this->userSession->user.permissions.canDelete();
|
||||
}
|
||||
|
||||
std::string accessErrorMessage() override
|
||||
{
|
||||
return "You don't have permission to delete pages";
|
||||
}
|
||||
|
||||
public:
|
||||
Response handleRequest(PageDao &pageDao, std::string pagename, const Request &r) override;
|
||||
using HandlerPage::HandlerPage;
|
||||
};
|
||||
|
||||
#endif // HANDLERPAGEDELETE_H
|
115
handlers/handlerpageedit.cpp
Normal file
115
handlers/handlerpageedit.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlerpageedit.h"
|
||||
#include "../database/exceptions.h"
|
||||
#include "../request.h"
|
||||
|
||||
#include "../parser.h"
|
||||
bool HandlerPageEdit::canAccess(std::string page)
|
||||
{
|
||||
return this->userSession->user.permissions.canEdit();
|
||||
}
|
||||
|
||||
bool HandlerPageEdit::pageMustExist()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Response HandlerPageEdit::handleRequest(PageDao &pageDao, std::string pagename, const Request &r)
|
||||
{
|
||||
bool pageexists = pageDao.exists(pagename);
|
||||
if(!pageexists && !this->userSession->user.permissions.canCreate())
|
||||
{
|
||||
return errorResponse("No permission", "You don't have permission to create new pages");
|
||||
}
|
||||
auto revisiondao = this->database->createRevisionDao();
|
||||
auto revision = this->database->createRevisionDao()->getCurrentForPage(pagename);
|
||||
std::string body;
|
||||
|
||||
if(revision)
|
||||
{
|
||||
body = revision->content;
|
||||
}
|
||||
if(r.getRequestMethod() == "POST")
|
||||
{
|
||||
if(r.post("do") == "submit")
|
||||
{
|
||||
std::string newContent = r.post("content");
|
||||
std::string newComment = r.post("comment");
|
||||
|
||||
Revision newRevision;
|
||||
newRevision.author = this->userSession->user.login;
|
||||
newRevision.comment = newComment;
|
||||
newRevision.page = pagename;
|
||||
newRevision.content = newContent;
|
||||
|
||||
// TODO: must check, whether categories differ, and perhaps don't allow every user
|
||||
// to set categories
|
||||
Parser parser;
|
||||
std::vector<std::string> cats = parser.extractCategories(newContent);
|
||||
try
|
||||
{
|
||||
this->database->beginTransaction();
|
||||
if(!pageexists)
|
||||
{
|
||||
Page newPage;
|
||||
newPage.current_revision = 0;
|
||||
newPage.listed = true;
|
||||
newPage.name = pagename;
|
||||
pageDao.save(newPage);
|
||||
}
|
||||
revisiondao->save(newRevision);
|
||||
pageDao.setCategories(pagename, cats);
|
||||
this->database->commitTransaction();
|
||||
this->cache->removePrefix("page:"); // TODO: overkill?
|
||||
}
|
||||
catch(const DatabaseException &e)
|
||||
{
|
||||
Logger::debug() << "Error saving revision: " << e.what();
|
||||
return errorResponse("Database error", "A database error occured while trying to save this revision");
|
||||
}
|
||||
|
||||
return Response::redirectTemporarily(urlProvider->page(pagename));
|
||||
}
|
||||
if(r.post("do") == "preview")
|
||||
{
|
||||
std::string newContent = r.post("content");
|
||||
Parser parser;
|
||||
TemplatePage templatePage = this->templ->getPage("page_creation_preview");
|
||||
templatePage.setVar("actionurl", urlProvider->editPage(pagename));
|
||||
templatePage.setVar("preview_content", parser.parse(pageDao, *this->urlProvider, newContent));
|
||||
templatePage.setVar("content", newContent);
|
||||
setPageVars(templatePage, pagename);
|
||||
|
||||
Response response;
|
||||
response.setBody(templatePage.render());
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
TemplatePage &templatePage = this->templ->getPage("page_creation");
|
||||
templatePage.setVar("actionurl", urlProvider->editPage(pagename));
|
||||
templatePage.setVar("content", body);
|
||||
setPageVars(templatePage, pagename);
|
||||
Response response;
|
||||
response.setBody(templatePage.render());
|
||||
return response;
|
||||
}
|
22
handlers/handlerpageedit.h
Normal file
22
handlers/handlerpageedit.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef HANDLERPAGEEDI_H
|
||||
#define HANDLERPAGEEDI_H
|
||||
|
||||
#include "handlerpage.h"
|
||||
#include "../page.h"
|
||||
|
||||
class HandlerPageEdit : public HandlerPage
|
||||
{
|
||||
protected:
|
||||
bool pageMustExist() override;
|
||||
bool canAccess(std::string page) override;
|
||||
|
||||
public:
|
||||
Response handleRequest(PageDao &pageDao, std::string pagename, const Request &r) override;
|
||||
|
||||
~HandlerPageEdit() override
|
||||
{
|
||||
}
|
||||
using HandlerPage::HandlerPage;
|
||||
};
|
||||
|
||||
#endif // HANDLERPAGEEDI_H
|
164
handlers/handlerpageview.cpp
Normal file
164
handlers/handlerpageview.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlerpageview.h"
|
||||
#include "../database/exceptions.h"
|
||||
#include "../logger.h"
|
||||
#include "../parser.h"
|
||||
#include "../htmllink.h"
|
||||
|
||||
bool HandlerPageView::canAccess(std::string page)
|
||||
{
|
||||
return this->userSession->user.permissions.canRead();
|
||||
}
|
||||
|
||||
std::string HandlerPageView::createIndexContent(IParser &parser, std::string content)
|
||||
{
|
||||
std::vector<Headline> headlines = parser.extractHeadlines(content);
|
||||
std::string indexcontent = "";
|
||||
unsigned int l = 0;
|
||||
for(const Headline &h : headlines)
|
||||
{
|
||||
if(h.level > l)
|
||||
{
|
||||
indexcontent += "<ul>";
|
||||
}
|
||||
else if(h.level < l)
|
||||
{
|
||||
indexcontent += "</ul>";
|
||||
}
|
||||
l = h.level;
|
||||
HtmlLink link;
|
||||
link.href = "#" + h.title;
|
||||
link.innervalue = h.title;
|
||||
link.cssclass = "indexlink";
|
||||
indexcontent += "<li>" + link.render() + "</li>";
|
||||
}
|
||||
indexcontent += "</ul>";
|
||||
return indexcontent;
|
||||
}
|
||||
|
||||
Response HandlerPageView::handleRequest(PageDao &pageDao, std::string pagename, const Request &r)
|
||||
{
|
||||
|
||||
std::string revisionparam = r.get("revision");
|
||||
unsigned int revisionid = 0;
|
||||
if(!revisionparam.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
revisionid = utils::toUInt(revisionparam);
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
return errorResponse("Error", "Supplied revisionid is misformated");
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Revision> revision;
|
||||
std::string templatepartname;
|
||||
try
|
||||
{
|
||||
if(revisionid > 0)
|
||||
{
|
||||
revision = this->database->createRevisionDao()->getRevisionForPage(pagename, revisionid);
|
||||
if(!revision)
|
||||
{
|
||||
return errorResponse("Revision not found", "No such revision found");
|
||||
}
|
||||
templatepartname = "page_view_revision";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!this->userSession->loggedIn)
|
||||
{
|
||||
auto content = this->cache->get("page:foranon:" + pagename);
|
||||
if(content)
|
||||
{
|
||||
Response r;
|
||||
r.setBody(*content);
|
||||
// TODO: etag?
|
||||
return r;
|
||||
}
|
||||
}
|
||||
revision = this->database->createRevisionDao()->getCurrentForPage(pagename);
|
||||
templatepartname = "page_view";
|
||||
}
|
||||
}
|
||||
catch(const DatabaseException &e)
|
||||
{
|
||||
Logger::error() << "DatabaseException in handlerpageview: " << e.what();
|
||||
return errorResponse("Database error", "While trying to fetch revision, a database error occured");
|
||||
}
|
||||
|
||||
TemplatePage &page = this->templ->getPage(templatepartname);
|
||||
|
||||
Parser parser;
|
||||
Response result;
|
||||
result.setStatus(200);
|
||||
std::string indexcontent;
|
||||
std::string parsedcontent;
|
||||
|
||||
if(revisionid > 0)
|
||||
{
|
||||
indexcontent = createIndexContent(parser, revision->content);
|
||||
parsedcontent = parser.parse(pageDao, *this->urlProvider, revision->content);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string cachekeyindexcontent = "page:indexcontent:" + pagename;
|
||||
std::string cachekeyparsedcontent = "page:parsedcontent:" + pagename;
|
||||
auto cachedindexcontent = this->cache->get(cachekeyindexcontent);
|
||||
auto cachedparsedcontent = this->cache->get(cachekeyparsedcontent);
|
||||
if(cachedindexcontent)
|
||||
{
|
||||
indexcontent = *cachedindexcontent;
|
||||
}
|
||||
else
|
||||
{
|
||||
indexcontent = createIndexContent(parser, revision->content);
|
||||
this->cache->put(cachekeyindexcontent, indexcontent);
|
||||
}
|
||||
if(cachedparsedcontent)
|
||||
{
|
||||
parsedcontent = *cachedparsedcontent;
|
||||
}
|
||||
else
|
||||
{
|
||||
parsedcontent = parser.parse(pageDao, *this->urlProvider, revision->content);
|
||||
this->cache->put(cachekeyparsedcontent, parsedcontent);
|
||||
}
|
||||
}
|
||||
page.setVar("content", parsedcontent);
|
||||
page.setVar("index", indexcontent);
|
||||
page.setVar("editedby", revision->author);
|
||||
page.setVar("editedon", utils::toISODate(revision->timestamp));
|
||||
page.setVar("historyurl", this->urlProvider->pageHistory(pagename));
|
||||
page.setVar("revision", revisionparam);
|
||||
setPageVars(page, pagename);
|
||||
std::string body = page.render();
|
||||
if(revisionid == 0 && !this->userSession->loggedIn)
|
||||
{
|
||||
this->cache->put("page:foranon:" + pagename, body);
|
||||
}
|
||||
result.addHeader("ETAG", std::to_string(revision->revision) + "+" + std::to_string(this->userSession->loggedIn));
|
||||
result.setBody(body);
|
||||
return result;
|
||||
}
|
26
handlers/handlerpageview.h
Normal file
26
handlers/handlerpageview.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef HANDLERPAGEVIEW_H
|
||||
#define HANDLERPAGEVIEW_H
|
||||
|
||||
#include "handler.h"
|
||||
#include "handlerpage.h"
|
||||
#include "../page.h"
|
||||
#include "../iparser.h"
|
||||
class HandlerPageView : public HandlerPage
|
||||
{
|
||||
protected:
|
||||
bool canAccess(std::string page) override;
|
||||
std::string accessErrorMessage() override
|
||||
{
|
||||
return "You don't have permission to view this page";
|
||||
}
|
||||
std::string createIndexContent(IParser &parser, std::string content);
|
||||
|
||||
public:
|
||||
Response handleRequest(PageDao &pageDao, std::string pagename, const Request &r) override;
|
||||
~HandlerPageView() override
|
||||
{
|
||||
}
|
||||
using HandlerPage::HandlerPage;
|
||||
};
|
||||
|
||||
#endif // HANDLERPAGEVIEW_H
|
63
handlers/handlersearch.cpp
Normal file
63
handlers/handlersearch.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "handlersearch.h"
|
||||
Response HandlerSearch::handle(const Request &r)
|
||||
{
|
||||
Response response;
|
||||
std::string q = r.get("q");
|
||||
if(q.empty())
|
||||
{
|
||||
return errorResponse("Missing search term", "No search term supplied");
|
||||
}
|
||||
|
||||
for(int x : q)
|
||||
{
|
||||
if(!isalnum(x) && !isspace(x))
|
||||
{
|
||||
return errorResponse(
|
||||
"Invalid char",
|
||||
"Currently, the search is limited and so only supports alpha numeric characters and spaces");
|
||||
}
|
||||
}
|
||||
auto pageDao = this->database->createPageDao();
|
||||
QueryOption qo = queryOption(r);
|
||||
try
|
||||
{
|
||||
auto resultList = pageDao->search(q, qo);
|
||||
if(resultList.size() == 0)
|
||||
{
|
||||
return errorResponse("No results", "Your search for " + q + " did not yield any results.");
|
||||
}
|
||||
TemplatePage &searchPage = this->templ->getPage("search");
|
||||
std::string body = this->templ->renderSearch(resultList);
|
||||
searchPage.setVar("pagelist", body);
|
||||
searchPage.setVar("searchterm", q);
|
||||
setGeneralVars(searchPage);
|
||||
response.setBody(searchPage.render());
|
||||
response.setStatus(200);
|
||||
return response;
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
Logger::error() << "Search failed, q: " << q << "Error: " << e.what();
|
||||
return errorResponse("Technical Error", "The system failed to perform your search");
|
||||
}
|
||||
}
|
13
handlers/handlersearch.h
Normal file
13
handlers/handlersearch.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef HANDLERSEARCH_H
|
||||
#define HANDLERSEARCH_H
|
||||
#include <vector>
|
||||
#include "handler.h"
|
||||
class HandlerSearch : public Handler
|
||||
{
|
||||
public:
|
||||
HandlerSearch();
|
||||
using Handler::Handler;
|
||||
Response handle(const Request &r) override;
|
||||
};
|
||||
|
||||
#endif // HANDLERSEARCH_H
|
21
headline.cpp
Normal file
21
headline.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "headline.h"
|
12
headline.h
Normal file
12
headline.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef HEADLINE_H
|
||||
#define HEADLINE_H
|
||||
|
||||
#include <string>
|
||||
class Headline
|
||||
{
|
||||
public:
|
||||
unsigned int level;
|
||||
std::string title;
|
||||
};
|
||||
|
||||
#endif // HEADLINE_H
|
25
htmllink.cpp
Normal file
25
htmllink.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2018 Albert S.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
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
|
||||
SOFTWARE.
|
||||
*/
|
||||
#include "htmllink.h"
|
||||
|
||||
HtmlLink::HtmlLink()
|
||||
{
|
||||
}
|
19
htmllink.h
Normal file
19
htmllink.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef HTMLLINK_H
|
||||
#define HTMLLINK_H
|
||||
#include <string>
|
||||
|
||||
class HtmlLink
|
||||
{
|
||||
public:
|
||||
HtmlLink();
|
||||
std::string href;
|
||||
std::string innervalue;
|
||||
std::string cssclass;
|
||||
|
||||
std::string render()
|
||||
{
|
||||
return "<a href=\"" + href + "\" class=\"" + cssclass + "\">" + innervalue + "</a>";
|
||||
}
|
||||
};
|
||||
|
||||
#endif // HTMLLINK_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user