${save-btn class="btn-primary"}
diff --git a/approot/admin-users.xml b/approot/admin-users.xml
index be2e36d9..481a79bd 100644
--- a/approot/admin-users.xml
+++ b/approot/admin-users.xml
@@ -11,7 +11,7 @@
- ${name} ${}${edit-btn} ${del-btn class="btn-danger"}${}
+ ${name} ${}${tag}${} ${}${edit-btn} ${del-btn class="btn-danger"}${}
diff --git a/approot/messages.xml b/approot/messages.xml
index 1912f986..561a2f49 100644
--- a/approot/messages.xml
+++ b/approot/messages.xml
@@ -36,10 +36,17 @@
New user
+
Admin
Delete
+
Demo
Edit
Users
+
+
Audio bitrate limit
+
Demo account
+
Demo account already exists!
+
Demo password must be the login name!
User already exists!
New user
New user created!
@@ -83,6 +90,7 @@
Audio
Auto
Bitrate
+
Cannot save using a demo account!
Encoding
MP3
OGA
diff --git a/conf/lms.conf b/conf/lms.conf
index 3d9b06f5..4c8acc54 100644
--- a/conf/lms.conf
+++ b/conf/lms.conf
@@ -20,4 +20,5 @@ wt-resources="/usr/share/Wt/resources";
docroot = "/usr/share/lms/docroot/;/resources,/css,/images,/js,/favicon.ico";
approot = "/usr/share/lms/approot";
-
+# Turn on this option to allow the demo account creation/use
+#demo = false;
diff --git a/src/database/User.cpp b/src/database/User.cpp
index dd8ed1dd..b687572f 100644
--- a/src/database/User.cpp
+++ b/src/database/User.cpp
@@ -33,7 +33,7 @@ User::audioBitrates =
User::User()
: _maxAudioBitrate(audioBitrates.back()),
-_isAdmin(false),
+_type(Type::REGULAR),
_audioBitrate(defaultAudioBitrate),
_audioEncoding(AudioEncoding::AUTO),
_curPlayingTrackPos(0)
@@ -48,6 +48,13 @@ User::getAll(Wt::Dbo::Session& session)
return std::vector
(res.begin(), res.end());
}
+User::pointer
+User::getDemo(Wt::Dbo::Session& session)
+{
+ pointer res = session.find().where("type = ?").bind(Type::DEMO);
+ return res;
+}
+
User::pointer
User::create(Wt::Dbo::Session& session)
{
@@ -55,7 +62,7 @@ User::create(Wt::Dbo::Session& session)
}
User::pointer
-User::getById(Wt::Dbo::Session& session, id_type id)
+User::getById(Wt::Dbo::Session& session, IdType id)
{
return session.find().where("id = ?").bind( id );
}
diff --git a/src/database/User.hpp b/src/database/User.hpp
index 325b11a9..fd536172 100644
--- a/src/database/User.hpp
+++ b/src/database/User.hpp
@@ -24,6 +24,8 @@
#include
#include
+#include "Types.hpp"
+
namespace Database {
class User;
@@ -43,12 +45,18 @@ enum class AudioEncoding
class User : public Wt::Dbo::Dbo
{
public:
- typedef Wt::Dbo::dbo_traits::IdType id_type;
- typedef Wt::Dbo::ptr pointer;
+ using pointer = Wt::Dbo::ptr;
static const std::size_t MinNameLength = 3;
static const std::size_t MaxNameLength = 15;
+ enum class Type
+ {
+ REGULAR,
+ ADMIN,
+ DEMO
+ };
+
// list of audio parameters
static const std::vector audioBitrates;
@@ -58,18 +66,20 @@ class User : public Wt::Dbo::Dbo
static pointer create(Wt::Dbo::Session& session);
// accessors
- static pointer getById(Wt::Dbo::Session& session, id_type id);
+ static pointer getById(Wt::Dbo::Session& session, IdType id);
static std::vector getAll(Wt::Dbo::Session& session);
+ static pointer getDemo(Wt::Dbo::Session& session);
// write
- void setAdmin(bool admin) { _isAdmin = admin; }
+ void setType(Type type) { _type = type; }
void setAudioBitrate(std::size_t bitrate);
void setAudioEncoding(AudioEncoding encoding) { _audioEncoding = encoding; }
void setMaxAudioBitrate(std::size_t bitrate);
void setCurPlayingTrackPos(std::size_t pos) { _curPlayingTrackPos = pos; }
// 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;
AudioEncoding getAudioEncoding() const { return _audioEncoding; }
std::size_t getMaxAudioBitrate() const;
@@ -79,7 +89,7 @@ class User : public Wt::Dbo::Dbo
void persist(Action& a)
{
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, _audioEncoding, "audio_encoding");
// User's dynamic data
@@ -93,7 +103,7 @@ class User : public Wt::Dbo::Dbo
// Admin defined settings
int _maxAudioBitrate;
- bool _isAdmin;
+ Type _type;
// User defined settings
int _audioBitrate;
diff --git a/src/ui/Auth.cpp b/src/ui/Auth.cpp
index c2837d2c..c3f4d4b5 100644
--- a/src/ui/Auth.cpp
+++ b/src/ui/Auth.cpp
@@ -40,6 +40,18 @@ Auth::Auth()
// LoginName
setFormWidget(Wt::Auth::AuthModel::LoginNameField, std::make_unique());
+ {
+ 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
auto password = std::make_unique();
password->setEchoMode(Wt::EchoMode::Password);
diff --git a/src/ui/SettingsView.cpp b/src/ui/SettingsView.cpp
index 5fbcb668..f6c7a8eb 100644
--- a/src/ui/SettingsView.cpp
+++ b/src/ui/SettingsView.cpp
@@ -295,6 +295,17 @@ SettingsView::refreshView()
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());
if (model->validate())
diff --git a/src/ui/admin/InitWizardView.cpp b/src/ui/admin/InitWizardView.cpp
index bbc97b0f..4bf99a02 100644
--- a/src/ui/admin/InitWizardView.cpp
+++ b/src/ui/admin/InitWizardView.cpp
@@ -69,7 +69,7 @@ class InitWizardModel : public Wt::WFormModel
authUser.setIdentity(Wt::Auth::Identity::LoginName, valueText(AdminLoginField));
Database::Handler::getPasswordService().updatePassword(authUser, valueText(PasswordField));
- user.modify()->setAdmin( true );
+ user.modify()->setType(Database::User::Type::ADMIN);
}
bool validateField(Field field)
diff --git a/src/ui/admin/UserView.cpp b/src/ui/admin/UserView.cpp
index da5ba9bd..d28de35d 100644
--- a/src/ui/admin/UserView.cpp
+++ b/src/ui/admin/UserView.cpp
@@ -30,6 +30,7 @@
#include
#include "common/Validators.hpp"
+#include "utils/Config.hpp"
#include "utils/Exception.hpp"
#include "utils/Logger.hpp"
#include "utils/Utils.hpp"
@@ -45,8 +46,9 @@ class UserModel : public Wt::WFormModel
static const Field LoginField;
static const Field PasswordField;
static const Field BitrateLimitField;
+ static const Field DemoField;
- UserModel(boost::optional userId)
+ UserModel(boost::optional userId)
: Wt::WFormModel(),
_userId(userId)
{
@@ -58,7 +60,7 @@ class UserModel : public Wt::WFormModel
addField(PasswordField);
addField(BitrateLimitField);
-
+ addField(DemoField);
if (!_userId)
setValidator(PasswordField, createMandatoryValidator());
@@ -76,8 +78,8 @@ class UserModel : public Wt::WFormModel
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
- Wt::Auth::User authUser = LmsApp->getDb().getUserDatabase().findWithId( std::to_string(*_userId) );
- Database::User::pointer user = LmsApp->getDb().getUser(authUser);
+ auto authUser = LmsApp->getDb().getUserDatabase().findWithId( std::to_string(*_userId) );
+ auto user = LmsApp->getDb().getUser(authUser);
if (user == LmsApp->getUser())
throw LmsException("Cannot edit ourselves");
@@ -117,6 +119,9 @@ class UserModel : public Wt::WFormModel
auto bitrateLimitRow = getBitrateLimitRow(Wt::asString(value(BitrateLimitField)));
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));
if (user.isValid())
error = Wt::WString::tr("Lms.Admin.User.user-already-exists");
- else
- return Wt::WFormModel::validateField(field);
}
else if (field == PasswordField)
{
if (!valueText(PasswordField).empty())
{
- // Evaluate the strength of the password
- auto res = Database::Handler::getPasswordService().strengthValidator()->evaluateStrength(valueText(PasswordField), getLogin(), "");
+ if (Wt::asNumber(value(DemoField)))
+ {
+ //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())
- error = res.message();
+ if (!res.isValid())
+ 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 getBitrateLimitRow(Wt::WString value)
@@ -219,12 +235,13 @@ class UserModel : public Wt::WFormModel
}
std::shared_ptr _bitrateModel;
- boost::optional _userId;
+ boost::optional _userId;
};
const Wt::WFormModel::Field UserModel::LoginField = "login";
const Wt::WFormModel::Field UserModel::PasswordField = "password";
const Wt::WFormModel::Field UserModel::BitrateLimitField = "audio-bitrate-limit";
+const Wt::WFormModel::Field UserModel::DemoField = "demo";
UserView::UserView()
{
@@ -242,7 +259,7 @@ UserView::refreshView()
if (!wApp->internalPathMatches("/admin/user"))
return;
- auto userId = readAs(wApp->internalPathNextPart("/admin/user/"));
+ auto userId = readAs(wApp->internalPathNextPart("/admin/user/"));
LMS_LOG(UI, DEBUG) << "userId = " << (userId ? std::to_string(*userId) : "none");
@@ -276,6 +293,11 @@ UserView::refreshView()
bitrate->setModel(model->bitrateModel());
t->setFormWidget(UserModel::BitrateLimitField, std::move(bitrate));
+ // Demo account
+ t->setFormWidget(UserModel::DemoField, std::make_unique());
+ if (!userId && Config::instance().getBool("demo", false))
+ t->setCondition("if-demo", true);
+
Wt::WPushButton* saveBtn = t->bindNew("save-btn", Wt::WString::tr(userId ? "Lms.save" : "Lms.create"));
saveBtn->clicked().connect(std::bind([=]
{
diff --git a/src/ui/admin/UsersView.cpp b/src/ui/admin/UsersView.cpp
index e38140b3..226a3acc 100644
--- a/src/ui/admin/UsersView.cpp
+++ b/src/ui/admin/UsersView.cpp
@@ -74,6 +74,13 @@ UsersView::refreshView()
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
if (LmsApp->getUser() == user)
continue;