refactoring

This commit is contained in:
Wieczorek Bartosz 2017-03-05 09:56:47 +01:00
parent fb02774123
commit 8cd3957ad4
5 changed files with 226 additions and 208 deletions

View File

@ -4,9 +4,6 @@ project(eedb)
add_definitions( -std=c++17 )
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "/usr/share/cmake/Modules/")
#set(EEDB_WT_INSTALL_PATH /usr/local/wt_gcc6/)
find_package(Wt REQUIRED)
find_package(Sqlpp11 REQUIRED)
find_package(PostgreSQL REQUIRED)

View File

@ -9,6 +9,7 @@
#include <Wt/WApplication>
#include <Wt/WBorderLayout>
#include <Wt/WContainerWidget>
#include <Wt/WEnvironment>
#include <Wt/WLineEdit>
#include <Wt/WMessageBox>
#include <Wt/WNavigationBar>
@ -20,144 +21,151 @@
class AuthApplication : public Wt::WApplication {
public:
auto getDbConfig(const Wt::WEnvironment & env) {
auto config = std::make_unique< sqlpp::postgresql::connection_config >();
auto readString = [&env](auto && name, auto & val, auto def) {
if(!env.server()->readConfigurationProperty(name, val)) {
val = def;
}
};
auto readInt = [&env](auto && name, auto & val, auto def) {
std::string tmp;
if(env.server()->readConfigurationProperty(name, tmp)) {
val = std::atoi(tmp.c_str());
} else {
val = def;
}
};
auto readBool = [&env](auto && name, auto & val, auto def) {
std::string tmp;
if(env.server()->readConfigurationProperty(name, tmp)) {
val = tmp == "true";
} else {
val = def;
}
};
readString("db_host", config->host, "localhost");
readString("db_user", config->user, "postgres");
readString("db_password", config->password, "postgres");
readString("db_name", config->dbname, "eedb");
readInt("db_port", config->port, 5432);
readBool("db_debug", config->debug, true);
return config;
}
AuthApplication(const Wt::WEnvironment & env) : Wt::WApplication(env) {
login_.changed().connect(this, &AuthApplication::authEvent);
_login.changed().connect(this, &AuthApplication::authEvent);
auto config = std::make_shared< sqlpp::postgresql::connection_config >();
config->host = "10.154.46.106";
config->port = 5432;
config->user = "postgres";
config->password = "postgres";
config->dbname = "eedb";
config->debug = true;
conn_ = std::make_unique< eedb::db::PgConnection >(config);
userDatabase_ = std::make_unique< eedb::auth::PgUserAuth >(*conn_, env);
_dbConnection = std::make_unique< eedb::db::PgConnection >(getDbConfig(env));
_userDatabase = std::make_unique< eedb::auth::PgUserAuth >(*_dbConnection, env);
root()->addStyleClass("container");
useStyleSheet("/resources/style.css");
setTheme(eedb::BootstrapTheme(this).create());
_authWidget = new eedb::AuthWidget(eedb::auth::Services{}, *userDatabase_, login_);
_authWidget = new eedb::AuthWidget(eedb::auth::Services{}, *_userDatabase, _login);
root()->addWidget(_authWidget);
}
void authEvent() {
using namespace Wt;
if(login_.loggedIn()) {
if(_login.loggedIn()) {
Wt::WContainerWidget * container = root();
setInternalPath("/app");
root()->removeStyleClass("container");
// Create a navigation bar with a link to a web page.
Wt::WNavigationBar * navigation = new Wt::WNavigationBar(container);
auto navigation = new Wt::WNavigationBar(container);
navigation->setTitle("eedb", "http://eedb.pl");
navigation->setResponsive(true);
Wt::WStackedWidget * contentsStack = new Wt::WStackedWidget(container);
auto contentsStack = new Wt::WStackedWidget(container);
contentsStack->addStyleClass("contents");
// Setup a Left-aligned menu.
Wt::WMenu * leftMenu = new Wt::WMenu(contentsStack, container);
navigation->addMenu(leftMenu);
Wt::WText * searchResult = new Wt::WText("Buy or Sell... Bye!");
leftMenu->addItem("Home", new Wt::WText("There is no better place!"));
leftMenu->addItem("Sales", searchResult);
Wt::WMenu * mainTabs = new Wt::WMenu(contentsStack, container);
mainTabs->addItem("Home");
navigation->addMenu(mainTabs);
// Setup a Right-aligned menu.
Wt::WMenu * rightMenu = new Wt::WMenu();
Wt::WMenu * sessionMenu = new Wt::WMenu();
navigation->addMenu(rightMenu, Wt::AlignRight);
navigation->addMenu(sessionMenu, Wt::AlignRight);
// Create a popup submenu for the Help menu.
Wt::WPopupMenu * popup = new Wt::WPopupMenu();
auto popup = new Wt::WPopupMenu();
popup->addItem("Contents");
popup->addItem("Index");
popup->addSeparator();
popup->addItem("About");
popup->itemSelected().connect(std::bind(
[=](Wt::WMenuItem * item) {
Wt::WMessageBox * messageBox = new Wt::WMessageBox(
"Help", Wt::WString::fromUTF8("<p>Showing Help: {1}</p>").arg(item->text()), Wt::Information, Wt::Ok);
messageBox->buttonClicked().connect(std::bind([=]() { delete messageBox; }));
messageBox->show();
},
std::placeholders::_1));
Wt::WMenuItem * help = new Wt::WMenuItem("Help");
popup->itemSelected().connect([](auto && item, auto...) {
auto messageBox =
new Wt::WMessageBox("Help", Wt::WString::fromUTF8("<p>Showing Help: {1}</p>").arg(item->text()), Wt::Information, Wt::Ok);
messageBox->buttonClicked().connect([messageBox = messageBox](auto...) { delete messageBox; });
messageBox->show();
});
auto help = new Wt::WMenuItem("Help");
help->setMenu(popup);
auto rightMenu = new Wt::WMenu();
rightMenu->addItem(help);
// sessionMenu->addItem("session", _authWidget);
navigation->addMenu(rightMenu, Wt::AlignRight);
// Setup a Right-aligned menu.
// Create a popup submenu for the Help menu.
auto sessionMenuPopup = new Wt::WPopupMenu();
sessionMenuPopup->addItem("Logout");
sessionMenuPopup->itemSelected().connect([=](auto...) {
this->_authWidget->login().logout();
std::cout << "logout";
});
auto sessionItem = new Wt::WMenuItem("Session");
sessionItem->setMenu(sessionMenuPopup);
auto sessionMenu = new Wt::WMenu();
sessionMenu->addItem(sessionItem);
navigation->addMenu(sessionMenu, Wt::AlignRight);
// Add a Search control.
Wt::WLineEdit * edit = new Wt::WLineEdit();
edit->setEmptyText("Enter a search item");
edit->enterPressed().connect(std::bind([=]() {
leftMenu->select(2); // is the index of the "Sales"
searchResult->setText(Wt::WString("Nothing found for {1}.").arg(edit->text()));
}));
navigation->addSearch(edit, Wt::AlignRight);
// navigation->addSearch(edit, Wt::AlignRight);
Wt::WBorderLayout * layout = new Wt::WBorderLayout();
container->setLayout(layout);
const char * cell = "{1} item";
Wt::WStackedWidget * contents = new Wt::WStackedWidget();
auto menu = new Wt::WMenu(contents, container);
menu->setStyleClass("nav nav-pills nav-stacked");
// Add menu items using the default lazy loading policy.
menu->addItem("Internal paths", new Wt::WText("Internal paths contents"));
menu->addItem("Anchor", new Wt::WTextArea("Anchor contents"));
menu->addItem("Tab widget", new Wt::WTextArea("Tab widget contents"));
menu->addItem("Menu", new Wt::WTextArea("Menu contents"));
layout->addWidget(navigation, Wt::WBorderLayout::North);
Wt::WText * item = new Wt::WText(Wt::WString(cell).arg("North"));
item->setStyleClass("green-box");
layout->addWidget(menu, Wt::WBorderLayout::West);
layout->addWidget(new Wt::WText("West"), Wt::WBorderLayout::West);
item = new Wt::WText(Wt::WString(cell).arg("East"));
auto item = new Wt::WText(Wt::WString("East"));
item->setStyleClass("green-box");
layout->addWidget(item, Wt::WBorderLayout::East);
item = new Wt::WText(Wt::WString(cell).arg("South"));
item = new Wt::WText(Wt::WString("South"));
item->setStyleClass("green-box");
layout->addWidget(item, Wt::WBorderLayout::South);
item = new Wt::WText(Wt::WString(cell).arg("Center"));
item->setStyleClass("green-box");
layout->addWidget(contents, Wt::WBorderLayout::Center);
} else {
// Wt::Auth::AuthWidget * authWidget = new Wt::Auth::AuthWidget(*eedb::auth::Services::authService(), *userDatabase_,
// login_);
// root()->clear();
// authWidget->model()->addPasswordAuth(eedb::auth::Services::passwordService());
// authWidget->model()->addOAuth(eedb::auth::Services::oAuthServices());
// authWidget->setRegistrationEnabled(true);
// root()->addWidget(authWidget);
Wt::Auth::AuthWidget * authWidget = new Wt::Auth::AuthWidget(*eedb::auth::Services::authService(), *_userDatabase, _login);
root()->clear();
authWidget->model()->addPasswordAuth(eedb::auth::Services::passwordService());
authWidget->model()->addOAuth(eedb::auth::Services::oAuthServices());
authWidget->setRegistrationEnabled(true);
root()->addWidget(authWidget);
Wt::log("notice") << "User logged out.";
}
}
private:
std::unique_ptr< eedb::db::PgConnection > conn_;
std::unique_ptr< eedb::auth::PgUserAuth > userDatabase_;
Wt::Auth::Login login_;
std::unique_ptr< eedb::db::PgConnection > _dbConnection;
std::unique_ptr< eedb::auth::PgUserAuth > _userDatabase;
Wt::Auth::Login _login;
eedb::AuthWidget * _authWidget;
};

View File

@ -1,11 +1,9 @@
#include "PgUserAuth.hpp"
#include <eedb/db/connection.hpp>
#include <eedb/auth/Services.hpp>
#include <sqlpp11/sqlpp11.h>
#include <eedb/auth/Services.hpp>
#include <eedb/db/connection.hpp>
#include <eedb/model/auth_identity.h>
#include <eedb/model/auth_info.h>
#include <eedb/model/auth_token.h>
@ -19,6 +17,7 @@
#include <iostream>
#include <random>
#include <string>
//#include <string_view>
#include <Wt/Auth/AuthService>
#include <Wt/Auth/Dbo/AuthInfo>
@ -32,6 +31,9 @@ using namespace sqlpp;
using namespace Wt::Auth;
using namespace std::string_literals;
// enum LoginActions { Login, Logout };
// static std::array< std::string_view, 2 > UserActionNames = {{"login", "logout"}};
std::string RandomString(int len) {
using namespace std;
srand(time(0));
@ -65,26 +67,25 @@ struct TransactionGuard : public Wt::Auth::AbstractUserDatabase::Transaction {
namespace eedb::auth {
namespace {
SQLPP_ALIAS_PROVIDER(fk_auth_info_id);
SQLPP_ALIAS_PROVIDER(user_status);
constexpr eedb::user t_user;
constexpr eedb::user_audit t_user_history;
constexpr eedb::user_action t_user_action;
constexpr eedb::auth_identity authIdentity;
constexpr eedb::auth_info authInfo;
constexpr eedb::auth_identity t_identity;
constexpr eedb::auth_info t_info;
constexpr eedb::auth_token t_auth_token;
auto auth = t_user.join(authInfo).on(t_user.uid == authInfo.user_uid).join(authIdentity).on(authInfo.id == authIdentity.auth_info_id);
auto auth_info_identity = authInfo.join(authIdentity).on(authInfo.id == authIdentity.auth_info_id);
auto user_auth_info = t_user.join(authInfo).on(authInfo.user_uid == t_user.uid);
auto auth_token_info = user_auth_info.join(t_auth_token).on(t_auth_token.auth_info_id == authInfo.id);
auto auth_info_identity = t_info.join(t_identity).on(t_info.id == t_identity.auth_info_id);
auto user_auth_info = t_user.join(t_info).on(t_info.user_uid == t_user.uid);
auto auth_token_info = user_auth_info.join(t_auth_token).on(t_auth_token.auth_info_id == t_info.id);
const auto select_login_action_id = select(t_user_action.id) //
.from(t_user_action) //
.where(t_user_action.name == "login") //
.limit(1u);
const auto select_logout_action_id = select(t_user_action.id) //
.from(t_user_action) //
.where(t_user_action.name == "logout") //
.limit(1u);
}
PgUserAuth::~PgUserAuth() {}
@ -112,10 +113,10 @@ User PgUserAuth::findWithIdentity(const std::string & provider, const Wt::WStrin
std::transform(_identity.begin(), _identity.end(), _identity.begin(), ::tolower);
}
auto identity_eq = authIdentity.identity == _identity;
auto provider_eq = authIdentity.provider == provider;
auto identity_eq = t_identity.identity == _identity;
auto provider_eq = t_identity.provider == provider;
auto result = db(select(authInfo.user_uid) //
auto result = db(select(t_info.user_uid) //
.from(auth_info_identity) //
.where(provider_eq and identity_eq));
@ -126,11 +127,11 @@ User PgUserAuth::findWithIdentity(const std::string & provider, const Wt::WStrin
}
void PgUserAuth::addIdentity(const User & user, const std::string & provider, const Wt::WString & identity) {
const auto uid_eq = authInfo.user_uid == std::atoi(user.id().c_str());
const auto identity_eq = authIdentity.identity == identity.toUTF8();
const auto provider_eq = authIdentity.provider == provider;
const auto uid_eq = t_info.user_uid == std::atoi(user.id().c_str());
const auto identity_eq = t_identity.identity == identity.toUTF8();
const auto provider_eq = t_identity.provider == provider;
auto res = db(select(authInfo.user_uid, authInfo.id) //
auto res = db(select(t_info.user_uid, t_info.id) //
.from(auth_info_identity)
.where(identity_eq and provider_eq and uid_eq));
@ -139,42 +140,42 @@ void PgUserAuth::addIdentity(const User & user, const std::string & provider, co
return;
}
auto auth_info_id = db(select(authInfo.id)
.from(authInfo) //
auto auth_info_id = db(select(t_info.id)
.from(t_info) //
.where(uid_eq));
if(auth_info_id.empty()) {
throw std::exception();
}
db(insert_into(authIdentity)
.set(authIdentity.identity = identity.toUTF8(), //
authIdentity.provider = provider, //
authIdentity.auth_info_id = auth_info_id.front().id));
db(insert_into(t_identity)
.set(t_identity.identity = identity.toUTF8(), //
t_identity.provider = provider, //
t_identity.auth_info_id = auth_info_id.front().id));
Wt::log("info") << "created new identity for user";
}
void PgUserAuth::setIdentity(const User & user, const std::string & provider, const Wt::WString & identity) {
const auto uid = std::atoi(user.id().c_str());
const auto provider_eq = authIdentity.provider == provider;
const auto provider_eq = t_identity.provider == provider;
db(update(authIdentity) //
.set(authIdentity.identity = identity.toUTF8()) //
.where(authIdentity.auth_info_id ==
select(authInfo.id) //
.from(authInfo) //
.where(authInfo.user_uid == uid) and
db(update(t_identity) //
.set(t_identity.identity = identity.toUTF8()) //
.where(t_identity.auth_info_id ==
select(t_info.id) //
.from(t_info) //
.where(t_info.user_uid == uid) and
provider_eq));
}
Wt::WString PgUserAuth::identity(const User & user, const std::string & provider) const {
const auto uid = std::atoi(user.id().c_str());
const auto id_eq = authInfo.user_uid == uid;
const auto provider_eq = authIdentity.provider == provider;
const int uid = std::atoi(user.id().c_str());
const auto id_eq = t_info.user_uid == uid;
const auto provider_eq = t_identity.provider == provider;
auto res = db(select(authIdentity.identity) //
.from(auth_info_identity) //
auto res = db(select(t_identity.identity) //
.from(auth_info_identity) //
.where(id_eq and provider_eq));
if(res.empty())
@ -183,10 +184,10 @@ Wt::WString PgUserAuth::identity(const User & user, const std::string & provider
}
void PgUserAuth::removeIdentity(const User & user, const std::string & provider) {
const auto id_eq = authIdentity.id == std::atoi(user.id().c_str());
const auto provider_eq = authIdentity.provider == provider;
const auto id_eq = t_identity.id == std::atoi(user.id().c_str());
const auto provider_eq = t_identity.provider == provider;
db(remove_from(authIdentity) //
db(remove_from(t_identity) //
.where(id_eq and provider_eq));
}
@ -199,19 +200,19 @@ User PgUserAuth::registerNew() {
.front()
.uid;
db(insert_into(authInfo).set( //
authInfo.password_hash = "NONE", //
authInfo.password_method = "NONE", //
authInfo.password_salt = "NONE", //
authInfo.user_uid = user_id, //
authInfo.email = RandomString(20) + "@NONE.org"));
db(insert_into(t_info).set( //
t_info.password_hash = "NONE", //
t_info.password_method = "NONE", //
t_info.password_salt = "NONE", //
t_info.user_uid = user_id, //
t_info.email = RandomString(20) + "@NONE.org"));
return User{std::to_string(user_id), *this};
}
void PgUserAuth::deleteUser(const User & user) {
db(remove_from(authInfo) //
.where(authInfo.id == std::atoi(user.id().c_str())));
db(remove_from(t_info) //
.where(t_info.id == std::atoi(user.id().c_str())));
}
// User::Status PgUserAuth::status(const User & user) const {
@ -232,19 +233,19 @@ void PgUserAuth::deleteUser(const User & user) {
//}
void PgUserAuth::setPassword(const User & user, const PasswordHash & password) {
db(update(authInfo)
.set( //
authInfo.password_hash = password.value(), //
authInfo.password_method = password.function(), //
authInfo.password_salt = password.salt())
.where(authInfo.user_uid == std::atoi(user.id().c_str())));
db(update(t_info)
.set( //
t_info.password_hash = password.value(), //
t_info.password_method = password.function(), //
t_info.password_salt = password.salt())
.where(t_info.user_uid == std::atoi(user.id().c_str())));
}
PasswordHash PgUserAuth::password(const User & user) const {
const auto id_eq = authInfo.user_uid == std::atoi(user.id().c_str());
const auto id_eq = t_info.user_uid == std::atoi(user.id().c_str());
auto row = db(select(authInfo.password_hash, authInfo.password_method, authInfo.password_salt)
.from(authInfo) //
auto row = db(select(t_info.password_hash, t_info.password_method, t_info.password_salt)
.from(t_info) //
.where(id_eq));
if(row.empty())
return PasswordHash();
@ -253,20 +254,20 @@ PasswordHash PgUserAuth::password(const User & user) const {
}
bool PgUserAuth::setEmail(const User & user, const std::string & address) {
const auto uid_eq = authInfo.user_uid == std::atoi(user.id().c_str());
const auto uid_eq = t_info.user_uid == std::atoi(user.id().c_str());
db(update(authInfo) //
.set( //
authInfo.email = address,
authInfo.email_verified = true) //
db(update(t_info) //
.set( //
t_info.email = address,
t_info.email_verified = true) //
.where(uid_eq));
return true;
}
std::string PgUserAuth::email(const User & user) const {
auto ret = db(select(authInfo.email) //
.from(authInfo) //
.where(authInfo.user_uid == std::atoi(user.id().c_str()) and authInfo.email_verified == true));
auto ret = db(select(t_info.email) //
.from(t_info) //
.where(t_info.user_uid == std::atoi(user.id().c_str()) and t_info.email_verified == true));
if(ret.empty())
return {};
return std::move(ret.front().email);
@ -277,30 +278,30 @@ void PgUserAuth::setUnverifiedEmail(const User & user, const std::string & addre
// different fields in database. So in order to verify email, they just copy the unverified_email to email and then
// set unverified_email to empty string (db don't allow empty strings as email*)
if(address.empty())
db(update(authInfo) //
.set(authInfo.email_verified = true) //
.where(authInfo.user_uid == std::atoi(user.id().c_str())));
db(update(t_info) //
.set(t_info.email_verified = true) //
.where(t_info.user_uid == std::atoi(user.id().c_str())));
else
db(update(authInfo) //
.set( //
authInfo.email = address, //
authInfo.email_verified = false) //
.where(authInfo.user_uid == std::atoi(user.id().c_str())));
db(update(t_info) //
.set( //
t_info.email = address, //
t_info.email_verified = false) //
.where(t_info.user_uid == std::atoi(user.id().c_str())));
}
std::string PgUserAuth::unverifiedEmail(const User & user) const {
auto ret = db(select(authInfo.email) //
.from(authInfo) //
.where(authInfo.user_uid == std::atoi(user.id().c_str()) and authInfo.email_verified == false));
auto ret = db(select(t_info.email) //
.from(t_info) //
.where(t_info.user_uid == std::atoi(user.id().c_str()) and t_info.email_verified == false));
if(ret.empty())
return {};
return std::move(ret.front().email);
}
User PgUserAuth::findWithEmail(const std::string & address) const {
auto ret = db(select(authInfo.user_uid) //
.from(authInfo) //
.where(authInfo.email == address and authInfo.email_verified == true));
auto ret = db(select(t_info.user_uid) //
.from(t_info) //
.where(t_info.email == address and t_info.email_verified == true));
if(ret.empty())
return {};
@ -309,18 +310,18 @@ User PgUserAuth::findWithEmail(const std::string & address) const {
void PgUserAuth::setEmailToken(const User & user, const Token & token, User::EmailTokenRole role) {
auto exp = ::date::floor<::std::chrono::milliseconds >(std::chrono::system_clock::from_time_t(token.expirationTime().toTime_t()));
db(update(authInfo) //
.set( //
authInfo.email_token = token.hash(), //
authInfo.email_token_expires = exp,
authInfo.email_token_role = static_cast< int >(role)) //
.where(authInfo.user_uid == std::atoi(user.id().c_str())));
db(update(t_info) //
.set( //
t_info.email_token = token.hash(), //
t_info.email_token_expires = exp,
t_info.email_token_role = static_cast< int >(role)) //
.where(t_info.user_uid == std::atoi(user.id().c_str())));
}
Token PgUserAuth::emailToken(const User & user) const {
auto ret = db(select(authInfo.email_token, authInfo.email_token_expires) //
.from(authInfo) //
.where(authInfo.user_uid == std::atoi(user.id().c_str())));
auto ret = db(select(t_info.email_token, t_info.email_token_expires) //
.from(t_info) //
.where(t_info.user_uid == std::atoi(user.id().c_str())));
if(ret.empty())
return {};
auto exp = Wt::WDateTime();
@ -331,9 +332,9 @@ Token PgUserAuth::emailToken(const User & user) const {
}
User::EmailTokenRole PgUserAuth::emailTokenRole(const User & user) const {
auto ret = db(select(authInfo.email_token_role) //
.from(authInfo) //
.where(authInfo.user_uid == std::atoi(user.id().c_str())));
auto ret = db(select(t_info.email_token_role) //
.from(t_info) //
.where(t_info.user_uid == std::atoi(user.id().c_str())));
if(ret.empty())
throw std::exception();
auto val = ret.front().email_token_role;
@ -343,7 +344,7 @@ User::EmailTokenRole PgUserAuth::emailTokenRole(const User & user) const {
User PgUserAuth::findWithEmailToken(const std::string & hash) const {
auto ret = db(select(t_user.uid) //
.from(user_auth_info) //
.where(authInfo.email_token == hash));
.where(t_info.email_token == hash));
if(ret.empty())
return {};
@ -351,9 +352,9 @@ User PgUserAuth::findWithEmailToken(const std::string & hash) const {
}
void PgUserAuth::addAuthToken(const User & user, const Token & token) {
auto select_identity_id = select(authInfo.id) //
.from(authInfo)
.where(authInfo.user_uid == std::atoi(user.id().c_str()))
auto select_identity_id = select(t_info.id) //
.from(t_info)
.where(t_info.user_uid == std::atoi(user.id().c_str()))
.limit(1u);
db(insert_into(t_auth_token) //
.set( //
@ -368,11 +369,11 @@ void PgUserAuth::removeAuthToken(const User &, const std::string & hash) {
User PgUserAuth::findWithAuthToken(const std::string & hash) const {
auto fullUser = t_auth_token //
.join(authInfo)
.on(authInfo.id == t_auth_token.auth_info_id);
.join(t_info)
.on(t_info.id == t_auth_token.auth_info_id);
auto ret = db(select(authInfo.user_uid) //
.from(fullUser) //
auto ret = db(select(t_info.user_uid) //
.from(fullUser) //
.where(t_auth_token.value == hash and t_auth_token.expires > std::chrono::system_clock::now()));
if(ret.empty())
@ -383,9 +384,9 @@ User PgUserAuth::findWithAuthToken(const std::string & hash) const {
int PgUserAuth::updateAuthToken(const User & user, const std::string & oldhash, const std::string & newhash) {
// method called only after successful login
using namespace std::chrono;
auto identity_id = db(select(authInfo.id) //
.from(authInfo) //
.where(authInfo.user_uid == std::atoi(user.id().c_str())));
auto identity_id = db(select(t_info.id) //
.from(t_info) //
.where(t_info.user_uid == std::atoi(user.id().c_str())));
if(identity_id.empty())
return 0;
@ -438,23 +439,24 @@ void PgUserAuth::setFailedLoginAttempts(const User & user, int count) {
}
template < typename T >
inline std::string name_of(const T&) {
inline std::string name_of(const T &) {
static_assert(sqlpp::is_column_t< T >::value, "T should by a calumn");
return std::string{sqlpp::name_of< typename T::_table >::char_ptr()} + '.' + sqlpp::name_of< T >::char_ptr();
}
int PgUserAuth::failedLoginAttempts(const User & user) const {
auto res = db(select(count(t_user_history.id)) //
.from(t_user_history) //
.where(t_user_history.user_id == std::atoi(user.id().c_str()) and //
t_user_history.action_id == select_login_action_id and //
sqlpp::verbatim< sqlpp::boolean >(name_of(t_user_history.data) + "->>'status' = 'failed'") and //
t_user_history.id > select(t_user_history.id) //
.from(t_user_history) //
.where(t_user_history.user_id == std::atoi(user.id().c_str()) and //
t_user_history.action_id == select_login_action_id and //
sqlpp::verbatim< sqlpp::boolean >(name_of(t_user_history.data) + "->>'status' = 'success'")) //
.limit(1u)));
auto res =
db(select(count(t_user_history.id)) //
.from(t_user_history) //
.where(t_user_history.user_id == std::atoi(user.id().c_str()) and //
t_user_history.action_id == select_login_action_id and //
sqlpp::verbatim< sqlpp::boolean >(name_of(t_user_history.data) + "->>'status' = 'failed'") and //
t_user_history.id > select(t_user_history.id) //
.from(t_user_history) //
.where(t_user_history.user_id == std::atoi(user.id().c_str()) and //
t_user_history.action_id == select_login_action_id and //
sqlpp::verbatim< sqlpp::boolean >(name_of(t_user_history.data) + "->>'status' = 'success'")) //
.limit(1u)));
return static_cast< int >(res.front().count);
}
@ -476,6 +478,15 @@ Wt::WDateTime PgUserAuth::lastLoginAttempt(const User & user) const {
return lastLogin;
}
void PgUserAuth::logout(const User & user) {
const tao::json::value data{{"status"s, "success"}};
db(insert_into(t_user_history)
.set(t_user_history.user_id = std::atoi(user.id().c_str()),
t_user_history.action_id = select_logout_action_id, //
t_user_history.data = tao::json::to_string(data)));
}
AbstractUserDatabase::Transaction * PgUserAuth::startTransaction() {
return new TransactionGuard< decltype(db) >(db);
}

View File

@ -61,6 +61,8 @@ class PgUserAuth : public Wt::Auth::AbstractUserDatabase {
int failedLoginAttempts(const Wt::Auth::User & user) const override;
void setLastLoginAttempt(const Wt::Auth::User & user, const Wt::WDateTime & t) override;
Wt::WDateTime lastLoginAttempt(const Wt::Auth::User & user) const override;
void logout(const Wt::Auth::User & user);
private:
eedb::db::PgConnection & db;

View File

@ -19,31 +19,31 @@ SQLPP_ALIAS_PROVIDER(fk_auth_info_id);
SQLPP_ALIAS_PROVIDER(user_status);
constexpr eedb::user t_user;
constexpr eedb::auth_identity authIdentity;
constexpr eedb::auth_info authInfo;
constexpr eedb::auth_identity t_identity;
constexpr eedb::auth_info t_info;
constexpr eedb::auth_token authToken;
auto auth = t_user.join(authInfo).on(t_user.uid == authInfo.user_uid).join(authIdentity).on(authInfo.id == authIdentity.auth_info_id);
auto auth = t_user.join(t_info).on(t_user.uid == t_info.user_uid).join(t_identity).on(t_info.id == t_identity.auth_info_id);
auto auth_info_identity = authInfo.join(authIdentity).on(authInfo.id == authIdentity.auth_info_id);
auto user_auth_info = t_user.join(authInfo).on(authInfo.user_uid == t_user.uid);
auto auth_token_info = user_auth_info.join(authToken).on(authToken.auth_info_id == authInfo.id);
auto auth_info_identity = t_info.join(t_identity).on(t_info.id == t_identity.auth_info_id);
auto user_auth_info = t_user.join(t_info).on(t_info.user_uid == t_user.uid);
auto auth_token_info = user_auth_info.join(authToken).on(authToken.auth_info_id == t_info.id);
}
namespace eedb {
PgUserIdentity::PgUserIdentity(db::PgConnection & con, int uid, string provider)
: _db(con), _provider(std::move(provider)), _email("") {
select(all_of(authIdentity)) //
select(all_of(t_identity)) //
.from(auth_info_identity) //
.where(authInfo.user_uid == uid);
.where(t_info.user_uid == uid);
}
AuthIdentity::string_view PgUserIdentity::identity() const {
const auto id_eq = authInfo.user_uid == 0;
const auto provider_eq = authIdentity.provider == _provider;
const auto id_eq = t_info.user_uid == 0;
const auto provider_eq = t_identity.provider == _provider;
auto res = _db(select(authIdentity.identity) //
auto res = _db(select(t_identity.identity) //
.from(auth_info_identity) //
.where(id_eq and provider_eq));