WIP. Added Account and Audio forms
This commit is contained in:
@@ -66,7 +66,10 @@ lms_SOURCES = \
|
|||||||
$(top_srcdir)/ui/video/VideoMediaPlayerWidget.cpp \
|
$(top_srcdir)/ui/video/VideoMediaPlayerWidget.cpp \
|
||||||
$(top_srcdir)/ui/video/VideoParametersDialog.cpp \
|
$(top_srcdir)/ui/video/VideoParametersDialog.cpp \
|
||||||
$(top_srcdir)/ui/settings/Settings.cpp \
|
$(top_srcdir)/ui/settings/Settings.cpp \
|
||||||
|
$(top_srcdir)/ui/settings/SettingsAccountFormView.cpp \
|
||||||
|
$(top_srcdir)/ui/settings/SettingsAudioFormView.cpp \
|
||||||
$(top_srcdir)/ui/settings/SettingsDatabaseFormView.cpp \
|
$(top_srcdir)/ui/settings/SettingsDatabaseFormView.cpp \
|
||||||
|
$(top_srcdir)/ui/settings/SettingsUserFormView.cpp \
|
||||||
$(top_srcdir)/ui/settings/SettingsUsers.cpp
|
$(top_srcdir)/ui/settings/SettingsUsers.cpp
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,14 @@ Handler::configureAuth(void)
|
|||||||
verifier->addHashFunction(new Wt::Auth::BCryptHashFunction(8));
|
verifier->addHashFunction(new Wt::Auth::BCryptHashFunction(8));
|
||||||
passwordService.setVerifier(verifier);
|
passwordService.setVerifier(verifier);
|
||||||
passwordService.setAttemptThrottlingEnabled(true);
|
passwordService.setAttemptThrottlingEnabled(true);
|
||||||
passwordService.setStrengthValidator(new Wt::Auth::PasswordStrengthValidator());
|
|
||||||
|
Wt::Auth::PasswordStrengthValidator* strengthValidator = new Wt::Auth::PasswordStrengthValidator();
|
||||||
|
// Reduce some constraints...
|
||||||
|
strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthValidator::TwoCharClass, 11);
|
||||||
|
strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthValidator::ThreeCharClass, 8 );
|
||||||
|
strengthValidator->setMinimumLength( Wt::Auth::PasswordStrengthValidator::FourCharClass, 6 );
|
||||||
|
|
||||||
|
passwordService.setStrengthValidator(strengthValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Wt::Auth::AuthService&
|
const Wt::Auth::AuthService&
|
||||||
|
|||||||
@@ -4,6 +4,33 @@
|
|||||||
|
|
||||||
namespace Database {
|
namespace Database {
|
||||||
|
|
||||||
|
|
||||||
|
// must be ordered
|
||||||
|
const std::vector<std::size_t>
|
||||||
|
User::audioBitrates =
|
||||||
|
{
|
||||||
|
64000,
|
||||||
|
96000,
|
||||||
|
128000,
|
||||||
|
160000,
|
||||||
|
192000,
|
||||||
|
224000,
|
||||||
|
256000,
|
||||||
|
320000,
|
||||||
|
512000
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const std::vector<std::size_t>
|
||||||
|
User::videoBitrates =
|
||||||
|
{
|
||||||
|
256000,
|
||||||
|
512000,
|
||||||
|
1024000,
|
||||||
|
2048000,
|
||||||
|
4096000,
|
||||||
|
8192000
|
||||||
|
};
|
||||||
User::User()
|
User::User()
|
||||||
: _maxAudioBitrate(maxAudioBitrate),
|
: _maxAudioBitrate(maxAudioBitrate),
|
||||||
_maxVideoBitrate(maxVideoBitrate),
|
_maxVideoBitrate(maxVideoBitrate),
|
||||||
@@ -27,6 +54,73 @@ User::getById(Wt::Dbo::Session& session, std::string id)
|
|||||||
return session.find<User>().where("id = ?").bind( id );
|
return session.find<User>().where("id = ?").bind( id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
User::getId( pointer user)
|
||||||
|
{
|
||||||
|
std::ostringstream oss; oss << user.id();
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
User::setAudioBitrate(std::size_t bitrate)
|
||||||
|
{
|
||||||
|
_audioBitrate = std::min(bitrate, std::min(static_cast<std::size_t>(_maxAudioBitrate), audioBitrates.back()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
User::setVideoBitrate(std::size_t bitrate)
|
||||||
|
{
|
||||||
|
_videoBitrate = std::min(bitrate, std::min(static_cast<std::size_t>(_maxVideoBitrate), videoBitrates.back()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
User::setMaxAudioBitrate(std::size_t bitrate)
|
||||||
|
{
|
||||||
|
_maxAudioBitrate = std::min(bitrate, static_cast<std::size_t>(_maxAudioBitrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
User::setMaxVideoBitrate(std::size_t bitrate)
|
||||||
|
{
|
||||||
|
_maxVideoBitrate = std::min(bitrate, static_cast<std::size_t>(_maxVideoBitrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
User::getVideoBitrate(void) const
|
||||||
|
{
|
||||||
|
if (!isAdmin())
|
||||||
|
return std::min(static_cast<std::size_t>(_videoBitrate), std::min(static_cast<std::size_t>(_maxVideoBitrate), videoBitrates.back()));
|
||||||
|
else
|
||||||
|
return std::min(static_cast<std::size_t>(_videoBitrate), videoBitrates.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
User::getMaxAudioBitrate(void) const
|
||||||
|
{
|
||||||
|
if (!isAdmin())
|
||||||
|
return std::min(static_cast<std::size_t>(_maxAudioBitrate), audioBitrates.back());
|
||||||
|
else
|
||||||
|
return audioBitrates.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
User::getMaxVideoBitrate(void) const
|
||||||
|
{
|
||||||
|
if (!isAdmin())
|
||||||
|
return std::min(static_cast<std::size_t>(_maxVideoBitrate), videoBitrates.back());
|
||||||
|
else
|
||||||
|
return videoBitrates.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Database
|
} // namespace Database
|
||||||
|
|
||||||
|
|||||||
+15
-6
@@ -14,6 +14,10 @@ class User {
|
|||||||
public:
|
public:
|
||||||
static const std::size_t MaxNameLength = 15;
|
static const std::size_t MaxNameLength = 15;
|
||||||
|
|
||||||
|
// list of commonly used bitrates
|
||||||
|
static const std::vector<std::size_t> audioBitrates;
|
||||||
|
static const std::vector<std::size_t> videoBitrates;
|
||||||
|
|
||||||
User();
|
User();
|
||||||
|
|
||||||
typedef Wt::Dbo::ptr<User> pointer;
|
typedef Wt::Dbo::ptr<User> pointer;
|
||||||
@@ -21,16 +25,21 @@ class User {
|
|||||||
// accessors
|
// accessors
|
||||||
static pointer getById(Wt::Dbo::Session& session, std::string id);
|
static pointer getById(Wt::Dbo::Session& session, std::string id);
|
||||||
static std::vector<pointer> getAll(Wt::Dbo::Session& session);
|
static std::vector<pointer> getAll(Wt::Dbo::Session& session);
|
||||||
|
static std::string getId(pointer user);
|
||||||
|
|
||||||
// write
|
// write
|
||||||
void setAdmin(bool admin) { _isAdmin = admin; }
|
void setAdmin(bool admin) { _isAdmin = admin; }
|
||||||
void setMaxAudioBitrate(std::size_t bitrate) { _maxAudioBitrate = bitrate; }
|
void setAudioBitrate(std::size_t bitrate);
|
||||||
void setMaxVideoBitrate(std::size_t bitrate) { _maxVideoBitrate = bitrate; }
|
void setVideoBitrate(std::size_t bitrate);
|
||||||
|
void setMaxAudioBitrate(std::size_t bitrate);
|
||||||
|
void setMaxVideoBitrate(std::size_t bitrate);
|
||||||
|
|
||||||
// read
|
// read
|
||||||
bool isAdmin() const {return _isAdmin;}
|
bool isAdmin() const {return _isAdmin;}
|
||||||
std::size_t getMaxAudioBitrate() const { return _maxAudioBitrate; }
|
std::size_t getAudioBitrate() const;
|
||||||
std::size_t getMaxVideoBitrate() const { return _maxVideoBitrate; }
|
std::size_t getVideoBitrate() const;
|
||||||
|
std::size_t getMaxAudioBitrate() const;
|
||||||
|
std::size_t getMaxVideoBitrate() const;
|
||||||
|
|
||||||
template<class Action>
|
template<class Action>
|
||||||
void persist(Action& a)
|
void persist(Action& a)
|
||||||
@@ -45,10 +54,10 @@ class User {
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
static const std::size_t maxAudioBitrate = 320000;
|
static const std::size_t maxAudioBitrate = 320000;
|
||||||
static const std::size_t maxVideoBitrate = 7500000;
|
static const std::size_t maxVideoBitrate = 2048000;
|
||||||
|
|
||||||
static const std::size_t defaultAudioBitrate = 128000;
|
static const std::size_t defaultAudioBitrate = 128000;
|
||||||
static const std::size_t defaultVideoBitrate = 1500000;
|
static const std::size_t defaultVideoBitrate = 1024000;
|
||||||
|
|
||||||
// Admin defined settings
|
// Admin defined settings
|
||||||
int _maxAudioBitrate;
|
int _maxAudioBitrate;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<legend>Access</legend>
|
<legend>${access}</legend>
|
||||||
<div class="form-horizontal">
|
<div class="form-horizontal">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="${id:admin}">
|
<label class="control-label col-sm-2" for="${id:admin}">
|
||||||
@@ -91,6 +91,8 @@
|
|||||||
${video-bitrate-limit-info}
|
${video-bitrate-limit-info}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-horizontal">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
${save-button} ${cancel-button}
|
${save-button} ${cancel-button}
|
||||||
@@ -100,6 +102,88 @@
|
|||||||
|
|
||||||
</message>
|
</message>
|
||||||
|
|
||||||
|
<message id="userAccountForm-template">
|
||||||
|
<legend>${title}</legend>
|
||||||
|
<div class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="${id:name}">
|
||||||
|
Name
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-5">
|
||||||
|
${name}
|
||||||
|
</div>
|
||||||
|
<div class="help-block col-sm-5">
|
||||||
|
${name-info}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="${id:email}">
|
||||||
|
e-Mail
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-5">
|
||||||
|
${email}
|
||||||
|
</div>
|
||||||
|
<div class="help-block col-sm-5">
|
||||||
|
${email-info}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="${id:password}">
|
||||||
|
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:password-confirm}">
|
||||||
|
Confirm password
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-5">
|
||||||
|
${password-confirm}
|
||||||
|
</div>
|
||||||
|
<div class="help-block col-sm-5">
|
||||||
|
${password-confirm-info}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
${save-button} ${cancel-button}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
${apply-info}
|
||||||
|
</div>
|
||||||
|
</message>
|
||||||
|
|
||||||
|
<message id="audioForm-template">
|
||||||
|
<legend>${title}</legend>
|
||||||
|
<div class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="${id:bitrate}">
|
||||||
|
Audio bitrate
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-5">
|
||||||
|
<div class="input-group">
|
||||||
|
${bitrate}
|
||||||
|
<span class="input-group-addon">kbps</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="help-block col-sm-5">
|
||||||
|
${bitrate-info}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
${save-button} ${cancel-button}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
${apply-info}
|
||||||
|
</div>
|
||||||
|
</message>
|
||||||
|
|
||||||
<message id="databaseForm-template">
|
<message id="databaseForm-template">
|
||||||
<legend>${title}</legend>
|
<legend>${title}</legend>
|
||||||
<div class="form-horizontal">
|
<div class="form-horizontal">
|
||||||
@@ -150,7 +234,6 @@
|
|||||||
${update-request-immediate-scan-info}
|
${update-request-immediate-scan-info}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
${apply-button} ${discard-button}
|
${apply-button} ${discard-button}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace UserInterface {
|
|||||||
|
|
||||||
AudioWidget::AudioWidget(SessionData& sessionData, Wt::WContainerWidget* parent)
|
AudioWidget::AudioWidget(SessionData& sessionData, Wt::WContainerWidget* parent)
|
||||||
: Wt::WContainerWidget(parent),
|
: Wt::WContainerWidget(parent),
|
||||||
_sessionData(sessionData),
|
_db(sessionData.getDatabaseHandler()),
|
||||||
_audioDbWidget(nullptr),
|
_audioDbWidget(nullptr),
|
||||||
_mediaPlayer(nullptr),
|
_mediaPlayer(nullptr),
|
||||||
_imgResource(nullptr),
|
_imgResource(nullptr),
|
||||||
@@ -39,11 +39,22 @@ AudioWidget::playTrack(boost::filesystem::path p)
|
|||||||
{
|
{
|
||||||
std::cout << "play track '" << p << "'" << std::endl;
|
std::cout << "play track '" << p << "'" << std::endl;
|
||||||
try {
|
try {
|
||||||
// TODO get user's encoding preference
|
|
||||||
|
std::size_t bitrate = 0;
|
||||||
|
|
||||||
|
// Get user preferences
|
||||||
|
{
|
||||||
|
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||||
|
Database::User::pointer user = _db.getCurrentUser();
|
||||||
|
if (user)
|
||||||
|
bitrate = user->getAudioBitrate();
|
||||||
|
else
|
||||||
|
return; // TODO logout?
|
||||||
|
}
|
||||||
|
|
||||||
Transcode::InputMediaFile inputFile(p);
|
Transcode::InputMediaFile inputFile(p);
|
||||||
|
|
||||||
Transcode::Parameters parameters(inputFile, Transcode::Format::get(Transcode::Format::OGA), 128000);
|
Transcode::Parameters parameters(inputFile, Transcode::Format::get(Transcode::Format::OGA), bitrate);
|
||||||
|
|
||||||
_mediaPlayer->load( parameters );
|
_mediaPlayer->load( parameters );
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class AudioWidget : public Wt::WContainerWidget
|
|||||||
|
|
||||||
void handleTrackEnded(void);
|
void handleTrackEnded(void);
|
||||||
|
|
||||||
SessionData& _sessionData;
|
Database::Handler& _db;
|
||||||
|
|
||||||
AudioDatabaseWidget* _audioDbWidget;
|
AudioDatabaseWidget* _audioDbWidget;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
#include <Wt/WRegExpValidator>
|
|
||||||
|
|
||||||
namespace UserInterface {
|
|
||||||
|
|
||||||
static inline Wt::WValidator *createEmailValidator()
|
|
||||||
{
|
|
||||||
return new Wt::WRegExpValidator("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace UserInterface
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#include <Wt/WRegExpValidator>
|
||||||
|
#include <Wt/WLengthValidator>
|
||||||
|
|
||||||
|
#include "database/User.hpp"
|
||||||
|
|
||||||
|
namespace UserInterface {
|
||||||
|
|
||||||
|
static inline Wt::WValidator *createEmailValidator()
|
||||||
|
{
|
||||||
|
Wt::WValidator *res = new Wt::WRegExpValidator("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}");
|
||||||
|
res->setMandatory(true);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline Wt::WValidator *createNameValidator() {
|
||||||
|
Wt::WLengthValidator *v = new Wt::WLengthValidator();
|
||||||
|
v->setMandatory(true);
|
||||||
|
v->setMinimumLength(3);
|
||||||
|
v->setMaximumLength(::Database::User::MaxNameLength);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace UserInterface
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
#include <Wt/WStackedWidget>
|
#include <Wt/WStackedWidget>
|
||||||
#include <Wt/WTextArea>
|
#include <Wt/WTextArea>
|
||||||
|
|
||||||
|
#include "SettingsAudioFormView.hpp"
|
||||||
|
#include "SettingsUserFormView.hpp"
|
||||||
|
#include "SettingsAccountFormView.hpp"
|
||||||
#include "SettingsDatabaseFormView.hpp"
|
#include "SettingsDatabaseFormView.hpp"
|
||||||
#include "SettingsUsers.hpp"
|
#include "SettingsUsers.hpp"
|
||||||
|
|
||||||
@@ -28,16 +31,16 @@ _sessionData(sessionData)
|
|||||||
// Must be logged in here
|
// Must be logged in here
|
||||||
assert(user);
|
assert(user);
|
||||||
|
|
||||||
|
menu->addItem("Audio", new AudioFormView(sessionData, Database::User::getId(user)));
|
||||||
if (user->isAdmin())
|
if (user->isAdmin())
|
||||||
{
|
{
|
||||||
// TODO Special admin settings
|
|
||||||
menu->addItem("Database", new DatabaseFormView(sessionData));
|
menu->addItem("Database", new DatabaseFormView(sessionData));
|
||||||
menu->addItem("Users", new Users(sessionData));
|
menu->addItem("Users", new Users(sessionData));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// User specifics settings
|
{
|
||||||
menu->addItem("Transcoding", new Wt::WTextArea("User's transcoding settings here!"));
|
menu->addItem("Account", new AccountFormView(sessionData, Database::User::getId(user)));
|
||||||
menu->addItem("Personal", new Wt::WTextArea("User's password + mail here!"));
|
}
|
||||||
|
|
||||||
addWidget(contents);
|
addWidget(contents);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,266 @@
|
|||||||
|
#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 "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)
|
||||||
|
{
|
||||||
|
std::cerr << "Dbo exception: " << exception.what() << std::endl;
|
||||||
|
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,32 @@
|
|||||||
|
#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,178 @@
|
|||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Wt/WStringListModel>
|
||||||
|
#include <Wt/WFormModel>
|
||||||
|
#include <Wt/WComboBox>
|
||||||
|
#include <Wt/WPushButton>
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
std::cerr << "Dbo exception: " << exception.what() << std::endl;
|
||||||
|
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,32 @@
|
|||||||
|
#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
|
||||||
@@ -250,25 +250,35 @@ DatabaseFormView::DatabaseFormView(SessionData& sessionData, Wt::WContainerWidge
|
|||||||
addFunction("id", &WTemplate::Functions::id);
|
addFunction("id", &WTemplate::Functions::id);
|
||||||
addFunction("block", &WTemplate::Functions::id);
|
addFunction("block", &WTemplate::Functions::id);
|
||||||
|
|
||||||
|
applyInfo = new Wt::WText();
|
||||||
|
applyInfo->setInline(false);
|
||||||
|
applyInfo->hide();
|
||||||
|
bindWidget("apply-info", applyInfo);
|
||||||
|
|
||||||
// Path
|
// Path
|
||||||
setFormWidget(DatabaseFormModel::PathField, new Wt::WLineEdit());
|
Wt::WLineEdit *pathEdit = new Wt::WLineEdit();
|
||||||
|
setFormWidget(DatabaseFormModel::PathField, pathEdit);
|
||||||
|
pathEdit->changed().connect(applyInfo, &Wt::WWidget::hide);
|
||||||
|
|
||||||
// Update Period
|
// Update Period
|
||||||
Wt::WComboBox *updatePeriodCB = new Wt::WComboBox();
|
Wt::WComboBox *updatePeriodCB = new Wt::WComboBox();
|
||||||
setFormWidget(DatabaseFormModel::UpdatePeriodField, updatePeriodCB);
|
setFormWidget(DatabaseFormModel::UpdatePeriodField, updatePeriodCB);
|
||||||
updatePeriodCB->setModel(model->updatePeriodModel());
|
updatePeriodCB->setModel(model->updatePeriodModel());
|
||||||
|
updatePeriodCB->changed().connect(applyInfo, &Wt::WWidget::hide);
|
||||||
|
|
||||||
// Update Start Time
|
// Update Start Time
|
||||||
Wt::WComboBox *updateStartTimeCB = new Wt::WComboBox();
|
Wt::WComboBox *updateStartTimeCB = new Wt::WComboBox();
|
||||||
setFormWidget(DatabaseFormModel::UpdateStartTimeField, updateStartTimeCB);
|
setFormWidget(DatabaseFormModel::UpdateStartTimeField, updateStartTimeCB);
|
||||||
updateStartTimeCB->setModel(model->updateStartTimeModel());
|
updateStartTimeCB->setModel(model->updateStartTimeModel());
|
||||||
|
updateStartTimeCB->changed().connect(applyInfo, &Wt::WWidget::hide);
|
||||||
|
|
||||||
// Request Immediate scan
|
// Request Immediate scan
|
||||||
setFormWidget(DatabaseFormModel::UpdateRequestImmediateField, new Wt::WCheckBox());
|
Wt::WCheckBox *immScan = new Wt::WCheckBox();
|
||||||
|
setFormWidget(DatabaseFormModel::UpdateRequestImmediateField, immScan);
|
||||||
|
immScan->changed().connect(applyInfo, &Wt::WWidget::hide);
|
||||||
|
|
||||||
// Title & Buttons
|
// Title & Buttons
|
||||||
Wt::WString title = Wt::WString("Media directories settings");
|
bindString("title", "Media directories settings");
|
||||||
bindString("title", title);
|
|
||||||
|
|
||||||
Wt::WPushButton *saveButton = new Wt::WPushButton("Apply");
|
Wt::WPushButton *saveButton = new Wt::WPushButton("Apply");
|
||||||
bindWidget("apply-button", saveButton);
|
bindWidget("apply-button", saveButton);
|
||||||
@@ -277,11 +287,6 @@ DatabaseFormView::DatabaseFormView(SessionData& sessionData, Wt::WContainerWidge
|
|||||||
Wt::WPushButton *discardButton = new Wt::WPushButton("Discard");
|
Wt::WPushButton *discardButton = new Wt::WPushButton("Discard");
|
||||||
bindWidget("discard-button", discardButton);
|
bindWidget("discard-button", discardButton);
|
||||||
|
|
||||||
applyInfo = new Wt::WText();
|
|
||||||
applyInfo->setInline(false);
|
|
||||||
applyInfo->hide();
|
|
||||||
bindWidget("apply-info", applyInfo);
|
|
||||||
|
|
||||||
saveButton->clicked().connect(this, &DatabaseFormView::processSave);
|
saveButton->clicked().connect(this, &DatabaseFormView::processSave);
|
||||||
discardButton->clicked().connect(this, &DatabaseFormView::processDiscard);
|
discardButton->clicked().connect(this, &DatabaseFormView::processDiscard);
|
||||||
|
|
||||||
@@ -325,15 +330,13 @@ DatabaseFormView::processSave()
|
|||||||
|
|
||||||
applyInfo->setText( Wt::WString::fromUTF8("New parameters successfully applied!"));
|
applyInfo->setText( Wt::WString::fromUTF8("New parameters successfully applied!"));
|
||||||
applyInfo->setStyleClass("alert alert-success");
|
applyInfo->setStyleClass("alert alert-success");
|
||||||
|
}
|
||||||
// Udate the view: Delete any validation message in the view, etc.
|
else {
|
||||||
updateView(model);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
applyInfo->setText( Wt::WString::fromUTF8("Cannot apply new parameters!"));
|
applyInfo->setText( Wt::WString::fromUTF8("Cannot apply new parameters!"));
|
||||||
applyInfo->setStyleClass("alert alert-danger");
|
applyInfo->setStyleClass("alert alert-danger");
|
||||||
updateView(model);
|
|
||||||
}
|
}
|
||||||
|
// Udate the view: Delete any validation message in the view, etc.
|
||||||
|
updateView(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,20 +2,17 @@
|
|||||||
|
|
||||||
#include <Wt/WStringListModel>
|
#include <Wt/WStringListModel>
|
||||||
#include <Wt/WFormModel>
|
#include <Wt/WFormModel>
|
||||||
#include <Wt/WLengthValidator>
|
|
||||||
#include <Wt/WLineEdit>
|
#include <Wt/WLineEdit>
|
||||||
#include <Wt/WCheckBox>
|
#include <Wt/WCheckBox>
|
||||||
#include <Wt/WComboBox>
|
#include <Wt/WComboBox>
|
||||||
#include <Wt/WPushButton>
|
#include <Wt/WPushButton>
|
||||||
#include <Wt/Auth/Identity>
|
#include <Wt/Auth/Identity>
|
||||||
#include <Wt/Auth/PasswordStrengthValidator>
|
|
||||||
#include <Wt/Auth/AbstractPasswordService>
|
|
||||||
#include <Wt/Auth/PasswordVerifier>
|
|
||||||
|
|
||||||
#include "common/EmailValidator.hpp"
|
#include "common/Validators.hpp"
|
||||||
|
|
||||||
#include "SettingsUserFormView.hpp"
|
#include "SettingsUserFormView.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace UserInterface {
|
namespace UserInterface {
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
@@ -34,7 +31,7 @@ class UserFormModel : public Wt::WFormModel
|
|||||||
|
|
||||||
UserFormModel(SessionData& sessionData, std::string userId, Wt::WObject *parent = 0)
|
UserFormModel(SessionData& sessionData, std::string userId, Wt::WObject *parent = 0)
|
||||||
: Wt::WFormModel(parent),
|
: Wt::WFormModel(parent),
|
||||||
_sessionData(sessionData),
|
_db(sessionData.getDatabaseHandler()),
|
||||||
_userId(userId)
|
_userId(userId)
|
||||||
{
|
{
|
||||||
initializeModels();
|
initializeModels();
|
||||||
@@ -48,9 +45,7 @@ class UserFormModel : public Wt::WFormModel
|
|||||||
addField(VideoBitrateLimitField);
|
addField(VideoBitrateLimitField);
|
||||||
|
|
||||||
setValidator(NameField, createNameValidator());
|
setValidator(NameField, createNameValidator());
|
||||||
Wt::WValidator *emailValidator = createEmailValidator();
|
setValidator(EmailField, createEmailValidator());
|
||||||
emailValidator->setMandatory(true);
|
|
||||||
setValidator(EmailField, emailValidator);
|
|
||||||
// If creating a user, passwords are mandatory
|
// If creating a user, passwords are mandatory
|
||||||
if (_userId.empty())
|
if (_userId.empty())
|
||||||
{
|
{
|
||||||
@@ -72,67 +67,60 @@ class UserFormModel : public Wt::WFormModel
|
|||||||
|
|
||||||
if (!userId.empty())
|
if (!userId.empty())
|
||||||
{
|
{
|
||||||
Database::Handler& db = _sessionData.getDatabaseHandler();
|
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||||
|
|
||||||
Wt::Dbo::Transaction transaction(db.getSession());
|
Wt::Auth::User authUser = _db.getUserDatabase().findWithId( userId );
|
||||||
|
Database::User::pointer user = _db.getUser(authUser);
|
||||||
Wt::Auth::User authUser = db.getUserDatabase().findWithId( userId );
|
|
||||||
Database::User::pointer user = db.getUser(authUser);
|
|
||||||
|
|
||||||
Wt::Auth::User currentUser = _sessionData.getDatabaseHandler().getLogin().user();
|
|
||||||
|
|
||||||
if (user && 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Wt::Auth::User currentUser = _db.getLogin().user();
|
||||||
|
|
||||||
if (user && authUser.isValid())
|
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));
|
setValue(NameField, authUser.identity(Wt::Auth::Identity::LoginName));
|
||||||
if (!authUser.email().empty())
|
if (!authUser.email().empty())
|
||||||
setValue(EmailField, authUser.email());
|
setValue(EmailField, authUser.email());
|
||||||
else
|
else
|
||||||
setValue(EmailField, authUser.unverifiedEmail());
|
setValue(EmailField, authUser.unverifiedEmail());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user)
|
|
||||||
{
|
|
||||||
setValue(AudioBitrateLimitField, user->getMaxAudioBitrate() / 1000); // in kbps
|
|
||||||
setValue(VideoBitrateLimitField, user->getMaxVideoBitrate() / 1000); // in kbps
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool saveData()
|
bool saveData()
|
||||||
{
|
{
|
||||||
// DBO transaction active here
|
|
||||||
try {
|
try {
|
||||||
Database::Handler& db = _sessionData.getDatabaseHandler();
|
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||||
Wt::Dbo::Transaction transaction(db.getSession());
|
|
||||||
|
|
||||||
if (_userId.empty())
|
if (_userId.empty())
|
||||||
{
|
{
|
||||||
// Create user
|
// Create user
|
||||||
Wt::Auth::User authUser = db.getUserDatabase().registerNew();
|
Wt::Auth::User authUser = _db.getUserDatabase().registerNew();
|
||||||
Database::User::pointer user = db.getUser(authUser);
|
Database::User::pointer user = _db.getUser(authUser);
|
||||||
|
|
||||||
// Account
|
// Account
|
||||||
authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(NameField));
|
authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(NameField));
|
||||||
authUser.setEmail(valueText(EmailField).toUTF8());
|
authUser.setEmail(valueText(EmailField).toUTF8());
|
||||||
db.getPasswordService().updatePassword(authUser, valueText(PasswordField));
|
Database::Handler::getPasswordService().updatePassword(authUser, valueText(PasswordField));
|
||||||
|
|
||||||
// Access
|
// Access
|
||||||
{
|
{
|
||||||
@@ -153,10 +141,9 @@ class UserFormModel : public Wt::WFormModel
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
// Update user
|
// Update user
|
||||||
Wt::Auth::User authUser = db.getUserDatabase().findWithId(_userId);
|
Wt::Auth::User authUser = _db.getUserDatabase().findWithId(_userId);
|
||||||
Database::User::pointer user = db.getUser( authUser );
|
Database::User::pointer user = _db.getUser( authUser );
|
||||||
|
|
||||||
// user may have been deleted by someone else
|
// user may have been deleted by someone else
|
||||||
if (!authUser.isValid()) {
|
if (!authUser.isValid()) {
|
||||||
@@ -175,7 +162,7 @@ class UserFormModel : public Wt::WFormModel
|
|||||||
|
|
||||||
// Password
|
// Password
|
||||||
if (!valueText(PasswordField).empty())
|
if (!valueText(PasswordField).empty())
|
||||||
db.getPasswordService().updatePassword(authUser, valueText(PasswordField));
|
Database::Handler::getPasswordService().updatePassword(authUser, valueText(PasswordField));
|
||||||
|
|
||||||
// Access
|
// Access
|
||||||
if (!isReadOnly(AdminField))
|
if (!isReadOnly(AdminField))
|
||||||
@@ -207,15 +194,13 @@ class UserFormModel : public Wt::WFormModel
|
|||||||
|
|
||||||
bool validateField(Field field)
|
bool validateField(Field field)
|
||||||
{
|
{
|
||||||
// DBO transaction active here
|
|
||||||
|
|
||||||
Wt::WString error;
|
Wt::WString error;
|
||||||
|
|
||||||
if (field == NameField)
|
if (field == NameField)
|
||||||
{
|
{
|
||||||
Wt::Dbo::Transaction transaction(_sessionData.getDatabaseHandler().getSession());
|
Wt::Dbo::Transaction transaction(_db.getSession());
|
||||||
// Must be unique since used as LoginIdentity
|
// Must be unique since used as LoginIdentity
|
||||||
Wt::Auth::User user = _sessionData.getDatabaseHandler().getUserDatabase().findWithIdentity(Wt::Auth::Identity::LoginName, valueText(field));
|
Wt::Auth::User user = _db.getUserDatabase().findWithIdentity(Wt::Auth::Identity::LoginName, valueText(field));
|
||||||
if (user.isValid() && user.id() != _userId)
|
if (user.isValid() && user.id() != _userId)
|
||||||
error = "Already exists";
|
error = "Already exists";
|
||||||
else
|
else
|
||||||
@@ -227,17 +212,10 @@ class UserFormModel : public Wt::WFormModel
|
|||||||
if (!valueText(PasswordField).empty())
|
if (!valueText(PasswordField).empty())
|
||||||
{
|
{
|
||||||
// Evaluate the strength of the password
|
// Evaluate the strength of the password
|
||||||
Wt::Auth::PasswordStrengthValidator validator;
|
|
||||||
|
|
||||||
// Reduce some constraints...
|
|
||||||
validator.setMinimumLength( Wt::Auth::PasswordStrengthValidator::TwoCharClass, 11);
|
|
||||||
validator.setMinimumLength( Wt::Auth::PasswordStrengthValidator::ThreeCharClass, 8 );
|
|
||||||
validator.setMinimumLength( Wt::Auth::PasswordStrengthValidator::FourCharClass, 6 );
|
|
||||||
|
|
||||||
Wt::Auth::AbstractPasswordService::StrengthValidatorResult res
|
Wt::Auth::AbstractPasswordService::StrengthValidatorResult res
|
||||||
= validator.evaluateStrength(valueText(PasswordField),
|
= Database::Handler::getPasswordService().strengthValidator()->evaluateStrength(valueText(PasswordField),
|
||||||
valueText(NameField),
|
valueText(NameField),
|
||||||
valueText(EmailField).toUTF8());
|
valueText(EmailField).toUTF8());
|
||||||
|
|
||||||
if (!res.isValid())
|
if (!res.isValid())
|
||||||
error = res.message();
|
error = res.message();
|
||||||
@@ -267,58 +245,21 @@ class UserFormModel : public Wt::WFormModel
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static Wt::WValidator *createNameValidator() {
|
|
||||||
Wt::WLengthValidator *v = new Wt::WLengthValidator();
|
|
||||||
v->setMandatory(true);
|
|
||||||
v->setMinimumLength(3);
|
|
||||||
v->setMaximumLength(::Database::User::MaxNameLength);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initializeModels()
|
void initializeModels()
|
||||||
{
|
{
|
||||||
|
|
||||||
// AUDIO
|
// AUDIO
|
||||||
// TODO move defaults somewhere else?
|
|
||||||
static const std::vector<std::size_t>
|
|
||||||
audioBitrateLimits =
|
|
||||||
{
|
|
||||||
64,
|
|
||||||
96,
|
|
||||||
128,
|
|
||||||
160,
|
|
||||||
192,
|
|
||||||
224,
|
|
||||||
256,
|
|
||||||
320,
|
|
||||||
512
|
|
||||||
};
|
|
||||||
|
|
||||||
_audioBitrateModel = new Wt::WStringListModel();
|
_audioBitrateModel = new Wt::WStringListModel();
|
||||||
for (std::size_t i = 0; i < audioBitrateLimits.size(); ++i)
|
BOOST_FOREACH(std::size_t bitrate, Database::User::audioBitrates)
|
||||||
_audioBitrateModel->addString( Wt::WString("{1}").arg( audioBitrateLimits[i] ) );
|
_audioBitrateModel->addString( Wt::WString("{1}").arg( bitrate / 1000 ) ); // in kbps
|
||||||
|
|
||||||
|
|
||||||
// VIDEO
|
// VIDEO
|
||||||
// TODO move defaults somewhere else?
|
|
||||||
static const std::vector<std::size_t>
|
|
||||||
videoBitrateLimits =
|
|
||||||
{
|
|
||||||
256,
|
|
||||||
512,
|
|
||||||
1024,
|
|
||||||
2048,
|
|
||||||
4096,
|
|
||||||
8192
|
|
||||||
};
|
|
||||||
|
|
||||||
_videoBitrateModel = new Wt::WStringListModel();
|
_videoBitrateModel = new Wt::WStringListModel();
|
||||||
for (std::size_t i = 0; i < videoBitrateLimits.size(); ++i)
|
BOOST_FOREACH(std::size_t bitrate, Database::User::videoBitrates)
|
||||||
_videoBitrateModel->addString( Wt::WString("{1}").arg( videoBitrateLimits[i] ) );
|
_videoBitrateModel->addString( Wt::WString("{1}").arg( bitrate / 1000 ) ); // in kbps
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionData& _sessionData;
|
Database::Handler& _db;
|
||||||
std::string _userId;
|
std::string _userId;
|
||||||
Wt::WStringListModel* _audioBitrateModel;
|
Wt::WStringListModel* _audioBitrateModel;
|
||||||
Wt::WStringListModel* _videoBitrateModel;
|
Wt::WStringListModel* _videoBitrateModel;
|
||||||
@@ -334,8 +275,7 @@ const Wt::WFormModel::Field UserFormModel::VideoBitrateLimitField = "video-bitra
|
|||||||
|
|
||||||
|
|
||||||
UserFormView::UserFormView(SessionData& sessionData, std::string userId, Wt::WContainerWidget *parent)
|
UserFormView::UserFormView(SessionData& sessionData, std::string userId, Wt::WContainerWidget *parent)
|
||||||
: Wt::WTemplateFormView(parent),
|
: Wt::WTemplateFormView(parent)
|
||||||
_sessionData(sessionData)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
_model = new UserFormModel(sessionData, userId, this);
|
_model = new UserFormModel(sessionData, userId, this);
|
||||||
@@ -360,9 +300,10 @@ UserFormView::UserFormView(SessionData& sessionData, std::string userId, Wt::WCo
|
|||||||
setFormWidget(UserFormModel::PasswordConfirmField, passwordConfirmEdit);
|
setFormWidget(UserFormModel::PasswordConfirmField, passwordConfirmEdit);
|
||||||
passwordConfirmEdit->setEchoMode(Wt::WLineEdit::Password);
|
passwordConfirmEdit->setEchoMode(Wt::WLineEdit::Password);
|
||||||
|
|
||||||
|
bindString("access", "Access");
|
||||||
|
|
||||||
// Admin Field
|
// Admin Field
|
||||||
Wt::WCheckBox *admin = new Wt::WCheckBox();
|
setFormWidget(UserFormModel::AdminField, new Wt::WCheckBox());
|
||||||
setFormWidget(UserFormModel::AdminField, admin);
|
|
||||||
|
|
||||||
// AudioBitrate
|
// AudioBitrate
|
||||||
Wt::WComboBox *audioBitrateCB = new Wt::WComboBox();
|
Wt::WComboBox *audioBitrateCB = new Wt::WComboBox();
|
||||||
@@ -418,7 +359,7 @@ UserFormView::UserFormView(SessionData& sessionData, std::string userId, Wt::WCo
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UserFormView::processCancel()
|
UserFormView::processCancel()
|
||||||
{
|
{
|
||||||
// parent widget will delete this widget
|
// parent widget will delete this widget
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class UserFormModel;
|
|||||||
class UserFormView : public Wt::WTemplateFormView
|
class UserFormView : public Wt::WTemplateFormView
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
UserFormView(SessionData& sessionData, std::string userId, Wt::WContainerWidget *parent = 0);
|
UserFormView(SessionData& sessionData, std::string userId, Wt::WContainerWidget *parent = 0);
|
||||||
|
|
||||||
// Signal emitted once the form is completed
|
// Signal emitted once the form is completed
|
||||||
@@ -24,8 +25,6 @@ class UserFormView : public Wt::WTemplateFormView
|
|||||||
|
|
||||||
Wt::Signal<bool> _sigCompleted;
|
Wt::Signal<bool> _sigCompleted;
|
||||||
|
|
||||||
SessionData& _sessionData;
|
|
||||||
|
|
||||||
void processSave();
|
void processSave();
|
||||||
void processCancel();
|
void processCancel();
|
||||||
|
|
||||||
|
|||||||
@@ -67,11 +67,7 @@ Users::refresh(void)
|
|||||||
for (std::size_t i = 0; i < users.size(); ++i)
|
for (std::size_t i = 0; i < users.size(); ++i)
|
||||||
{
|
{
|
||||||
|
|
||||||
std::string userId;
|
std::string userId = Database::User::getId(users[i]);
|
||||||
{
|
|
||||||
std::ostringstream oss; oss << users[i].id();
|
|
||||||
userId = oss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
Wt::Auth::User authUser;
|
Wt::Auth::User authUser;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user