Various UI small improvements (better error reporting in case of bad url, made the password change fields more explicit)

This commit is contained in:
emeric
2019-10-06 18:59:13 +02:00
parent b5cfe014ec
commit 174158aa63
17 changed files with 182 additions and 57 deletions
+1 -1
View File
@@ -1,4 +1,5 @@
*.sw?
*.in
build/
Makefile.in
aclocal.m4
@@ -7,4 +8,3 @@ configure
depcomp
install-sh
missing
include/config.h.in
+1
View File
@@ -36,6 +36,7 @@ dist_lms_approot_DATA = \
approot/artistlink.xml \
approot/artists.xml \
approot/artistsinfo.xml \
approot/error.xml \
approot/explore.xml \
approot/login.xml \
approot/mediaplayer.xml \
+8 -4
View File
@@ -86,16 +86,20 @@
<label class="control-label col-sm-2" for="${id:last-scan}">
${tr:Lms.Admin.Database.Status.last-scan}
</label>
<div class="col-sm-5 well well-sm">
${last-scan}
<div class="col-sm-5">
<div class="well well-sm">
${last-scan}
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="${id:status}">
${tr:Lms.Admin.Database.Status.status}
</label>
<div class="col-sm-5 well well-sm">
${status}
<div class="col-sm-5">
<div class="well well-sm">
${status}
</div>
</div>
</div>
</div>
+4 -2
View File
@@ -12,7 +12,9 @@
${tr:Lms.Admin.User.last-login}
</label>
<div class="col-sm-5">
${last-login}
<div class="well well-sm">
${last-login}
</div>
</div>
</div>
${</if-has-last-login>}
@@ -31,7 +33,7 @@
${</if-has-login>}
<div class="form-group">
<label class="control-label col-sm-2" for="${id:password}">
${tr:Lms.password}
${tr:Lms.password-new}
</label>
<div class="col-sm-5">
${password}
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<messages xmlns:if="Wt.WTemplate.conditions">
<message id="Lms.Error.template">
<div class="container">
<div class="page-header">
<h2>${tr:Lms.Error.error-occurred}</h2>
</div>
<p><strong>${error}</strong></p>
${btn-go-home class="btn btn-primary"}
</div>
</message>
</messages>
+11 -2
View File
@@ -16,6 +16,7 @@
<message id="Lms.password-bad-login-combination">Bad login / password combination</message>
<message id="Lms.password-client-throttled">Login throttled, please try again later</message>
<message id="Lms.password-confirm">Confirm password</message>
<message id="Lms.password-new">New password</message>
<message id="Lms.password-old">Old password</message>
<message id="Lms.password-too-weak">Password too weak</message>
<message id="Lms.passwords-dont-match">Passwords don't match</message>
@@ -23,9 +24,17 @@
<message id="Lms.quit-other-session">Another session has been open. Reopen this one?</message>
<message id="Lms.save">Save</message>
<!--Errors-->
<message id="Lms.Error.artist-not-found">Artist not found</message>
<message id="Lms.Error.error-occurred">Error occured!</message>
<message id="Lms.Error.go-home">Go home</message>
<message id="Lms.Error.release-not-found">Release not found</message>
<message id="Lms.Error.user-not-allowed">You are not allowed to perform this operation</message>
<message id="Lms.Error.user-not-found">User not found</message>
<!--Administration-->
<message id="Lms.Admin.Database.daily">Daily</message>
<message id="Lms.Admin.Database.database">Database</message>
<message id="Lms.Admin.Database.database">Music collection</message>
<message id="Lms.Admin.Database.immediate-scan">Scan now!</message>
<message id="Lms.Admin.Database.monthly">Monthly</message>
<message id="Lms.Admin.Database.never">Never</message>
@@ -134,8 +143,8 @@
<!--Settings-->
<message id="Lms.Settings.account">Account</message>
<message id="Lms.Settings.audio">Audio</message>
<message id="Lms.Settings.change-password">Change password</message>
<message id="Lms.Settings.demo-cannot-save">Cannot save using a demo account!</message>
<message id="Lms.Settings.password-bad">Bad password</message>
<message id="Lms.Settings.password-must-fill-old-password">Old password must be filled in</message>
+11 -3
View File
@@ -16,6 +16,7 @@
<message id="Lms.password-bad-login-combination">Mauvaise combinaison login / mot de passe</message>
<message id="Lms.password-client-throttled">Trop de tentatives de connexion, veuillez réessayer plus tard</message>
<message id="Lms.password-confirm">Confirmation du mot de passe</message>
<message id="Lms.password-new">Nouveau mot de passe</message>
<message id="Lms.password-old">Ancien mot de passe</message>
<message id="Lms.password-too-weak">Mot de passe trop faible</message>
<message id="Lms.passwords-dont-match">Les mots de passe ne correspondent pas</message>
@@ -23,9 +24,17 @@
<message id="Lms.quit-other-session">Une autre session a été ouverte. Reouvrir celle-ci ?</message>
<message id="Lms.save">Sauvegarder</message>
<!--Errors-->
<message id="Lms.Error.artist-not-found">Cet artiste n'existe pas</message>
<message id="Lms.Error.error-occurred">Une erreur est survenue!</message>
<message id="Lms.Error.go-home">Retour à l'accueil</message>
<message id="Lms.Error.release-not-found">Cet album n'existe pas</message>
<message id="Lms.Error.user-not-allowed">Vous n'avez pas les droits pour effectuer cette opération</message>
<message id="Lms.Error.user-not-found">L'utilisateur n'existe pas</message>
<!--Administration-->
<message id="Lms.Admin.Database.daily">Tous les jours</message>
<message id="Lms.Admin.Database.database">Base de données</message>
<message id="Lms.Admin.Database.database">Collection de musiques</message>
<message id="Lms.Admin.Database.immediate-scan">Scanner maintenant !</message>
<message id="Lms.Admin.Database.monthly">Tous les mois</message>
<message id="Lms.Admin.Database.never">Jamais</message>
@@ -134,9 +143,8 @@
<!--Settings-->
<message id="Lms.Settings.account">Compte</message>
<message id="Lms.Settings.audio">Audio</message>
<message id="Lms.Settings.auto">Auto</message>
<message id="Lms.Settings.change-password">Changement de mot de passe</message>
<message id="Lms.Settings.demo-cannot-save">Impossible de sauvegarder en utilisant un compte de démo !</message>
<message id="Lms.Settings.password-bad">Mauvais mot de passe</message>
<message id="Lms.Settings.password-must-fill-old-password">L'ancien mot de passe doit être renseigné</message>
+2 -2
View File
@@ -43,7 +43,7 @@
</div>
</div>
</div>
<legend>${tr:Lms.Settings.account}</legend>
<legend>${tr:Lms.Settings.change-password}</legend>
<div class="form-horizontal">
${<if-has-old-password>}
<div class="form-group">
@@ -60,7 +60,7 @@
${</if-has-old-password>}
<div class="form-group">
<label class="control-label col-sm-2" for="${id:password}">
${tr:Lms.password}
${tr:Lms.password-new}
</label>
<div class="col-sm-5">
${password}
+1
View File
@@ -82,6 +82,7 @@ lms_SOURCES = \
$(srcdir)/ui/Auth.hpp \
$(srcdir)/ui/LmsApplication.cpp \
$(srcdir)/ui/LmsApplication.hpp \
$(srcdir)/ui/LmsApplicationException.hpp \
$(srcdir)/ui/LmsApplicationGroup.cpp \
$(srcdir)/ui/LmsApplicationGroup.hpp \
$(srcdir)/ui/MediaPlayer.cpp \
@@ -92,8 +92,11 @@ networkToCacheFile(const SOM::Network& network, std::filesystem::path path)
static
std::optional<SOM::Network>
createNetworkFromCacheFile(std::filesystem::path path)
createNetworkFromCacheFile(const std::filesystem::path& path)
{
if (!std::filesystem::exists(path))
return std::nullopt;
try
{
LMS_LOG(SIMILARITY, INFO) << "Reading network from cache...";
+46 -22
View File
@@ -48,6 +48,7 @@
#include "resource/ImageResource.hpp"
#include "resource/AudioResource.hpp"
#include "Auth.hpp"
#include "LmsApplicationException.hpp"
#include "MediaPlayer.hpp"
#include "PlayHistoryView.hpp"
#include "PlayQueueView.hpp"
@@ -134,6 +135,7 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env,
messageResourceBundle().use(appRoot() + "artistlink");
messageResourceBundle().use(appRoot() + "artists");
messageResourceBundle().use(appRoot() + "artistsinfo");
messageResourceBundle().use(appRoot() + "error");
messageResourceBundle().use(appRoot() + "explore");
messageResourceBundle().use(appRoot() + "login");
messageResourceBundle().use(appRoot() + "mediaplayer");
@@ -178,7 +180,20 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env,
const auto userId {processAuthToken(env)};
if (userId)
{
handleUserLoggedIn(*userId, false);
try
{
handleUserLoggedIn(*userId, false);
}
catch (LmsApplicationException& e)
{
LMS_LOG(UI, WARNING) << "Caught a LmsApplication exception: " << e.what();
handleException(e);
}
catch (std::exception& e)
{
LMS_LOG(UI, ERROR) << "Caught exception: " << e.what();
throw LmsException {"Internal error"}; // Do not put details here at it may appear on the user rendered html
}
}
else
{
@@ -267,9 +282,19 @@ LmsApplication::createCluster(Database::Cluster::pointer cluster, bool canDelete
}
void
LmsApplication::goHome()
LmsApplication::handleException(LmsApplicationException& e)
{
setInternalPath("/artists", true);
root()->clear();
Wt::WTemplate* t {root()->addNew<Wt::WTemplate>(Wt::WString::tr("Lms.Error.template"))};
t->addFunction("tr", &Wt::WTemplate::Functions::tr);
t->bindString("error", e.what());
Wt::WPushButton* btn {t->bindNew<Wt::WPushButton>("btn-go-home", Wt::WString::tr("Lms.Error.go-home"))};
btn->clicked().connect([this]()
{
setConfirmCloseMessage("");
redirect("/");
});
}
void
@@ -359,25 +384,17 @@ LmsApplication::handleUserLoggedIn(Database::IdType userId, bool strongAuth)
root()->clear();
try
const LmsApplicationInfo info {LmsApplicationInfo::fromEnvironment(environment())};
LMS_LOG(UI, INFO) << "User '" << getUserLoginName() << "' logged in from '" << environment().clientAddress() << "', user agent = " << environment().userAgent();
getApplicationGroup().join(info);
getApplicationGroup().postOthers([info]
{
const LmsApplicationInfo info {LmsApplicationInfo::fromEnvironment(environment())};
LmsApp->getEvents().appOpen(info);
});
LMS_LOG(UI, INFO) << "User '" << getUserLoginName() << "' logged in from '" << environment().clientAddress() << "', user agent = " << environment().userAgent();
getApplicationGroup().join(info);
getApplicationGroup().postOthers([info]
{
LmsApp->getEvents().appOpen(info);
});
createHome();
}
catch (std::exception& e)
{
LMS_LOG(UI, ERROR) << "Error while handling auth event: " << e.what();
throw LmsException {"Internal error"}; // Do not put details here at it appears on the user rendered html
}
createHome();
}
void
@@ -581,10 +598,15 @@ LmsApplication::notify(const Wt::WEvent& event)
{
WApplication::notify(event);
}
catch (LmsApplicationException& e)
{
LMS_LOG(UI, WARNING) << "Caught a LmsApplication exception: " << e.what();
handleException(e);
}
catch (std::exception& e)
{
LMS_LOG(UI, ERROR) << "Caught exception: " << e.what();
throw LmsException("Internal error"); // Do not put details here at it appears on the user rendered html
throw LmsException {"Internal error"}; // Do not put details here at it may appear on the user rendered html
}
}
@@ -606,7 +628,9 @@ LmsApplication::post(std::function<void()> func)
Wt::WServer::instance()->post(LmsApp->sessionId(), std::move(func));
}
static std::string escape(std::string str)
static
std::string
escape(const std::string& str)
{
return replaceInString(std::move(str), "\'", "\\\'");
}
+5 -4
View File
@@ -38,8 +38,9 @@ namespace Database {
namespace UserInterface {
class AudioResource;
class ImageResource;
class Auth;
class ImageResource;
class LmsApplicationException;
// Events that can be listen from anywhere in the application
struct Events
@@ -91,9 +92,6 @@ class LmsApplication : public Wt::WApplication
Events& getEvents() { return _events; }
// Utils
void goHome();
void goHomeAndQuit();
void post(std::function<void()> func);
void notifyMsg(MsgType type, const Wt::WString& message, std::chrono::milliseconds duration = std::chrono::milliseconds(4000));
@@ -108,6 +106,9 @@ class LmsApplication : public Wt::WApplication
private:
void handleException(LmsApplicationException& e);
void goHomeAndQuit();
LmsApplicationGroup& getApplicationGroup();
// Signal slots
+59
View File
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2019 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "database/Types.hpp"
#include "utils/Exception.hpp"
namespace UserInterface {
class LmsApplicationException : public LmsException
{
public:
LmsApplicationException(const Wt::WString& error) : LmsException {error.toUTF8()} {}
};
class ArtistNotFoundException : public LmsApplicationException
{
public:
ArtistNotFoundException(Database::IdType artistId) : LmsApplicationException {Wt::WString::tr("Lms.Error.artist-not-found").arg(artistId)} {}
};
class ReleaseNotFoundException : public LmsApplicationException
{
public:
ReleaseNotFoundException(Database::IdType releaseId) : LmsApplicationException {Wt::WString::tr("Lms.Error.release-not-found").arg(releaseId)} {}
};
class UserNotFoundException : public LmsApplicationException
{
public:
UserNotFoundException(Database::IdType userId) : LmsApplicationException {Wt::WString::tr("Lms.Error.user-not-found").arg(userId)} {}
};
class UserNotAllowedException : public LmsApplicationException
{
public:
UserNotAllowedException() : LmsApplicationException {Wt::WString::tr("Lms.Error.user-not-allowed")} {}
};
}
+10 -7
View File
@@ -39,6 +39,7 @@
#include "common/Validators.hpp"
#include "common/ValueStringModel.hpp"
#include "LmsApplication.hpp"
#include "LmsApplicationException.hpp"
namespace UserInterface {
@@ -54,8 +55,7 @@ class UserModel : public Wt::WFormModel
static const Field DemoField;
UserModel(std::optional<Database::IdType> userId)
: Wt::WFormModel(),
_userId(userId)
: _userId {userId}
{
if (!_userId)
{
@@ -126,8 +126,10 @@ class UserModel : public Wt::WFormModel
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
const Database::User::pointer user {Database::User::getById(LmsApp->getDbSession(), *_userId)};
if (user == LmsApp->getUser())
throw LmsException("Cannot edit ourselves");
if (!user)
throw UserNotFoundException {*_userId};
else if (user == LmsApp->getUser())
throw UserNotAllowedException {};
auto transcodeBitrateLimitRow {_bitrateModel->getRowFromValue(user->getMaxAudioTranscodeBitrate())};
if (transcodeBitrateLimitRow)
@@ -240,12 +242,13 @@ UserView::refreshView()
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
const Database::User::pointer user {Database::User::getById(LmsApp->getDbSession(), *userId)};
if (!user)
throw UserNotFoundException {*userId};
t->bindString("title", Wt::WString::tr("Lms.Admin.User.user-edit").arg(user->getLoginName()), Wt::TextFormat::Plain);
t->setCondition("if-has-last-login", true);
Wt::WLineEdit *lastLogin {t->bindNew<Wt::WLineEdit>("last-login")};
lastLogin->setText(user->getLastLogin().toString());
lastLogin->setEnabled(false);
t->bindString("last-login", user->getLastLogin().toString(), Wt::TextFormat::Plain);
}
else
{
+2 -4
View File
@@ -33,6 +33,7 @@
#include "resource/ImageResource.hpp"
#include "LmsApplication.hpp"
#include "LmsApplicationException.hpp"
#include "Filters.hpp"
using namespace Database;
@@ -70,10 +71,7 @@ Artist::refresh()
const Database::Artist::pointer artist = Database::Artist::getById(LmsApp->getDbSession(), *artistId);
if (!artist)
{
LmsApp->goHome();
return;
}
throw ArtistNotFoundException {*artistId};
Wt::WTemplate* t {addNew<Wt::WTemplate>(Wt::WString::tr("Lms.Explore.Artist.template"))};
t->addFunction("tr", &Wt::WTemplate::Functions::tr);
+2 -4
View File
@@ -34,6 +34,7 @@
#include "resource/ImageResource.hpp"
#include "LmsApplication.hpp"
#include "LmsApplicationException.hpp"
#include "Filters.hpp"
using namespace Database;
@@ -71,10 +72,7 @@ Release::refresh()
const Database::Release::pointer release {Database::Release::getById(LmsApp->getDbSession(), *releaseId)};
if (!release)
{
LmsApp->goHome();
return;
}
throw ReleaseNotFoundException {*releaseId};
Wt::WTemplate* t {addNew<Wt::WTemplate>(Wt::WString::tr("Lms.Explore.Release.template"))};
t->addFunction("tr", &Wt::WTemplate::Functions::tr);
+1 -1
View File
@@ -25,6 +25,6 @@
class LmsException : public std::runtime_error
{
public:
LmsException(const std::string& error) : std::runtime_error(error) {}
LmsException(const std::string& error = "") : std::runtime_error {error} {}
};