Adding User edit/create view

This commit is contained in:
emeric
2018-04-10 13:24:14 +02:00
parent 05fd8a47d8
commit 2f7697d278
21 changed files with 510 additions and 64 deletions
+1
View File
@@ -22,6 +22,7 @@ lms_js_DATA = \
lms_approot_DATA = \
approot/admin-database.xml \
approot/admin-user.xml \
approot/admin-users.xml \
approot/admin-initwizard.xml \
approot/artist.xml \
+57
View File
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" ?>
<messages xmlns:if="Wt.WTemplate.conditions">
<message id="Lms.Admin.User.template">
<div class="page-header">
<h2>${title}</h2>
</div>
<div class="form-horizontal">
${<if-has-login>}
<div class="form-group">
<label class="control-label col-sm-2" for="${id:login}">
${tr:Lms.login}
</label>
<div class="col-sm-5">
${login}
</div>
<div class="help-block col-sm-5">
${login-info}
</div>
</div>
${</if-has-login>}
<div class="form-group">
<label class="control-label col-sm-2" for="${id:password}">
${tr:Lms.password}
</label>
<div class="col-sm-5">
${password}
</div>
<div class="help-block col-sm-5">
${password-info}
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:audio-bitrate-limit}">
Audio Bitrate Limit
</label>
<div class="col-sm-5">
<div class="input-group">
${audio-bitrate-limit}
<span class="input-group-addon">kbps</span>
</div>
</div>
<div class="help-block col-sm-5">
${audio-bitrate-limit-info}
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
${save-btn class="btn-primary"}
</div>
</div>
</div>
</message>
</messages>
+6
View File
@@ -15,6 +15,7 @@
<message id="Lms.password-confirm">Confirm password</message>
<message id="Lms.passwords-dont-match">Passwords don't match</message>
<message id="Lms.quit-confirm">Are you sure?</message>
<message id="Lms.save">Save</message>
<!--Administration-->
<message id="Lms.Admin.Database.daily">Daily</message>
@@ -36,6 +37,11 @@
<message id="Lms.Admin.Users.edit">Edit</message>
<message id="Lms.Admin.Users.users">Users</message>
<message id="Lms.Admin.User.user-create">New user</message>
<message id="Lms.Admin.User.user-created">New user created!</message>
<message id="Lms.Admin.User.user-edit">Edit user {1}</message>
<message id="Lms.Admin.User.user-updated">User updated!</message>
<!--Wizard-->
<message id="Lms.Admin.InitWizard.done">Administration account created. Please refresh to continue!</message>
<message id="Lms.Admin.InitWizard.header">Create administrator account</message>
+1
View File
@@ -29,6 +29,7 @@ lms_SOURCES = \
$(srcdir)/ui/SettingsView.cpp \
$(srcdir)/ui/admin/DatabaseSettingsView.cpp \
$(srcdir)/ui/admin/InitWizardView.cpp \
$(srcdir)/ui/admin/UserView.cpp \
$(srcdir)/ui/admin/UsersView.cpp \
$(srcdir)/ui/common/InputRange.cpp \
$(srcdir)/ui/common/LineEdit.cpp \
+12 -5
View File
@@ -164,7 +164,6 @@ Handler::getCurrentUser()
User::pointer
Handler::getUser(const Wt::Auth::User& authUser)
{
if (!authUser.isValid()) {
LMS_LOG(DB, ERROR) << "Handler::getUser: invalid authUser";
return User::pointer();
@@ -172,13 +171,21 @@ Handler::getUser(const Wt::Auth::User& authUser)
Wt::Dbo::ptr<AuthInfo> authInfo = _users->find(authUser);
User::pointer user = authInfo->user();
return authInfo->user();
}
if (!user) {
user = _session.add(new User());
authInfo.modify()->setUser(user);
User::pointer
Handler::createUser(const Wt::Auth::User& authUser)
{
if (!authUser.isValid()) {
LMS_LOG(DB, ERROR) << "Handler::getUser: invalid authUser";
return User::pointer();
}
User::pointer user = _session.add(new User());
Wt::Dbo::ptr<AuthInfo> authInfo = _users->find(authUser);
authInfo.modify()->setUser(user);
return user;
}
+2 -1
View File
@@ -48,7 +48,8 @@ class Handler
Wt::Dbo::Session& getSession() { return _session; }
Wt::Dbo::ptr<User> getCurrentUser(); // get the current user, may return empty
Wt::Dbo::ptr<User> getUser(const Wt::Auth::User& authUser); // Get or create the given user
Wt::Dbo::ptr<User> getUser(const Wt::Auth::User& authUser);
Wt::Dbo::ptr<User> createUser(const Wt::Auth::User& authUser);
Wt::Auth::AbstractUserDatabase& getUserDatabase();
Wt::Auth::Login& getLogin() { return _login; }
+7 -11
View File
@@ -32,7 +32,7 @@ User::audioBitrates =
};
User::User()
: _maxAudioBitrate(maxAudioBitrate),
: _maxAudioBitrate(audioBitrates.back()),
_isAdmin(false),
_audioBitrate(defaultAudioBitrate),
_audioEncoding(AudioEncoding::AUTO),
@@ -63,31 +63,27 @@ User::getById(Wt::Dbo::Session& session, id_type id)
void
User::setAudioBitrate(std::size_t bitrate)
{
_audioBitrate = std::min(bitrate, std::min(static_cast<std::size_t>(_maxAudioBitrate), audioBitrates.back()));
_audioBitrate = std::min(bitrate, static_cast<std::size_t>(_maxAudioBitrate));
}
void
User::setMaxAudioBitrate(std::size_t bitrate)
{
_maxAudioBitrate = std::min(bitrate, static_cast<std::size_t>(_maxAudioBitrate));
_maxAudioBitrate = std::min(bitrate, audioBitrates.back());
if (_audioBitrate > _maxAudioBitrate)
_audioBitrate = _maxAudioBitrate;
}
std::size_t
User::getAudioBitrate(void) const
{
if (!isAdmin())
return std::min(static_cast<std::size_t>(_audioBitrate), std::min(static_cast<std::size_t>(_maxAudioBitrate), audioBitrates.back()));
else
return std::min(static_cast<std::size_t>(_audioBitrate), audioBitrates.back());
return _audioBitrate;
}
std::size_t
User::getMaxAudioBitrate(void) const
{
if (!isAdmin())
return std::min(static_cast<std::size_t>(_maxAudioBitrate), audioBitrates.back());
else
return audioBitrates.back();
return _maxAudioBitrate;
}
} // namespace Database
+3 -4
View File
@@ -41,7 +41,7 @@ enum class AudioEncoding
WEBMA,
};
class User
class User : public Wt::Dbo::Dbo<User>
{
public:
typedef Wt::Dbo::dbo_traits<User>::IdType id_type;
@@ -70,9 +70,9 @@ class User
void setCurPlayingTrackPos(std::size_t pos) { _curPlayingTrackPos = pos; }
// read
bool isAdmin() const {return _isAdmin;}
bool isAdmin() const { return _isAdmin; }
std::size_t getAudioBitrate() const;
AudioEncoding getAudioEncoding() const { return _audioEncoding;}
AudioEncoding getAudioEncoding() const { return _audioEncoding; }
std::size_t getMaxAudioBitrate() const;
std::size_t getCurPlayingTrackPos() const { return _curPlayingTrackPos; }
@@ -90,7 +90,6 @@ class User
private:
static const std::size_t maxAudioBitrate = 320000;
static const std::size_t defaultAudioBitrate = 128000;
// Admin defined settings
-2
View File
@@ -30,8 +30,6 @@
#include "feature/FeatureExtractor.hpp"
#include "scanner/MediaScanner.hpp"
//#include "database/updater/DatabaseFeatureExtractor.hpp"
//#include "database/updater/DatabaseHighLevelCluster.hpp"
#include "ui/LmsApplication.hpp"
+13 -14
View File
@@ -57,20 +57,8 @@ Auth::Auth(Wt::WContainerWidget *parent)
auto loginBtn = new Wt::WPushButton(Wt::WString::tr("Lms.login"));
bindWidget("login-btn", loginBtn);
loginBtn->clicked().connect(std::bind([=]
{
updateModel(_model);
if (_model->validate())
_model->login(DbHandler().getLogin());
else
updateView(_model);
}));
password->enterPressed().connect(std::bind([=]
{
loginBtn->clicked().emit(Wt::WMouseEvent());
}));
loginBtn->clicked().connect(this, &Auth::processAuth);
password->enterPressed().connect(this, &Auth::processAuth);
DbHandler().getLogin().changed().connect(std::bind([=]
{
@@ -84,6 +72,17 @@ Auth::Auth(Wt::WContainerWidget *parent)
updateView(_model);
}
void
Auth::processAuth()
{
updateModel(_model);
if (_model->validate())
_model->login(DbHandler().getLogin());
else
updateView(_model);
}
void
Auth::logout()
{
+2
View File
@@ -34,6 +34,8 @@ class Auth : public Wt::WTemplateFormView
void logout();
private:
void processAuth();
Wt::Auth::AuthModel* _model;
};
+39 -10
View File
@@ -39,6 +39,7 @@
#include "admin/InitWizardView.hpp"
#include "admin/DatabaseSettingsView.hpp"
#include "admin/UserView.hpp"
#include "admin/UsersView.hpp"
#include "resource/ImageResource.hpp"
@@ -87,6 +88,7 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti
// Add a resource bundle
messageResourceBundle().use(appRoot() + "admin-database");
messageResourceBundle().use(appRoot() + "admin-user");
messageResourceBundle().use(appRoot() + "admin-users");
messageResourceBundle().use(appRoot() + "admin-wizard");
messageResourceBundle().use(appRoot() + "artist");
@@ -103,6 +105,9 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti
messageResourceBundle().use(appRoot() + "tracks");
messageResourceBundle().use(appRoot() + "templates");
// Require js here to avoid async problems
require("/js/mediaplayer.js");
setTitle("LMS");
// If here is no account in the database, launch the first connection wizard
@@ -121,7 +126,18 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti
}
else
{
DbHandler().getLogin().changed().connect(this, &LmsApplication::handleAuthEvent);
DbHandler().getLogin().changed().connect(std::bind([=]
{
try
{
handleAuthEvent();
}
catch (std::exception& e)
{
LMS_LOG(UI, ERROR) << "Error while handling auth event: " << e.what();
throw std::runtime_error("Internal error");
}
}));
_auth = new Auth();
root()->addWidget(_auth);
@@ -199,6 +215,7 @@ LmsApplication::goHome()
void
LmsApplication::quit()
{
setConfirmCloseMessage("");
WApplication::quit("");
redirect("/");
}
@@ -211,6 +228,7 @@ enum IdxRoot
IdxSettings,
IdxAdminDatabase,
IdxAdminUsers,
IdxAdminUser,
};
static void
@@ -233,6 +251,7 @@ handlePathChange(Wt::WStackedWidget* stack, bool isAdmin)
{ "/settings", IdxSettings, false },
{ "/admin/database", IdxAdminDatabase, true },
{ "/admin/users", IdxAdminUsers, true },
{ "/admin/user", IdxAdminUser, true },
};
LMS_LOG(UI, DEBUG) << "Internal path changed to '" << wApp->internalPath() << "'";
@@ -270,8 +289,6 @@ LmsApplication::handleAuthEvent(void)
_isAdmin = CurrentUser()->isAdmin();
}
require("/js/mediaplayer.js");
_imageResource = new ImageResource(_db, root());
_transcodeResource = new TranscodeResource(_db, root());
@@ -368,6 +385,9 @@ LmsApplication::handleAuthEvent(void)
auto users = new UsersView();
mainStack->addWidget(users);
auto user = new UserView();
mainStack->addWidget(user);
}
explore->tracksAdd.connect(std::bind([=] (std::vector<Database::Track::pointer> tracks)
@@ -411,7 +431,7 @@ LmsApplication::handleAuthEvent(void)
{
Wt::WServer::instance()->post(sessionId, [=]
{
notify(Wt::WString::tr("Lms.Admin.Database.scan-complete")
notifyMsg(Wt::WString::tr("Lms.Admin.Database.scan-complete")
.arg(stats.nbFiles())
.arg(stats.additions)
.arg(stats.deletions)
@@ -431,17 +451,26 @@ LmsApplication::handleAuthEvent(void)
}
void
LmsApplication::notify(const Wt::WString& message)
LmsApplication::notify(const Wt::WEvent& event)
{
try
{
WApplication::notify(event);
}
catch (std::exception& e)
{
LMS_LOG(UI, ERROR) << "Caught exception: " << e.what();
throw std::runtime_error("Internal error");
}
}
void
LmsApplication::notifyMsg(const Wt::WString& message)
{
LMS_LOG(UI, INFO) << "Notifying message '" << message.toUTF8() << "'";
root()->addWidget(new Wt::WText(message));
}
void notify(const Wt::WString& message)
{
LmsApplication::instance()->notify(message);
}
} // namespace UserInterface
+2 -1
View File
@@ -49,7 +49,7 @@ class LmsApplication : public Wt::WApplication
// Utils
void goHome();
void quit();
void notify(const Wt::WString& message);
void notifyMsg(const Wt::WString& message);
static Wt::WAnchor* createArtistAnchor(Database::Artist::pointer artist, bool addText = true);
static Wt::WAnchor* createReleaseAnchor(Database::Release::pointer release, bool addText = true);
@@ -59,6 +59,7 @@ class LmsApplication : public Wt::WApplication
LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool, Scanner::MediaScanner& scanner);
void handleAuthEvent(void);
void notify(const Wt::WEvent& event) override;
Database::Handler _db;
Auth* _auth;
+12 -3
View File
@@ -156,13 +156,13 @@ class SettingsModel : public Wt::WFormModel
std::size_t bitrate(int row)
{
return boost::any_cast<std::size_t>
(_bitrateModel->data(_encodingModel->index(row, 0), Wt::UserRole));
(_bitrateModel->data(_bitrateModel->index(row, 0), Wt::UserRole));
}
Wt::WString bitrateString(int row)
{
return boost::any_cast<Wt::WString>
(_bitrateModel->data(_encodingModel->index(row, 0), Wt::DisplayRole));
(_bitrateModel->data(_bitrateModel->index(row, 0), Wt::DisplayRole));
}
boost::optional<int> getEncodingRow(Wt::WString value)
@@ -207,9 +207,18 @@ class SettingsModel : public Wt::WFormModel
_bitrateModel = new Wt::WStringListModel(this);
std::size_t maxAudioBitrate;
{
Wt::Dbo::Transaction transaction(DboSession());
maxAudioBitrate = CurrentUser()->getMaxAudioBitrate();
}
std::size_t id = 0;
for (auto bitrate : Database::User::audioBitrates)
{
if (bitrate > maxAudioBitrate)
break;
_bitrateModel->addString( Wt::WString::fromUTF8(std::to_string(bitrate / 1000)) );
_bitrateModel->setData( id++, 0, bitrate, Wt::UserRole);
}
@@ -282,7 +291,7 @@ SettingsView::SettingsView(Wt::WContainerWidget *parent)
if (model->validate())
{
model->saveData();
LmsApp->notify(Wt::WString::tr("Lms.Settings.settings-saved"));
LmsApp->notifyMsg(Wt::WString::tr("Lms.Settings.settings-saved"));
}
// Udate the view: Delete any validation message in the view, etc.
+2 -2
View File
@@ -267,7 +267,7 @@ DatabaseSettingsView::DatabaseSettingsView(Wt::WContainerWidget *parent)
model->saveData();
LmsApp->getMediaScanner().reschedule();
LmsApp->notify(Wt::WString::tr("Lms.Admin.Database.settings-saved"));
LmsApp->notifyMsg(Wt::WString::tr("Lms.Admin.Database.settings-saved"));
}
// Udate the view: Delete any validation message in the view, etc.
@@ -284,7 +284,7 @@ DatabaseSettingsView::DatabaseSettingsView(Wt::WContainerWidget *parent)
immScanBtn->clicked().connect(std::bind([=] ()
{
LmsApp->getMediaScanner().scheduleImmediateScan();
LmsApp->notify(Wt::WString::tr("Lms.Admin.Database.scan-launched"));
LmsApp->notifyMsg(Wt::WString::tr("Lms.Admin.Database.scan-launched"));
}));
updateView(model);
+1 -1
View File
@@ -148,7 +148,7 @@ InitWizardView::InitWizardView(Wt::WContainerWidget *parent)
if (model->validate())
{
model->saveData();
LmsApp->notify(Wt::WString::tr("Lms.Admin.InitWizard.done"));
LmsApp->notifyMsg(Wt::WString::tr("Lms.Admin.InitWizard.done"));
saveButton->setEnabled(false);
}
+258
View File
@@ -0,0 +1,258 @@
/*
* Copyright (C) 2018 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Wt/WApplication>
#include <Wt/WCheckBox>
#include <Wt/WComboBox>
#include <Wt/WLineEdit>
#include <Wt/WPushButton>
#include <Wt/WTemplateFormView>
#include <Wt/WFormModel>
#include <Wt/WStringListModel>
#include "common/Validators.hpp"
#include "utils/Utils.hpp"
#include "utils/Logger.hpp"
#include "LmsApplication.hpp"
#include "UserView.hpp"
namespace UserInterface {
class UserModel : public Wt::WFormModel
{
public:
static const Field LoginField;
static const Field PasswordField;
static const Field BitrateLimitField;
UserModel(boost::optional<Database::User::id_type> userId, Wt::WObject *parent = 0)
: Wt::WFormModel(parent),
_userId(userId)
{
if (!_userId)
{
addField(LoginField);
setValidator(LoginField, createNameValidator());
}
addField(PasswordField);
addField(BitrateLimitField);
if (!_userId)
setValidator(PasswordField, createMandatoryValidator());
initializeModels();
// populate the model with initial data
loadData();
}
void loadData()
{
if (!_userId)
return;
Wt::Dbo::Transaction transaction(DboSession());
Wt::Auth::User authUser = DbHandler().getUserDatabase().findWithId( std::to_string(*_userId) );
Database::User::pointer user = DbHandler().getUser(authUser);
if (user == CurrentUser())
throw std::runtime_error("Cannot edit ourselves");
auto bitrate = getBitrateLimitRow(user->getMaxAudioBitrate());
if (bitrate)
setValue(BitrateLimitField, bitrateLimitString(*bitrate));
}
void saveData()
{
Wt::Dbo::Transaction transaction(DboSession());
if (_userId)
{
// Update user
Wt::Auth::User authUser = DbHandler().getUserDatabase().findWithId( std::to_string(*_userId) );
Database::User::pointer user = DbHandler().getUser( authUser );
// Account
if (!valueText(PasswordField).empty())
Database::Handler::getPasswordService().updatePassword(authUser, valueText(PasswordField));
auto bitrateLimitRow = getBitrateLimitRow(Wt::asString(value(BitrateLimitField)));
user.modify()->setMaxAudioBitrate(bitrateLimit(*bitrateLimitRow));
LMS_LOG(UI, DEBUG) << "Max audio bitrate set to " << bitrateLimit(*bitrateLimitRow);
}
else
{
// Create user
Wt::Auth::User authUser = DbHandler().getUserDatabase().registerNew();
Database::User::pointer user = DbHandler().createUser(authUser);
// Account
authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(LoginField));
Database::Handler::getPasswordService().updatePassword(authUser, valueText(PasswordField));
auto bitrateLimitRow = getBitrateLimitRow(Wt::asString(value(BitrateLimitField)));
user.modify()->setMaxAudioBitrate(bitrateLimit(*bitrateLimitRow));
}
}
boost::optional<int> getBitrateLimitRow(Wt::WString value)
{
for (int i = 0; i < _bitrateModel->rowCount(); ++i)
{
if (bitrateLimitString(i) == value)
return i;
}
return boost::none;
}
boost::optional<int> getBitrateLimitRow(std::size_t value)
{
for (int i = 0; i < _bitrateModel->rowCount(); ++i)
{
if (bitrateLimit(i) == value)
return i;
}
return boost::none;
}
std::size_t bitrateLimit(int row)
{
return boost::any_cast<std::size_t>
(_bitrateModel->data(_bitrateModel->index(row, 0), Wt::UserRole));
}
Wt::WString bitrateLimitString(int row)
{
return boost::any_cast<Wt::WString>
(_bitrateModel->data(_bitrateModel->index(row, 0), Wt::DisplayRole));
}
Wt::WAbstractItemModel *bitrateModel() { return _bitrateModel; }
private:
void initializeModels()
{
_bitrateModel = new Wt::WStringListModel(this);
std::size_t id = 0;
for (auto bitrate : Database::User::audioBitrates)
{
_bitrateModel->addString( Wt::WString::fromUTF8(std::to_string(bitrate / 1000)) );
_bitrateModel->setData( id++, 0, bitrate, Wt::UserRole);
}
}
Wt::WStringListModel* _bitrateModel;
boost::optional<Database::User::id_type> _userId;
};
const Wt::WFormModel::Field UserModel::LoginField = "login";
const Wt::WFormModel::Field UserModel::PasswordField = "password";
const Wt::WFormModel::Field UserModel::BitrateLimitField = "audio-bitrate-limit";
UserView::UserView(Wt::WContainerWidget* parent)
: Wt::WContainerWidget(parent)
{
wApp->internalPathChanged().connect(std::bind([=]
{
refresh();
}));
refresh();
}
void
UserView::refresh()
{
if (!wApp->internalPathMatches("/admin/user"))
return;
auto userId = readLong(wApp->internalPathNextPart("/admin/user/"));
clear();
auto t = new Wt::WTemplateFormView(Wt::WString::tr("Lms.Admin.User.template"), this);
t->addFunction("tr", &Wt::WTemplate::Functions::tr);
t->addFunction("id", &Wt::WTemplate::Functions::id);
auto model = new UserModel(userId ? boost::make_optional<Database::User::id_type>(*userId) : boost::none, this);
if (userId)
{
auto authUser = DbHandler().getUserDatabase().findWithId( std::to_string(*userId) );
auto name = authUser.identity(Wt::Auth::Identity::LoginName);
t->bindString("title", Wt::WString::tr("Lms.Admin.User.user-edit").arg(name), Wt::PlainText);
}
else
{
// Login
t->setCondition("if-has-login", true);
t->setFormWidget(UserModel::LoginField, new Wt::WLineEdit());
t->bindString("title", Wt::WString::tr("Lms.Admin.User.user-create"));
}
// Password
Wt::WLineEdit* passwordEdit = new Wt::WLineEdit();
t->setFormWidget(UserModel::PasswordField, passwordEdit );
passwordEdit->setEchoMode(Wt::WLineEdit::Password);
// AudioBitrate
Wt::WComboBox *bitrateCB = new Wt::WComboBox();
t->setFormWidget(UserModel::BitrateLimitField, bitrateCB);
bitrateCB->setModel(model->bitrateModel());
auto saveBtn = new Wt::WPushButton(Wt::WString::tr(userId ? "Lms.save" : "Lms.create"));
t->bindWidget("save-btn", saveBtn);
saveBtn->clicked().connect(std::bind([=]
{
t->updateModel(model);
if (model->validate())
{
model->saveData();
LmsApp->notifyMsg(Wt::WString::tr(userId ? "Lms.Admin.User.user-updated" : "Lms.Admin.User.user-created"));
LmsApp->setInternalPath("/admin/users", true);
}
else
{
t->updateView(model);
}
}));
t->updateView(model);
}
} // namespace UserInterface
+37
View File
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2018 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <Wt/WContainerWidget>
namespace UserInterface {
class UserView : public Wt::WContainerWidget
{
public:
UserView(Wt::WContainerWidget *parent = 0);
private:
void refresh();
};
} // namespace UserInterface
+37 -10
View File
@@ -31,7 +31,6 @@ namespace UserInterface {
UsersView::UsersView(Wt::WContainerWidget *parent)
: Wt::WContainerWidget(parent)
{
LMS_LOG(UI, DEBUG) << "TEST";
auto t = new Wt::WTemplate(Wt::WString::tr("Lms.Admin.Users.template"), this);
t->addFunction("tr", &Wt::WTemplate::Functions::tr);
@@ -41,12 +40,25 @@ UsersView::UsersView(Wt::WContainerWidget *parent)
auto addBtn = new Wt::WPushButton(Wt::WString::tr("Lms.Admin.Users.add"));
t->bindWidget("add-btn", addBtn);
addBtn->clicked().connect(std::bind([=]
{
LmsApp->setInternalPath("/admin/user", true);
}));
wApp->internalPathChanged().connect(std::bind([=]
{
refresh();
}));
refresh();
}
void
UsersView::refresh()
{
if (!wApp->internalPathMatches("/admin/users"))
return;
_container->clear();
Wt::Dbo::Transaction transaction(DboSession());
@@ -54,9 +66,10 @@ UsersView::refresh()
auto users = Database::User::getAll(DboSession());
for (auto user : users)
{
auto userId = std::to_string(user.id());
auto entry = new Wt::WTemplate(Wt::WString::tr("Lms.Admin.Users.template.entry"), _container);
Wt::Auth::User authUser = DbHandler().getUserDatabase().findWithId(std::to_string(user.id()));
Wt::Auth::User authUser = DbHandler().getUserDatabase().findWithId(userId);
if (!authUser.isValid()) {
LMS_LOG(UI, ERROR) << "Skipping invalid userId = " << user.id();
@@ -66,15 +79,29 @@ UsersView::refresh()
entry->bindString("name", authUser.identity(Wt::Auth::Identity::LoginName), Wt::PlainText);
// Don't edit ourself this way
if (CurrentUser() != user)
{
entry->setCondition("if-edit", true);
auto editBtn = new Wt::WPushButton(Wt::WString::tr("Lms.Admin.Users.edit"));
entry->bindWidget("edit-btn", editBtn);
if (CurrentUser() == user)
continue;
auto delBtn = new Wt::WPushButton(Wt::WString::tr("Lms.Admin.Users.del"));
entry->bindWidget("del-btn", delBtn);
}
entry->setCondition("if-edit", true);
auto editBtn = new Wt::WPushButton(Wt::WString::tr("Lms.Admin.Users.edit"));
entry->bindWidget("edit-btn", editBtn);
editBtn->clicked().connect(std::bind([=]
{
LmsApp->setInternalPath("/admin/user/" + std::to_string(user.id()), true);
}));
auto delBtn = new Wt::WPushButton(Wt::WString::tr("Lms.Admin.Users.del"));
entry->bindWidget("del-btn", delBtn);
delBtn->clicked().connect(std::bind([=]
{
Wt::Dbo::Transaction transaction(DboSession());
auto authUser = DbHandler().getUserDatabase().findWithId(userId);
auto user = DbHandler().getUser(authUser);
DbHandler().getUserDatabase().deleteUser( authUser );
user.remove();
_container->removeWidget(entry);
}));
}
}
+13
View File
@@ -27,6 +27,19 @@
#include "Utils.hpp"
boost::optional<long>
readLong(const std::string& str)
{
try
{
return std::stol(str);
}
catch (std::exception& e)
{
return boost::none;
}
}
bool readAsPosixTime(const std::string& str, boost::posix_time::ptime& time)
{
const std::locale formats[] = {
+5
View File
@@ -24,8 +24,13 @@
#include <list>
#include <boost/locale.hpp>
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
boost::optional<long>
readLong(const std::string& str);
bool
readAsPosixTime(const std::string& str, boost::posix_time::ptime& time);