refactoring
This commit is contained in:
parent
fb02774123
commit
8cd3957ad4
@ -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)
|
||||
|
||||
164
src/app/main.cpp
164
src/app/main.cpp
@ -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;
|
||||
};
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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));
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user