Added demo account support

This commit is contained in:
emeric
2018-08-01 12:57:03 +02:00
parent a31fb3c062
commit 4cadb915ba
11 changed files with 124 additions and 34 deletions
+16 -4
View File
@@ -33,19 +33,31 @@
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-2" for="${id:audio-bitrate-limit}"> <label class="control-label col-sm-2" for="${id:audio-bitrate-limit}">
Audio Bitrate Limit ${tr:Lms.Admin.User.audio-bitrate-limit}
</label> </label>
<div class="col-sm-5"> <div class="col-sm-5">
<div class="input-group"> <div class="input-group">
${audio-bitrate-limit} ${audio-bitrate-limit}
<span class="input-group-addon">kbps</span> <span class="input-group-addon">kbps</span>
</div> </div>
</div> </div>
<div class="help-block col-sm-5"> <div class="help-block col-sm-5">
${audio-bitrate-limit-info} ${audio-bitrate-limit-info}
</div> </div>
</div> </div>
${<if-demo>}
<div class="form-group">
<label class="control-label col-sm-2" for="${id:demo}">
${tr:Lms.Admin.User.demo-account}
</label>
<div class="col-sm-5">
${demo}
</div>
<div class="help-block col-sm-5">
${demo-info}
</div>
</div>
${</if-demo>}
<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-btn class="btn-primary"} ${save-btn class="btn-primary"}
+1 -1
View File
@@ -11,7 +11,7 @@
<message id="Lms.Admin.Users.template.entry"> <message id="Lms.Admin.Users.template.entry">
<div class="list-group-item"> <div class="list-group-item">
${name} ${<if-edit>}${edit-btn} ${del-btn class="btn-danger"}${</if-edit>} ${name} ${<if-tag>}<span class="badge">${tag}</span>${</if-tag>} ${<if-edit>}${edit-btn} ${del-btn class="btn-danger"}${</if-edit>}
</div> </div>
</message> </message>
+8
View File
@@ -36,10 +36,17 @@
<!--Users--> <!--Users-->
<message id="Lms.Admin.Users.add">New user</message> <message id="Lms.Admin.Users.add">New user</message>
<message id="Lms.Admin.Users.admin">Admin</message>
<message id="Lms.Admin.Users.del">Delete</message> <message id="Lms.Admin.Users.del">Delete</message>
<message id="Lms.Admin.Users.demo">Demo</message>
<message id="Lms.Admin.Users.edit">Edit</message> <message id="Lms.Admin.Users.edit">Edit</message>
<message id="Lms.Admin.Users.users">Users</message> <message id="Lms.Admin.Users.users">Users</message>
<!--User-->
<message id="Lms.Admin.User.audio-bitrate-limit">Audio bitrate limit</message>
<message id="Lms.Admin.User.demo-account">Demo account</message>
<message id="Lms.Admin.User.demo-account-already-exists">Demo account already exists!</message>
<message id="Lms.Admin.User.demo-password-invalid">Demo password must be the login name!</message>
<message id="Lms.Admin.User.user-already-exists">User already exists!</message> <message id="Lms.Admin.User.user-already-exists">User already exists!</message>
<message id="Lms.Admin.User.user-create">New user</message> <message id="Lms.Admin.User.user-create">New user</message>
<message id="Lms.Admin.User.user-created">New user created!</message> <message id="Lms.Admin.User.user-created">New user created!</message>
@@ -83,6 +90,7 @@
<message id="Lms.Settings.audio">Audio</message> <message id="Lms.Settings.audio">Audio</message>
<message id="Lms.Settings.auto">Auto</message> <message id="Lms.Settings.auto">Auto</message>
<message id="Lms.Settings.bitrate">Bitrate</message> <message id="Lms.Settings.bitrate">Bitrate</message>
<message id="Lms.Settings.demo-cannot-save">Cannot save using a demo account!</message>
<message id="Lms.Settings.encoding">Encoding</message> <message id="Lms.Settings.encoding">Encoding</message>
<message id="Lms.Settings.mp3">MP3</message> <message id="Lms.Settings.mp3">MP3</message>
<message id="Lms.Settings.oga">OGA</message> <message id="Lms.Settings.oga">OGA</message>
+2 -1
View File
@@ -20,4 +20,5 @@ wt-resources="/usr/share/Wt/resources";
docroot = "/usr/share/lms/docroot/;/resources,/css,/images,/js,/favicon.ico"; docroot = "/usr/share/lms/docroot/;/resources,/css,/images,/js,/favicon.ico";
approot = "/usr/share/lms/approot"; approot = "/usr/share/lms/approot";
# Turn on this option to allow the demo account creation/use
#demo = false;
+9 -2
View File
@@ -33,7 +33,7 @@ User::audioBitrates =
User::User() User::User()
: _maxAudioBitrate(audioBitrates.back()), : _maxAudioBitrate(audioBitrates.back()),
_isAdmin(false), _type(Type::REGULAR),
_audioBitrate(defaultAudioBitrate), _audioBitrate(defaultAudioBitrate),
_audioEncoding(AudioEncoding::AUTO), _audioEncoding(AudioEncoding::AUTO),
_curPlayingTrackPos(0) _curPlayingTrackPos(0)
@@ -48,6 +48,13 @@ User::getAll(Wt::Dbo::Session& session)
return std::vector<pointer>(res.begin(), res.end()); return std::vector<pointer>(res.begin(), res.end());
} }
User::pointer
User::getDemo(Wt::Dbo::Session& session)
{
pointer res = session.find<User>().where("type = ?").bind(Type::DEMO);
return res;
}
User::pointer User::pointer
User::create(Wt::Dbo::Session& session) User::create(Wt::Dbo::Session& session)
{ {
@@ -55,7 +62,7 @@ User::create(Wt::Dbo::Session& session)
} }
User::pointer User::pointer
User::getById(Wt::Dbo::Session& session, id_type id) User::getById(Wt::Dbo::Session& session, IdType id)
{ {
return session.find<User>().where("id = ?").bind( id ); return session.find<User>().where("id = ?").bind( id );
} }
+17 -7
View File
@@ -24,6 +24,8 @@
#include <Wt/Dbo/Dbo.h> #include <Wt/Dbo/Dbo.h>
#include <Wt/Auth/Dbo/AuthInfo.h> #include <Wt/Auth/Dbo/AuthInfo.h>
#include "Types.hpp"
namespace Database { namespace Database {
class User; class User;
@@ -43,12 +45,18 @@ enum class AudioEncoding
class User : public Wt::Dbo::Dbo<User> class User : public Wt::Dbo::Dbo<User>
{ {
public: public:
typedef Wt::Dbo::dbo_traits<User>::IdType id_type; using pointer = Wt::Dbo::ptr<User>;
typedef Wt::Dbo::ptr<User> pointer;
static const std::size_t MinNameLength = 3; static const std::size_t MinNameLength = 3;
static const std::size_t MaxNameLength = 15; static const std::size_t MaxNameLength = 15;
enum class Type
{
REGULAR,
ADMIN,
DEMO
};
// list of audio parameters // list of audio parameters
static const std::vector<std::size_t> audioBitrates; static const std::vector<std::size_t> audioBitrates;
@@ -58,18 +66,20 @@ class User : public Wt::Dbo::Dbo<User>
static pointer create(Wt::Dbo::Session& session); static pointer create(Wt::Dbo::Session& session);
// accessors // accessors
static pointer getById(Wt::Dbo::Session& session, id_type id); static pointer getById(Wt::Dbo::Session& session, IdType id);
static std::vector<pointer> getAll(Wt::Dbo::Session& session); static std::vector<pointer> getAll(Wt::Dbo::Session& session);
static pointer getDemo(Wt::Dbo::Session& session);
// write // write
void setAdmin(bool admin) { _isAdmin = admin; } void setType(Type type) { _type = type; }
void setAudioBitrate(std::size_t bitrate); void setAudioBitrate(std::size_t bitrate);
void setAudioEncoding(AudioEncoding encoding) { _audioEncoding = encoding; } void setAudioEncoding(AudioEncoding encoding) { _audioEncoding = encoding; }
void setMaxAudioBitrate(std::size_t bitrate); void setMaxAudioBitrate(std::size_t bitrate);
void setCurPlayingTrackPos(std::size_t pos) { _curPlayingTrackPos = pos; } void setCurPlayingTrackPos(std::size_t pos) { _curPlayingTrackPos = pos; }
// read // read
bool isAdmin() const { return _isAdmin; } bool isAdmin() const { return _type == Type::ADMIN; }
bool isDemo() const { return _type == Type::DEMO; }
std::size_t getAudioBitrate() const; std::size_t getAudioBitrate() const;
AudioEncoding getAudioEncoding() const { return _audioEncoding; } AudioEncoding getAudioEncoding() const { return _audioEncoding; }
std::size_t getMaxAudioBitrate() const; std::size_t getMaxAudioBitrate() const;
@@ -79,7 +89,7 @@ class User : public Wt::Dbo::Dbo<User>
void persist(Action& a) void persist(Action& a)
{ {
Wt::Dbo::field(a, _maxAudioBitrate, "max_audio_bitrate"); Wt::Dbo::field(a, _maxAudioBitrate, "max_audio_bitrate");
Wt::Dbo::field(a, _isAdmin, "admin"); Wt::Dbo::field(a, _type, "type");
Wt::Dbo::field(a, _audioBitrate, "audio_bitrate"); Wt::Dbo::field(a, _audioBitrate, "audio_bitrate");
Wt::Dbo::field(a, _audioEncoding, "audio_encoding"); Wt::Dbo::field(a, _audioEncoding, "audio_encoding");
// User's dynamic data // User's dynamic data
@@ -93,7 +103,7 @@ class User : public Wt::Dbo::Dbo<User>
// Admin defined settings // Admin defined settings
int _maxAudioBitrate; int _maxAudioBitrate;
bool _isAdmin; Type _type;
// User defined settings // User defined settings
int _audioBitrate; int _audioBitrate;
+12
View File
@@ -40,6 +40,18 @@ Auth::Auth()
// LoginName // LoginName
setFormWidget(Wt::Auth::AuthModel::LoginNameField, std::make_unique<Wt::WLineEdit>()); setFormWidget(Wt::Auth::AuthModel::LoginNameField, std::make_unique<Wt::WLineEdit>());
{
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
auto demoUser = Database::User::getDemo(LmsApp->getDboSession());
if (demoUser)
{
Wt::Auth::User authUser = LmsApp->getDb().getUserDatabase().findWithId(std::to_string(demoUser.id()));
_model->setValue(Wt::Auth::AuthModel::LoginNameField, authUser.identity(Wt::Auth::Identity::LoginName));
_model->setValue(Wt::Auth::AuthModel::PasswordField, authUser.identity(Wt::Auth::Identity::LoginName));
}
}
// Password // Password
auto password = std::make_unique<Wt::WLineEdit>(); auto password = std::make_unique<Wt::WLineEdit>();
password->setEchoMode(Wt::EchoMode::Password); password->setEchoMode(Wt::EchoMode::Password);
+11
View File
@@ -295,6 +295,17 @@ SettingsView::refreshView()
saveBtn->clicked().connect(std::bind([=] () saveBtn->clicked().connect(std::bind([=] ()
{ {
{
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
if (LmsApp->getUser()->isDemo())
{
LmsApp->notifyMsg(Wt::WString::tr("Lms.Settings.demo-cannot-save"));
return;
}
}
t->updateModel(model.get()); t->updateModel(model.get());
if (model->validate()) if (model->validate())
+1 -1
View File
@@ -69,7 +69,7 @@ class InitWizardModel : public Wt::WFormModel
authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(AdminLoginField)); authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(AdminLoginField));
Database::Handler::getPasswordService().updatePassword(authUser, valueText(PasswordField)); Database::Handler::getPasswordService().updatePassword(authUser, valueText(PasswordField));
user.modify()->setAdmin( true ); user.modify()->setType(Database::User::Type::ADMIN);
} }
bool validateField(Field field) bool validateField(Field field)
+40 -18
View File
@@ -30,6 +30,7 @@
#include <Wt/WStringListModel.h> #include <Wt/WStringListModel.h>
#include "common/Validators.hpp" #include "common/Validators.hpp"
#include "utils/Config.hpp"
#include "utils/Exception.hpp" #include "utils/Exception.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "utils/Utils.hpp" #include "utils/Utils.hpp"
@@ -45,8 +46,9 @@ class UserModel : public Wt::WFormModel
static const Field LoginField; static const Field LoginField;
static const Field PasswordField; static const Field PasswordField;
static const Field BitrateLimitField; static const Field BitrateLimitField;
static const Field DemoField;
UserModel(boost::optional<Database::User::id_type> userId) UserModel(boost::optional<Database::IdType> userId)
: Wt::WFormModel(), : Wt::WFormModel(),
_userId(userId) _userId(userId)
{ {
@@ -58,7 +60,7 @@ class UserModel : public Wt::WFormModel
addField(PasswordField); addField(PasswordField);
addField(BitrateLimitField); addField(BitrateLimitField);
addField(DemoField);
if (!_userId) if (!_userId)
setValidator(PasswordField, createMandatoryValidator()); setValidator(PasswordField, createMandatoryValidator());
@@ -76,8 +78,8 @@ class UserModel : public Wt::WFormModel
Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
Wt::Auth::User authUser = LmsApp->getDb().getUserDatabase().findWithId( std::to_string(*_userId) ); auto authUser = LmsApp->getDb().getUserDatabase().findWithId( std::to_string(*_userId) );
Database::User::pointer user = LmsApp->getDb().getUser(authUser); auto user = LmsApp->getDb().getUser(authUser);
if (user == LmsApp->getUser()) if (user == LmsApp->getUser())
throw LmsException("Cannot edit ourselves"); throw LmsException("Cannot edit ourselves");
@@ -117,6 +119,9 @@ class UserModel : public Wt::WFormModel
auto bitrateLimitRow = getBitrateLimitRow(Wt::asString(value(BitrateLimitField))); auto bitrateLimitRow = getBitrateLimitRow(Wt::asString(value(BitrateLimitField)));
user.modify()->setMaxAudioBitrate(bitrateLimit(*bitrateLimitRow)); user.modify()->setMaxAudioBitrate(bitrateLimit(*bitrateLimitRow));
if (Wt::asNumber(value(DemoField)))
user.modify()->setType(Database::User::Type::DEMO);
} }
} }
@@ -140,30 +145,41 @@ class UserModel : public Wt::WFormModel
auto user = LmsApp->getDb().getUserDatabase().findWithIdentity(Wt::Auth::Identity::LoginName, valueText(LoginField)); auto user = LmsApp->getDb().getUserDatabase().findWithIdentity(Wt::Auth::Identity::LoginName, valueText(LoginField));
if (user.isValid()) if (user.isValid())
error = Wt::WString::tr("Lms.Admin.User.user-already-exists"); error = Wt::WString::tr("Lms.Admin.User.user-already-exists");
else
return Wt::WFormModel::validateField(field);
} }
else if (field == PasswordField) else if (field == PasswordField)
{ {
if (!valueText(PasswordField).empty()) if (!valueText(PasswordField).empty())
{ {
// Evaluate the strength of the password if (Wt::asNumber(value(DemoField)))
auto res = Database::Handler::getPasswordService().strengthValidator()->evaluateStrength(valueText(PasswordField), getLogin(), ""); {
//Demo account: password must be the same as the login name
if (valueText(PasswordField) != getLogin())
error = Wt::WString::tr("Lms.Admin.User.demo-password-invalid");
}
else
{
// Evaluate the strength of the password for non demo accounts
auto res = Database::Handler::getPasswordService().strengthValidator()->evaluateStrength(valueText(PasswordField), getLogin(), "");
if (!res.isValid()) if (!res.isValid())
error = res.message(); error = res.message();
}
} }
else
return Wt::WFormModel::validateField(field);
} }
else else if (field == DemoField)
{ {
return Wt::WFormModel::validateField(field); Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
if (Wt::asNumber(value(DemoField)) && Database::User::getDemo(LmsApp->getDboSession()))
error = Wt::WString::tr("Lms.Admin.User.demo-account-already-exists");
} }
setValidation(field, Wt::WValidator::Result( error.empty() ? Wt::ValidationState::Valid : Wt::ValidationState::Invalid, error)); if (error.empty())
return Wt::WFormModel::validateField(field);
return (validation(field).state() == Wt::ValidationState::Valid); setValidation(field, Wt::WValidator::Result( Wt::ValidationState::Invalid, error));
return false;
} }
boost::optional<int> getBitrateLimitRow(Wt::WString value) boost::optional<int> getBitrateLimitRow(Wt::WString value)
@@ -219,12 +235,13 @@ class UserModel : public Wt::WFormModel
} }
std::shared_ptr<Wt::WStringListModel> _bitrateModel; std::shared_ptr<Wt::WStringListModel> _bitrateModel;
boost::optional<Database::User::id_type> _userId; boost::optional<Database::IdType> _userId;
}; };
const Wt::WFormModel::Field UserModel::LoginField = "login"; const Wt::WFormModel::Field UserModel::LoginField = "login";
const Wt::WFormModel::Field UserModel::PasswordField = "password"; const Wt::WFormModel::Field UserModel::PasswordField = "password";
const Wt::WFormModel::Field UserModel::BitrateLimitField = "audio-bitrate-limit"; const Wt::WFormModel::Field UserModel::BitrateLimitField = "audio-bitrate-limit";
const Wt::WFormModel::Field UserModel::DemoField = "demo";
UserView::UserView() UserView::UserView()
{ {
@@ -242,7 +259,7 @@ UserView::refreshView()
if (!wApp->internalPathMatches("/admin/user")) if (!wApp->internalPathMatches("/admin/user"))
return; return;
auto userId = readAs<Database::User::id_type>(wApp->internalPathNextPart("/admin/user/")); auto userId = readAs<Database::IdType>(wApp->internalPathNextPart("/admin/user/"));
LMS_LOG(UI, DEBUG) << "userId = " << (userId ? std::to_string(*userId) : "none"); LMS_LOG(UI, DEBUG) << "userId = " << (userId ? std::to_string(*userId) : "none");
@@ -276,6 +293,11 @@ UserView::refreshView()
bitrate->setModel(model->bitrateModel()); bitrate->setModel(model->bitrateModel());
t->setFormWidget(UserModel::BitrateLimitField, std::move(bitrate)); t->setFormWidget(UserModel::BitrateLimitField, std::move(bitrate));
// Demo account
t->setFormWidget(UserModel::DemoField, std::make_unique<Wt::WCheckBox>());
if (!userId && Config::instance().getBool("demo", false))
t->setCondition("if-demo", true);
Wt::WPushButton* saveBtn = t->bindNew<Wt::WPushButton>("save-btn", Wt::WString::tr(userId ? "Lms.save" : "Lms.create")); Wt::WPushButton* saveBtn = t->bindNew<Wt::WPushButton>("save-btn", Wt::WString::tr(userId ? "Lms.save" : "Lms.create"));
saveBtn->clicked().connect(std::bind([=] saveBtn->clicked().connect(std::bind([=]
{ {
+7
View File
@@ -74,6 +74,13 @@ UsersView::refreshView()
entry->bindString("name", authUser.identity(Wt::Auth::Identity::LoginName), Wt::TextFormat::Plain); entry->bindString("name", authUser.identity(Wt::Auth::Identity::LoginName), Wt::TextFormat::Plain);
// Create tag
if (user->isAdmin() || user->isDemo())
{
entry->setCondition("if-tag", true);
entry->bindString("tag", Wt::WString::tr(user->isAdmin() ? "Lms.Admin.Users.admin" : "Lms.Admin.Users.demo"));
}
// Don't edit ourself this way // Don't edit ourself this way
if (LmsApp->getUser() == user) if (LmsApp->getUser() == user)
continue; continue;