From a9640bbda56a082bec65a2e8d1374b7260217cb8 Mon Sep 17 00:00:00 2001 From: luocai Date: Mon, 11 Nov 2024 19:21:48 +0800 Subject: [PATCH] remove blog example source. --- Server/main.cpp | 5 +- WebApplication/BlogApplication.cpp | 16 - WebApplication/BlogApplication.h | 11 - WebApplication/CMakeLists.txt | 15 +- WebApplication/Hello.cpp | 6 +- WebApplication/Session.cpp | 38 +-- WebApplication/Session.h | 6 +- WebApplication/User.cpp | 5 + WebApplication/User.h | 17 + WebApplication/WebApplication.cpp | 42 ++- WebApplication/WebApplication.h | 20 +- WebApplication/asciidoc.css | 296 ---------------- WebApplication/blog.css | 128 ------- WebApplication/blog.xml | 258 -------------- WebApplication/blogexample.css | 52 --- WebApplication/model/BlogSession.cpp | 118 ------- WebApplication/model/BlogSession.h | 35 -- WebApplication/model/BlogUserDatabase.cpp | 140 -------- WebApplication/model/BlogUserDatabase.h | 40 --- WebApplication/model/Comment.cpp | 76 ----- WebApplication/model/Comment.h | 50 --- WebApplication/model/Post.cpp | 36 -- WebApplication/model/Post.h | 58 ---- WebApplication/model/Tag.cpp | 7 - WebApplication/model/Tag.h | 26 -- WebApplication/model/Token.cpp | 11 - WebApplication/model/Token.h | 30 -- WebApplication/model/User.cpp | 23 -- WebApplication/model/User.h | 60 ---- WebApplication/model/asciidoc.cpp | 94 ------ WebApplication/model/asciidoc.h | 7 - WebApplication/rss.png | Bin 1534 -> 0 bytes WebApplication/view/BlogLoginWidget.cpp | 40 --- WebApplication/view/BlogLoginWidget.h | 14 - WebApplication/view/BlogView.cpp | 392 ---------------------- WebApplication/view/BlogView.h | 16 - WebApplication/view/CommentView.cpp | 146 -------- WebApplication/view/CommentView.h | 27 -- WebApplication/view/EditUsers.cpp | 70 ---- WebApplication/view/EditUsers.h | 35 -- WebApplication/view/PostView.cpp | 188 ----------- WebApplication/view/PostView.h | 40 --- 42 files changed, 75 insertions(+), 2619 deletions(-) delete mode 100644 WebApplication/BlogApplication.cpp delete mode 100644 WebApplication/BlogApplication.h create mode 100644 WebApplication/User.cpp create mode 100644 WebApplication/User.h delete mode 100644 WebApplication/asciidoc.css delete mode 100644 WebApplication/blog.css delete mode 100644 WebApplication/blog.xml delete mode 100644 WebApplication/blogexample.css delete mode 100644 WebApplication/model/BlogSession.cpp delete mode 100644 WebApplication/model/BlogSession.h delete mode 100644 WebApplication/model/BlogUserDatabase.cpp delete mode 100644 WebApplication/model/BlogUserDatabase.h delete mode 100644 WebApplication/model/Comment.cpp delete mode 100644 WebApplication/model/Comment.h delete mode 100644 WebApplication/model/Post.cpp delete mode 100644 WebApplication/model/Post.h delete mode 100644 WebApplication/model/Tag.cpp delete mode 100644 WebApplication/model/Tag.h delete mode 100644 WebApplication/model/Token.cpp delete mode 100644 WebApplication/model/Token.h delete mode 100644 WebApplication/model/User.cpp delete mode 100644 WebApplication/model/User.h delete mode 100644 WebApplication/model/asciidoc.cpp delete mode 100644 WebApplication/model/asciidoc.h delete mode 100644 WebApplication/rss.png delete mode 100644 WebApplication/view/BlogLoginWidget.cpp delete mode 100644 WebApplication/view/BlogLoginWidget.h delete mode 100644 WebApplication/view/BlogView.cpp delete mode 100644 WebApplication/view/BlogView.h delete mode 100644 WebApplication/view/CommentView.cpp delete mode 100644 WebApplication/view/CommentView.h delete mode 100644 WebApplication/view/EditUsers.cpp delete mode 100644 WebApplication/view/EditUsers.h delete mode 100644 WebApplication/view/PostView.cpp delete mode 100644 WebApplication/view/PostView.h diff --git a/Server/main.cpp b/Server/main.cpp index 3a6f6f6..aaf9580 100644 --- a/Server/main.cpp +++ b/Server/main.cpp @@ -79,8 +79,7 @@ int main(int argc, char const *argv[]) { corpContext->start(); auto live2d = std::make_shared(); - LOG(info) << "hardware_concurrency: " << std::thread::hardware_concurrency() - << ",threads: " << application->getThreads(); + LOG(info) << "hardware_concurrency: " << std::thread::hardware_concurrency() << ",threads: " << application->getThreads(); LOG(info) << "working directory: " << prefix.generic_string(); LOG(info) << "server: " << application->getServer() << ",port: " << application->getPort(); LOG(info) << "document root: " << application->getDocumentRoot(); @@ -102,7 +101,7 @@ int main(int argc, char const *argv[]) { auto udpServer = std::make_shared(application->ioContext()); auto mediaServer = std::make_shared(554, false); - auto webApp = std::make_unique(); + auto webApp = Singleton::instance(); using namespace boost::asio::ip; auto proxyAddress = make_address(application->getServer()); diff --git a/WebApplication/BlogApplication.cpp b/WebApplication/BlogApplication.cpp deleted file mode 100644 index ccc949d..0000000 --- a/WebApplication/BlogApplication.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "BlogApplication.h" -#include "view/BlogView.h" -#include - -static const char *FeedUrl = "/blog/feed/"; - -BlogApplication::BlogApplication(const Wt::WEnvironment &env, Wt::Dbo::SqlConnectionPool &blogDb) - : Wt::WApplication(env) { - messageResourceBundle().use(Wt::WApplication::appRoot() + "blog"); - useStyleSheet("/css/blog.css"); - useStyleSheet("/css/asciidoc.css"); - - - root()->addWidget(std::make_unique("/", blogDb, FeedUrl)); - useStyleSheet("css/blogexample.css"); -} diff --git a/WebApplication/BlogApplication.h b/WebApplication/BlogApplication.h deleted file mode 100644 index 77a4b91..0000000 --- a/WebApplication/BlogApplication.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __BLOGAPPLICATION_H__ -#define __BLOGAPPLICATION_H__ - -#include - -class BlogApplication : public Wt::WApplication { -public: - BlogApplication(const Wt::WEnvironment &env, Wt::Dbo::SqlConnectionPool &blogDb); -}; - -#endif // __BLOGAPPLICATION_H__ \ No newline at end of file diff --git a/WebApplication/CMakeLists.txt b/WebApplication/CMakeLists.txt index e2c6498..1299693 100644 --- a/WebApplication/CMakeLists.txt +++ b/WebApplication/CMakeLists.txt @@ -1,23 +1,10 @@ add_library(WebApplication WebApplication.h WebApplication.cpp - BlogApplication.h BlogApplication.cpp + User.h User.cpp Hello.h Hello.cpp Restful.h Restful.cpp Dialog.h Dialog.cpp Session.h Session.cpp - model/asciidoc.h model/asciidoc.cpp - model/BlogSession.h model/BlogSession.cpp - model/BlogUserDatabase.h model/BlogUserDatabase.cpp - model/Comment.h model/Comment.cpp - model/Post.h model/Post.cpp - model/Tag.h model/Tag.cpp - model/Token.h model/Token.cpp - model/User.h model/User.cpp - view/BlogLoginWidget.h view/BlogLoginWidget.cpp - view/BlogView.h view/BlogView.cpp - view/CommentView.h view/CommentView.cpp - view/EditUsers.h view/EditUsers.cpp - view/PostView.h view/PostView.cpp ) target_include_directories(WebApplication diff --git a/WebApplication/Hello.cpp b/WebApplication/Hello.cpp index c9fb649..14b05bf 100644 --- a/WebApplication/Hello.cpp +++ b/WebApplication/Hello.cpp @@ -2,6 +2,7 @@ #include "BoostLog.h" #include "Dialog.h" #include "Session.h" +#include "WebApplication.h" #include #include #include @@ -57,8 +58,9 @@ Hello::Hello(const Wt::WEnvironment &env, bool embedded) : Wt::WApplication(env) b->clicked().connect(this, &Hello::greet); m_nameEdit->enterPressed().connect(this, &Hello::greet); - auto authWidget = std::make_unique(Session::auth(), m_session->users(), m_session->login()); - authWidget->model()->addPasswordAuth(&Session::passwordAuth()); + auto app = Amass::Singleton::instance(); + auto authWidget = std::make_unique(app->authService(), m_session->users(), m_session->login()); + authWidget->model()->addPasswordAuth(&app->passwordService()); authWidget->setRegistrationEnabled(true); authWidget->processEnvironment(); top->addWidget(std::move(authWidget)); diff --git a/WebApplication/Session.cpp b/WebApplication/Session.cpp index 4ca949f..efc0dfe 100644 --- a/WebApplication/Session.cpp +++ b/WebApplication/Session.cpp @@ -10,10 +10,6 @@ #include #include -Wt::Auth::AuthService myAuthService; -Wt::Auth::PasswordService myPasswordService(myAuthService); -std::vector> myOAuthServices; - Session::Session(const std::string &sqliteDb) { auto connection = std::make_unique(sqliteDb); @@ -45,36 +41,4 @@ Wt::Auth::AbstractUserDatabase &Session::users() { Wt::Auth::Login &Session::login() { return m_login; -} - -void Session::configureAuth() { - myAuthService.setAuthTokensEnabled(true, "logincookie"); - // myAuthService.setEmailVerificationEnabled(true); - // myAuthService.setEmailVerificationRequired(true); - - auto verifier = std::make_unique(); - verifier->addHashFunction(std::make_unique(7)); - myPasswordService.setVerifier(std::move(verifier)); - myPasswordService.setPasswordThrottle(std::make_unique()); - myPasswordService.setStrengthValidator(std::make_unique()); - - if (Wt::Auth::GoogleService::configured()) { - myOAuthServices.push_back(std::make_unique(myAuthService)); - } - - if (Wt::Auth::FacebookService::configured()) { - myOAuthServices.push_back(std::make_unique(myAuthService)); - } - - for (const auto &oAuthService : myOAuthServices) { - oAuthService->generateRedirectEndpoint(); - } -} - -const Wt::Auth::AuthService &Session::auth() { - return myAuthService; -} - -const Wt::Auth::PasswordService &Session::passwordAuth() { - return myPasswordService; -} +} \ No newline at end of file diff --git a/WebApplication/Session.h b/WebApplication/Session.h index 5b800e8..6b65dd9 100644 --- a/WebApplication/Session.h +++ b/WebApplication/Session.h @@ -1,11 +1,10 @@ #ifndef __SESSION_H__ #define __SESSION_H__ -#include "model/User.h" +#include "User.h" #include #include -using AuthInfo = Wt::Auth::Dbo::AuthInfo; using UserDatabase = Wt::Auth::Dbo::UserDatabase; class Session : public Wt::Dbo::Session { @@ -14,9 +13,6 @@ public: ~Session(); Wt::Auth::AbstractUserDatabase &users(); Wt::Auth::Login &login(); - static void configureAuth(); - static const Wt::Auth::AuthService &auth(); - static const Wt::Auth::PasswordService &passwordAuth(); private: std::unique_ptr m_users; diff --git a/WebApplication/User.cpp b/WebApplication/User.cpp new file mode 100644 index 0000000..acf47a0 --- /dev/null +++ b/WebApplication/User.cpp @@ -0,0 +1,5 @@ +#include "User.h" +#include +#include + +DBO_INSTANTIATE_TEMPLATES(User) \ No newline at end of file diff --git a/WebApplication/User.h b/WebApplication/User.h new file mode 100644 index 0000000..9e1ec3f --- /dev/null +++ b/WebApplication/User.h @@ -0,0 +1,17 @@ +#ifndef __USER_H__ +#define __USER_H__ + +#include + +class User; +using AuthInfo = Wt::Auth::Dbo::AuthInfo; + +class User { +public: + template + void persist(Action &a) { + } +}; +DBO_EXTERN_TEMPLATES(User); + +#endif // __USER_H__ \ No newline at end of file diff --git a/WebApplication/WebApplication.cpp b/WebApplication/WebApplication.cpp index 9f83c6d..f8f8471 100644 --- a/WebApplication/WebApplication.cpp +++ b/WebApplication/WebApplication.cpp @@ -1,10 +1,13 @@ #include "WebApplication.h" -#include "BlogApplication.h" #include "BoostLog.h" #include "Hello.h" #include "Restful.h" #include "Session.h" -#include "model/BlogSession.h" +#include +#include +#include +#include +#include #include #include @@ -12,11 +15,6 @@ static std::unique_ptr createApplication(const Wt::WEnvironmen return std::make_unique(env, false); } -std::unique_ptr createBlogApplication(const Wt::WEnvironment &env, - Wt::Dbo::SqlConnectionPool *blogDb) { - return std::make_unique(env, *blogDb); -} - static std::unique_ptr createWidgetSet(const Wt::WEnvironment &env) { return std::make_unique(env, true); } @@ -28,27 +26,39 @@ WebApplication::WebApplication() { args.push_back("--docroot=./build"); args.push_back("--http-listen=127.0.0.1:8855"); // --docroot=. --no-compression --http-listen 127.0.0.1:8855 + initializeAuthenticationService(); m_server = std::make_unique("./build", args); m_server->addEntryPoint(Wt::EntryPointType::Application, createApplication, "/hello"); - - BlogSession::configureAuth(); - m_blogSqlConnectionPool = BlogSession::createConnectionPool(m_server->appRoot() + "database.sqlite"); - m_server->addEntryPoint(Wt::EntryPointType::Application, - std::bind(&createBlogApplication, std::placeholders::_1, m_blogSqlConnectionPool.get()), - "/blog"); m_server->addEntryPoint(Wt::EntryPointType::WidgetSet, createWidgetSet, "/gui/hello.js"); - Session::configureAuth(); m_server->addResource(std::make_shared(), "/json"); m_server->addResource(std::make_shared(), "/plaintext"); m_server->addResource(std::make_shared("database.sqlite"), "/db"); - m_server->start(); + m_server->start(); } catch (const std::exception &e) { LOG(error) << e.what(); } } WebApplication::~WebApplication() { - } +void WebApplication::initializeAuthenticationService() { + m_authService = std::make_unique(); + m_authService->setAuthTokensEnabled(true, "logincookie"); + m_passwordService = std::make_unique(*m_authService); + + auto verifier = std::make_unique(); + verifier->addHashFunction(std::make_unique(7)); + m_passwordService->setVerifier(std::move(verifier)); + m_passwordService->setPasswordThrottle(std::make_unique()); + m_passwordService->setStrengthValidator(std::make_unique()); +} + +const Wt::Auth::AuthService &WebApplication::authService() { + return *m_authService; +} + +const Wt::Auth::PasswordService &WebApplication::passwordService() { + return *m_passwordService; +} diff --git a/WebApplication/WebApplication.h b/WebApplication/WebApplication.h index a86acde..777c1b2 100644 --- a/WebApplication/WebApplication.h +++ b/WebApplication/WebApplication.h @@ -2,7 +2,7 @@ #define __WEBAPPLICATION_H__ #include -#include +#include "Singleton.h" namespace Wt { class WServer; @@ -10,16 +10,32 @@ class WServer; namespace Dbo { class SqlConnectionPool; } + +namespace Auth { +class AuthService; +class PasswordService; +} // namespace Auth + }; // namespace Wt class WebApplication { + friend class Amass::Singleton; public: - WebApplication(); ~WebApplication(); + void initializeAuthenticationService(); + const Wt::Auth::AuthService &authService(); + const Wt::Auth::PasswordService &passwordService(); + +protected: + WebApplication(); + private: std::unique_ptr m_server; std::unique_ptr m_blogSqlConnectionPool; + + std::unique_ptr m_authService; + std::unique_ptr m_passwordService; }; #endif // __WEBAPPLICATION_H__ \ No newline at end of file diff --git a/WebApplication/asciidoc.css b/WebApplication/asciidoc.css deleted file mode 100644 index ac97edf..0000000 --- a/WebApplication/asciidoc.css +++ /dev/null @@ -1,296 +0,0 @@ -.asciidoc em { - font-style: italic; - color: #111111; -} - -.asciidoc strong { - font-weight: bold; - color: #111111; -} - -.asciidoc tt { - color: #111111; -} - -.asciidoc h1, .asciidoc h2, .asciidoc h3, .asciidoc h4, .asciidoc h5, .asciidoc h6 { - color: #111111; - font-family: sans-serif; - margin-top: 1.2em; - margin-bottom: 0.5em; - line-height: 1.3; -} - -.asciidoc h1, .asciidoc h2, .asciidoc h3 { - border-bottom: 2px solid silver; -} - -.asciidoc h2 { - padding-top: 0.5em; -} - -.asciidoc h3 { - float: left; -} - -.asciidoc h3 + * { - clear: left; -} - -.asciidoc div.sectionbody { - font-family: serif; - margin-left: 0; -} - -.asciidoc hr { - border: 1px solid silver; -} - -.asciidoc p { - margin-top: 0.5em; - margin-bottom: 0.5em; -} - -.asciidoc ul, .asciidoc ol, .asciidoc li > p { - margin-top: 0; -} - -.asciidoc pre { - padding: 0; - margin: 0; - line-height: 14px; - font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; - font-size: 12px; -} - -.asciidoc div.tableblock, .asciidoc div.imageblock, .asciidoc div.exampleblock, -.asciidoc div.verseblock, .asciidoc div.quoteblock, .asciidoc div.literalblock, -.asciidoc div.listingblock, .asciidoc div.sidebarblock, -.asciidoc div.admonitionblock { - margin-top: 1.5em; - margin-bottom: 1.5em; -} - -.asciidoc div.admonitionblock { - margin-top: 2.5em; - margin-bottom: 2.5em; -} - -.asciidoc div.content { /* Block element content. */ - padding: 0; -} - -/* Block element titles. */ -.asciidoc div.title, .asciidoc caption.title, .asciidoc div.sidebar-title { - color: #111111; - font-family: sans-serif; - font-weight: bold; - text-align: left; - margin-top: 1.0em; - margin-bottom: 0.5em; -} -.asciidoc div.title + * { - margin-top: 0; -} - -.asciidoc td div.title:first-child { - margin-top: 0.0em; -} -.asciidoc div.content div.title:first-child { - margin-top: 0.0em; -} -.asciidoc div.content + div.title { - margin-top: 0.0em; -} - -.asciidoc div.sidebarblock > div.sidebar-content { - background: #ffffee; - border: 1px solid silver; - padding: 0.5em; -} - -.asciidoc div.listingblock > div.content { - border: 1px solid silver; - background: #f4f4f4; - padding: 0.5em; -} - -.asciidoc div.quoteblock { - padding-left: 2.0em; - margin-right: 10%; -} -.asciidoc div.quoteblock > div.attribution { - padding-top: 0.5em; - text-align: right; -} - -.asciidoc div.verseblock { - padding-left: 2.0em; - margin-right: 10%; -} -.asciidoc div.verseblock > div.content { - white-space: pre; -} -.asciidoc div.verseblock > div.attribution { - padding-top: 0.75em; - text-align: left; -} -/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ -.asciidoc div.verseblock + div.attribution { - text-align: left; -} - -.asciidoc div.admonitionblock .icon { - vertical-align: top; - font-size: 1.1em; - font-weight: bold; - text-decoration: underline; - color: #111111; - padding-right: 0.5em; -} -.asciidoc div.admonitionblock td.content { - padding-left: 0.5em; - border-left: 2px solid silver; -} - -.asciidoc div.exampleblock > div.content { - border-left: 2px solid silver; - padding: 0.5em; -} - -.asciidoc div.imageblock div.content { padding-left: 0; } -.asciidoc span.image img { border-style: none; } -.asciidoc a.image:visited { color: white; } - -.asciidoc dl { - margin-top: 0.8em; - margin-bottom: 0.8em; -} -.asciidoc dt { - margin-top: 0.5em; - margin-bottom: 0; - font-style: normal; - color: #111111; -} -.asciidoc dd > *:first-child { - margin-top: 0.1em; -} - -.asciidoc ul, ol { - list-style-position: outside; -} -.asciidoc ol.arabic { - list-style-type: decimal; -} -.asciidoc ol.loweralpha { - list-style-type: lower-alpha; -} -.asciidoc ol.upperalpha { - list-style-type: upper-alpha; -} -.asciidoc ol.lowerroman { - list-style-type: lower-roman; -} -.asciidoc ol.upperroman { - list-style-type: upper-roman; -} - -.asciidoc div.compact ul, .asciidoc div.compact ol, -.asciidoc div.compact p, .asciidoc div.compact p, -.asciidoc div.compact div, .asciidoc div.compact div { - margin-top: 0.1em; - margin-bottom: 0.1em; -} - -.asciidoc div.tableblock > table { - border: 3px solid #527bbd; -} -.asciidoc thead { - font-family: sans-serif; - font-weight: bold; -} -.asciidoc tfoot { - font-weight: bold; -} -.asciidoc td > div.verse { - white-space: pre; -} -.asciidoc p.table { - margin-top: 0; -} -/* Because the table frame attribute is overriden by CSS in most browsers. */ -.asciidoc div.tableblock > table[frame="void"] { - border-style: none; -} -.asciidoc div.tableblock > table[frame="hsides"] { - border-left-style: none; - border-right-style: none; -} -.asciidoc div.tableblock > table[frame="vsides"] { - border-top-style: none; - border-bottom-style: none; -} - - -.asciidoc div.hdlist { - margin-top: 0.8em; - margin-bottom: 0.8em; -} -.asciidoc div.hdlist tr { - padding-bottom: 15px; -} -.asciidoc dt.hdlist1.strong, .asciidoc td.hdlist1.strong { - font-weight: bold; -} -.asciidoc td.hdlist1 { - vertical-align: top; - font-style: normal; - padding-right: 0.8em; - color: #111111; -} -.asciidoc td.hdlist2 { - vertical-align: top; -} -.asciidoc div.hdlist.compact tr { - margin: 0; - padding-bottom: 0; -} - -.asciidoc .comment { - background: yellow; -} - -@media print { - div#footer-badges { display: none; } -} - -.asciidoc div#toctitle { - color: #111111; - font-family: sans-serif; - font-size: 1.1em; - font-weight: bold; - margin-top: 1.0em; - margin-bottom: 0.1em; -} - -.asciidoc div.toclevel1, -.asciidoc div.toclevel2, -.asciidoc div.toclevel3, -.asciidoc div.toclevel4 { - margin-top: 0; - margin-bottom: 0; -} - -.asciidoc div.toclevel2 { - margin-left: 2em; - font-size: 0.9em; -} - -.asciidoc div.toclevel3 { - margin-left: 4em; - font-size: 0.9em; -} - -.asciidoc div.toclevel4 { - margin-left: 6em; - font-size: 0.9em; -} diff --git a/WebApplication/blog.css b/WebApplication/blog.css deleted file mode 100644 index 180b45b..0000000 --- a/WebApplication/blog.css +++ /dev/null @@ -1,128 +0,0 @@ -.login-box { - margin-bottom: -10px; - height: 25px; -} - -.user-menu { -} - -.login-menu { - float: right; - white-space: nowrap; -} - -.Wt-auth-logged-in { - display: inline; -} - -.link { - text-decoration: underline; - cursor: pointer; -} - -.invalid { - background-color: #EE9999; -} - -.comment-icon { - float: left; - margin-top: 3px; - width: 20px; - height: 20px; - background-image: url(comment.png); - background-repeat: no-repeat; -} - -.comment-edit-icon { - float: left; - margin-top: 3px; - width: 20px; - height: 20px; - background-image: url(comment_edit.png); - background-repeat: no-repeat; -} - -.comment-info { - color: rgb(136,136,136); -} - -.poster { - color: rgb(51, 102, 53); - font-weight: bold; -} - -.author-panel { - margin-top: 10px; - border: 1px #528B12 dashed; - padding: 5px; -} - -.user-editor { - margin-top: 10px; - border: 1px #528B12 dashed; - padding: 5px; -} - -.profile-panel { - margin-top: 10px; - border: 1px #528B12 dashed; - padding: 5px; -} - -.comment-body { - overflow: hidden; /* trick that makes alignment work properly */ - margin-left: 3px; -} - -.comment-body .vspace { - margin: 10px 0px; -} - -.comment-body pre { - line-height: 140%; - border: 1px solid silver; - background: #f4f4f4; - padding: 0.5em; -} - -.comment-edit { - width: 400px; -} - -.comment-edit textarea { - width: 396px; -} - -.comment-links { - margin-bottom: 3px; -} - -.blogpost-edit { - width: 500px; - margin: 10x; -} - -.blogpost-edit div { - margin: 5px 0px; -} -.blogpost-edit input { - width: 450px; -} - -.blogpost-edit textarea { - width: 496px; - height: 150px; -} - -.archive-month-title { - color: #528B12; - display: block; - font-size: 1.3em; - line-height: 1.8; - margin-top: 15px; - font-weight: bold; -} - -.asciidoc .subtitle { - font-size: 1.4em; -} diff --git a/WebApplication/blog.xml b/WebApplication/blog.xml deleted file mode 100644 index ec0ba0b..0000000 --- a/WebApplication/blog.xml +++ /dev/null @@ -1,258 +0,0 @@ - - - - - ${user-name} ${password} ${remember-me} Remember me - ${login}${}, or use ${icons}${} - - - - - - - -

Registered users

- ${user-list} - Limit list to user names containing : ${limit-edit} ${limit-button} -
- - -
-

Edit user ${username}

- ${role-button} -
-
- - -

Editing user ${user}

- ${save-button} ${cancel-button} -
- - -
-

This user id is invalid

-
-
- - -
-

You need to log in to access this function

-
-
- - -
-

You need to be administrator to access this function

-
-
- - -

Register

-

- To register as a user to post comments with your own login, - please fill out the following form. -

- - - - - - - - - - - - - - - - - - - - - - - -
Login:${name}
Password:${passwd}
Repeat password:${passwd2}
- ${ok-button} - ${cancel-button} -
-
- - -
-

Registered users

- Search for ${searchstring} ${search-button}
-
-
- - -
-

Profile panel for ${user}

- - - - - - - - - - - - - - - -
New password:${passwd}
Repeat password:${passwd2}
- ${ok-button} - ${cancel-button} -
-
-
- - -
-

Author panel for ${user}

- Statistics: -
    -
  • ${unpublished-count} unpublished post(s)
  • -
  • ${published-count} published post(s)
  • -
- ${new-post} - ${unpublished-posts} -
-
- - -

${title}

-
-
by ${author} on ${date}
-
- ${brief+body} -
-
${comment-count}
-
- ${publish} ${edit} ${delete} -
-
-
- ${comments} -
-
- - -

${title}

-
by ${author} on ${date}
-
- ${brief} -
-
${read-more}
-
- ${publish} ${edit} ${delete} -
-
${comment-count}
-
- - -

-
-
Title: ${title-edit}
-
${brief-edit}
-
${body-edit}
-
- ${save} ${cancel} -
-
-
- - -
-
-
- ${author} - ${date} ${collapse-expand} -
- ${contents} - - ${children} -
- - - - - ${children} - - - -
-
-
${area}
-
plain text or (<code>...</code>)
- ${save} - ${cancel} -
- - - -

No posts found

- Sorry, no blog posts found that match your selection. -
- - -

No author

- Sorry, {1} is not a registered blog author. -
- - -

Archive

-
- - Login - Login too short (must be at least {1} characters) - Passwords don't match. - Register - Logout - Archive - Profile - Authoring panel - Edit users - Add comment - Reply - Edit - Delete - [[Comment deleted]] - Read the rest of this post >> - New post - Publish - Retract - Delete - Edit - Save - Cancel - Search - Demote this administrator to a regular visitor - Promote this user to administrator - No users found - diff --git a/WebApplication/blogexample.css b/WebApplication/blogexample.css deleted file mode 100644 index c1f1666..0000000 --- a/WebApplication/blogexample.css +++ /dev/null @@ -1,52 +0,0 @@ -body { - color: #333333; - font-family: arial,sans-serif; - font-size: 80%; - line-height:1.5em; - background-color:#FFF; - min-width:750px; - overflow-x: hidden; -} - -a { - text-decoration: underline; - color: #528B12; /*#70BD1A;*/ -} - -.link { - color: #528B12; /*#70BD1A;*/ -} - -a.blank { - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -h4 { - font-size: 1.3em; - line-height: 1.8; - border-top : 1px solid #528B12; - padding-bottom:10px; - margin-top:15px; - color: #528B12; - display: block; -} - -p { - font-size: 1.1em; - font-weight: normal; - line-height: 1.4; - margin-bottom : 15px; - color: #333333; -} -p.intro { - font-size: 1.3em; - font-weight: normal; - line-height: 1.4; - padding-bottom : 15px; - color: #333333; -} - diff --git a/WebApplication/model/BlogSession.cpp b/WebApplication/model/BlogSession.cpp deleted file mode 100644 index 54eddc2..0000000 --- a/WebApplication/model/BlogSession.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "BlogSession.h" -#include "BoostLog.h" -#include "Post.h" -#include "Token.h" -#include "User.h" -#include "asciidoc.h" -#include -#include -#include -#include -#include -#include -#include - -const std::string ADMIN_USERNAME = "admin"; -const std::string ADMIN_PASSWORD = "admin"; - -class BlogOAuth : public std::vector { -public: - ~BlogOAuth() { - for (unsigned i = 0; i < size(); ++i) delete (*this)[i]; - } -}; - -Wt::Auth::AuthService blogAuth; -Wt::Auth::PasswordService blogPasswords(blogAuth); -BlogOAuth blogOAuth; - -BlogSession::BlogSession(Wt::Dbo::SqlConnectionPool &connectionPool) - : m_connectionPool(connectionPool), m_users(*this) { - setConnectionPool(m_connectionPool); - mapClass("comment"); - mapClass("post"); - mapClass("tag"); - mapClass("token"); - mapClass("user"); - - try { - Wt::Dbo::Transaction t(*this); - createTables(); - Wt::Dbo::ptr admin = add(std::make_unique()); - User *a = admin.modify(); - a->name = ADMIN_USERNAME; - a->role = User::Admin; - - Wt::Auth::User authAdmin = m_users.findWithIdentity(Wt::Auth::Identity::LoginName, a->name); - blogPasswords.updatePassword(authAdmin, ADMIN_PASSWORD); - - Wt::Dbo::ptr post = add(std::make_unique()); - Post *p = post.modify(); - - p->state = Post::Published; - p->author = admin; - p->title = "Welcome!"; - p->briefSrc = "Welcome to your own blog."; - p->bodySrc = "We have created for you an " + ADMIN_USERNAME + " user with password " + ADMIN_PASSWORD; - p->briefHtml = asciidoc(p->briefSrc); - p->bodyHtml = asciidoc(p->bodySrc); - p->date = Wt::WDateTime::currentDateTime(); - - Wt::Dbo::ptr rootComment = add(std::make_unique()); - rootComment.modify()->post = post; - - t.commit(); - - LOG(info) << "Created database, and user " << ADMIN_USERNAME << " / " << ADMIN_PASSWORD << std::endl; - } catch (std::exception &e) { - LOG(error) << e.what() << std::endl; - LOG(info) << "Using existing database"; - } -} - -void BlogSession::configureAuth() { - blogAuth.setAuthTokensEnabled(true, "bloglogin"); - - std::unique_ptr verifier = std::make_unique(); - verifier->addHashFunction(std::make_unique(7)); -#ifdef WT_WITH_SSL - verifier->addHashFunction(std::make_unique()); -#endif -#ifdef HAVE_CRYPT - verifier->addHashFunction(std::make_unique()); -#endif - blogPasswords.setVerifier(std::move(verifier)); - blogPasswords.setPasswordThrottle(std::make_unique()); - blogPasswords.setStrengthValidator(std::make_unique()); - - if (Wt::Auth::GoogleService::configured()) blogOAuth.push_back(new Wt::Auth::GoogleService(blogAuth)); -} - -std::unique_ptr BlogSession::createConnectionPool(const std::string &sqlite3) { - auto connection = std::make_unique(sqlite3); - - connection->setProperty("show-queries", "true"); - connection->setDateTimeStorage(Wt::Dbo::SqlDateTimeType::DateTime, - Wt::Dbo::backend::DateTimeStorage::PseudoISO8601AsText); - - return std::make_unique(std::move(connection), 10); -} - -Wt::Dbo::ptr BlogSession::user() const { - if (m_login.loggedIn()) - return m_users.find(m_login.user()); - else - return Wt::Dbo::ptr(); -} - -Wt::Signal> &BlogSession::commentsChanged() { - return m_commentsChanged; -} - -Wt::Auth::PasswordService *BlogSession::passwordAuth() const { - return &blogPasswords; -} - -const std::vector &BlogSession::oAuth() const { - return blogOAuth; -} diff --git a/WebApplication/model/BlogSession.h b/WebApplication/model/BlogSession.h deleted file mode 100644 index 39ec755..0000000 --- a/WebApplication/model/BlogSession.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __BLOGSESSION_H__ -#define __BLOGSESSION_H__ - -#include "BlogUserDatabase.h" -#include -#include -#include -#include - -class Comment; - -class BlogSession : public Wt::Dbo::Session { -public: - BlogSession(Wt::Dbo::SqlConnectionPool &connectionPool); - static void configureAuth(); - - static std::unique_ptr createConnectionPool(const std::string &sqlite3); - Wt::Auth::Login &login() { - return m_login; - } - Wt::Dbo::ptr user() const; - Wt::Signal> &commentsChanged(); - BlogUserDatabase &users() { - return m_users; - } - Wt::Auth::PasswordService *passwordAuth() const; - const std::vector &oAuth() const; - -private: - Wt::Dbo::SqlConnectionPool &m_connectionPool; - BlogUserDatabase m_users; - Wt::Auth::Login m_login; - Wt::Signal> m_commentsChanged; -}; -#endif // __BLOGSESSION_H__ \ No newline at end of file diff --git a/WebApplication/model/BlogUserDatabase.cpp b/WebApplication/model/BlogUserDatabase.cpp deleted file mode 100644 index 91e2cf0..0000000 --- a/WebApplication/model/BlogUserDatabase.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "User.h" - -#include "BlogUserDatabase.h" - -#include - -class TransactionImpl : public Wt::Auth::AbstractUserDatabase::Transaction, public Wt::Dbo::Transaction { -public: - TransactionImpl(Wt::Dbo::Session &session) : Wt::Dbo::Transaction(session) { - } - - virtual ~TransactionImpl() noexcept(false) { - } - - virtual void commit() { - Wt::Dbo::Transaction::commit(); - } - - virtual void rollback() { - Wt::Dbo::Transaction::rollback(); - } -}; - -class InvalidUser : public std::runtime_error { -public: - InvalidUser(const std::string &id) : std::runtime_error("Invalid user: " + id) { - } -}; - -BlogUserDatabase::BlogUserDatabase(Wt::Dbo::Session &session) : m_session(session) { -} - -BlogUserDatabase::~BlogUserDatabase() { -} - -Wt::Dbo::ptr BlogUserDatabase::find(const Wt::Auth::User &user) const { - getUser(user.id()); - return m_user; -} - -Wt::Auth::User BlogUserDatabase::find(Wt::Dbo::ptr user) const { - m_user = user; - return Wt::Auth::User(std::to_string(m_user.id()), *this); -} - -BlogUserDatabase::Transaction *BlogUserDatabase::startTransaction() { - return new TransactionImpl(m_session); -} - -Wt::Auth::User BlogUserDatabase::findWithId(const std::string &id) const { - getUser(id); - - if (m_user) - return Wt::Auth::User(id, *this); - else - return Wt::Auth::User(); -} - -Wt::Auth::User BlogUserDatabase::findWithIdentity(const std::string &provider, const Wt::WString &identity) const { - Wt::Dbo::Transaction t(m_session); - if (provider == Wt::Auth::Identity::LoginName) { - if (!m_user || m_user->name != identity) m_user = m_session.find().where("name = ?").bind(identity); - } else - m_user = m_session.find().where("oauth_id = ?").bind(identity.toUTF8()).where("oauth_provider = ?").bind(provider); - t.commit(); - - if (m_user) - return Wt::Auth::User(std::to_string(m_user.id()), *this); - else - return Wt::Auth::User(); -} - -void BlogUserDatabase::addIdentity(const Wt::Auth::User &user, const std::string &provider, const Wt::WString &identity) { - WithUser find(*this, user); - - if (provider == Wt::Auth::Identity::LoginName) - m_user.modify()->name = identity; - else { - m_user.modify()->oAuthProvider = provider; - m_user.modify()->oAuthId = identity.toUTF8(); - } -} - -void BlogUserDatabase::removeIdentity(const Wt::Auth::User &user, const std::string &provider) { - WithUser find(*this, user); - - if (provider == Wt::Auth::Identity::LoginName) - m_user.modify()->name = ""; - else if (provider == m_user->oAuthProvider) { - m_user.modify()->oAuthProvider = std::string(); - m_user.modify()->oAuthId = std::string(); - } -} - -Wt::WString BlogUserDatabase::identity(const Wt::Auth::User &user, const std::string &provider) const { - WithUser find(*this, user); - - if (provider == Wt::Auth::Identity::LoginName) - return m_user->name; - else if (provider == m_user->oAuthProvider) - return Wt::WString(m_user->oAuthId); - else - return Wt::WString::Empty; -} - -void BlogUserDatabase::setLastLoginAttempt(const Wt::Auth::User &user, const Wt::WDateTime &t) { - WithUser find(*this, user); - - m_user.modify()->lastLoginAttempt = t; -} - -Wt::Auth::PasswordHash BlogUserDatabase::password(const Wt::Auth::User &user) const { - WithUser find(*this, user); - return Wt::Auth::PasswordHash(m_user->passwordMethod, m_user->passwordSalt, m_user->password); -} - -void BlogUserDatabase::setPassword(const Wt::Auth::User &user, const Wt::Auth::PasswordHash &password) { - WithUser find(*this, user); - m_user.modify()->password = password.value(); - m_user.modify()->passwordMethod = password.function(); - m_user.modify()->passwordSalt = password.salt(); -} - -BlogUserDatabase::WithUser::WithUser(const BlogUserDatabase &self, const Wt::Auth::User &user) : transaction(self.m_session) { - self.getUser(user.id()); - - if (!self.m_user) throw InvalidUser(user.id()); -} - -BlogUserDatabase::WithUser::~WithUser() { - transaction.commit(); -} - -void BlogUserDatabase::getUser(const std::string &id) const { - if (!m_user || std::to_string(m_user.id()) != id) { - Wt::Dbo::Transaction t(m_session); - m_user = m_session.find().where("id = ?").bind(User::stringToId(id)); - t.commit(); - } -} diff --git a/WebApplication/model/BlogUserDatabase.h b/WebApplication/model/BlogUserDatabase.h deleted file mode 100644 index 46c4c47..0000000 --- a/WebApplication/model/BlogUserDatabase.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __BLOGUSERDATABASE_H__ -#define __BLOGUSERDATABASE_H__ - -#include -#include -#include - -class User; - -class BlogUserDatabase : public Wt::Auth::AbstractUserDatabase { -public: - BlogUserDatabase(Wt::Dbo::Session &session); - ~BlogUserDatabase(); - Wt::Dbo::ptr find(const Wt::Auth::User &user) const; - Wt::Auth::User find(Wt::Dbo::ptr user) const; - - Transaction *startTransaction() final; - Wt::Auth::User findWithId(const std::string &id) const final; - Wt::Auth::User findWithIdentity(const std::string &provider, const Wt::WString &identity) const final; - void addIdentity(const Wt::Auth::User &user, const std::string &provider, const Wt::WString &identity) final; - void removeIdentity(const Wt::Auth::User &user, const std::string &provider) final; - Wt::WString identity(const Wt::Auth::User &user, const std::string &provider) const final; - void setLastLoginAttempt(const Wt::Auth::User &user, const Wt::WDateTime &t) final; - Wt::Auth::PasswordHash password(const Wt::Auth::User &user) const final; - void setPassword(const Wt::Auth::User &user, const Wt::Auth::PasswordHash &password) final; - -protected: - struct WithUser { - WithUser(const BlogUserDatabase &self, const Wt::Auth::User &user); - ~WithUser(); - - Wt::Dbo::Transaction transaction; - }; - void getUser(const std::string &id) const; - -private: - Wt::Dbo::Session &m_session; - mutable Wt::Dbo::ptr m_user; -}; -#endif // __BLOGUSERDATABASE_H__ \ No newline at end of file diff --git a/WebApplication/model/Comment.cpp b/WebApplication/model/Comment.cpp deleted file mode 100644 index 2a04050..0000000 --- a/WebApplication/model/Comment.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "Comment.h" -#include "Post.h" -#include "Tag.h" -#include "User.h" -#include -#include - -DBO_INSTANTIATE_TEMPLATES(Comment) - -static std::string &replace(std::string &s, const std::string &k, const std::string &r) { - std::string::size_type p = 0; - - while ((p = s.find(k, p)) != std::string::npos) { - s.replace(p, k.length(), r); - p += r.length(); - } - - return s; -} - -void Comment::setText(const Wt::WString &text) { - textSrc_ = text; - - std::string html = Wt::WWebWidget::escapeText(text, true).toUTF8(); - - std::string::size_type b = 0; - - // Replace <code>...</code> with
...
- // This is kind of very ad-hoc! - - while ((b = html.find("<code>", b)) != std::string::npos) { - std::string::size_type e = html.find("</code>", b); - if (e == std::string::npos) - break; - else { - if (b > 6 && html.substr(b - 6, 6) == "
") { - html.erase(b - 6, 6); - b -= 6; - e -= 6; - } - - html.replace(b, 12, "
");
-            e -= 7;
-
-            if (html.substr(b + 5, 6) == "
") { - html.erase(b + 5, 6); - e -= 6; - } - - if (html.substr(e - 6, 6) == "
") { - html.erase(e - 6, 6); - e -= 6; - } - - html.replace(e, 13, "
"); - e += 6; - - if (e + 6 <= html.length() && html.substr(e, 6) == "
") { - html.erase(e, 6); - e -= 6; - } - - b = e; - } - } - - // We would also want to replace

(empty line) with - //
- replace(html, "

", "
"); - - textHtml_ = Wt::WString(html); -} - -void Comment::setDeleted() { - textHtml_ = Wt::WString::tr("comment-deleted"); -} diff --git a/WebApplication/model/Comment.h b/WebApplication/model/Comment.h deleted file mode 100644 index 390d91d..0000000 --- a/WebApplication/model/Comment.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef __COMMENT_H__ -#define __COMMENT_H__ - -#include -#include -#include - -class Comment; -using Comments = Wt::Dbo::collection>; -class Post; -class User; - -class Comment { -public: - Wt::Dbo::ptr author; - Wt::Dbo::ptr post; - Wt::Dbo::ptr parent; - - Wt::WDateTime date; - - void setText(const Wt::WString &text); - void setDeleted(); - - const Wt::WString &textSrc() const { - return textSrc_; - } - const Wt::WString &textHtml() const { - return textHtml_; - } - - Comments children; - - template - void persist(Action &a) { - Wt::Dbo::field(a, date, "date"); - Wt::Dbo::field(a, textSrc_, "text_source"); - Wt::Dbo::field(a, textHtml_, "text_html"); - - Wt::Dbo::belongsTo(a, post, "post", Wt::Dbo::OnDeleteCascade); - Wt::Dbo::belongsTo(a, author, "author"); - Wt::Dbo::belongsTo(a, parent, "parent", Wt::Dbo::OnDeleteCascade); - - Wt::Dbo::hasMany(a, children, Wt::Dbo::ManyToOne, "parent"); - } - -private: - Wt::WString textSrc_; - Wt::WString textHtml_; -}; -#endif // __COMMENT_H__ \ No newline at end of file diff --git a/WebApplication/model/Post.cpp b/WebApplication/model/Post.cpp deleted file mode 100644 index 3de1cd5..0000000 --- a/WebApplication/model/Post.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "Post.h" -#include "User.h" -#include - -DBO_INSTANTIATE_TEMPLATES(Post) - -std::string Post::permaLink() const { - return date.toString("yyyy/MM/dd/'" + titleToUrl() + '\'').toUTF8(); -} - -std::string Post::commentCount() const { - int count = (int)comments.size() - 1; - if (count == 1) - return "1 comment"; - else - return std::to_string(count) + " comments"; -} - -std::string Post::titleToUrl() const { - std::string result = title.narrow(); - for (unsigned i = 0; i < result.length(); ++i) { - if (!isalnum(result[i])) - result[i] = '_'; - else - result[i] = tolower(result[i]); - } - - return result; -} - -Wt::Dbo::ptr Post::rootComment() const { - if (session()) - return session()->find().where("post_id = ?").bind(id()).where("parent_id is null"); - else - return Wt::Dbo::ptr(); -} diff --git a/WebApplication/model/Post.h b/WebApplication/model/Post.h deleted file mode 100644 index c381718..0000000 --- a/WebApplication/model/Post.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef __POST_H__ -#define __POST_H__ - -#include "Comment.h" -#include "Tag.h" -#include -#include -#include - -class User; - -typedef Wt::Dbo::collection> Comments; -typedef Wt::Dbo::collection> Tags; - -class Post : public Wt::Dbo::Dbo { -public: - enum State { - Unpublished = 0, - Published = 1, - }; - - std::string permaLink() const; - std::string commentCount() const; - std::string titleToUrl() const; - Wt::Dbo::ptr rootComment() const; - - template - void persist(Action &a) { - Wt::Dbo::field(a, state, "state"); - Wt::Dbo::field(a, date, "date"); - Wt::Dbo::field(a, title, "title"); - Wt::Dbo::field(a, briefSrc, "brief_src"); - Wt::Dbo::field(a, briefHtml, "brief_html"); - Wt::Dbo::field(a, bodySrc, "body_src"); - Wt::Dbo::field(a, bodyHtml, "body_html"); - - Wt::Dbo::belongsTo(a, author, "author"); - - Wt::Dbo::hasMany(a, comments, Wt::Dbo::ManyToOne, "post"); - Wt::Dbo::hasMany(a, tags, Wt::Dbo::ManyToMany, "post_tag"); - } - - Wt::Dbo::ptr author; - State state; - - Wt::WDateTime date; - Wt::WString title; - Wt::WString briefSrc; - Wt::WString briefHtml; - Wt::WString bodySrc; - Wt::WString bodyHtml; - - Comments comments; - Tags tags; -}; -DBO_EXTERN_TEMPLATES(Post) - -#endif // __POST_H__ \ No newline at end of file diff --git a/WebApplication/model/Tag.cpp b/WebApplication/model/Tag.cpp deleted file mode 100644 index e296fdd..0000000 --- a/WebApplication/model/Tag.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "Tag.h" -#include "Comment.h" -#include "Post.h" -#include "User.h" -#include - -DBO_INSTANTIATE_TEMPLATES(Tag) \ No newline at end of file diff --git a/WebApplication/model/Tag.h b/WebApplication/model/Tag.h deleted file mode 100644 index c1e9641..0000000 --- a/WebApplication/model/Tag.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __TAG_H__ -#define __TAG_H__ - -#include - -class Post; -using Posts= Wt::Dbo::collection> ; - -class Tag { -public: - Tag() = default; - Tag(const std::string &aName) : name(aName) { - } - template - void persist(Action &a) { - Wt::Dbo::field(a, name, "name"); - - Wt::Dbo::hasMany(a, posts, Wt::Dbo::ManyToMany, "post_tag"); - } - - std::string name; - Posts posts; -}; - -DBO_EXTERN_TEMPLATES(Tag) -#endif // __TAG_H__ \ No newline at end of file diff --git a/WebApplication/model/Token.cpp b/WebApplication/model/Token.cpp deleted file mode 100644 index 90106dd..0000000 --- a/WebApplication/model/Token.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "Token.h" -#include "User.h" -#include - -DBO_INSTANTIATE_TEMPLATES(Token) - -Token::Token() { -} - -Token::Token(const std::string &v, const Wt::WDateTime &e) : value(v), expires(e) { -} diff --git a/WebApplication/model/Token.h b/WebApplication/model/Token.h deleted file mode 100644 index 5e83cd6..0000000 --- a/WebApplication/model/Token.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __TOKENS_H__ -#define __TOKENS_H__ - -#include -#include - -class User; - -class Token : public Wt::Dbo::Dbo { -public: - Token(); - Token(const std::string &value, const Wt::WDateTime &expires); - - Wt::Dbo::ptr user; - - std::string value; - Wt::WDateTime expires; - - template - void persist(Action &a) { - Wt::Dbo::field(a, value, "value"); - Wt::Dbo::field(a, expires, "expires"); - - Wt::Dbo::belongsTo(a, user, "user"); - } -}; - -DBO_EXTERN_TEMPLATES(Token) - -#endif // __TOKENS_H__ \ No newline at end of file diff --git a/WebApplication/model/User.cpp b/WebApplication/model/User.cpp deleted file mode 100644 index 4669d13..0000000 --- a/WebApplication/model/User.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "User.h" -#include - -DBO_INSTANTIATE_TEMPLATES(User) -Wt::Dbo::dbo_traits::IdType User::stringToId(const std::string &s) { - std::size_t pos = std::string::npos; - auto result = std::stoll(s, &pos); - if (pos != s.size()) - return Wt::Dbo::dbo_traits::invalidId(); - else - return result; -} - -Posts User::latestPosts(int count) const { - return posts.find().where("state = ?").bind(Post::Published).orderBy("date desc").limit(count); -} - -Posts User::allPosts(Post::State state) const { - return posts.find().where("state = ?").bind(state).orderBy("date desc"); -} - -User::User() : role(Visitor), failedLoginAttempts(0) { -} diff --git a/WebApplication/model/User.h b/WebApplication/model/User.h deleted file mode 100644 index 9d5573f..0000000 --- a/WebApplication/model/User.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef __USER_H__ -#define __USER_H__ - -#include "Post.h" -#include "Token.h" -#include -#include -#include -#include - -using Tokens = Wt::Dbo::collection>; - -class User { -public: - enum Role { - Visitor = 0, - Admin = 1, - }; - User(); - - static Wt::Dbo::dbo_traits::IdType stringToId(const std::string &s); - Posts latestPosts(int count = 10) const; - Posts allPosts(Post::State state) const; - Wt::WString name; - Role role; - - std::string password; - std::string passwordMethod; - std::string passwordSalt; - int failedLoginAttempts; - Wt::WDateTime lastLoginAttempt; - - std::string oAuthId; - std::string oAuthProvider; - - Tokens authTokens; - Comments comments; - Posts posts; - - template - void persist(Action &a) { - Wt::Dbo::field(a, name, "name"); - Wt::Dbo::field(a, password, "password"); - Wt::Dbo::field(a, passwordMethod, "password_method"); - Wt::Dbo::field(a, passwordSalt, "password_salt"); - Wt::Dbo::field(a, role, "role"); - Wt::Dbo::field(a, failedLoginAttempts, "failed_login_attempts"); - Wt::Dbo::field(a, lastLoginAttempt, "last_login_attempt"); - Wt::Dbo::field(a, oAuthId, "oauth_id"); - Wt::Dbo::field(a, oAuthProvider, "oauth_provider"); - - Wt::Dbo::hasMany(a, comments, Wt::Dbo::ManyToOne, "author"); - Wt::Dbo::hasMany(a, posts, Wt::Dbo::ManyToOne, "author"); - Wt::Dbo::hasMany(a, authTokens, Wt::Dbo::ManyToOne, "user"); - } -}; - -DBO_EXTERN_TEMPLATES(User) - -#endif // __USER_H__ \ No newline at end of file diff --git a/WebApplication/model/asciidoc.cpp b/WebApplication/model/asciidoc.cpp deleted file mode 100644 index 21912f1..0000000 --- a/WebApplication/model/asciidoc.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "asciidoc.h" - -#include -#include -#include -#include - -#include "Wt/WString.h" - -#ifndef WT_WIN32 -#include -#endif - -namespace { - -std::string tempFileName() -{ -#ifndef WT_WIN32 - char spool[20]; - strcpy(spool, "/tmp/wtXXXXXX"); - - int i = mkstemp(spool); - close(i); -#else - char spool[2 * L_tmpnam]; - tmpnam(spool); -#endif - return std::string(spool); -} - -std::string readFileToString(const std::string& fileName) -{ - std::fstream file(fileName.c_str(), std::ios::in | std::ios::binary | std::ios::ate); - int length = file.tellg(); - file.seekg(0, std::ios::beg); - - std::unique_ptr buf(new char[length]); - file.read(buf.get(), length); - file.close(); - - return std::string(buf.get(), length); -} - -} - -Wt::WString asciidoc(const Wt::WString& src) -{ - std::string srcFileName = tempFileName(); - std::string htmlFileName = tempFileName(); - - { - std::ofstream srcFile(srcFileName.c_str(), std::ios::out); - std::string ssrc = src.toUTF8(); - srcFile.write(ssrc.c_str(), (std::streamsize)ssrc.length()); - srcFile.close(); - } - -#if defined(ASCIIDOCTOR_EXECUTABLE) -#define xstr(s) str(s) -#define str(s) #s - std::string cmd = xstr(ASCIIDOCTOR_EXECUTABLE); -#else - std::string cmd = "asciidoctor"; -#endif - std::string command = cmd + " -a htmlsyntax=xml -o " + htmlFileName + " -s " + srcFileName; - -#ifndef WT_WIN32 - /* - * So, asciidoc apparently sends a SIGINT which is caught by its parent - * process.. So we have to temporarily ignore it. - */ - struct sigaction newAction, oldAction; - newAction.sa_handler = SIG_IGN; - newAction.sa_flags = 0; - sigemptyset(&newAction.sa_mask); - sigaction(SIGINT, &newAction, &oldAction); -#endif - bool ok = system(command.c_str()) == 0; -#ifndef WT_WIN32 - sigaction(SIGINT, &oldAction, 0); -#endif - - Wt::WString result; - - if (ok) { - result = Wt::WString(readFileToString(htmlFileName)); - } else - result = Wt::WString("Could not execute asciidoc"); - - unlink(srcFileName.c_str()); - unlink(htmlFileName.c_str()); - - return result; -} diff --git a/WebApplication/model/asciidoc.h b/WebApplication/model/asciidoc.h deleted file mode 100644 index 3b1c607..0000000 --- a/WebApplication/model/asciidoc.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __ASCIIDOC_H__ -#define __ASCIIDOC_H__ - -#include - -Wt::WString asciidoc(const Wt::WString &src); -#endif // __ASCIIDOC_H__ \ No newline at end of file diff --git a/WebApplication/rss.png b/WebApplication/rss.png deleted file mode 100644 index 09e756e25f83d53e989a95a200edf50368eec04f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1534 zcmVP000^Y0ssI2%^zTz00001b5ch_0Itp) z=>Px#32;bRa{vGf6951U69E94oEQKA00(qQO+^RU3j_@wCwRnI<^TW%kV!;AR5;6h zlu3+TXAyq4$pNv; zjujxWKq3neC`=X-ScWGfE8LO(e{Lk{$V|wL{S_2fgkeZPYfh#0rCP6}F%%DM-AZii_Lcip6e17{wU%slbE3J`IT7oJ_(Dr!Rv7hZx z+&(LW5e_=w?jj_K)%oErXEdGd&<+tW%;^wZlt{9mL#jk!Loha)0Z9%VZD3jRyBJ~zwt93{I<>< zl6}u$ayqVD58Wl5eJ6eR*Q(ys?T?G)*~VSIezTqbV-QGHptp#;gE*+}xV}8&to5Ym zSwi^Scj_A+kk$s>@L;y%34ZEpg(KX0%Zr>J{Vk1b;mnQweB-MJ+<&Qk!;<4|K! z_8R(w8I>^;pg_nz{Z(sErkDhe%KG8mO)Fizis+ z89WLI*b4R7jBw1{0M&TrFXfqE%GFaT4ZSrPTI0#8Fnw^?7!4Orgw>_wh0c5#FdyCG zm)?-h)lxKbgTPjUet$+VW-vIBRsAqnu=x*o?s&ZRFKbT9mOV_dKE1zKxuw@n+uZy3 zDb7VrI8g)r1V`$9P}m8B~E zV2wRbdC1_T(+RkV8KP;X0ez8xnxE#Dm;*Whgf9(vAB<%9AB;Zs*3`YNm+QrBmVz?i{}#jdn(h z^H;dGHL=4TSoDdw z(cz$bAVAQGk+^c_$A?;9f5mmYd;EtJ{n;c8!NbzU{QPf}DJ@(JsZ@bpK3RwvD2o?7 zfFeQCkiykxCz_MXa3;7o`V|Fei>H7@skxUBuM!D5G-wpfhGirifIxzZdw?yhOiTIX zx6%T@OiW;0r)a6WfC*VLOP-}v7i2^bz*2~%2LyqN1QM2_SU!hv=mi=5%F*6^`_pnM z>I}dd3jVJK_`N>Y(7Q9HE&yi{cR$lQbcA_T`qJ#`Yd>oI{nZfrAlH)j|BLX*6q2vD kx7WXLWZjpJ>d5$i0Y@5vdo-T(jq07*qoM6N<$f+(iyc>n+a diff --git a/WebApplication/view/BlogLoginWidget.cpp b/WebApplication/view/BlogLoginWidget.cpp deleted file mode 100644 index 2bc4a8c..0000000 --- a/WebApplication/view/BlogLoginWidget.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "BlogLoginWidget.h" -#include "model/BlogSession.h" -#include -#include -#include - -BlogLoginWidget::BlogLoginWidget(BlogSession &session, const std::string &basePath) : AuthWidget(session.login()) { - setInline(true); - - auto model = std::make_unique(session.passwordAuth()->baseAuth(), session.users()); - model->addPasswordAuth(session.passwordAuth()); - model->addOAuth(session.oAuth()); - - setModel(std::move(model)); - - setInternalBasePath(basePath + "login"); -} - -void BlogLoginWidget::createLoginView() { - AuthWidget::createLoginView(); - - setTemplateText(tr("blog-login")); - - Wt::WLineEdit *userName = resolve("user-name"); - userName->setPlaceholderText("login"); - userName->setToolTip("login"); - - Wt::WLineEdit *password = resolve("password"); - password->setPlaceholderText("password"); - password->setToolTip("password"); -} - -void BlogLoginWidget::createLoggedInView() { - AuthWidget::createLoggedInView(); - - auto logout = std::make_unique(tr("logout")); - logout->setStyleClass("link"); - logout->clicked().connect(&login(), &Wt::Auth::Login::logout); - bindWidget("logout", std::move(logout)); -} diff --git a/WebApplication/view/BlogLoginWidget.h b/WebApplication/view/BlogLoginWidget.h deleted file mode 100644 index 3270459..0000000 --- a/WebApplication/view/BlogLoginWidget.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __BLOGLOGINWIDGET_H__ -#define __BLOGLOGINWIDGET_H__ - -#include - -class BlogSession; - -class BlogLoginWidget : public Wt::Auth::AuthWidget { -public: - BlogLoginWidget(BlogSession &session, const std::string &basePath); - void createLoginView() final; - void createLoggedInView() final; -}; -#endif // __BLOGLOGINWIDGET_H__ \ No newline at end of file diff --git a/WebApplication/view/BlogView.cpp b/WebApplication/view/BlogView.cpp deleted file mode 100644 index cd000ab..0000000 --- a/WebApplication/view/BlogView.cpp +++ /dev/null @@ -1,392 +0,0 @@ -#include "BlogView.h" -#include "BlogLoginWidget.h" -#include "EditUsers.h" -#include "PostView.h" -#include "model/BlogSession.h" -#include "model/Post.h" -#include "model/Tag.h" -#include -#include -#include -#include -#include -#include -#include - -static int try_stoi(const std::string &v) { - std::size_t pos; - auto result = std::stoi(v, &pos); - if (pos != v.length()) throw std::invalid_argument("stoi() of " + v + " failed"); - return result; -} - -class BlogImpl : public Wt::WContainerWidget { -public: - BlogImpl(const std::string &basePath, Wt::Dbo::SqlConnectionPool &connectionPool, const std::string &rssFeedUrl, - BlogView *blogView) - : m_basePath(basePath), m_rssFeedUrl(rssFeedUrl), m_session(connectionPool) { - Wt::WApplication::instance()->internalPathChanged().connect(this, &BlogImpl::handlePathChange); - m_loginStatus = this->addWidget(std::make_unique(tr("blog-login-status"))); - m_panel = this->addWidget(std::make_unique()); - m_items = this->addWidget(std::make_unique()); - - m_session.login().changed().connect(this, &BlogImpl::onUserChanged); - - auto loginWidget = std::make_unique(m_session, basePath); - m_loginWidget = loginWidget.get(); - m_loginWidget->hide(); - - auto loginLink = std::make_unique(tr("login")); - auto lPtr = loginLink.get(); - loginLink->setStyleClass("link"); - loginLink->clicked().connect(m_loginWidget, &BlogLoginWidget::show); - loginLink->clicked().connect(lPtr, &WWidget::hide); - - auto registerLink = std::make_unique(tr("Wt.Auth.register")); - registerLink->setStyleClass("link"); - registerLink->clicked().connect(m_loginWidget, &BlogLoginWidget::registerNewUser); - - auto archiveLink = - std::make_unique(Wt::WLink(Wt::LinkType::InternalPath, m_basePath + "all"), tr("archive")); - - m_loginStatus->bindWidget("login", std::move(loginWidget)); - m_loginStatus->bindWidget("login-link", std::move(loginLink)); - m_loginStatus->bindWidget("register-link", std::move(registerLink)); - m_loginStatus->bindString("feed-url", m_rssFeedUrl); - m_loginStatus->bindWidget("archive-link", std::move(archiveLink)); - - onUserChanged(); - - m_loginWidget->processEnvironment(); - } - -protected: - void handlePathChange(const std::string &) { - Wt::WApplication *app = Wt::WApplication::instance(); - - if (app->internalPathMatches(m_basePath)) { - Wt::Dbo::Transaction t(m_session); - - std::string path = app->internalPathNextPart(m_basePath); - - m_items->clear(); - - if (m_users) { - m_users = 0; - } - - if (path.empty()) - showPosts(m_session - .find("where state = ? " - "order by date desc " - "limit 10") - .bind(Post::Published), - m_items); - - else if (path == "author") { - std::string author = app->internalPathNextPart(m_basePath + path + '/'); - Wt::Dbo::ptr user = findUser(author); - - if (user) - showPosts(user); - else - showError(tr("blog-no-author").arg(author)); - } else if (path == "edituser") { - editUser(app->internalPathNextPart(m_basePath + path + '/')); - } else if (path == "all") { - showArchive(m_items); - } else { - std::string remainder = app->internalPath().substr(m_basePath.length()); - showPostsByDateTopic(remainder, m_items); - } - - t.commit(); - } - } - - void showArchive(WContainerWidget *parent) { - static const char *dateFormat = "MMMM yyyy"; - - parent->addWidget(std::make_unique(tr("archive-title"))); - - Posts posts = m_session.find("order by date desc"); - - Wt::WDateTime formerDate; - for (auto post : posts) { - if (post->state != Post::Published) continue; - - if (formerDate.isNull() || yearMonthDiffer(formerDate, post->date)) { - Wt::WText *title = - parent->addWidget(std::make_unique(post->date.date().toString(dateFormat))); - title->setStyleClass("archive-month-title"); - } - - Wt::WAnchor *a = parent->addWidget(std::make_unique( - Wt::WLink(Wt::LinkType::InternalPath, m_basePath + post->permaLink()), post->title)); - a->setInline(false); - - formerDate = post->date; - } - } - - bool yearMonthDiffer(const Wt::WDateTime &dt1, const Wt::WDateTime &dt2) { - return dt1.date().year() != dt2.date().year() || dt1.date().month() != dt2.date().month(); - } - - Wt::Dbo::ptr findUser(const std::string &name) { - return m_session.find("where name = ?").bind(name); - } - - bool checkLoggedIn() { - if (m_session.user()) return true; - m_panel->show(); - if (!m_mustLoginWarning) { - m_mustLoginWarning = m_panel->addWidget(std::make_unique(tr("blog-mustlogin"))); - } - m_panel->setCurrentWidget(m_mustLoginWarning); - return false; - } - - bool checkAdministrator() { - if (m_session.user() && (m_session.user()->role == User::Admin)) return true; - m_panel->show(); - if (!m_mustBeAdministratorWarning) { - m_mustBeAdministratorWarning = - m_panel->addWidget(std::make_unique(tr("blog-mustbeadministrator"))); - } - m_panel->setCurrentWidget(m_mustBeAdministratorWarning); - return false; - } - - void editUser(const std::string &ids) { - if (!checkLoggedIn()) return; - if (!checkAdministrator()) return; - Wt::Dbo::dbo_traits::IdType id = User::stringToId(ids); - - m_panel->show(); - try { - Wt::Dbo::Transaction t(m_session); - Wt::Dbo::ptr target(m_session.load(id)); - if (!m_userEditor) { - m_userEditor = m_panel->addWidget(std::make_unique(m_session)); - } - m_userEditor->switchUser(target); - m_panel->setCurrentWidget(m_userEditor); - } catch (Wt::Dbo::ObjectNotFoundException &) { - if (!m_invalidUser) { - m_invalidUser = m_panel->addWidget(std::make_unique(tr("blog-invaliduser"))); - } - m_panel->setCurrentWidget(m_invalidUser); - } - } - - void showPostsByDateTopic(const std::string &path, WContainerWidget *parent) { - std::vector parts; - boost::split(parts, path, boost::is_any_of("/")); - - Wt::WDate lower, upper; - try { - int year = try_stoi(parts[0]); - - if (parts.size() > 1) { - int month = try_stoi(parts[1]); - - if (parts.size() > 2) { - int day = try_stoi(parts[2]); - - lower.setDate(year, month, day); - upper = lower.addDays(1); - } else { - lower.setDate(year, month, 1); - upper = lower.addMonths(1); - } - } else { - lower.setDate(year, 1, 1); - upper = lower.addYears(1); - } - } catch (std::invalid_argument &) { - showError(tr("blog-no-post")); - return; - } - - Posts posts = m_session - .find("where date >= ? " - "and date < ? " - "and (state = ? or author_id = ?)") - .bind(Wt::WDateTime(lower)) - .bind(Wt::WDateTime(upper)) - .bind(Post::Published) - .bind(m_session.user().id()); - - if (parts.size() > 3) { - std::string title = parts[3]; - - for (auto post : posts) - if (post->titleToUrl() == title) { - showPost(post, PostView::Detail, parent); - return; - } - - showError(tr("blog-no-post")); - } else { - showPosts(posts, parent); - } - } - - void showPosts(Wt::Dbo::ptr user) { - showPosts(user->latestPosts(), m_items); - } - - void showPosts(const Posts &posts, WContainerWidget *parent) { - for (auto post : posts) showPost(post, PostView::Brief, parent); - } - - void onUserChanged() { - if (m_session.login().loggedIn()) - loggedIn(); - else - loggedOut(); - } - - void editUsers() { - m_panel->show(); - - if (!m_users) { - m_users = m_panel->addWidget(std::make_unique(m_session, m_basePath)); - bindPanelTemplates(); - } - - m_panel->setCurrentWidget(m_users); - } - BlogSession &session() { - return m_session; - } - void loggedIn() { - Wt::WApplication::instance()->changeSessionId(); - - refresh(); - - m_loginStatus->resolveWidget("login")->show(); - m_loginStatus->resolveWidget("login-link")->hide(); - m_loginStatus->resolveWidget("register-link")->hide(); - - auto profileLink = std::make_unique(tr("profile")); - profileLink->setStyleClass("link"); - profileLink->clicked().connect(this, &BlogImpl::editProfile); - - Wt::Dbo::ptr user = session().user(); - - if (user->role == User::Admin) { - auto editUsersLink = std::make_unique(tr("edit-users")); - editUsersLink->setStyleClass("link"); - editUsersLink->clicked().connect(this, &BlogImpl::editUsers); - m_loginStatus->bindWidget("userlist-link", std::move(editUsersLink)); - - auto authorPanelLink = std::make_unique(tr("author-post")); - authorPanelLink->setStyleClass("link"); - authorPanelLink->clicked().connect(this, &BlogImpl::authorPanel); - m_loginStatus->bindWidget("author-panel-link", std::move(authorPanelLink)); - } else { - m_loginStatus->bindEmpty("userlist-link"); - m_loginStatus->bindEmpty("author-panel-link"); - } - - m_loginStatus->bindWidget("profile-link", std::move(profileLink)); - - bindPanelTemplates(); - } - - void loggedOut() { - m_loginStatus->bindEmpty("profile-link"); - m_loginStatus->bindEmpty("author-panel-link"); - m_loginStatus->bindEmpty("userlist-link"); - - m_loginStatus->resolveWidget("login")->hide(); - m_loginStatus->resolveWidget("login-link")->show(); - m_loginStatus->resolveWidget("register-link")->show(); - - refresh(); - m_panel->hide(); - } - - void editProfile() { - m_loginWidget->letUpdatePassword(m_session.login().user(), true); - } - - void showError(const Wt::WString &msg) { - m_items->addWidget(std::make_unique(msg)); - } - - void authorPanel() { - m_panel->show(); - if (!m_authorPanel) { - m_authorPanel = m_panel->addWidget(std::make_unique(tr("blog-author-panel"))); - bindPanelTemplates(); - } - m_panel->setCurrentWidget(m_authorPanel); - } - - void showPost(const Wt::Dbo::ptr post, PostView::RenderType type, Wt::WContainerWidget *parent) { - parent->addWidget(std::make_unique(m_session, m_basePath, post, type)); - } - - void newPost() { - Wt::Dbo::Transaction t(m_session); - - authorPanel(); - WContainerWidget *unpublishedPosts = m_authorPanel->resolve("unpublished-posts"); - - Wt::Dbo::ptr post(std::make_unique()); - - Post *p = post.modify(); - p->state = Post::Unpublished; - p->author = m_session.user(); - p->title = "Title"; - p->briefSrc = "Brief ..."; - p->bodySrc = "Body ..."; - - showPost(post, PostView::Edit, unpublishedPosts); - - t.commit(); - } - - void bindPanelTemplates() { - if (!m_session.user()) return; - - Wt::Dbo::Transaction t(m_session); - - if (m_authorPanel) { - auto newPost = std::make_unique(tr("new-post")); - newPost->clicked().connect(this, &BlogImpl::newPost); - auto unpublishedPosts = std::make_unique(); - showPosts(m_session.user()->allPosts(Post::Unpublished), unpublishedPosts.get()); - - m_authorPanel->bindString("user", m_session.user()->name); - m_authorPanel->bindInt("unpublished-count", (int)m_session.user()->allPosts(Post::Unpublished).size()); - m_authorPanel->bindInt("published-count", (int)m_session.user()->allPosts(Post::Published).size()); - m_authorPanel->bindWidget("new-post", std::move(newPost)); - m_authorPanel->bindWidget("unpublished-posts", std::move(unpublishedPosts)); - } - - t.commit(); - } - -private: - std::string m_basePath, m_rssFeedUrl; - BlogSession m_session; - BlogLoginWidget *m_loginWidget = nullptr; - Wt::WStackedWidget *m_panel = nullptr; - Wt::WTemplate *m_authorPanel = nullptr; - EditUsers *m_users = nullptr; - EditUser *m_userEditor = nullptr; - Wt::WTemplate *m_mustLoginWarning = nullptr; - Wt::WTemplate *m_mustBeAdministratorWarning = nullptr; - Wt::WTemplate *m_invalidUser = nullptr; - Wt::WTemplate *m_loginStatus = nullptr; - WContainerWidget *m_items = nullptr; -}; - -BlogView::BlogView(const std::string &basePath, Wt::Dbo::SqlConnectionPool &db, const std::string &rssFeedUrl) - : WCompositeWidget(), m_userChanged() { - m_impl = setImplementation(std::make_unique(basePath, db, rssFeedUrl, this)); -} diff --git a/WebApplication/view/BlogView.h b/WebApplication/view/BlogView.h deleted file mode 100644 index 0c21a9e..0000000 --- a/WebApplication/view/BlogView.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __BLOGVIEW_H__ -#define __BLOGVIEW_H__ - -#include - -class BlogImpl; - -class BlogView : public Wt::WCompositeWidget { -public: - BlogView(const std::string &basePath, Wt::Dbo::SqlConnectionPool &db, const std::string &rssFeedUrl); - -private: - BlogImpl *m_impl; - Wt::Signal m_userChanged; -}; -#endif // __BLOGVIEW_H__ \ No newline at end of file diff --git a/WebApplication/view/CommentView.cpp b/WebApplication/view/CommentView.cpp deleted file mode 100644 index b7d0278..0000000 --- a/WebApplication/view/CommentView.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "CommentView.h" -#include "model/BlogSession.h" -#include "model/Comment.h" -#include "model/User.h" -#include -#include - -CommentView::CommentView(BlogSession &session, long long parentId) : session_(session) { - Wt::Dbo::ptr parent = session_.load(parentId); - - comment_ = std::make_unique(); - comment_.modify()->parent = parent; - comment_.modify()->post = parent->post; - - edit(); -} - -CommentView::CommentView(BlogSession &session, Wt::Dbo::ptr comment) : session_(session), comment_(comment) { - comment_ = comment; - renderView(); -} - -void CommentView::cancel() { - if (isNew()) - removeFromParent(); - else { - Wt::Dbo::Transaction t(session_); - renderView(); - t.commit(); - } -} - -void CommentView::renderView() { - clear(); - - bool isRootComment = !comment_->parent; - setTemplateText(isRootComment ? tr("blog-root-comment") : tr("blog-comment")); - - bindString("collapse-expand", Wt::WString::Empty); // NYI - - auto replyText = std::make_unique(isRootComment ? tr("comment-add") : tr("comment-reply")); - replyText->setStyleClass("link"); - replyText->clicked().connect(this, &CommentView::reply); - bindWidget("reply", std::move(replyText)); - - bool mayEdit = session_.user() && (comment_->author == session_.user() || session_.user()->role == User::Admin); - - if (mayEdit) { - auto editText = std::make_unique(tr("comment-edit")); - editText->setStyleClass("link"); - editText->clicked().connect(this, &CommentView::edit); - bindWidget("edit", std::move(editText)); - } else - bindString("edit", Wt::WString::Empty); - - bool mayDelete = - (session_.user() && session_.user() == comment_->author) || session_.user() == comment_->post->author; - - if (mayDelete) { - auto deleteText = std::make_unique(tr("comment-delete")); - deleteText->setStyleClass("link"); - deleteText->clicked().connect(this, &CommentView::rm); - bindWidget("delete", std::move(deleteText)); - } else - bindString("delete", Wt::WString::Empty); - - typedef std::vector> CommentVector; - CommentVector comments; - { - Wt::Dbo::collection> cmts = comment_->children.find().orderBy("date"); - comments.insert(comments.end(), cmts.begin(), cmts.end()); - } - - auto children = std::make_unique(); - for (int i = (int)comments.size() - 1; i >= 0; --i) - children->addWidget(std::make_unique(session_, comments[i])); - - bindWidget("children", std::move(children)); -} - -bool CommentView::isNew() const { - return comment_.id() == -1; -} -void CommentView::rm() { - Wt::Dbo::Transaction t(session_); - - comment_.modify()->setDeleted(); - renderView(); - - t.commit(); -} - -void CommentView::reply() { - Wt::Dbo::Transaction t(session_); - - Wt::WContainerWidget *c = resolve("children"); - c->insertWidget(0, std::make_unique(session_, comment_.id())); - - t.commit(); -} - -void CommentView::save() { - Wt::Dbo::Transaction t(session_); - - bool isNew = comment_.id() == -1; - - Comment *comment = comment_.modify(); - - comment->setText(editArea_->text()); - - if (isNew) { - session_.add(comment_); - comment->date = Wt::WDateTime::currentDateTime(); - comment->author = session_.user(); - session_.commentsChanged().emit(comment_); - } - - renderView(); - - t.commit(); -} - -void CommentView::edit() { - clear(); - - Wt::Dbo::Transaction t(session_); - - setTemplateText(tr("blog-edit-comment")); - - auto editArea = std::make_unique(); - editArea_ = editArea.get(); - editArea_->setText(comment_->textSrc()); - editArea_->setFocus(); - - auto save = std::make_unique(tr("save")); - save->clicked().connect(this, &CommentView::save); - - auto cancel = std::make_unique(tr("cancel")); - cancel->clicked().connect(this, &CommentView::cancel); - - bindWidget("area", std::move(editArea)); - bindWidget("save", std::move(save)); - bindWidget("cancel", std::move(cancel)); - - t.commit(); -} diff --git a/WebApplication/view/CommentView.h b/WebApplication/view/CommentView.h deleted file mode 100644 index a61f49f..0000000 --- a/WebApplication/view/CommentView.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __COMMENTVIEW_H__ -#define __COMMENTVIEW_H__ - -#include -#include - -class BlogSession; -class Comment; - -class CommentView : public Wt::WTemplate { -public: - CommentView(BlogSession &session, long long parentId); - CommentView(BlogSession& session, Wt::Dbo::ptr comment); -protected: - void edit(); - void save(); - void cancel(); - void renderView(); - bool isNew() const; - void reply(); - void rm(); -private: - BlogSession &session_; - Wt::Dbo::ptr comment_; - Wt::WTextArea *editArea_; -}; -#endif // __COMMENTVIEW_H__ \ No newline at end of file diff --git a/WebApplication/view/EditUsers.cpp b/WebApplication/view/EditUsers.cpp deleted file mode 100644 index c2a1123..0000000 --- a/WebApplication/view/EditUsers.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "EditUsers.h" -#include -#include -#include -#include - -EditUsers::EditUsers(Wt::Dbo::Session &aSession, const std::string &basePath) - : m_session(aSession), m_basePath(basePath) { - setStyleClass("user-editor"); - setTemplateText(tr("edit-users-list")); - auto limitEdit = std::make_unique(); - auto goLimit = std::make_unique(tr("go-limit")); - goLimit->clicked().connect(this, &EditUsers::limitList); - - m_limitEdit = bindWidget("limit-edit", std::move(limitEdit)); - bindWidget("limit-button", std::move(goLimit)); - limitList(); -} - -void EditUsers::onUserClicked(Wt::Dbo::dbo_traits::IdType id) { - Wt::WApplication::instance()->setInternalPath(m_basePath + "edituser/" + std::to_string(id), true); -} - -void EditUsers::limitList() { - auto listPtr = std::make_unique(); - auto list = listPtr.get(); - bindWidget("user-list", std::move(listPtr)); - - typedef Wt::Dbo ::collection> UserList; - Wt::Dbo ::Transaction t(m_session); - UserList users = m_session.find().where("name like ?").bind("%" + m_limitEdit->text() + "%").orderBy("name"); - - for (auto user : users) { - Wt::WText *t = list->addWidget(std::make_unique(user->name)); - t->setStyleClass("link"); - list->addWidget(std::make_unique()); - t->clicked().connect(std::bind(&EditUsers::onUserClicked, this, user.id())); - } - if (!users.size()) list->addWidget(std::make_unique(tr("no-users-found"))); -} - -EditUser::EditUser(Wt::Dbo::Session &aSession) : WTemplate(tr("edit-user")), session_(aSession) { - auto roleButton = std::make_unique(); - roleButton_ = bindWidget("role-button", std::move(roleButton)); - roleButton_->clicked().connect(this, &EditUser::switchRole); -} - -void EditUser::switchUser(Wt::Dbo::ptr target) { - target_ = target; - bindTemplate(); -} - -void EditUser::bindTemplate() { - bindString("username", target_->name); - if (target_->role == User::Admin) - roleButton_->setText(tr("demote-admin")); - else - roleButton_->setText(tr("promote-user")); -} - -void EditUser::switchRole() { - Wt::Dbo::Transaction t(session_); - target_.reread(); - if (target_->role == User::Admin) - target_.modify()->role = User::Visitor; - else - target_.modify()->role = User::Admin; - t.commit(); - bindTemplate(); -} diff --git a/WebApplication/view/EditUsers.h b/WebApplication/view/EditUsers.h deleted file mode 100644 index 8b982e0..0000000 --- a/WebApplication/view/EditUsers.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __EDITUSERS_H__ -#define __EDITUSERS_H__ - -#include "model/User.h" -#include -#include - -class EditUsers : public Wt::WTemplate { -public: - EditUsers(Wt::Dbo::Session &aSession, const std::string &basePath); - -private: - void onUserClicked(Wt::Dbo::dbo_traits::IdType id); - void limitList(); - - Wt::Dbo::Session &m_session; - std::string m_basePath; - Wt::WLineEdit *m_limitEdit; -}; - -class EditUser : public Wt::WTemplate { -public: - EditUser(Wt::Dbo::Session &aSession); - void switchUser(Wt::Dbo::ptr target); - -private: - void bindTemplate(); - void switchRole(); - - Wt::Dbo::Session &session_; - Wt::Dbo::ptr target_; - Wt::WPushButton *roleButton_; -}; - -#endif // __EDITUSERS_H__ \ No newline at end of file diff --git a/WebApplication/view/PostView.cpp b/WebApplication/view/PostView.cpp deleted file mode 100644 index cb33003..0000000 --- a/WebApplication/view/PostView.cpp +++ /dev/null @@ -1,188 +0,0 @@ -#include "PostView.h" -#include "CommentView.h" -#include "model/BlogSession.h" -#include "model/User.h" -#include "model/asciidoc.h" -#include -#include -#include -#include -#include -#include - -PostView::PostView(BlogSession &session, const std::string &basePath, Wt::Dbo::ptr post, RenderType type) - : session_(session), basePath_(basePath), post_(post) { - viewType_ = Brief; - render(type); -} - -void PostView::render(RenderType type) { - if (type != Edit) viewType_ = type; - - clear(); - - switch (type) { - case Detail: { - setTemplateText(tr("blog-post")); - - session_.commentsChanged().connect(this, &PostView::updateCommentCount); - - commentCount_ = bindWidget("comment-count", std::make_unique(post_->commentCount())); - bindWidget("comments", std::make_unique(session_, post_->rootComment())); - bindString("anchor", basePath_ + post_->permaLink()); - - break; - } - case Brief: { - setTemplateText(tr("blog-post-brief")); - - auto titleAnchor = std::make_unique( - Wt::WLink(Wt::LinkType::InternalPath, basePath_ + post_->permaLink()), post_->title); - bindWidget("title", std::move(titleAnchor)); - - if (!post_->briefSrc.empty()) { - auto moreAnchor = std::make_unique( - Wt::WLink(Wt::LinkType::InternalPath, basePath_ + post_->permaLink() + "/more"), tr("blog-read-more")); - bindWidget("read-more", std::move(moreAnchor)); - } else { - bindString("read-more", Wt::WString::Empty); - } - - auto commentsAnchor = std::make_unique( - Wt::WLink(Wt::LinkType::InternalPath, basePath_ + post_->permaLink() + "/comments")); - commentCount_ = commentsAnchor->addWidget(std::make_unique("(" + post_->commentCount() + ")")); - bindWidget("comment-count", std::move(commentsAnchor)); - - break; - } - case Edit: { - setTemplateText(tr("blog-post-edit")); - - titleEdit_ = bindWidget("title-edit", std::make_unique(post_->title)); - briefEdit_ = bindWidget("brief-edit", std::make_unique(post_->briefSrc)); - bodyEdit_ = bindWidget("body-edit", std::make_unique(post_->bodySrc)); - - auto saveButton = bindWidget("save", std::make_unique(tr("save"))); - auto cancelButton = bindWidget("cancel", std::make_unique(tr("cancel"))); - - saveButton->clicked().connect(this, &PostView::saveEdit); - cancelButton->clicked().connect(this, &PostView::showView); - - break; - } - } - - if (type == Detail || type == Brief) { - if (session_.user() == post_->author) { - std::unique_ptr publishButton; - if (post_->state != Post::Published) { - publishButton = std::make_unique(tr("publish")); - publishButton->clicked().connect(this, &PostView::publish); - } else { - publishButton = std::make_unique(tr("retract")); - publishButton->clicked().connect(this, &PostView::retract); - } - bindWidget("publish", std::move(publishButton)); - - auto editButton(std::make_unique(tr("edit"))); - editButton->clicked().connect(this, &PostView::showEdit); - bindWidget("edit", std::move(editButton)); - - auto deleteButton(std::make_unique(tr("delete"))); - deleteButton->clicked().connect(this, &PostView::rm); - bindWidget("delete", std::move(deleteButton)); - } else { - bindString("publish", Wt::WString::Empty); - bindString("edit", Wt::WString::Empty); - bindString("delete", Wt::WString::Empty); - } - } - - auto postAnchor = std::make_unique( - Wt::WLink(Wt::LinkType::InternalPath, basePath_ + "author/" + post_->author->name.toUTF8()), - post_->author->name); - bindWidget("author", std::move(postAnchor)); -} -void PostView::publish() { - setState(Post::Published); -} -void PostView::showEdit() { - Wt::Dbo::Transaction t(session_); - - render(Edit); - - t.commit(); -} - -void PostView::rm() { - Wt::Dbo::Transaction t(session_); - post_.remove(); - t.commit(); - - this->removeFromParent(); -} -void PostView::retract() { - setState(Post::Unpublished); -} - -void PostView::setState(Post::State state) { - Wt::Dbo::Transaction t(session_); - - post_.modify()->state = state; - if (state == Post::Published) post_.modify()->date = Wt::WDateTime::currentDateTime(); - - render(viewType_); - - t.commit(); -} -void PostView::saveEdit() { - Wt::Dbo::Transaction t(session_); - - bool newPost = post_.id() == -1; - - Post *post = post_.modify(); - - post->title = titleEdit_->text(); - post->briefSrc = briefEdit_->text(); - post->bodySrc = bodyEdit_->text(); - - post->briefHtml = asciidoc(post->briefSrc); - post->bodyHtml = asciidoc(post->bodySrc); - - if (newPost) { - session_.add(post_); - - post->date = Wt::WDateTime::currentDateTime(); - post->state = Post::Unpublished; - post->author = session_.user(); - - Wt::Dbo::ptr rootComment = session_.add(std::make_unique()); - rootComment.modify()->post = post_; - } - - session_.flush(); - - render(viewType_); - - t.commit(); -} - -void PostView::showView() { - if (post_.id() == -1) - this->removeFromParent(); - else { - Wt::Dbo::Transaction t(session_); - render(viewType_); - t.commit(); - } -} -void PostView::updateCommentCount(Wt::Dbo::ptr comment) { - if (comment->post == post_) { - std::string count = comment->post->commentCount(); - - if (commentCount_->text().toUTF8()[0] == '(') - commentCount_->setText("(" + count + ")"); - else - commentCount_->setText(count); - } -} diff --git a/WebApplication/view/PostView.h b/WebApplication/view/PostView.h deleted file mode 100644 index 916acdc..0000000 --- a/WebApplication/view/PostView.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __POSTVIEW_H__ -#define __POSTVIEW_H__ - -#include "model/Post.h" -#include - -class BlogSession; - -class PostView : public Wt::WTemplate { -public: - enum RenderType { - Brief, - Detail, - Edit, - }; - - PostView(BlogSession &session, const std::string &basePath, Wt::Dbo::ptr post, RenderType type); - -protected: - void render(RenderType type); - void updateCommentCount(Wt::Dbo::ptr comment); - void saveEdit(); - void showView(); - void publish(); - void retract(); - void setState(Post::State state); - void showEdit(); - void rm(); - -private: - BlogSession &session_; - std::string basePath_; - Wt::Dbo::ptr post_; - - RenderType viewType_; - Wt::WText *commentCount_; - Wt::WLineEdit *titleEdit_; - Wt::WTextArea *briefEdit_, *bodyEdit_; -}; -#endif // __POSTVIEW_H__ \ No newline at end of file