Made the Opensubsonic API key management separated + added a copy button, fixes #796
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
<message id="Lms.add">Add</message>
|
||||
<message id="Lms.administration">Administration</message>
|
||||
<message id="Lms.cancel">Cancel</message>
|
||||
<message id="Lms.copy">Copy</message>
|
||||
<message id="Lms.clusters">Tags</message>
|
||||
<message id="Lms.create">Create</message>
|
||||
<message id="Lms.delete">Delete</message>
|
||||
@@ -364,7 +365,14 @@
|
||||
<message id="Lms.Settings.original-date-desc">Original Release Date (Descending)</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>
|
||||
<message id="Lms.Settings.regen-token">Generate</message>
|
||||
<message id="Lms.Settings.generate-token">Generate</message>
|
||||
<message id="Lms.Settings.subsonic-token-copied">API key copied to clipboard!</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm">Delete</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-body">Deleting the key will disconnect all clients currently using it.</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-title">Delete API key?</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm">Regenerate</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-body">Generating a new key will invalidate all clients currently using the existing key.</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-title">Regenerate API key?</message>
|
||||
<message id="Lms.Settings.replaygain-mode">ReplayGain mode</message>
|
||||
<message id="Lms.Settings.replaygain-mode.none">No ReplayGain</message>
|
||||
<message id="Lms.Settings.replaygain-mode.auto">Auto</message>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<message id="Lms.add">Añadir</message>
|
||||
<message id="Lms.administration">Administración</message>
|
||||
<message id="Lms.cancel">Cancelar</message>
|
||||
<message id="Lms.copy">Copiar</message>
|
||||
<message id="Lms.clusters">Etiquetas</message>
|
||||
<message id="Lms.create">Crear</message>
|
||||
<message id="Lms.delete">Eliminar</message>
|
||||
@@ -364,7 +365,14 @@
|
||||
<message id="Lms.Settings.original-date-desc">Fecha de publicación original (Descendiente)</message>
|
||||
<message id="Lms.Settings.password-bad">Contraseña incorrecta</message>
|
||||
<message id="Lms.Settings.password-must-fill-old-password">La contraseña antigua debe ser introducida</message>
|
||||
<message id="Lms.Settings.regen-token">Regenerar</message>
|
||||
<message id="Lms.Settings.generate-token">Regenerar</message>
|
||||
<message id="Lms.Settings.subsonic-token-copied">¡Clave API copiada al portapapeles!</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm">Eliminar</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-body">Eliminar la clave desconectará todos los clientes que la estén usando actualmente.</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-title">¿Eliminar la clave API?</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm">Regenerar</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-body">Generar una nueva clave invalidará todos los clientes que usen la clave actual.</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-title">¿Regenerar la clave API?</message>
|
||||
<message id="Lms.Settings.replaygain-mode">Modo ReplayGain</message>
|
||||
<message id="Lms.Settings.replaygain-mode.none">Sin ReplayGain</message>
|
||||
<message id="Lms.Settings.replaygain-mode.auto">Automático</message>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<message id="Lms.add">Ajouter</message>
|
||||
<message id="Lms.administration">Administration</message>
|
||||
<message id="Lms.cancel">Annuler</message>
|
||||
<message id="Lms.copy">Copier</message>
|
||||
<message id="Lms.clusters">Tags</message>
|
||||
<message id="Lms.create">Créer</message>
|
||||
<message id="Lms.delete">Supprimer</message>
|
||||
@@ -364,7 +365,14 @@
|
||||
<message id="Lms.Settings.original-date-desc">Date de sortie originale (Décroissant)</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>
|
||||
<message id="Lms.Settings.regen-token">Regénérer</message>
|
||||
<message id="Lms.Settings.generate-token">Regénérer</message>
|
||||
<message id="Lms.Settings.subsonic-token-copied">Clé API copiée dans le presse-papiers !</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm">Supprimer</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-body">Supprimer la clé déconnectera tous les clients qui l'utilisent actuellement.</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-title">Supprimer la clé API ?</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm">Regénérer</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-body">Générer une nouvelle clé invalidera tous les clients utilisant actuellement la clé existante.</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-title">Regénérer la clé API ?</message>
|
||||
<message id="Lms.Settings.replaygain-mode">Mode ReplayGain</message>
|
||||
<message id="Lms.Settings.replaygain-mode.none">Pas de ReplayGain</message>
|
||||
<message id="Lms.Settings.replaygain-mode.auto">Automatique</message>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<message id="Lms.add">Aggiungi</message>
|
||||
<message id="Lms.administration">Amministrazione</message>
|
||||
<message id="Lms.cancel">Annulla</message>
|
||||
<message id="Lms.copy">Copia</message>
|
||||
<message id="Lms.clusters">Tags</message>
|
||||
<message id="Lms.create">Crea</message>
|
||||
<message id="Lms.delete">Elimina</message>
|
||||
@@ -364,7 +365,14 @@
|
||||
<message id="Lms.Settings.original-date-desc">Data di uscita originale (Decrescente)</message>
|
||||
<message id="Lms.Settings.password-bad">Password errata</message>
|
||||
<message id="Lms.Settings.password-must-fill-old-password">Devi inserire la password attuale</message>
|
||||
<message id="Lms.Settings.regen-token">Genera</message>
|
||||
<message id="Lms.Settings.generate-token">Genera</message>
|
||||
<message id="Lms.Settings.subsonic-token-copied">Chiave API copiata negli appunti!</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm">Elimina</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-body">Eliminare la chiave disconnetterà tutti i client che la stanno utilizzando.</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-title">Eliminare la chiave API?</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm">Rigenera</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-body">Generare una nuova chiave invaliderà tutti i client che attualmente utilizzano la chiave esistente.</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-title">Rigenerare la chiave API?</message>
|
||||
<message id="Lms.Settings.replaygain-mode">Modalità ReplayGain</message>
|
||||
<message id="Lms.Settings.replaygain-mode.none">No ReplayGain</message>
|
||||
<message id="Lms.Settings.replaygain-mode.auto">Automatica</message>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<message id="Lms.add">Dodaj</message>
|
||||
<message id="Lms.administration">Zarządzanie</message>
|
||||
<message id="Lms.cancel">Cofnij</message>
|
||||
<message id="Lms.copy">Kopiuj</message>
|
||||
<message id="Lms.clusters">Znaczniki</message>
|
||||
<message id="Lms.create">Utwórz</message>
|
||||
<message id="Lms.delete">Usuń</message>
|
||||
@@ -390,7 +391,14 @@
|
||||
<message id="Lms.Settings.original-date-desc">Oryginalna data wydania (Malejąco)</message>
|
||||
<message id="Lms.Settings.password-bad">Błędne hasło</message>
|
||||
<message id="Lms.Settings.password-must-fill-old-password">Należy podać stare hasło</message>
|
||||
<message id="Lms.Settings.regen-token">Generuj</message>
|
||||
<message id="Lms.Settings.generate-token">Generuj</message>
|
||||
<message id="Lms.Settings.subsonic-token-copied">Klucz API skopiowany do schowka!</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm">Usuń</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-body">Usunięcie klucza rozłączy wszystkich klientów, którzy aktualnie go używają.</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-title">Usunąć klucz API?</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm">Regeneruj</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-body">Wygenerowanie nowego klucza spowoduje unieważnienie wszystkich klientów korzystających z istniejącego klucza.</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-title">Regenerować klucz API?</message>
|
||||
<message id="Lms.Settings.replaygain-mode">Tryb ReplayGain</message>
|
||||
<message id="Lms.Settings.replaygain-mode.none">Bez ReplayGain</message>
|
||||
<message id="Lms.Settings.replaygain-mode.auto">Auto</message>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<message id="Lms.add">添加</message>
|
||||
<message id="Lms.administration">管理</message>
|
||||
<message id="Lms.cancel">取消</message>
|
||||
<message id="Lms.copy">复制</message>
|
||||
<message id="Lms.clusters">标签</message>
|
||||
<message id="Lms.create">新建</message>
|
||||
<message id="Lms.delete">删除</message>
|
||||
@@ -335,7 +336,14 @@
|
||||
<message id="Lms.Settings.original-date-desc">原始发行日期(降序)</message>
|
||||
<message id="Lms.Settings.password-bad">无效密码</message>
|
||||
<message id="Lms.Settings.password-must-fill-old-password">必须填写旧密码</message>
|
||||
<message id="Lms.Settings.regen-token">生成</message>
|
||||
<message id="Lms.Settings.generate-token">生成</message>
|
||||
<message id="Lms.Settings.subsonic-token-copied">API 密钥已复制到剪贴板!</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm">删除</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-body">删除密钥将断开所有当前使用该密钥的客户端连接。</message>
|
||||
<message id="Lms.Settings.subsonic-token-del-confirm-title">删除 API 密钥?</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm">重新生成</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-body">生成新密钥将使所有当前使用现有密钥的客户端失效。</message>
|
||||
<message id="Lms.Settings.subsonic-token-regen-confirm-title">重新生成 API 密钥?</message>
|
||||
<message id="Lms.Settings.replaygain-mode">ReplayGain 模式</message>
|
||||
<message id="Lms.Settings.replaygain-mode.none">没有 ReplayGain</message>
|
||||
<message id="Lms.Settings.replaygain-mode.auto">自动模式</message>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<message id="Lms.template.more-btn"><i class="fa fa-fw fa-ellipsis-v"></i></message>
|
||||
<message id="Lms.template.play-btn"><i class="fa fa-fw fa-play"></i></message>
|
||||
<message id="Lms.template.star-btn"><i class="fa fa-fw fa-star-o"></i></message>
|
||||
<message id="Lms.template.copy-btn"><i class="fa fa-fw fa-copy"></i></message>
|
||||
<message id="Lms.template.toggle-visibility-btn"><i class="fa fa-fw fa-eye"></i></message>
|
||||
<message id="Lms.template.unstar-btn"><i class="fa fa-fw fa-star"></i></message>
|
||||
|
||||
|
||||
@@ -1,28 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<messages xmlns:if="Wt.WTemplate.conditions">
|
||||
|
||||
<message id="Lms.Settings.subsonic.template">
|
||||
<message id="Lms.Settings.subsonic.template.form">
|
||||
<form class="row g-3">
|
||||
<legend>${tr:Lms.Settings.subsonic-api}</legend>
|
||||
<div class="col-lg-12">
|
||||
<label class="form-label" for="${id:subsonic-token}">
|
||||
${tr:Lms.Settings.subsonic-token}
|
||||
${<if-has-subsonic-token-usage>}
|
||||
<button type="button" class="btn btn-sm p-0" data-bs-toggle="tooltip" data-bs-placement="right" title="${tr:Lms.Settings.subsonic-token-usage}">
|
||||
<i class="fa fa-fw fa-info-circle" aria-hidden="true"></i>
|
||||
</button>
|
||||
${</if-has-subsonic-token-usage>}
|
||||
</label>
|
||||
<div class="input-group mb-3">
|
||||
${subsonic-token-regen-btn class="btn btn-outline-secondary"}
|
||||
${subsonic-token-del-btn class="btn btn-outline-warning"}
|
||||
${subsonic-token class="form-control"}
|
||||
${subsonic-token-visibility-btn class="btn btn-outline-secondary"}
|
||||
<div class="invalid-feedback">
|
||||
${subsonic-token-info class="help-block"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="form-check">
|
||||
${subsonic-enable-transcoding-by-default class="form-check-input"}
|
||||
@@ -69,4 +50,68 @@
|
||||
${save-btn class="btn btn-primary me-1"}${discard-btn class="btn btn-secondary"}
|
||||
</message>
|
||||
|
||||
<message id="Lms.Settings.subsonic.template.key">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">
|
||||
${tr:Lms.Settings.subsonic-token}
|
||||
${<if-has-subsonic-token-usage>}
|
||||
<button type="button" class="btn btn-sm p-0" data-bs-toggle="tooltip" data-bs-placement="right" title="${tr:Lms.Settings.subsonic-token-usage}">
|
||||
<i class="fa fa-fw fa-info-circle" aria-hidden="true"></i>
|
||||
</button>
|
||||
${</if-has-subsonic-token-usage>}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="input-group mb-3">
|
||||
${subsonic-token class="form-control"}
|
||||
${subsonic-token-visibility-btn class="btn btn-outline-secondary"}
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
${subsonic-token-regen-btn class="btn btn-secondary"}
|
||||
${subsonic-token-copy-btn class="btn btn-secondary"}
|
||||
<div class="ms-auto">
|
||||
${subsonic-token-del-btn class="btn btn-secondary"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</message>
|
||||
|
||||
<message id="Lms.Settings.subsonic.template.regen-confirm">
|
||||
<div class="modal fade" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">${tr:Lms.Settings.subsonic-token-regen-confirm-title}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
${tr:Lms.Settings.subsonic-token-regen-confirm-body}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
${confirm-btn class="btn btn-warning me-1"}${cancel-btn class="btn btn-secondary"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</message>
|
||||
|
||||
<message id="Lms.Settings.subsonic.template.del-confirm">
|
||||
<div class="modal fade" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">${tr:Lms.Settings.subsonic-token-del-confirm-title}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
${tr:Lms.Settings.subsonic-token-del-confirm-body}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
${confirm-btn class="btn btn-danger me-1"}${cancel-btn class="btn btn-secondary"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</message>
|
||||
|
||||
</messages>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <Wt/WAnchor.h>
|
||||
#include <Wt/WText.h>
|
||||
|
||||
#include "core/String.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "database/objects/Artist.hpp"
|
||||
#include "database/objects/Cluster.hpp"
|
||||
@@ -501,4 +502,9 @@ namespace lms::ui::utils
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void copyToClipboard(std::string_view text)
|
||||
{
|
||||
LmsApp->doJavaScript("navigator.clipboard.writeText('" + core::stringUtils::jsEscape(text) + "').catch(function(){})");
|
||||
}
|
||||
} // namespace lms::ui::utils
|
||||
|
||||
@@ -93,4 +93,6 @@ namespace lms::ui::utils
|
||||
std::map<Wt::WString, std::vector<db::ObjectPtr<db::Artist>>> getTrackArtistsByRole(db::ObjectPtr<db::Release> release);
|
||||
|
||||
std::unique_ptr<Wt::WInteractWidget> createCopyright(std::string_view copyright, std::string_view copyrightURL);
|
||||
|
||||
void copyToClipboard(std::string_view text);
|
||||
} // namespace lms::ui::utils
|
||||
|
||||
@@ -32,17 +32,17 @@
|
||||
#include "core/UUID.hpp"
|
||||
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Types.hpp"
|
||||
#include "database/objects/User.hpp"
|
||||
#include "services/auth/IAuthTokenService.hpp"
|
||||
|
||||
#include "LmsApplication.hpp"
|
||||
#include "ModalManager.hpp"
|
||||
#include "Tooltip.hpp"
|
||||
#include "common/MandatoryValidator.hpp"
|
||||
#include "common/UUIDValidator.hpp"
|
||||
#include "common/ValueStringModel.hpp"
|
||||
|
||||
#include "SettingsViewUtils.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace lms::ui
|
||||
{
|
||||
@@ -51,14 +51,12 @@ namespace lms::ui
|
||||
class SubsonicSettingsModel : public Wt::WFormModel
|
||||
{
|
||||
public:
|
||||
static inline const Field SubsonicTokenField{ "subsonic-token" };
|
||||
static inline const Field SubsonicEnableTranscodingByDefault{ "subsonic-enable-transcoding-by-default" };
|
||||
static inline const Field SubsonicArtistListModeField{ "subsonic-artist-list-mode" };
|
||||
static inline const Field SubsonicTranscodingOutputFormatField{ "subsonic-transcoding-output-format" };
|
||||
static inline const Field SubsonicTranscodingOutputBitrateField{ "subsonic-transcoding-output-bitrate" };
|
||||
|
||||
explicit SubsonicSettingsModel(auth::IAuthTokenService& authTokenService)
|
||||
: _authTokenService{ authTokenService }
|
||||
SubsonicSettingsModel()
|
||||
{
|
||||
_transcodingOutputBitrateModel = std::make_shared<ValueStringModel<db::Bitrate>>();
|
||||
db::visitAllowedAudioBitrates([&](const db::Bitrate bitrate) {
|
||||
@@ -75,13 +73,11 @@ namespace lms::ui
|
||||
_subsonicArtistListModeModel->add(Wt::WString::tr("Lms.Settings.subsonic-artist-list-mode.release-artists"), db::SubsonicArtistListMode::ReleaseArtists);
|
||||
_subsonicArtistListModeModel->add(Wt::WString::tr("Lms.Settings.subsonic-artist-list-mode.track-artists"), db::SubsonicArtistListMode::TrackArtists);
|
||||
|
||||
addField(SubsonicTokenField);
|
||||
addField(SubsonicEnableTranscodingByDefault);
|
||||
addField(SubsonicTranscodingOutputBitrateField);
|
||||
addField(SubsonicTranscodingOutputFormatField);
|
||||
addField(SubsonicArtistListModeField);
|
||||
|
||||
setValidator(SubsonicTokenField, createUUIDValidator());
|
||||
setValidator(SubsonicTranscodingOutputBitrateField, createMandatoryValidator());
|
||||
setValidator(SubsonicTranscodingOutputFormatField, createMandatoryValidator());
|
||||
|
||||
@@ -97,29 +93,6 @@ namespace lms::ui
|
||||
auto transaction{ LmsApp->getDbSession().createWriteTransaction() };
|
||||
db::User::pointer user{ LmsApp->getUser() };
|
||||
|
||||
const std::string token{ Wt::asString(value(SubsonicTokenField)).toUTF8() };
|
||||
if (token.empty())
|
||||
{
|
||||
_authTokenService.clearAuthTokens("subsonic", user->getId());
|
||||
}
|
||||
else
|
||||
{
|
||||
bool hasNonMatchingToken{ false };
|
||||
bool hasMatchingToken{ false };
|
||||
_authTokenService.visitAuthTokens("subsonic", user->getId(), [&](const auth::IAuthTokenService::AuthTokenInfo&, std::string_view storedToken) {
|
||||
if (storedToken == token)
|
||||
hasMatchingToken = true;
|
||||
else
|
||||
hasNonMatchingToken = true;
|
||||
});
|
||||
|
||||
if (!hasMatchingToken || hasNonMatchingToken)
|
||||
{
|
||||
_authTokenService.clearAuthTokens("subsonic", user->getId());
|
||||
_authTokenService.createAuthToken("subsonic", user->getId(), token);
|
||||
}
|
||||
}
|
||||
|
||||
user.modify()->setSubsonicEnableTranscodingByDefault(Wt::asNumber(value(SubsonicEnableTranscodingByDefault)) != 0);
|
||||
|
||||
auto subsonicTranscodingOutputBitrateRow{ _transcodingOutputBitrateModel->getRowFromString(valueText(SubsonicTranscodingOutputBitrateField)) };
|
||||
@@ -140,11 +113,6 @@ namespace lms::ui
|
||||
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
|
||||
const db::User::pointer user{ LmsApp->getUser() };
|
||||
|
||||
_authTokenService.visitAuthTokens("subsonic", user->getId(), [&](const auth::IAuthTokenService::AuthTokenInfo&, std::string_view storedToken) {
|
||||
if (Wt::asString(value(SubsonicTokenField)).empty())
|
||||
setValue(SubsonicTokenField, Wt::WString::fromUTF8(std::string{ storedToken }));
|
||||
});
|
||||
|
||||
setValue(SubsonicEnableTranscodingByDefault, user->getSubsonicEnableTranscodingByDefault());
|
||||
|
||||
auto subsonicTranscodingOutputBitrateRow{ _transcodingOutputBitrateModel->getRowFromValue(user->getSubsonicDefaultTranscodingOutputBitrate()) };
|
||||
@@ -161,7 +129,6 @@ namespace lms::ui
|
||||
}
|
||||
|
||||
private:
|
||||
auth::IAuthTokenService& _authTokenService;
|
||||
std::shared_ptr<ValueStringModel<db::Bitrate>> _transcodingOutputBitrateModel;
|
||||
std::shared_ptr<ValueStringModel<db::TranscodingOutputFormat>> _transcodingOutputFormatModel;
|
||||
std::shared_ptr<ValueStringModel<db::SubsonicArtistListMode>> _subsonicArtistListModeModel;
|
||||
@@ -184,34 +151,15 @@ namespace lms::ui
|
||||
|
||||
clear();
|
||||
|
||||
auto* t{ addNew<Wt::WTemplateFormView>(Wt::WString::tr("Lms.Settings.subsonic.template")) };
|
||||
t->setCondition("if-has-subsonic-token-usage", core::Service<core::IConfig>::get()->getBool("api-subsonic-support-user-password-auth", true));
|
||||
refreshForm();
|
||||
refreshSubsonicKey();
|
||||
}
|
||||
|
||||
auto model{ std::make_shared<SubsonicSettingsModel>(*core::Service<auth::IAuthTokenService>::get()) };
|
||||
void SubsonicSettingsView::refreshForm()
|
||||
{
|
||||
auto model{ std::make_shared<SubsonicSettingsModel>() };
|
||||
|
||||
auto subsonicToken{ std::make_unique<Wt::WLineEdit>() };
|
||||
Wt::WLineEdit* subsonicTokenPtr{ subsonicToken.get() };
|
||||
subsonicTokenPtr->setEchoMode(Wt::EchoMode::Password);
|
||||
subsonicTokenPtr->setReadOnly(true);
|
||||
t->setFormWidget(SubsonicSettingsModel::SubsonicTokenField, std::move(subsonicToken));
|
||||
|
||||
auto subsonicTokenRegenBtn{ std::make_unique<Wt::WPushButton>(Wt::WString::tr("Lms.Settings.regen-token")) };
|
||||
subsonicTokenRegenBtn->clicked().connect(this, [subsonicTokenPtr] {
|
||||
subsonicTokenPtr->setValueText(Wt::WString::fromUTF8(std::string{ core::UUID::generate().getAsString() }));
|
||||
});
|
||||
t->bindWidget("subsonic-token-regen-btn", std::move(subsonicTokenRegenBtn));
|
||||
|
||||
auto subsonicTokenVisibilityBtn{ std::make_unique<Wt::WPushButton>(Wt::WString::tr("Lms.template.toggle-visibility-btn"), Wt::TextFormat::XHTML) };
|
||||
subsonicTokenVisibilityBtn->clicked().connect(this, [subsonicTokenPtr] {
|
||||
subsonicTokenPtr->setEchoMode(subsonicTokenPtr->echoMode() == Wt::EchoMode::Password ? Wt::EchoMode::Normal : Wt::EchoMode::Password);
|
||||
});
|
||||
t->bindWidget("subsonic-token-visibility-btn", std::move(subsonicTokenVisibilityBtn));
|
||||
|
||||
auto subsonicTokenDelBtn{ std::make_unique<Wt::WPushButton>(Wt::WString::tr("Lms.template.trash-btn"), Wt::TextFormat::XHTML) };
|
||||
subsonicTokenDelBtn->clicked().connect(this, [subsonicTokenPtr] {
|
||||
subsonicTokenPtr->setValueText("");
|
||||
});
|
||||
t->bindWidget("subsonic-token-del-btn", std::move(subsonicTokenDelBtn));
|
||||
auto* t{ addNew<Wt::WTemplateFormView>(Wt::WString::tr("Lms.Settings.subsonic.template.form")) };
|
||||
|
||||
t->setFormWidget(SubsonicSettingsModel::SubsonicEnableTranscodingByDefault, std::make_unique<Wt::WCheckBox>());
|
||||
|
||||
@@ -231,4 +179,136 @@ namespace lms::ui
|
||||
t->updateView(model.get());
|
||||
initTooltipsForWidgetTree(*t);
|
||||
}
|
||||
|
||||
void SubsonicSettingsView::refreshSubsonicKey()
|
||||
{
|
||||
auto* t{ addNew<Wt::WTemplate>(Wt::WString::tr("Lms.Settings.subsonic.template.key")) };
|
||||
t->addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||
|
||||
t->setCondition("if-has-subsonic-token-usage", core::Service<core::IConfig>::get()->getBool("api-subsonic-support-user-password-auth", true));
|
||||
|
||||
std::string currentToken;
|
||||
{
|
||||
auto transaction{ LmsApp->getDbSession().createReadTransaction() };
|
||||
core::Service<auth::IAuthTokenService>::get()->visitAuthTokens("subsonic", LmsApp->getUser()->getId(),
|
||||
[&](const auth::IAuthTokenService::AuthTokenInfo&, std::string_view storedToken) {
|
||||
currentToken = std::string{ storedToken };
|
||||
});
|
||||
}
|
||||
|
||||
auto subsonicToken{ std::make_unique<Wt::WLineEdit>() };
|
||||
Wt::WLineEdit* subsonicTokenPtr{ subsonicToken.get() };
|
||||
subsonicTokenPtr->setEchoMode(Wt::EchoMode::Password);
|
||||
subsonicTokenPtr->setReadOnly(true);
|
||||
subsonicTokenPtr->setValueText(Wt::WString::fromUTF8(currentToken));
|
||||
t->bindWidget("subsonic-token", std::move(subsonicToken));
|
||||
|
||||
auto subsonicTokenDelBtn{ std::make_unique<Wt::WPushButton>(Wt::WString::tr("Lms.delete")) };
|
||||
Wt::WPushButton* subsonicTokenDelBtnPtr{ subsonicTokenDelBtn.get() };
|
||||
|
||||
auto subsonicTokenCopyBtn{ std::make_unique<Wt::WPushButton>(Wt::WString::tr("Lms.copy")) };
|
||||
Wt::WPushButton* subsonicTokenCopyBtnPtr{ subsonicTokenCopyBtn.get() };
|
||||
|
||||
auto updateKeyButtonStates{ [subsonicTokenDelBtnPtr, subsonicTokenCopyBtnPtr, subsonicTokenPtr] {
|
||||
const bool hasToken{ !subsonicTokenPtr->valueText().empty() };
|
||||
subsonicTokenDelBtnPtr->setDisabled(!hasToken);
|
||||
subsonicTokenCopyBtnPtr->setDisabled(!hasToken);
|
||||
} };
|
||||
updateKeyButtonStates();
|
||||
|
||||
auto subsonicTokenRegenBtn{ std::make_unique<Wt::WPushButton>(Wt::WString::tr("Lms.Settings.generate-token")) };
|
||||
subsonicTokenRegenBtn->clicked().connect(t, [t, subsonicTokenPtr, updateKeyButtonStates] {
|
||||
if (LmsApp->getUserType() == db::UserType::DEMO)
|
||||
{
|
||||
LmsApp->notifyMsg(Notification::Type::Warning, Wt::WString::tr("Lms.Settings.demo-cannot-save"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto doGenerate{ [subsonicTokenPtr, updateKeyButtonStates] {
|
||||
const std::string newToken{ core::UUID::generate().getAsString() };
|
||||
{
|
||||
auto transaction{ LmsApp->getDbSession().createWriteTransaction() };
|
||||
auto& authService{ *core::Service<auth::IAuthTokenService>::get() };
|
||||
authService.clearAuthTokens("subsonic", LmsApp->getUser()->getId());
|
||||
authService.createAuthToken("subsonic", LmsApp->getUser()->getId(), newToken);
|
||||
}
|
||||
subsonicTokenPtr->setValueText(Wt::WString::fromUTF8(newToken));
|
||||
updateKeyButtonStates();
|
||||
} };
|
||||
|
||||
if (!subsonicTokenPtr->valueText().empty())
|
||||
{
|
||||
auto modal{ std::make_unique<Wt::WTemplate>(Wt::WString::tr("Lms.Settings.subsonic.template.regen-confirm")) };
|
||||
modal->addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||
Wt::WWidget* modalPtr{ modal.get() };
|
||||
modal->bindNew<Wt::WPushButton>("confirm-btn", Wt::WString::tr("Lms.Settings.subsonic-token-regen-confirm"))
|
||||
->clicked()
|
||||
.connect(t, [doGenerate, modalPtr] {
|
||||
doGenerate();
|
||||
LmsApp->getModalManager().dispose(modalPtr);
|
||||
});
|
||||
modal->bindNew<Wt::WPushButton>("cancel-btn", Wt::WString::tr("Lms.cancel"))
|
||||
->clicked()
|
||||
.connect(t, [modalPtr] {
|
||||
LmsApp->getModalManager().dispose(modalPtr);
|
||||
});
|
||||
|
||||
LmsApp->getModalManager().show(std::move(modal));
|
||||
}
|
||||
else
|
||||
{
|
||||
doGenerate();
|
||||
}
|
||||
});
|
||||
t->bindWidget("subsonic-token-regen-btn", std::move(subsonicTokenRegenBtn));
|
||||
|
||||
subsonicTokenDelBtn->clicked().connect(t, [t, subsonicTokenPtr, updateKeyButtonStates] {
|
||||
if (LmsApp->getUserType() == db::UserType::DEMO)
|
||||
{
|
||||
LmsApp->notifyMsg(Notification::Type::Warning, Wt::WString::tr("Lms.Settings.demo-cannot-save"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto modal{ std::make_unique<Wt::WTemplate>(Wt::WString::tr("Lms.Settings.subsonic.template.del-confirm")) };
|
||||
modal->addFunction("tr", &Wt::WTemplate::Functions::tr);
|
||||
Wt::WWidget* modalPtr{ modal.get() };
|
||||
modal->bindNew<Wt::WPushButton>("confirm-btn", Wt::WString::tr("Lms.Settings.subsonic-token-del-confirm"))
|
||||
->clicked()
|
||||
.connect(t, [subsonicTokenPtr, updateKeyButtonStates, modalPtr] {
|
||||
{
|
||||
auto transaction{ LmsApp->getDbSession().createWriteTransaction() };
|
||||
core::Service<auth::IAuthTokenService>::get()->clearAuthTokens("subsonic", LmsApp->getUser()->getId());
|
||||
}
|
||||
subsonicTokenPtr->setValueText("");
|
||||
updateKeyButtonStates();
|
||||
LmsApp->getModalManager().dispose(modalPtr);
|
||||
});
|
||||
modal->bindNew<Wt::WPushButton>("cancel-btn", Wt::WString::tr("Lms.cancel"))
|
||||
->clicked()
|
||||
.connect(t, [modalPtr] {
|
||||
LmsApp->getModalManager().dispose(modalPtr);
|
||||
});
|
||||
|
||||
LmsApp->getModalManager().show(std::move(modal));
|
||||
});
|
||||
t->bindWidget("subsonic-token-del-btn", std::move(subsonicTokenDelBtn));
|
||||
|
||||
subsonicTokenCopyBtn->clicked().connect(t, [subsonicTokenPtr] {
|
||||
const std::string val{ subsonicTokenPtr->valueText().toUTF8() };
|
||||
if (!val.empty())
|
||||
{
|
||||
utils::copyToClipboard(val);
|
||||
LmsApp->notifyMsg(Notification::Type::Info, Wt::WString::tr("Lms.Settings.subsonic-token-copied"));
|
||||
}
|
||||
});
|
||||
t->bindWidget("subsonic-token-copy-btn", std::move(subsonicTokenCopyBtn));
|
||||
|
||||
auto subsonicTokenVisibilityBtn{ std::make_unique<Wt::WPushButton>(Wt::WString::tr("Lms.template.toggle-visibility-btn"), Wt::TextFormat::XHTML) };
|
||||
subsonicTokenVisibilityBtn->clicked().connect(t, [subsonicTokenPtr] {
|
||||
subsonicTokenPtr->setEchoMode(subsonicTokenPtr->echoMode() == Wt::EchoMode::Password ? Wt::EchoMode::Normal : Wt::EchoMode::Password);
|
||||
});
|
||||
t->bindWidget("subsonic-token-visibility-btn", std::move(subsonicTokenVisibilityBtn));
|
||||
|
||||
initTooltipsForWidgetTree(*t);
|
||||
}
|
||||
} // namespace lms::ui
|
||||
|
||||
@@ -30,5 +30,7 @@ namespace lms::ui
|
||||
|
||||
private:
|
||||
void refreshView();
|
||||
void refreshForm();
|
||||
void refreshSubsonicKey();
|
||||
};
|
||||
} // namespace lms::ui
|
||||
|
||||
Reference in New Issue
Block a user