Reworked the project layout
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/WMenu>
|
||||
#include <Wt/WStackedWidget>
|
||||
#include <Wt/WTextArea>
|
||||
#include <Wt/WHBoxLayout>
|
||||
|
||||
#include "SettingsAudioFormView.hpp"
|
||||
#include "SettingsUserFormView.hpp"
|
||||
#include "SettingsAccountFormView.hpp"
|
||||
#include "SettingsDatabaseFormView.hpp"
|
||||
#include "SettingsMediaDirectories.hpp"
|
||||
#include "SettingsUsers.hpp"
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
|
||||
#include "service/ServiceManager.hpp"
|
||||
#include "service/DatabaseUpdateService.hpp"
|
||||
|
||||
#include "Settings.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
Settings::Settings(SessionData& sessionData, Wt::WContainerWidget* parent)
|
||||
: Wt::WContainerWidget(parent),
|
||||
_sessionData(sessionData)
|
||||
{
|
||||
Wt::WHBoxLayout* hLayout = new Wt::WHBoxLayout(this);
|
||||
|
||||
// Create a stack where the contents will be located.
|
||||
Wt::WStackedWidget *contents = new Wt::WStackedWidget();
|
||||
|
||||
contents->setStyleClass("contents");
|
||||
contents->setOverflow(WContainerWidget::OverflowHidden);
|
||||
|
||||
Wt::WMenu *menu = new Wt::WMenu(contents, Wt::Vertical);
|
||||
menu->setStyleClass("nav nav-pills nav-stacked submenu");
|
||||
menu->setWidth(150);
|
||||
|
||||
hLayout->addWidget(menu);
|
||||
hLayout->addWidget(contents, 1);
|
||||
|
||||
Wt::Dbo::Transaction transaction( sessionData.getDatabaseHandler().getSession());
|
||||
|
||||
::Database::User::pointer user = sessionData.getDatabaseHandler().getCurrentUser();
|
||||
|
||||
// Must be logged in here
|
||||
assert(user);
|
||||
|
||||
menu->addItem("Audio", new AudioFormView(sessionData, Database::User::getId(user)));
|
||||
if (user->isAdmin())
|
||||
{
|
||||
MediaDirectories* mediaDirectory = new MediaDirectories(sessionData);
|
||||
mediaDirectory->changed().connect(this, &Settings::handleDatabaseDirectoriesChanged);
|
||||
menu->addItem("Media Folders", mediaDirectory);
|
||||
|
||||
DatabaseFormView* databaseFormView = new DatabaseFormView(sessionData);
|
||||
databaseFormView->changed().connect(this, &Settings::restartDatabaseUpdateService);
|
||||
menu->addItem("Database Update", databaseFormView);
|
||||
|
||||
menu->addItem("Users", new Users(sessionData));
|
||||
}
|
||||
else
|
||||
{
|
||||
menu->addItem("Account", new AccountFormView(sessionData, Database::User::getId(user)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Settings::handleDatabaseDirectoriesChanged()
|
||||
{
|
||||
LMS_LOG(MOD_UI, SEV_NOTICE) << "Media directories have changed: requesting imediate scan";
|
||||
// On directory add or delete, request an immediate scan
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_sessionData.getDatabaseHandler().getSession());
|
||||
Database::MediaDirectorySettings::get(_sessionData.getDatabaseHandler().getSession()).modify()->setManualScanRequested(true);
|
||||
}
|
||||
|
||||
restartDatabaseUpdateService();
|
||||
}
|
||||
|
||||
void
|
||||
Settings::restartDatabaseUpdateService()
|
||||
{
|
||||
// Restarting the update service
|
||||
boost::lock_guard<boost::mutex> serviceLock (Service::ServiceManager::instance().mutex());
|
||||
|
||||
Service::DatabaseUpdateService::pointer service = Service::ServiceManager::instance().getService<Service::DatabaseUpdateService>();
|
||||
if (service)
|
||||
service->restart();
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/WContainerWidget>
|
||||
|
||||
#include "common/SessionData.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class Settings : public Wt::WContainerWidget
|
||||
{
|
||||
public:
|
||||
Settings(SessionData& sessionData, Wt::WContainerWidget* parent = 0);
|
||||
|
||||
private:
|
||||
|
||||
void handleDatabaseDirectoriesChanged();
|
||||
|
||||
void restartDatabaseUpdateService(void);
|
||||
|
||||
SessionData& _sessionData;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 <vector>
|
||||
|
||||
#include <Wt/WStringListModel>
|
||||
#include <Wt/WFormModel>
|
||||
#include <Wt/WLineEdit>
|
||||
#include <Wt/WCheckBox>
|
||||
#include <Wt/WComboBox>
|
||||
#include <Wt/WPushButton>
|
||||
#include <Wt/Auth/Identity>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
|
||||
#include "common/Validators.hpp"
|
||||
|
||||
#include "SettingsAccountFormView.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class AccountFormModel : public Wt::WFormModel
|
||||
{
|
||||
public:
|
||||
|
||||
// Associate each field with a unique string literal.
|
||||
static const Field NameField;
|
||||
static const Field EmailField;
|
||||
static const Field PasswordField;
|
||||
static const Field PasswordConfirmField;
|
||||
|
||||
AccountFormModel(SessionData& sessionData, std::string userId, Wt::WObject *parent = 0)
|
||||
: Wt::WFormModel(parent),
|
||||
_db(sessionData.getDatabaseHandler()),
|
||||
_userId(userId)
|
||||
{
|
||||
addField(NameField);
|
||||
addField(EmailField);
|
||||
addField(PasswordField);
|
||||
addField(PasswordConfirmField);
|
||||
|
||||
setValidator(NameField, createNameValidator());
|
||||
setValidator(EmailField, createEmailValidator());
|
||||
|
||||
// populate the model with initial data
|
||||
loadData();
|
||||
}
|
||||
|
||||
void loadData()
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
Wt::Auth::User authUser = _db.getUserDatabase().findWithId( _userId );
|
||||
Database::User::pointer user = _db.getUser(authUser);
|
||||
|
||||
if (user && authUser.isValid())
|
||||
{
|
||||
setValue(NameField, authUser.identity(Wt::Auth::Identity::LoginName));
|
||||
if (!authUser.email().empty())
|
||||
setValue(EmailField, authUser.email());
|
||||
else
|
||||
setValue(EmailField, authUser.unverifiedEmail());
|
||||
}
|
||||
setValue(PasswordField, Wt::WString());
|
||||
setValue(PasswordConfirmField, Wt::WString());
|
||||
}
|
||||
|
||||
bool saveData(Wt::WString& error)
|
||||
{
|
||||
// DBO transaction active here
|
||||
try {
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
// Update user
|
||||
Wt::Auth::User authUser = _db.getUserDatabase().findWithId(_userId);
|
||||
Database::User::pointer user = _db.getUser( authUser );
|
||||
|
||||
// user may have been deleted by someone else
|
||||
if (!authUser.isValid()) {
|
||||
error = Wt::WString("User identity does not exist");
|
||||
return false;
|
||||
}
|
||||
else if(!user)
|
||||
{
|
||||
error = Wt::WString("User not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Account
|
||||
authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(NameField));
|
||||
authUser.setEmail(valueText(EmailField).toUTF8());
|
||||
|
||||
// Password
|
||||
if (!valueText(PasswordField).empty())
|
||||
Database::Handler::getPasswordService().updatePassword(authUser, valueText(PasswordField));
|
||||
|
||||
setValue(PasswordField, Wt::WString());
|
||||
setValue(PasswordConfirmField, Wt::WString());
|
||||
|
||||
}
|
||||
catch(Wt::Dbo::Exception& exception)
|
||||
{
|
||||
LMS_LOG(MOD_UI, SEV_ERROR) << "Dbo exception: " << exception.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateField(Field field)
|
||||
{
|
||||
// DBO transaction active here
|
||||
|
||||
Wt::WString error;
|
||||
|
||||
if (field == NameField)
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
// Must be unique since used as LoginIdentity
|
||||
Wt::Auth::User user = _db.getUserDatabase().findWithIdentity(Wt::Auth::Identity::LoginName, valueText(field));
|
||||
if (user.isValid() && user.id() != _userId)
|
||||
error = "Already exists";
|
||||
else
|
||||
return Wt::WFormModel::validateField(field);
|
||||
}
|
||||
else if (field == PasswordField)
|
||||
{
|
||||
// Password is mandatory if we create the user
|
||||
if (!valueText(PasswordField).empty())
|
||||
{
|
||||
// Evaluate the strength of the password
|
||||
Wt::Auth::AbstractPasswordService::StrengthValidatorResult res
|
||||
= Database::Handler::getPasswordService().strengthValidator()->evaluateStrength(valueText(PasswordField),
|
||||
valueText(NameField),
|
||||
valueText(EmailField).toUTF8());
|
||||
|
||||
if (!res.isValid())
|
||||
error = res.message();
|
||||
}
|
||||
else
|
||||
return Wt::WFormModel::validateField(field);
|
||||
}
|
||||
else if (field == PasswordConfirmField)
|
||||
{
|
||||
if (validation(PasswordField).state() == Wt::WValidator::Valid)
|
||||
{
|
||||
if (valueText(PasswordField) != valueText(PasswordConfirmField))
|
||||
error = Wt::WString::tr("Wt.Auth.passwords-dont-match");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Apply validators
|
||||
return Wt::WFormModel::validateField(field);
|
||||
}
|
||||
|
||||
setValidation(field, Wt::WValidator::Result( error.empty() ? Wt::WValidator::Valid : Wt::WValidator::Invalid, error));
|
||||
|
||||
return validation(field).state() == Wt::WValidator::Valid;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
Database::Handler& _db;
|
||||
std::string _userId;
|
||||
};
|
||||
|
||||
const Wt::WFormModel::Field AccountFormModel::NameField = "name";
|
||||
const Wt::WFormModel::Field AccountFormModel::EmailField = "email";
|
||||
const Wt::WFormModel::Field AccountFormModel::PasswordField = "password";
|
||||
const Wt::WFormModel::Field AccountFormModel::PasswordConfirmField = "password-confirm";
|
||||
|
||||
AccountFormView::AccountFormView(SessionData& sessionData, std::string userId, Wt::WContainerWidget *parent)
|
||||
: Wt::WTemplateFormView(parent)
|
||||
{
|
||||
|
||||
_model = new AccountFormModel(sessionData, userId, this);
|
||||
|
||||
setTemplateText(tr("userAccountForm-template"));
|
||||
addFunction("id", &WTemplate::Functions::id);
|
||||
addFunction("block", &WTemplate::Functions::id);
|
||||
|
||||
_applyInfo = new Wt::WText();
|
||||
_applyInfo->setInline(false);
|
||||
_applyInfo->hide();
|
||||
bindWidget("apply-info", _applyInfo);
|
||||
|
||||
// Name
|
||||
Wt::WLineEdit* accountEdit = new Wt::WLineEdit();
|
||||
setFormWidget(AccountFormModel::NameField, accountEdit);
|
||||
accountEdit->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Email
|
||||
Wt::WLineEdit* emailEdit = new Wt::WLineEdit();
|
||||
setFormWidget(AccountFormModel::EmailField, emailEdit);
|
||||
emailEdit->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Password
|
||||
Wt::WLineEdit* passwordEdit = new Wt::WLineEdit();
|
||||
setFormWidget(AccountFormModel::PasswordField, passwordEdit );
|
||||
passwordEdit->setEchoMode(Wt::WLineEdit::Password);
|
||||
passwordEdit->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Password confirmation
|
||||
Wt::WLineEdit* passwordConfirmEdit = new Wt::WLineEdit();
|
||||
setFormWidget(AccountFormModel::PasswordConfirmField, passwordConfirmEdit);
|
||||
passwordConfirmEdit->setEchoMode(Wt::WLineEdit::Password);
|
||||
passwordConfirmEdit->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Title & Buttons
|
||||
bindString("title", "Account settings");
|
||||
|
||||
Wt::WPushButton *saveButton = new Wt::WPushButton("Apply");
|
||||
saveButton->setStyleClass("btn-primary");
|
||||
bindWidget("save-button", saveButton);
|
||||
saveButton->clicked().connect(this, &AccountFormView::processSave);
|
||||
|
||||
Wt::WPushButton *cancelButton = new Wt::WPushButton("Discard");
|
||||
bindWidget("cancel-button", cancelButton);
|
||||
cancelButton->clicked().connect(this, &AccountFormView::processCancel);
|
||||
|
||||
updateView(_model);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
AccountFormView::processCancel()
|
||||
{
|
||||
_applyInfo->show();
|
||||
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Parameters reverted!"));
|
||||
_applyInfo->setStyleClass("alert alert-info");
|
||||
_model->loadData();
|
||||
|
||||
_model->validate();
|
||||
updateView(_model);
|
||||
}
|
||||
|
||||
void
|
||||
AccountFormView::processSave()
|
||||
{
|
||||
updateModel(_model);
|
||||
|
||||
_applyInfo->show();
|
||||
if (_model->validate())
|
||||
{
|
||||
Wt::WString error;
|
||||
// commit model into DB
|
||||
if (_model->saveData(error) )
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("New parameters successfully applied!"));
|
||||
_applyInfo->setStyleClass("alert alert-success");
|
||||
}
|
||||
else
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Cannot apply new parameters: ") + error);
|
||||
_applyInfo->setStyleClass("alert alert-danger");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Cannot apply new parameters!"));
|
||||
_applyInfo->setStyleClass("alert alert-danger");
|
||||
}
|
||||
updateView(_model);
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/>.
|
||||
*/
|
||||
|
||||
#ifndef UI_SETTINGS_ACCOUNT_FORM_VIEW_HPP
|
||||
#define UI_SETTINGS_ACCOUNT_FORM_VIEW_HPP
|
||||
|
||||
#include <Wt/WContainerWidget>
|
||||
#include <Wt/WTemplateFormView>
|
||||
#include <Wt/WText>
|
||||
|
||||
#include "common/SessionData.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class AccountFormModel;
|
||||
|
||||
class AccountFormView : public Wt::WTemplateFormView
|
||||
{
|
||||
public:
|
||||
AccountFormView(SessionData& sessionData, std::string userId, Wt::WContainerWidget *parent = 0);
|
||||
|
||||
private:
|
||||
void processCancel(); // reload from DB
|
||||
void processSave(); // commit into DB
|
||||
|
||||
AccountFormModel* _model;
|
||||
Wt::WText* _applyInfo;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 <vector>
|
||||
|
||||
#include <Wt/WStringListModel>
|
||||
#include <Wt/WFormModel>
|
||||
#include <Wt/WComboBox>
|
||||
#include <Wt/WPushButton>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
|
||||
#include "common/Validators.hpp"
|
||||
|
||||
#include "SettingsAudioFormView.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class AudioFormModel : public Wt::WFormModel
|
||||
{
|
||||
public:
|
||||
|
||||
// Associate each field with a unique string literal.
|
||||
static const Field BitrateField;
|
||||
|
||||
AudioFormModel(SessionData& sessionData, std::string userId, Wt::WObject *parent = 0)
|
||||
: Wt::WFormModel(parent),
|
||||
_db(sessionData.getDatabaseHandler()),
|
||||
_userId(userId)
|
||||
{
|
||||
initializeModels();
|
||||
|
||||
addField(BitrateField);
|
||||
|
||||
setValidator(BitrateField, new Wt::WValidator(true)); // mandatory
|
||||
|
||||
// populate the model with initial data
|
||||
loadData();
|
||||
}
|
||||
|
||||
Wt::WAbstractItemModel *bitrateModel() { return _bitrateModel; }
|
||||
|
||||
void loadData()
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
Database::User::pointer user = Database::User::getById( _db.getSession(), _userId);
|
||||
|
||||
if (user)
|
||||
setValue(BitrateField, std::min(user->getMaxAudioBitrate(), user->getAudioBitrate()) / 1000); // in kps
|
||||
else
|
||||
setValue(BitrateField, Wt::WString());
|
||||
}
|
||||
|
||||
bool saveData(Wt::WString& error)
|
||||
{
|
||||
// DBO transaction active here
|
||||
try {
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
Database::User::pointer user = Database::User::getById( _db.getSession(), _userId);
|
||||
// user may have been deleted by someone else
|
||||
if (user)
|
||||
{
|
||||
user.modify()->setAudioBitrate( Wt::asNumber(value(BitrateField)) * 1000); // in kbps
|
||||
}
|
||||
|
||||
}
|
||||
catch(Wt::Dbo::Exception& exception)
|
||||
{
|
||||
LMS_LOG(MOD_UI, SEV_ERROR) << "Dbo exception: " << exception.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void initializeModels()
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
Database::User::pointer user = Database::User::getById(_db.getSession(), _userId);
|
||||
|
||||
_bitrateModel = new Wt::WStringListModel();
|
||||
BOOST_FOREACH(std::size_t bitrate, Database::User::audioBitrates)
|
||||
{
|
||||
if (user && bitrate <= user->getMaxAudioBitrate())
|
||||
_bitrateModel->addString( Wt::WString("{1}").arg( bitrate / 1000 ) ); // in kbps
|
||||
}
|
||||
}
|
||||
|
||||
Database::Handler& _db;
|
||||
std::string _userId;
|
||||
Wt::WStringListModel* _bitrateModel;
|
||||
};
|
||||
|
||||
const Wt::WFormModel::Field AudioFormModel::BitrateField = "bitrate";
|
||||
|
||||
AudioFormView::AudioFormView(SessionData& sessionData, std::string userId, Wt::WContainerWidget *parent)
|
||||
: Wt::WTemplateFormView(parent)
|
||||
{
|
||||
|
||||
_model = new AudioFormModel(sessionData, userId, this);
|
||||
|
||||
setTemplateText(tr("audioForm-template"));
|
||||
addFunction("id", &WTemplate::Functions::id);
|
||||
addFunction("block", &WTemplate::Functions::id);
|
||||
|
||||
_applyInfo = new Wt::WText();
|
||||
_applyInfo->setInline(false);
|
||||
_applyInfo->hide();
|
||||
bindWidget("apply-info", _applyInfo);
|
||||
|
||||
// Bitrate
|
||||
Wt::WComboBox *bitrateCB = new Wt::WComboBox();
|
||||
setFormWidget(AudioFormModel::BitrateField, bitrateCB);
|
||||
bitrateCB->setStyleClass("span2");
|
||||
bitrateCB->setModel(_model->bitrateModel());
|
||||
bitrateCB->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Title & Buttons
|
||||
bindString("title", "Audio settings");
|
||||
|
||||
Wt::WPushButton *saveButton = new Wt::WPushButton("Apply");
|
||||
saveButton->setStyleClass("btn-primary");
|
||||
bindWidget("save-button", saveButton);
|
||||
saveButton->clicked().connect(this, &AudioFormView::processSave);
|
||||
|
||||
Wt::WPushButton *cancelButton = new Wt::WPushButton("Discard");
|
||||
bindWidget("cancel-button", cancelButton);
|
||||
cancelButton->clicked().connect(this, &AudioFormView::processCancel);
|
||||
|
||||
|
||||
updateView(_model);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
AudioFormView::processCancel()
|
||||
{
|
||||
_applyInfo->show();
|
||||
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Parameters reverted!"));
|
||||
_applyInfo->setStyleClass("alert alert-info");
|
||||
_model->loadData();
|
||||
|
||||
_model->validate();
|
||||
updateView(_model);
|
||||
}
|
||||
|
||||
void
|
||||
AudioFormView::processSave()
|
||||
{
|
||||
updateModel(_model);
|
||||
|
||||
_applyInfo->show();
|
||||
if (_model->validate())
|
||||
{
|
||||
Wt::WString error;
|
||||
// commit model into DB
|
||||
if (_model->saveData(error) )
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("New parameters successfully applied!"));
|
||||
_applyInfo->setStyleClass("alert alert-success");
|
||||
}
|
||||
else
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Cannot apply new parameters: ") + error);
|
||||
_applyInfo->setStyleClass("alert alert-danger");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Cannot apply new parameters!"));
|
||||
_applyInfo->setStyleClass("alert alert-danger");
|
||||
}
|
||||
updateView(_model);
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/>.
|
||||
*/
|
||||
|
||||
#ifndef UI_SETTINGS_AUDIO_FORM_VIEW_HPP
|
||||
#define UI_SETTINGS_AUDIO_ACCOUNT_FORM_VIEW_HPP
|
||||
|
||||
#include <Wt/WContainerWidget>
|
||||
#include <Wt/WTemplateFormView>
|
||||
#include <Wt/WText>
|
||||
|
||||
#include "common/SessionData.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class AudioFormModel;
|
||||
|
||||
class AudioFormView : public Wt::WTemplateFormView
|
||||
{
|
||||
public:
|
||||
AudioFormView(SessionData& sessionData, std::string userId, Wt::WContainerWidget *parent = 0);
|
||||
|
||||
private:
|
||||
void processCancel(); // reload from DB
|
||||
void processSave(); // commit into DB
|
||||
|
||||
AudioFormModel* _model;
|
||||
Wt::WText* _applyInfo;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/WString>
|
||||
#include <Wt/WPushButton>
|
||||
#include <Wt/WCheckBox>
|
||||
#include <Wt/WComboBox>
|
||||
#include <Wt/WMessageBox>
|
||||
|
||||
#include <Wt/WFormModel>
|
||||
#include <Wt/WStringListModel>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
#include "database/MediaDirectory.hpp"
|
||||
|
||||
#include "common/DirectoryValidator.hpp"
|
||||
|
||||
#include "SettingsDatabaseFormView.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class DatabaseFormModel : public Wt::WFormModel
|
||||
{
|
||||
public:
|
||||
// Associate each field with a unique string literal.
|
||||
static const Field UpdatePeriodField;
|
||||
static const Field UpdateStartTimeField;
|
||||
|
||||
DatabaseFormModel(SessionData& sessionData, Wt::WObject *parent = 0)
|
||||
: Wt::WFormModel(parent),
|
||||
_sessionData(sessionData)
|
||||
{
|
||||
initializeModels();
|
||||
|
||||
addField(UpdatePeriodField);
|
||||
addField(UpdateStartTimeField);
|
||||
|
||||
setValidator(UpdatePeriodField, createUpdatePeriodValidator());
|
||||
setValidator(UpdateStartTimeField, createStartTimeValidator());
|
||||
|
||||
// populate the model with initial data
|
||||
loadData();
|
||||
}
|
||||
|
||||
Wt::WAbstractItemModel *updatePeriodModel() { return _updatePeriodModel; }
|
||||
Wt::WAbstractItemModel *updateStartTimeModel() { return _updateStartTimeModel; }
|
||||
|
||||
void loadData()
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_sessionData.getDatabaseHandler().getSession());
|
||||
|
||||
// Get refresh settings
|
||||
::Database::MediaDirectorySettings::pointer settings = ::Database::MediaDirectorySettings::get(_sessionData.getDatabaseHandler().getSession());
|
||||
|
||||
int periodRow = getUpdatePeriodModelRow( settings->getUpdatePeriod() );
|
||||
if (periodRow != -1)
|
||||
setValue(UpdatePeriodField, updatePeriod(periodRow));
|
||||
|
||||
int startTimeRow = getUpdateStartTimeModelRow( settings->getUpdateStartTime() );
|
||||
if (startTimeRow != -1)
|
||||
setValue(UpdateStartTimeField, updateStartTime( startTimeRow ) );
|
||||
|
||||
}
|
||||
|
||||
void saveData()
|
||||
{
|
||||
Wt::Dbo::Session& session( _sessionData.getDatabaseHandler().getSession());
|
||||
Wt::Dbo::Transaction transaction(session);
|
||||
|
||||
::Database::MediaDirectorySettings::pointer settings = ::Database::MediaDirectorySettings::get(_sessionData.getDatabaseHandler().getSession() );
|
||||
|
||||
int periodRow = getUpdatePeriodModelRow( boost::any_cast<Wt::WString>(value(UpdatePeriodField)));
|
||||
assert(periodRow != -1);
|
||||
settings.modify()->setUpdatePeriod( updatePeriodDuration( periodRow ) );
|
||||
|
||||
int startTimeRow = getUpdateStartTimeModelRow( boost::any_cast<Wt::WString>(value(UpdateStartTimeField)));
|
||||
assert(startTimeRow != -1);
|
||||
settings.modify()->setUpdateStartTime( updateStartTimeDuration( startTimeRow ) );
|
||||
|
||||
}
|
||||
|
||||
bool setImmediateScan(Wt::WString& error)
|
||||
{
|
||||
try {
|
||||
Wt::Dbo::Session& session( _sessionData.getDatabaseHandler().getSession());
|
||||
Wt::Dbo::Transaction transaction(session);
|
||||
|
||||
::Database::MediaDirectorySettings::pointer settings = ::Database::MediaDirectorySettings::get(_sessionData.getDatabaseHandler().getSession() );
|
||||
|
||||
settings.modify()->setManualScanRequested( true );
|
||||
}
|
||||
catch(Wt::Dbo::Exception& exception)
|
||||
{
|
||||
LMS_LOG(MOD_UI, SEV_ERROR) << "Dbo exception: " << exception.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int getUpdatePeriodModelRow(Wt::WString value)
|
||||
{
|
||||
for (int i = 0; i < _updatePeriodModel->rowCount(); ++i)
|
||||
{
|
||||
if (updatePeriod(i) == value)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int getUpdatePeriodModelRow(Database::MediaDirectorySettings::UpdatePeriod duration)
|
||||
{
|
||||
for (int i = 0; i < _updatePeriodModel->rowCount(); ++i)
|
||||
{
|
||||
if (updatePeriodDuration(i) == duration)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
Database::MediaDirectorySettings::UpdatePeriod updatePeriodDuration(int row) {
|
||||
return boost::any_cast<Database::MediaDirectorySettings::UpdatePeriod>
|
||||
(_updatePeriodModel->data(_updatePeriodModel->index(row, 0), Wt::UserRole));
|
||||
}
|
||||
|
||||
Wt::WString updatePeriod(int row) {
|
||||
return boost::any_cast<Wt::WString>
|
||||
(_updatePeriodModel->data(_updatePeriodModel->index(row, 0), Wt::DisplayRole));
|
||||
}
|
||||
|
||||
|
||||
int getUpdateStartTimeModelRow(Wt::WString value)
|
||||
{
|
||||
for (int i = 0; i < _updateStartTimeModel->rowCount(); ++i)
|
||||
{
|
||||
if (updateStartTime(i) == value)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int getUpdateStartTimeModelRow(boost::posix_time::time_duration duration)
|
||||
{
|
||||
for (int i = 0; i < _updateStartTimeModel->rowCount(); ++i)
|
||||
{
|
||||
if (updateStartTimeDuration(i) == duration)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
boost::posix_time::time_duration updateStartTimeDuration(int row) {
|
||||
return boost::any_cast<boost::posix_time::time_duration>
|
||||
(_updateStartTimeModel->data(_updateStartTimeModel->index(row, 0), Wt::UserRole));
|
||||
}
|
||||
|
||||
Wt::WString updateStartTime(int row) {
|
||||
return boost::any_cast<Wt::WString>
|
||||
(_updateStartTimeModel->data(_updateStartTimeModel->index(row, 0), Wt::DisplayRole));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void initializeModels() {
|
||||
|
||||
_updatePeriodModel = new Wt::WStringListModel(this);
|
||||
|
||||
_updatePeriodModel->addString("Never");
|
||||
_updatePeriodModel->setData(0, 0, Database::MediaDirectorySettings::Never, Wt::UserRole);
|
||||
|
||||
_updatePeriodModel->addString("Daily");
|
||||
_updatePeriodModel->setData(1, 0, Database::MediaDirectorySettings::Daily, Wt::UserRole);
|
||||
|
||||
_updatePeriodModel->addString("Weekly");
|
||||
_updatePeriodModel->setData(2, 0, Database::MediaDirectorySettings::Weekly, Wt::UserRole);
|
||||
|
||||
_updatePeriodModel->addString("Monthly");
|
||||
_updatePeriodModel->setData(3, 0, Database::MediaDirectorySettings::Monthly, Wt::UserRole);
|
||||
|
||||
_updateStartTimeModel = new Wt::WStringListModel(this);
|
||||
|
||||
for (std::size_t i = 0; i < 24; ++i)
|
||||
{
|
||||
boost::posix_time::time_duration dur = boost::posix_time::hours(i);
|
||||
|
||||
boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%H:%M");
|
||||
facet->time_duration_format("%H:%M");
|
||||
|
||||
std::ostringstream oss;
|
||||
oss.imbue(std::locale(oss.getloc(), facet));
|
||||
|
||||
oss << dur;
|
||||
|
||||
_updateStartTimeModel->addString( oss.str() );
|
||||
_updateStartTimeModel->setData(i, 0, dur, Wt::UserRole);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Wt::WValidator *createUpdatePeriodValidator() {
|
||||
Wt::WValidator* v = new Wt::WValidator();
|
||||
v->setMandatory(true);
|
||||
return v;
|
||||
}
|
||||
|
||||
Wt::WValidator *createStartTimeValidator() {
|
||||
Wt::WValidator* v = new Wt::WValidator();
|
||||
v->setMandatory(true);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
SessionData& _sessionData;
|
||||
Wt::WStringListModel* _updatePeriodModel;
|
||||
Wt::WStringListModel* _updateStartTimeModel;
|
||||
|
||||
};
|
||||
|
||||
const Wt::WFormModel::Field DatabaseFormModel::UpdatePeriodField = "update-period";
|
||||
const Wt::WFormModel::Field DatabaseFormModel::UpdateStartTimeField = "update-start-time";
|
||||
|
||||
|
||||
DatabaseFormView::DatabaseFormView(SessionData& sessionData, Wt::WContainerWidget *parent)
|
||||
: Wt::WTemplateFormView(parent)
|
||||
{
|
||||
_model = new DatabaseFormModel(sessionData, this);
|
||||
|
||||
setTemplateText(tr("databaseForm-template"));
|
||||
addFunction("id", &WTemplate::Functions::id);
|
||||
addFunction("block", &WTemplate::Functions::id);
|
||||
|
||||
_applyInfo = new Wt::WText();
|
||||
_applyInfo->setInline(false);
|
||||
_applyInfo->hide();
|
||||
bindWidget("apply-info", _applyInfo);
|
||||
|
||||
// Update Period
|
||||
Wt::WComboBox *updatePeriodCB = new Wt::WComboBox();
|
||||
setFormWidget(DatabaseFormModel::UpdatePeriodField, updatePeriodCB);
|
||||
updatePeriodCB->setModel(_model->updatePeriodModel());
|
||||
updatePeriodCB->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Update Start Time
|
||||
Wt::WComboBox *updateStartTimeCB = new Wt::WComboBox();
|
||||
setFormWidget(DatabaseFormModel::UpdateStartTimeField, updateStartTimeCB);
|
||||
updateStartTimeCB->setModel(_model->updateStartTimeModel());
|
||||
updateStartTimeCB->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Title & Buttons
|
||||
bindString("title", "Media folder settings");
|
||||
|
||||
Wt::WPushButton *saveButton = new Wt::WPushButton("Apply");
|
||||
bindWidget("apply-button", saveButton);
|
||||
saveButton->setStyleClass("btn-primary");
|
||||
|
||||
Wt::WPushButton *discardButton = new Wt::WPushButton("Discard");
|
||||
bindWidget("discard-button", discardButton);
|
||||
|
||||
saveButton->clicked().connect(this, &DatabaseFormView::processSave);
|
||||
discardButton->clicked().connect(this, &DatabaseFormView::processDiscard);
|
||||
|
||||
Wt::WPushButton *immediateScanButton = new Wt::WPushButton("Immediate scan");
|
||||
immediateScanButton->setStyleClass("btn-warning");
|
||||
bindWidget("immediate-scan-button", immediateScanButton);
|
||||
immediateScanButton->clicked().connect(this, &DatabaseFormView::processImmediateScan);
|
||||
|
||||
updateView(_model);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseFormView::processImmediateScan()
|
||||
{
|
||||
Wt::WString error;
|
||||
_applyInfo->show();
|
||||
|
||||
if (_model->setImmediateScan(error))
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Media folder scan has been started!" ) );
|
||||
_applyInfo->setStyleClass("alert alert-warning");
|
||||
|
||||
_sigChanged.emit();
|
||||
}
|
||||
else
|
||||
{
|
||||
_applyInfo->setText( error );
|
||||
_applyInfo->setStyleClass("alert alert-danger");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseFormView::processDiscard()
|
||||
{
|
||||
_applyInfo->show();
|
||||
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Parameters reverted!"));
|
||||
_applyInfo->setStyleClass("alert alert-info");
|
||||
|
||||
_model->loadData();
|
||||
|
||||
_model->validate();
|
||||
updateView(_model);
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseFormView::processSave()
|
||||
{
|
||||
updateModel(_model);
|
||||
|
||||
_applyInfo->show();
|
||||
|
||||
if (_model->validate()) {
|
||||
// Make the model to commit data into DB
|
||||
_model->saveData();
|
||||
|
||||
_sigChanged.emit();
|
||||
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("New parameters successfully applied!"));
|
||||
_applyInfo->setStyleClass("alert alert-success");
|
||||
}
|
||||
else {
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Cannot apply new parameters!"));
|
||||
_applyInfo->setStyleClass("alert alert-danger");
|
||||
}
|
||||
// Udate the view: Delete any validation message in the view, etc.
|
||||
updateView(_model);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/>.
|
||||
*/
|
||||
|
||||
#ifndef UI_SETTINGS_DB_FORM_VIEW_HPP
|
||||
#define UI_SETTINGS_DB_FORM_VIEW_HPP
|
||||
|
||||
#include <Wt/WContainerWidget>
|
||||
#include <Wt/WTemplateFormView>
|
||||
#include <Wt/WText>
|
||||
#include <Wt/WSignal>
|
||||
|
||||
#include "common/SessionData.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class DatabaseFormModel;
|
||||
|
||||
class DatabaseFormView : public Wt::WTemplateFormView
|
||||
{
|
||||
public:
|
||||
DatabaseFormView(SessionData& sessionData, Wt::WContainerWidget *parent = 0);
|
||||
|
||||
Wt::Signal<void>& changed() { return _sigChanged; }
|
||||
|
||||
private:
|
||||
|
||||
Wt::Signal<void> _sigChanged;
|
||||
|
||||
void processSave();
|
||||
void processDiscard();
|
||||
void processImmediateScan();
|
||||
|
||||
Wt::WText *_applyInfo;
|
||||
DatabaseFormModel *_model;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 <vector>
|
||||
|
||||
#include <Wt/WFormModel>
|
||||
#include <Wt/WLineEdit>
|
||||
#include <Wt/WPushButton>
|
||||
#include <Wt/Auth/Identity>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
|
||||
#include "common/Validators.hpp"
|
||||
|
||||
#include "SettingsFirstConnectionFormView.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class FirstConnectionFormModel : public Wt::WFormModel
|
||||
{
|
||||
public:
|
||||
|
||||
// Associate each field with a unique string literal.
|
||||
static const Field NameField;
|
||||
static const Field EmailField;
|
||||
static const Field PasswordField;
|
||||
static const Field PasswordConfirmField;
|
||||
|
||||
FirstConnectionFormModel(SessionData& sessionData, Wt::WObject *parent = 0)
|
||||
: Wt::WFormModel(parent),
|
||||
_db(sessionData.getDatabaseHandler())
|
||||
{
|
||||
addField(NameField);
|
||||
addField(EmailField);
|
||||
addField(PasswordField);
|
||||
addField(PasswordConfirmField);
|
||||
|
||||
setValidator(NameField, createNameValidator());
|
||||
setValidator(EmailField, createEmailValidator());
|
||||
|
||||
}
|
||||
|
||||
bool saveData(Wt::WString& error)
|
||||
{
|
||||
// DBO transaction active here
|
||||
try {
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
// Check if a user already exist
|
||||
// If it's the case, just do nothing
|
||||
if (Database::User::getAll(_db.getSession()).size() > 0)
|
||||
{
|
||||
LMS_LOG(MOD_UI, SEV_ERROR) << "Admin user already created";
|
||||
error = Wt::WString("Admin user already created!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create user
|
||||
Wt::Auth::User authUser = _db.getUserDatabase().registerNew();
|
||||
Database::User::pointer user = _db.getUser(authUser);
|
||||
|
||||
// Account
|
||||
authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(NameField));
|
||||
authUser.setEmail(valueText(EmailField).toUTF8());
|
||||
Database::Handler::getPasswordService().updatePassword(authUser, valueText(PasswordField));
|
||||
|
||||
user.modify()->setAdmin( true );
|
||||
|
||||
}
|
||||
catch(Wt::Dbo::Exception& exception)
|
||||
{
|
||||
LMS_LOG(MOD_UI, SEV_ERROR) << "Dbo exception: " << exception.what();
|
||||
error = Wt::WString(exception.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateField(Field field)
|
||||
{
|
||||
// DBO transaction active here
|
||||
|
||||
Wt::WString error;
|
||||
|
||||
if (field == PasswordField)
|
||||
{
|
||||
// Password is mandatory if we create the user
|
||||
if (!valueText(PasswordField).empty())
|
||||
{
|
||||
// Evaluate the strength of the password
|
||||
Wt::Auth::AbstractPasswordService::StrengthValidatorResult res
|
||||
= Database::Handler::getPasswordService().strengthValidator()->evaluateStrength(valueText(PasswordField),
|
||||
valueText(NameField),
|
||||
valueText(EmailField).toUTF8());
|
||||
|
||||
if (!res.isValid())
|
||||
error = res.message();
|
||||
}
|
||||
else
|
||||
return Wt::WFormModel::validateField(field);
|
||||
}
|
||||
else if (field == PasswordConfirmField)
|
||||
{
|
||||
if (validation(PasswordField).state() == Wt::WValidator::Valid)
|
||||
{
|
||||
if (valueText(PasswordField) != valueText(PasswordConfirmField))
|
||||
error = Wt::WString::tr("Wt.Auth.passwords-dont-match");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Apply validators
|
||||
return Wt::WFormModel::validateField(field);
|
||||
}
|
||||
|
||||
setValidation(field, Wt::WValidator::Result( error.empty() ? Wt::WValidator::Valid : Wt::WValidator::Invalid, error));
|
||||
|
||||
return validation(field).state() == Wt::WValidator::Valid;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
Database::Handler& _db;
|
||||
};
|
||||
|
||||
const Wt::WFormModel::Field FirstConnectionFormModel::NameField = "name";
|
||||
const Wt::WFormModel::Field FirstConnectionFormModel::EmailField = "email";
|
||||
const Wt::WFormModel::Field FirstConnectionFormModel::PasswordField = "password";
|
||||
const Wt::WFormModel::Field FirstConnectionFormModel::PasswordConfirmField = "password-confirm";
|
||||
|
||||
FirstConnectionFormView::FirstConnectionFormView(SessionData& sessionData, Wt::WContainerWidget *parent)
|
||||
: Wt::WTemplateFormView(parent)
|
||||
{
|
||||
|
||||
_model = new FirstConnectionFormModel(sessionData, this);
|
||||
|
||||
setTemplateText(tr("firstConnectionForm-template"));
|
||||
addFunction("id", &WTemplate::Functions::id);
|
||||
addFunction("block", &WTemplate::Functions::id);
|
||||
|
||||
_applyInfo = new Wt::WText();
|
||||
_applyInfo->setInline(false);
|
||||
_applyInfo->hide();
|
||||
bindWidget("apply-info", _applyInfo);
|
||||
|
||||
// Name
|
||||
Wt::WLineEdit* accountEdit = new Wt::WLineEdit();
|
||||
setFormWidget(FirstConnectionFormModel::NameField, accountEdit);
|
||||
accountEdit->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Email
|
||||
Wt::WLineEdit* emailEdit = new Wt::WLineEdit();
|
||||
setFormWidget(FirstConnectionFormModel::EmailField, emailEdit);
|
||||
emailEdit->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Password
|
||||
Wt::WLineEdit* passwordEdit = new Wt::WLineEdit();
|
||||
setFormWidget(FirstConnectionFormModel::PasswordField, passwordEdit );
|
||||
passwordEdit->setEchoMode(Wt::WLineEdit::Password);
|
||||
passwordEdit->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Password confirmation
|
||||
Wt::WLineEdit* passwordConfirmEdit = new Wt::WLineEdit();
|
||||
setFormWidget(FirstConnectionFormModel::PasswordConfirmField, passwordConfirmEdit);
|
||||
passwordConfirmEdit->setEchoMode(Wt::WLineEdit::Password);
|
||||
passwordConfirmEdit->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Title & Buttons
|
||||
bindString("title", "Create Admin account");
|
||||
|
||||
_saveButton = new Wt::WPushButton("Create");
|
||||
_saveButton->setStyleClass("btn-primary");
|
||||
bindWidget("save-button", _saveButton);
|
||||
_saveButton->clicked().connect(this, &FirstConnectionFormView::processSave);
|
||||
|
||||
updateView(_model);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
FirstConnectionFormView::processSave()
|
||||
{
|
||||
updateModel(_model);
|
||||
|
||||
_applyInfo->show();
|
||||
if (_model->validate())
|
||||
{
|
||||
Wt::WString error;
|
||||
// commit model into DB
|
||||
if (_model->saveData(error) )
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("New parameters successfully applied! Please refresh this page in order to login"));
|
||||
_applyInfo->setStyleClass("alert alert-success");
|
||||
_saveButton->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Cannot apply new parameters: ") + error);
|
||||
_applyInfo->setStyleClass("alert alert-danger");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Cannot apply new parameters!"));
|
||||
_applyInfo->setStyleClass("alert alert-danger");
|
||||
}
|
||||
updateView(_model);
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/>.
|
||||
*/
|
||||
|
||||
#ifndef UI_SETTINGS_FIRST_CONNECTION_FORM_VIEW_HPP
|
||||
#define UI_SETTINGS_FIRST_CONNECTION_FORM_VIEW_HPP
|
||||
|
||||
#include <Wt/WContainerWidget>
|
||||
#include <Wt/WTemplateFormView>
|
||||
#include <Wt/WText>
|
||||
#include <Wt/WPushButton>
|
||||
|
||||
#include "common/SessionData.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class FirstConnectionFormModel;
|
||||
|
||||
class FirstConnectionFormView : public Wt::WTemplateFormView
|
||||
{
|
||||
public:
|
||||
FirstConnectionFormView(SessionData& sessionData, Wt::WContainerWidget *parent = 0);
|
||||
|
||||
private:
|
||||
|
||||
void processSave();
|
||||
|
||||
Wt::WPushButton* _saveButton;
|
||||
FirstConnectionFormModel* _model;
|
||||
Wt::WText* _applyInfo;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/WGroupBox>
|
||||
#include <Wt/WText>
|
||||
#include <Wt/WPushButton>
|
||||
#include <Wt/WMessageBox>
|
||||
|
||||
#include "database/MediaDirectory.hpp"
|
||||
|
||||
#include "SettingsMediaDirectoryFormView.hpp"
|
||||
|
||||
#include "SettingsMediaDirectories.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
MediaDirectories::MediaDirectories(SessionData& sessionData, Wt::WContainerWidget *parent)
|
||||
: Wt::WContainerWidget(parent),
|
||||
_db(sessionData.getDatabaseHandler())
|
||||
{
|
||||
// Stack two widgets:
|
||||
_stack = new Wt::WStackedWidget(this);
|
||||
|
||||
// 1/ the media directory table view
|
||||
{
|
||||
Wt::WGroupBox *container = new Wt::WGroupBox("Media Folders", _stack);
|
||||
|
||||
_table = new Wt::WTable(container);
|
||||
|
||||
_table->addStyleClass("table form-inline");
|
||||
|
||||
_table->toggleStyleClass("table-hover", true);
|
||||
_table->toggleStyleClass("table-striped", true);
|
||||
|
||||
_table->setHeaderCount(1);
|
||||
|
||||
_table->elementAt(0, 0)->addWidget(new Wt::WText("#"));
|
||||
_table->elementAt(0, 1)->addWidget(new Wt::WText("Path"));
|
||||
_table->elementAt(0, 2)->addWidget(new Wt::WText("Type"));
|
||||
|
||||
Wt::WPushButton* addBtn = new Wt::WPushButton("Add Folder");
|
||||
addBtn->setStyleClass("btn-success");
|
||||
container->addWidget( addBtn );
|
||||
addBtn->clicked().connect(boost::bind(&MediaDirectories::handleCreateMediaDirectory, this));
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void
|
||||
MediaDirectories::refresh(void)
|
||||
{
|
||||
|
||||
assert(_table->rowCount() > 0);
|
||||
for (int i = _table->rowCount() - 1; i > 0; --i)
|
||||
_table->deleteRow(i);
|
||||
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
std::vector<Database::MediaDirectory::pointer> mediaDirectories = Database::MediaDirectory::getAll(_db.getSession());
|
||||
|
||||
std::size_t id = 1;
|
||||
BOOST_FOREACH(Database::MediaDirectory::pointer mediaDirectory, mediaDirectories)
|
||||
{
|
||||
_table->elementAt(id, 0)->addWidget(new Wt::WText( Wt::WString::fromUTF8("{1}").arg(id)));
|
||||
_table->elementAt(id, 1)->addWidget(new Wt::WText( Wt::WString::fromUTF8(mediaDirectory->getPath().string()) ));
|
||||
|
||||
Wt::WString dirType;
|
||||
switch(mediaDirectory->getType())
|
||||
{
|
||||
case Database::MediaDirectory::Video: dirType = "Video"; break;
|
||||
case Database::MediaDirectory::Audio: dirType = "Audio"; break;
|
||||
}
|
||||
|
||||
_table->elementAt(id, 2)->addWidget( new Wt::WText( dirType ));
|
||||
|
||||
Wt::WPushButton* delBtn = new Wt::WPushButton("Delete");
|
||||
delBtn->setStyleClass("btn-danger");
|
||||
_table->elementAt(id, 3)->addWidget(delBtn);
|
||||
delBtn->clicked().connect(boost::bind( &MediaDirectories::handleDelMediaDirectory, this, mediaDirectory->getPath(), mediaDirectory->getType() ) );
|
||||
|
||||
++id;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaDirectories::handleDelMediaDirectory(boost::filesystem::path p, Database::MediaDirectory::Type type)
|
||||
{
|
||||
Wt::WMessageBox *messageBox = new Wt::WMessageBox
|
||||
("Delete Folder",
|
||||
Wt::WString( "Deleting folder '{1}'?").arg(p.string()),
|
||||
Wt::Question, Wt::Yes | Wt::No);
|
||||
|
||||
messageBox->setModal(true);
|
||||
|
||||
messageBox->buttonClicked().connect(std::bind([=] () {
|
||||
if (messageBox->buttonResult() == Wt::Yes)
|
||||
{
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
// Delete the media diretory
|
||||
Database::MediaDirectory::pointer mediaDirectory = Database::MediaDirectory::get(_db.getSession(), p, type);
|
||||
if (mediaDirectory)
|
||||
mediaDirectory.remove();
|
||||
}
|
||||
|
||||
refresh();
|
||||
|
||||
// Emit something changed in the settings
|
||||
_sigChanged.emit();
|
||||
}
|
||||
|
||||
delete messageBox;
|
||||
}));
|
||||
|
||||
messageBox->show();
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
MediaDirectories::handleCreateMediaDirectory(void)
|
||||
{
|
||||
assert(_stack->count() == 1);
|
||||
|
||||
MediaDirectoryFormView* formView = new MediaDirectoryFormView(_db, _stack);
|
||||
formView->completed().connect(this, &MediaDirectories::handleMediaDirectoryFormCompleted);
|
||||
|
||||
_stack->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void
|
||||
MediaDirectories::handleMediaDirectoryFormCompleted(bool changed)
|
||||
{
|
||||
_stack->setCurrentIndex(0);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
// Refresh the user table if a change has been made
|
||||
refresh();
|
||||
|
||||
// Emit something changed in the settings
|
||||
_sigChanged.emit();
|
||||
}
|
||||
|
||||
// Delete the form view
|
||||
delete _stack->widget(1);
|
||||
|
||||
}
|
||||
|
||||
} // namespace UserInterface
|
||||
} // namespace Settings
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/>.
|
||||
*/
|
||||
|
||||
#ifndef UI_SETTINGS_MEDIA_DIRECTORIES_HPP
|
||||
#define UI_SETTINGS_MEDIA_DIRECTORIES_HPP
|
||||
|
||||
#include <Wt/WStackedWidget>
|
||||
#include <Wt/WContainerWidget>
|
||||
#include <Wt/WTable>
|
||||
#include <Wt/WSignal>
|
||||
|
||||
#include "database/MediaDirectory.hpp"
|
||||
|
||||
#include "common/SessionData.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class MediaDirectories : public Wt::WContainerWidget
|
||||
{
|
||||
public:
|
||||
MediaDirectories(SessionData& sessioNData, Wt::WContainerWidget *parent = 0);
|
||||
|
||||
void refresh();
|
||||
|
||||
Wt::Signal<void>& changed() { return _sigChanged; }
|
||||
|
||||
private:
|
||||
|
||||
Wt::Signal<void> _sigChanged;
|
||||
|
||||
void handleMediaDirectoryFormCompleted(bool changed);
|
||||
|
||||
void handleDelMediaDirectory(boost::filesystem::path p, Database::MediaDirectory::Type type);
|
||||
void handleCreateMediaDirectory(void);
|
||||
|
||||
Database::Handler& _db;
|
||||
|
||||
Wt::WStackedWidget* _stack;
|
||||
Wt::WTable* _table;
|
||||
};
|
||||
|
||||
} // namespace UserInterface
|
||||
} // namespace Settings
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 <vector>
|
||||
|
||||
#include <Wt/WStringListModel>
|
||||
#include <Wt/WLineEdit>
|
||||
#include <Wt/WFormModel>
|
||||
#include <Wt/WComboBox>
|
||||
#include <Wt/WPushButton>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
#include "database/MediaDirectory.hpp"
|
||||
|
||||
#include "common/DirectoryValidator.hpp"
|
||||
|
||||
|
||||
#include "SettingsMediaDirectoryFormView.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
// TODO validate if directory already exists
|
||||
class MediaDirectoryFormModel : public Wt::WFormModel
|
||||
{
|
||||
public:
|
||||
|
||||
// Associate each field with a unique string literal.
|
||||
static const Field PathField;
|
||||
static const Field TypeField;
|
||||
|
||||
MediaDirectoryFormModel(Database::Handler& db, Wt::WObject *parent = 0)
|
||||
: Wt::WFormModel(parent),
|
||||
_db(db)
|
||||
{
|
||||
initializeModels();
|
||||
|
||||
addField(PathField);
|
||||
addField(TypeField);
|
||||
|
||||
DirectoryValidator* dirValidator = new DirectoryValidator();
|
||||
dirValidator->setMandatory(true);
|
||||
setValidator(PathField, dirValidator);
|
||||
setValidator(TypeField, new Wt::WValidator(true)); // mandatory
|
||||
|
||||
}
|
||||
|
||||
Wt::WAbstractItemModel *typeModel() { return _typeModel; }
|
||||
|
||||
bool saveData(Wt::WString& error)
|
||||
{
|
||||
try {
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
Database::MediaDirectory::Type type
|
||||
= (valueText(TypeField) == "Audio") ? Database::MediaDirectory::Audio : Database::MediaDirectory::Video;
|
||||
|
||||
if (Database::MediaDirectory::get(_db.getSession(), valueText(PathField).toUTF8(), type))
|
||||
{
|
||||
error = "This Path/Type already exists!";
|
||||
return false;
|
||||
}
|
||||
|
||||
Database::MediaDirectory::create(_db.getSession(), valueText(PathField).toUTF8(), type);
|
||||
|
||||
}
|
||||
catch(Wt::Dbo::Exception& exception)
|
||||
{
|
||||
LMS_LOG(MOD_UI, SEV_ERROR) << "Dbo exception: " << exception.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void initializeModels()
|
||||
{
|
||||
_typeModel = new Wt::WStringListModel(this);
|
||||
_typeModel->addString("Audio");
|
||||
_typeModel->addString("Video");
|
||||
}
|
||||
|
||||
Database::Handler& _db;
|
||||
std::string _userId;
|
||||
Wt::WStringListModel* _typeModel;
|
||||
};
|
||||
|
||||
const Wt::WFormModel::Field MediaDirectoryFormModel::PathField = "path";
|
||||
const Wt::WFormModel::Field MediaDirectoryFormModel::TypeField = "type";
|
||||
|
||||
MediaDirectoryFormView::MediaDirectoryFormView(Database::Handler& db, Wt::WContainerWidget *parent)
|
||||
: Wt::WTemplateFormView(parent)
|
||||
{
|
||||
|
||||
_model = new MediaDirectoryFormModel(db, this);
|
||||
|
||||
setTemplateText(tr("mediaDirectoryForm-template"));
|
||||
addFunction("id", &WTemplate::Functions::id);
|
||||
addFunction("block", &WTemplate::Functions::id);
|
||||
|
||||
_applyInfo = new Wt::WText();
|
||||
_applyInfo->setInline(false);
|
||||
_applyInfo->hide();
|
||||
bindWidget("apply-info", _applyInfo);
|
||||
|
||||
// Path
|
||||
Wt::WLineEdit* pathEdit = new Wt::WLineEdit();
|
||||
setFormWidget(MediaDirectoryFormModel::PathField, pathEdit);
|
||||
pathEdit->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Type
|
||||
Wt::WComboBox *typeCB = new Wt::WComboBox();
|
||||
setFormWidget(MediaDirectoryFormModel::TypeField, typeCB);
|
||||
typeCB->setModel(_model->typeModel());
|
||||
typeCB->changed().connect(_applyInfo, &Wt::WWidget::hide);
|
||||
|
||||
// Title & Buttons
|
||||
bindString("title", "Add Media Folder");
|
||||
|
||||
Wt::WPushButton *saveButton = new Wt::WPushButton("Add");
|
||||
saveButton->setStyleClass("btn-primary");
|
||||
bindWidget("save-button", saveButton);
|
||||
saveButton->clicked().connect(this, &MediaDirectoryFormView::processSave);
|
||||
|
||||
Wt::WPushButton *cancelButton = new Wt::WPushButton("Cancel");
|
||||
bindWidget("cancel-button", cancelButton);
|
||||
cancelButton->clicked().connect(this, &MediaDirectoryFormView::processCancel);
|
||||
|
||||
updateView(_model);
|
||||
}
|
||||
|
||||
void
|
||||
MediaDirectoryFormView::processCancel()
|
||||
{
|
||||
// parent widget will delete this widget
|
||||
completed().emit(false);
|
||||
}
|
||||
|
||||
void
|
||||
MediaDirectoryFormView::processSave()
|
||||
{
|
||||
updateModel(_model);
|
||||
|
||||
_applyInfo->show();
|
||||
if (_model->validate())
|
||||
{
|
||||
Wt::WString error;
|
||||
// commit model into DB
|
||||
if (_model->saveData(error) ) {
|
||||
completed().emit(true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Cannot apply new parameters: ") + error);
|
||||
_applyInfo->setStyleClass("alert alert-danger");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_applyInfo->setText( Wt::WString::fromUTF8("Cannot apply new parameters!"));
|
||||
_applyInfo->setStyleClass("alert alert-danger");
|
||||
}
|
||||
|
||||
updateView(_model);
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/>.
|
||||
*/
|
||||
|
||||
#ifndef UI_SETTINGS_MEDIA_DIR_FORM_VIEW_HPP
|
||||
#define UI_SETTINGS_MEDIA_DIR_FORM_VIEW_HPP
|
||||
|
||||
#include <Wt/WContainerWidget>
|
||||
#include <Wt/WTemplateFormView>
|
||||
#include <Wt/WText>
|
||||
#include <Wt/WSignal>
|
||||
|
||||
#include "common/SessionData.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class MediaDirectoryFormModel;
|
||||
|
||||
class MediaDirectoryFormView : public Wt::WTemplateFormView
|
||||
{
|
||||
public:
|
||||
MediaDirectoryFormView(Database::Handler& db, Wt::WContainerWidget *parent = 0);
|
||||
|
||||
// Signal emitted once the form is completed
|
||||
Wt::Signal<bool>& completed() { return _sigCompleted; }
|
||||
|
||||
private:
|
||||
void processCancel(); // reload from DB
|
||||
void processSave(); // commit into DB
|
||||
|
||||
Wt::Signal<bool> _sigCompleted;
|
||||
MediaDirectoryFormModel* _model;
|
||||
Wt::WText* _applyInfo;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 <vector>
|
||||
|
||||
#include <Wt/WStringListModel>
|
||||
#include <Wt/WFormModel>
|
||||
#include <Wt/WLineEdit>
|
||||
#include <Wt/WCheckBox>
|
||||
#include <Wt/WComboBox>
|
||||
#include <Wt/WPushButton>
|
||||
#include <Wt/Auth/Identity>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
|
||||
#include "common/Validators.hpp"
|
||||
|
||||
#include "SettingsUserFormView.hpp"
|
||||
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class UserFormModel : public Wt::WFormModel
|
||||
{
|
||||
public:
|
||||
|
||||
// Associate each field with a unique string literal.
|
||||
static const Field NameField;
|
||||
static const Field EmailField;
|
||||
static const Field PasswordField;
|
||||
static const Field PasswordConfirmField;
|
||||
static const Field AdminField;
|
||||
static const Field AudioBitrateLimitField;
|
||||
static const Field VideoBitrateLimitField;
|
||||
|
||||
UserFormModel(SessionData& sessionData, std::string userId, Wt::WObject *parent = 0)
|
||||
: Wt::WFormModel(parent),
|
||||
_db(sessionData.getDatabaseHandler()),
|
||||
_userId(userId)
|
||||
{
|
||||
initializeModels();
|
||||
|
||||
addField(NameField);
|
||||
addField(EmailField);
|
||||
addField(PasswordField);
|
||||
addField(PasswordConfirmField);
|
||||
addField(AdminField);
|
||||
addField(AudioBitrateLimitField);
|
||||
addField(VideoBitrateLimitField);
|
||||
|
||||
setValidator(NameField, createNameValidator());
|
||||
setValidator(EmailField, createEmailValidator());
|
||||
// If creating a user, passwords are mandatory
|
||||
if (_userId.empty())
|
||||
{
|
||||
setValidator(PasswordField, new Wt::WValidator(true)); // mandatory
|
||||
setValidator(PasswordConfirmField, new Wt::WValidator(true)); // mandatory
|
||||
}
|
||||
setValidator(AudioBitrateLimitField, new Wt::WValidator(true)); // mandatory
|
||||
setValidator(VideoBitrateLimitField, new Wt::WValidator(true)); // mandatory
|
||||
|
||||
// populate the model with initial data
|
||||
loadData(userId);
|
||||
}
|
||||
|
||||
Wt::WAbstractItemModel *audioBitrateModel() { return _audioBitrateModel; }
|
||||
Wt::WAbstractItemModel *videoBitrateModel() { return _videoBitrateModel; }
|
||||
|
||||
void loadData(std::string userId)
|
||||
{
|
||||
|
||||
if (!userId.empty())
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
Wt::Auth::User authUser = _db.getUserDatabase().findWithId( userId );
|
||||
Database::User::pointer user = _db.getUser(authUser);
|
||||
|
||||
Wt::Auth::User currentUser = _db.getLogin().user();
|
||||
|
||||
if (user && authUser.isValid())
|
||||
{
|
||||
if (user->isAdmin())
|
||||
{
|
||||
setValue(AdminField, true);
|
||||
|
||||
// We can cannot remove admin rights to ourselves
|
||||
if (currentUser == authUser)
|
||||
setReadOnly(AdminField, true);
|
||||
|
||||
// if the user is admin, no need to limit it
|
||||
setReadOnly(AudioBitrateLimitField, true);
|
||||
setValidator(AudioBitrateLimitField, nullptr);
|
||||
|
||||
setReadOnly(VideoBitrateLimitField, true);
|
||||
setValidator(VideoBitrateLimitField, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
setValue(AudioBitrateLimitField, user->getMaxAudioBitrate() / 1000); // in kbps
|
||||
setValue(VideoBitrateLimitField, user->getMaxVideoBitrate() / 1000); // in kbps
|
||||
}
|
||||
|
||||
setValue(NameField, authUser.identity(Wt::Auth::Identity::LoginName));
|
||||
if (!authUser.email().empty())
|
||||
setValue(EmailField, authUser.email());
|
||||
else
|
||||
setValue(EmailField, authUser.unverifiedEmail());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool saveData()
|
||||
{
|
||||
try {
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
|
||||
if (_userId.empty())
|
||||
{
|
||||
// Create user
|
||||
Wt::Auth::User authUser = _db.getUserDatabase().registerNew();
|
||||
Database::User::pointer user = _db.getUser(authUser);
|
||||
|
||||
// Account
|
||||
authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(NameField));
|
||||
authUser.setEmail(valueText(EmailField).toUTF8());
|
||||
Database::Handler::getPasswordService().updatePassword(authUser, valueText(PasswordField));
|
||||
|
||||
// Access
|
||||
{
|
||||
boost::any v = value(AdminField);
|
||||
if (!v.empty() && boost::any_cast<bool>(v) == true)
|
||||
user.modify()->setAdmin( true );
|
||||
else
|
||||
user.modify()->setAdmin( false );
|
||||
}
|
||||
|
||||
if (!isReadOnly(AudioBitrateLimitField))
|
||||
user.modify()->setMaxAudioBitrate( Wt::asNumber(value(AudioBitrateLimitField)) * 1000); // in bps
|
||||
|
||||
if (!isReadOnly(VideoBitrateLimitField))
|
||||
user.modify()->setMaxVideoBitrate( Wt::asNumber(value(VideoBitrateLimitField)) * 1000); // in bps
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update user
|
||||
Wt::Auth::User authUser = _db.getUserDatabase().findWithId(_userId);
|
||||
Database::User::pointer user = _db.getUser( authUser );
|
||||
|
||||
// user may have been deleted by someone else
|
||||
if (!authUser.isValid()) {
|
||||
LMS_LOG(MOD_UI, SEV_ERROR) << "user identity does not exist!";
|
||||
return false;
|
||||
}
|
||||
else if(!user)
|
||||
{
|
||||
LMS_LOG(MOD_UI, SEV_ERROR) << "User not found!";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Account
|
||||
authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(NameField));
|
||||
authUser.setEmail(valueText(EmailField).toUTF8());
|
||||
|
||||
// Password
|
||||
if (!valueText(PasswordField).empty())
|
||||
Database::Handler::getPasswordService().updatePassword(authUser, valueText(PasswordField));
|
||||
|
||||
// Access
|
||||
if (!isReadOnly(AdminField))
|
||||
{
|
||||
boost::any v = value(AdminField);
|
||||
if (!v.empty() && boost::any_cast<bool>(v) == true)
|
||||
user.modify()->setAdmin( true );
|
||||
else
|
||||
user.modify()->setAdmin( false );
|
||||
}
|
||||
|
||||
if (!isReadOnly(AudioBitrateLimitField))
|
||||
user.modify()->setMaxAudioBitrate( Wt::asNumber(value(AudioBitrateLimitField)) * 1000); // in bps
|
||||
|
||||
if (!isReadOnly(VideoBitrateLimitField))
|
||||
user.modify()->setMaxVideoBitrate( Wt::asNumber(value(VideoBitrateLimitField)) * 1000); // in bps
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
catch(Wt::Dbo::Exception& exception)
|
||||
{
|
||||
LMS_LOG(MOD_UI, SEV_ERROR) << "Dbo exception: " << exception.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateField(Field field)
|
||||
{
|
||||
Wt::WString error;
|
||||
|
||||
if (field == NameField)
|
||||
{
|
||||
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||
// Must be unique since used as LoginIdentity
|
||||
Wt::Auth::User user = _db.getUserDatabase().findWithIdentity(Wt::Auth::Identity::LoginName, valueText(field));
|
||||
if (user.isValid() && user.id() != _userId)
|
||||
error = "Already exists";
|
||||
else
|
||||
return Wt::WFormModel::validateField(field);
|
||||
}
|
||||
else if (field == PasswordField)
|
||||
{
|
||||
// Password is mandatory if we create the user
|
||||
if (!valueText(PasswordField).empty())
|
||||
{
|
||||
// Evaluate the strength of the password
|
||||
Wt::Auth::AbstractPasswordService::StrengthValidatorResult res
|
||||
= Database::Handler::getPasswordService().strengthValidator()->evaluateStrength(valueText(PasswordField),
|
||||
valueText(NameField),
|
||||
valueText(EmailField).toUTF8());
|
||||
|
||||
if (!res.isValid())
|
||||
error = res.message();
|
||||
}
|
||||
else
|
||||
return Wt::WFormModel::validateField(field);
|
||||
}
|
||||
else if (field == PasswordConfirmField)
|
||||
{
|
||||
if (validation(PasswordField).state() == Wt::WValidator::Valid)
|
||||
{
|
||||
if (valueText(PasswordField) != valueText(PasswordConfirmField))
|
||||
error = Wt::WString::tr("Wt.Auth.passwords-dont-match");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Apply validators
|
||||
return Wt::WFormModel::validateField(field);
|
||||
}
|
||||
|
||||
setValidation(field, Wt::WValidator::Result( error.empty() ? Wt::WValidator::Valid : Wt::WValidator::Invalid, error));
|
||||
|
||||
return validation(field).state() == Wt::WValidator::Valid;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void initializeModels()
|
||||
{
|
||||
// AUDIO
|
||||
_audioBitrateModel = new Wt::WStringListModel();
|
||||
BOOST_FOREACH(std::size_t bitrate, Database::User::audioBitrates)
|
||||
_audioBitrateModel->addString( Wt::WString("{1}").arg( bitrate / 1000 ) ); // in kbps
|
||||
|
||||
// VIDEO
|
||||
_videoBitrateModel = new Wt::WStringListModel();
|
||||
BOOST_FOREACH(std::size_t bitrate, Database::User::videoBitrates)
|
||||
_videoBitrateModel->addString( Wt::WString("{1}").arg( bitrate / 1000 ) ); // in kbps
|
||||
|
||||
}
|
||||
|
||||
Database::Handler& _db;
|
||||
std::string _userId;
|
||||
Wt::WStringListModel* _audioBitrateModel;
|
||||
Wt::WStringListModel* _videoBitrateModel;
|
||||
};
|
||||
|
||||
const Wt::WFormModel::Field UserFormModel::NameField = "name";
|
||||
const Wt::WFormModel::Field UserFormModel::EmailField = "email";
|
||||
const Wt::WFormModel::Field UserFormModel::PasswordField = "password";
|
||||
const Wt::WFormModel::Field UserFormModel::PasswordConfirmField = "password-confirm";
|
||||
const Wt::WFormModel::Field UserFormModel::AdminField = "admin";
|
||||
const Wt::WFormModel::Field UserFormModel::AudioBitrateLimitField = "audio-bitrate-limit";
|
||||
const Wt::WFormModel::Field UserFormModel::VideoBitrateLimitField = "video-bitrate-limit";
|
||||
|
||||
|
||||
UserFormView::UserFormView(SessionData& sessionData, std::string userId, Wt::WContainerWidget *parent)
|
||||
: Wt::WTemplateFormView(parent)
|
||||
{
|
||||
|
||||
_model = new UserFormModel(sessionData, userId, this);
|
||||
|
||||
setTemplateText(tr("userForm-template"));
|
||||
addFunction("id", &WTemplate::Functions::id);
|
||||
addFunction("block", &WTemplate::Functions::id);
|
||||
|
||||
// Name
|
||||
setFormWidget(UserFormModel::NameField, new Wt::WLineEdit());
|
||||
|
||||
// Email
|
||||
setFormWidget(UserFormModel::EmailField, new Wt::WLineEdit());
|
||||
|
||||
// Password
|
||||
Wt::WLineEdit* passwordEdit = new Wt::WLineEdit();
|
||||
setFormWidget(UserFormModel::PasswordField, passwordEdit );
|
||||
passwordEdit->setEchoMode(Wt::WLineEdit::Password);
|
||||
|
||||
// Password confirmation
|
||||
Wt::WLineEdit* passwordConfirmEdit = new Wt::WLineEdit();
|
||||
setFormWidget(UserFormModel::PasswordConfirmField, passwordConfirmEdit);
|
||||
passwordConfirmEdit->setEchoMode(Wt::WLineEdit::Password);
|
||||
|
||||
bindString("access", "Access");
|
||||
|
||||
// Admin Field
|
||||
setFormWidget(UserFormModel::AdminField, new Wt::WCheckBox());
|
||||
|
||||
// AudioBitrate
|
||||
Wt::WComboBox *audioBitrateCB = new Wt::WComboBox();
|
||||
setFormWidget(UserFormModel::AudioBitrateLimitField, audioBitrateCB);
|
||||
audioBitrateCB->setStyleClass("span2");
|
||||
audioBitrateCB->setModel(_model->audioBitrateModel());
|
||||
|
||||
// VideoBitrate
|
||||
Wt::WComboBox *videoBitrateCB = new Wt::WComboBox();
|
||||
setFormWidget(UserFormModel::VideoBitrateLimitField, videoBitrateCB);
|
||||
videoBitrateCB->setStyleClass("span2");
|
||||
videoBitrateCB->setModel(_model->videoBitrateModel());
|
||||
|
||||
// Title & Buttons
|
||||
Wt::WString title;
|
||||
if (userId.empty()) {
|
||||
title = Wt::WString("Create user");
|
||||
}
|
||||
else {
|
||||
Database::Handler &db = sessionData.getDatabaseHandler();
|
||||
Wt::Dbo::Transaction transaction (db.getSession());
|
||||
Wt::Auth::User authUser = db.getUserDatabase().findWithId( userId );
|
||||
|
||||
Wt::WString userName;
|
||||
if (authUser.isValid())
|
||||
userName = authUser.identity(Wt::Auth::Identity::LoginName);
|
||||
else
|
||||
; // TODO display user deleted and close the widget
|
||||
|
||||
title = Wt::WString("Edit user {1}").arg(userName);
|
||||
}
|
||||
|
||||
bindString("title", title);
|
||||
|
||||
Wt::WPushButton *saveButton = new Wt::WPushButton();
|
||||
if (userId.empty()) {
|
||||
saveButton->setText("Create user");
|
||||
saveButton->setStyleClass("btn-success");
|
||||
}
|
||||
else
|
||||
{
|
||||
saveButton->setText("Save");
|
||||
saveButton->setStyleClass("btn-primary");
|
||||
}
|
||||
bindWidget("save-button", saveButton);
|
||||
saveButton->clicked().connect(this, &UserFormView::processSave);
|
||||
|
||||
Wt::WPushButton *cancelButton = new Wt::WPushButton("Cancel");
|
||||
bindWidget("cancel-button", cancelButton);
|
||||
cancelButton->clicked().connect(this, &UserFormView::processCancel);
|
||||
|
||||
updateView(_model);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
UserFormView::processCancel()
|
||||
{
|
||||
// parent widget will delete this widget
|
||||
completed().emit(false);
|
||||
}
|
||||
|
||||
void
|
||||
UserFormView::processSave()
|
||||
{
|
||||
updateModel(_model);
|
||||
|
||||
|
||||
if (_model->validate())
|
||||
{
|
||||
// commit model into DB
|
||||
if (_model->saveData() )
|
||||
{
|
||||
// parent widget will delete this widget
|
||||
completed().emit(true);
|
||||
}
|
||||
// else TODO display a nice error message
|
||||
}
|
||||
else
|
||||
{
|
||||
updateView(_model);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/>.
|
||||
*/
|
||||
|
||||
#ifndef UI_SETTINGS_USER_FORM_VIEW_HPP
|
||||
#define UI_SETTINGS_USER_FORM_VIEW_HPP
|
||||
|
||||
#include <Wt/WContainerWidget>
|
||||
#include <Wt/WTemplateFormView>
|
||||
#include <Wt/WSignal>
|
||||
|
||||
#include "common/SessionData.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class UserFormModel;
|
||||
|
||||
class UserFormView : public Wt::WTemplateFormView
|
||||
{
|
||||
public:
|
||||
|
||||
UserFormView(SessionData& sessionData, std::string userId, Wt::WContainerWidget *parent = 0);
|
||||
|
||||
// Signal emitted once the form is completed
|
||||
Wt::Signal<bool>& completed() { return _sigCompleted; }
|
||||
|
||||
private:
|
||||
|
||||
Wt::Signal<bool> _sigCompleted;
|
||||
|
||||
void processSave();
|
||||
void processCancel();
|
||||
|
||||
UserFormModel* _model;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Settings
|
||||
} // namespace UserInterface
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/WGroupBox>
|
||||
#include <Wt/WText>
|
||||
#include <Wt/WPushButton>
|
||||
#include <Wt/WMessageBox>
|
||||
|
||||
#include <Wt/Auth/Identity>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
|
||||
#include "SettingsUserFormView.hpp"
|
||||
|
||||
#include "SettingsUsers.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
Users::Users(SessionData& sessionData, Wt::WContainerWidget *parent)
|
||||
: Wt::WContainerWidget(parent),
|
||||
_sessionData(sessionData)
|
||||
{
|
||||
// Stack two widgets:
|
||||
_stack = new Wt::WStackedWidget(this);
|
||||
|
||||
// 1/ the user table view
|
||||
{
|
||||
Wt::WGroupBox *container = new Wt::WGroupBox("Users", _stack);
|
||||
|
||||
_table = new Wt::WTable(container);
|
||||
|
||||
_table->addStyleClass("table form-inline");
|
||||
|
||||
_table->toggleStyleClass("table-hover", true);
|
||||
_table->toggleStyleClass("table-striped", true);
|
||||
|
||||
_table->setHeaderCount(1);
|
||||
|
||||
_table->elementAt(0, 0)->addWidget(new Wt::WText("#"));
|
||||
_table->elementAt(0, 1)->addWidget(new Wt::WText("Name"));
|
||||
_table->elementAt(0, 2)->addWidget(new Wt::WText("e-Mail"));
|
||||
_table->elementAt(0, 3)->addWidget(new Wt::WText("Admin"));
|
||||
|
||||
Wt::WPushButton* addBtn = new Wt::WPushButton("Add User");
|
||||
addBtn->setStyleClass("btn-success");
|
||||
container->addWidget( addBtn );
|
||||
addBtn->clicked().connect(boost::bind(&Users::handleCreateUser, this, ""));
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void
|
||||
Users::refresh(void)
|
||||
{
|
||||
|
||||
assert(_table->rowCount() > 0);
|
||||
for (int i = _table->rowCount() - 1; i > 0; --i)
|
||||
_table->deleteRow(i);
|
||||
|
||||
Database::Handler& db = _sessionData.getDatabaseHandler();
|
||||
|
||||
Wt::Dbo::Transaction transaction(db.getSession());
|
||||
|
||||
const Wt::Auth::User& currentUser = db.getLogin().user();
|
||||
|
||||
std::vector<Database::User::pointer> users = Database::User::getAll(db.getSession());
|
||||
|
||||
std::size_t userIndex = 1;
|
||||
for (std::size_t i = 0; i < users.size(); ++i)
|
||||
{
|
||||
|
||||
std::string userId = Database::User::getId(users[i]);
|
||||
|
||||
Wt::Auth::User authUser;
|
||||
|
||||
// Hack try/catch here since it may fail!
|
||||
try {
|
||||
authUser = db.getUserDatabase().findWithId( userId );
|
||||
}
|
||||
catch(Wt::Dbo::Exception& e)
|
||||
{
|
||||
LMS_LOG(MOD_UI, SEV_ERROR) << "Caught exception when getting userId=" << userId << ": " << e.code();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!authUser.isValid()) {
|
||||
LMS_LOG(MOD_UI, SEV_ERROR) << "Users::refresh: skipping invalid userId = " << userId;
|
||||
continue;
|
||||
}
|
||||
|
||||
_table->elementAt(userIndex, 0)->addWidget(new Wt::WText( Wt::WString::fromUTF8("{1}").arg(userIndex)));
|
||||
_table->elementAt(userIndex, 1)->addWidget(new Wt::WText( authUser.identity(Wt::Auth::Identity::LoginName)) );
|
||||
|
||||
Wt::WText* email = new Wt::WText();
|
||||
if (!authUser.email().empty()) {
|
||||
email->setText(authUser.email());
|
||||
}
|
||||
else {
|
||||
email->setStyleClass("alert-danger");
|
||||
email->setText(authUser.unverifiedEmail());
|
||||
}
|
||||
_table->elementAt(userIndex, 2)->addWidget( email ) ;
|
||||
_table->elementAt(userIndex, 3)->addWidget(new Wt::WText( users[i]->isAdmin() ? "Yes" : "No" ));
|
||||
|
||||
Wt::WPushButton* editBtn = new Wt::WPushButton("Edit");
|
||||
_table->elementAt(userIndex, 4)->addWidget(editBtn);
|
||||
editBtn->clicked().connect(boost::bind( &Users::handleCreateUser, this, userId));
|
||||
|
||||
if (currentUser != authUser)
|
||||
{
|
||||
Wt::WPushButton* delBtn = new Wt::WPushButton("Delete");
|
||||
delBtn->setStyleClass("btn-danger");
|
||||
delBtn->setMargin(5, Wt::Left);
|
||||
_table->elementAt(userIndex, 4)->addWidget(delBtn);
|
||||
delBtn->clicked().connect(boost::bind( &Users::handleDelUser, this, authUser.identity(Wt::Auth::Identity::LoginName), userId));
|
||||
}
|
||||
|
||||
++userIndex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Users::handleDelUser(Wt::WString loginNameIdentity, std::string id)
|
||||
{
|
||||
Wt::WMessageBox *messageBox = new Wt::WMessageBox
|
||||
("Delete User",
|
||||
Wt::WString( "Deleting user '{1}'?").arg(loginNameIdentity),
|
||||
Wt::Question, Wt::Yes | Wt::No);
|
||||
|
||||
messageBox->setModal(true);
|
||||
|
||||
messageBox->buttonClicked().connect(std::bind([=] () {
|
||||
if (messageBox->buttonResult() == Wt::Yes)
|
||||
{
|
||||
Database::Handler& db = _sessionData.getDatabaseHandler();
|
||||
|
||||
Wt::Dbo::Transaction transaction(db.getSession());
|
||||
|
||||
// Delete the user
|
||||
Wt::Auth::User authUser = db.getUserDatabase().findWithId( id );
|
||||
|
||||
db.getUserDatabase().deleteUser( authUser );
|
||||
|
||||
Database::User::pointer user = Database::User::getById(db.getSession(), id);
|
||||
if (user)
|
||||
user.remove();
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
delete messageBox;
|
||||
}));
|
||||
|
||||
messageBox->show();
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Users::handleCreateUser(std::string id)
|
||||
{
|
||||
assert(_stack->count() == 1);
|
||||
|
||||
UserFormView* userFormView = new UserFormView(_sessionData, id, _stack);
|
||||
userFormView->completed().connect(this, &Users::handleUserFormCompleted);
|
||||
|
||||
_stack->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void
|
||||
Users::handleUserFormCompleted(bool changed)
|
||||
{
|
||||
_stack->setCurrentIndex(0);
|
||||
|
||||
// Refresh the user table if a change has been made
|
||||
if (changed)
|
||||
refresh();
|
||||
|
||||
// Delete the form view
|
||||
delete _stack->widget(1);
|
||||
|
||||
}
|
||||
|
||||
} // namespace UserInterface
|
||||
} // namespace Settings
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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/>.
|
||||
*/
|
||||
|
||||
#ifndef UI_SETTINGS_USERS_HPP
|
||||
#define UI_SETTINGS_USERS_HPP
|
||||
|
||||
#include <Wt/WStackedWidget>
|
||||
#include <Wt/WContainerWidget>
|
||||
#include <Wt/WTable>
|
||||
|
||||
#include "common/SessionData.hpp"
|
||||
|
||||
namespace UserInterface {
|
||||
namespace Settings {
|
||||
|
||||
class Users : public Wt::WContainerWidget
|
||||
{
|
||||
public:
|
||||
Users(SessionData& sessioNData, Wt::WContainerWidget *parent = 0);
|
||||
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
|
||||
void handleUserFormCompleted(bool changed);
|
||||
|
||||
void handleDelUser(Wt::WString loginNameIdentity, std::string id);
|
||||
void handleCreateUser(std::string id); // set the id in order to edit the user
|
||||
|
||||
SessionData& _sessionData;
|
||||
|
||||
Wt::WStackedWidget* _stack;
|
||||
Wt::WTable* _table;
|
||||
};
|
||||
|
||||
} // namespace UserInterface
|
||||
} // namespace Settings
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user