From 086cbea03e6514b78846f70eefd8df53e058a094 Mon Sep 17 00:00:00 2001 From: emeric Date: Tue, 10 Mar 2026 17:07:12 +0100 Subject: [PATCH] Removed UUID constraint on listenbrainz token, fixes #825 --- .../include/database/objects/User.hpp | 5 ++--- .../listenbrainz/FeedbacksSynchronizer.cpp | 12 +++++------ .../feedback/impl/listenbrainz/Utils.cpp | 15 ++++++++------ .../feedback/impl/listenbrainz/Utils.hpp | 4 ++-- .../impl/listenbrainz/ListensSynchronizer.cpp | 20 +++++++++---------- .../impl/listenbrainz/ListensSynchronizer.hpp | 2 +- .../scrobbling/impl/listenbrainz/Utils.cpp | 15 ++++++++------ .../scrobbling/impl/listenbrainz/Utils.hpp | 4 ++-- src/lms/ui/SettingsView.cpp | 12 ++++++----- src/lms/ui/admin/UserView.cpp | 2 ++ 10 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/libs/database/include/database/objects/User.hpp b/src/libs/database/include/database/objects/User.hpp index 88dd21c0..29618a7f 100644 --- a/src/libs/database/include/database/objects/User.hpp +++ b/src/libs/database/include/database/objects/User.hpp @@ -27,7 +27,6 @@ #include #include "core/EnumSet.hpp" -#include "core/UUID.hpp" #include "database/Object.hpp" #include "database/Types.hpp" @@ -118,7 +117,7 @@ namespace lms::db void setSubsonicArtistListMode(SubsonicArtistListMode mode) { _subsonicArtistListMode = mode; } void setFeedbackBackend(FeedbackBackend feedbackBackend) { _feedbackBackend = feedbackBackend; } void setScrobblingBackend(ScrobblingBackend scrobblingBackend) { _scrobblingBackend = scrobblingBackend; } - void setListenBrainzToken(const std::optional& MBID) { _listenbrainzToken = MBID ? MBID->getAsString() : ""; } + void setListenBrainzToken(std::string_view token) { _listenbrainzToken = token; } // read bool isAdmin() const { return _type == UserType::ADMIN; } @@ -134,7 +133,7 @@ namespace lms::db SubsonicArtistListMode getSubsonicArtistListMode() const { return _subsonicArtistListMode; } FeedbackBackend getFeedbackBackend() const { return _feedbackBackend; } ScrobblingBackend getScrobblingBackend() const { return _scrobblingBackend; } - std::optional getListenBrainzToken() const { return core::UUID::fromString(_listenbrainzToken); } + std::string_view getListenBrainzToken() const { return _listenbrainzToken; } template void persist(Action& a) diff --git a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp index 4e9133a0..0ba352a2 100644 --- a/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/FeedbacksSynchronizer.cpp @@ -118,13 +118,13 @@ namespace lms::feedback::listenBrainz return; } - const std::optional listenBrainzToken{ starredTrack->getUser()->getListenBrainzToken() }; - if (!listenBrainzToken) + const std::string listenBrainzToken{ starredTrack->getUser()->getListenBrainzToken() }; + if (listenBrainzToken.empty()) return; core::http::ClientPOSTRequestParameters request; request.relativeUrl = "/1/feedback/recording-feedback"; - request.message.addHeader("Authorization", "Token " + std::string{ listenBrainzToken->getAsString() }); + request.message.addHeader("Authorization", "Token " + listenBrainzToken); Wt::Json::Object root; root["recording_mbid"] = Wt::Json::Value{ std::string{ recordingMBID->getAsString() } }; @@ -310,8 +310,8 @@ namespace lms::feedback::listenBrainz { assert(context.listenBrainzUserName.empty()); - const std::optional listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), context.userId) }; - if (!listenBrainzToken) + const std::string listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), context.userId) }; + if (listenBrainzToken.empty()) { onSyncEnded(context); return; @@ -320,7 +320,7 @@ namespace lms::feedback::listenBrainz core::http::ClientGETRequestParameters request; request.priority = core::http::ClientRequestParameters::Priority::Low; request.relativeUrl = "/1/validate-token"; - request.headers = { { "Authorization", "Token " + std::string{ listenBrainzToken->getAsString() } } }; + request.headers = { { "Authorization", "Token " + listenBrainzToken } }; request.onSuccessFunc = [this, &context](const Wt::Http::Message& msg) { context.listenBrainzUserName = utils::parseValidateToken(msg.body()); if (context.listenBrainzUserName.empty()) diff --git a/src/libs/services/feedback/impl/listenbrainz/Utils.cpp b/src/libs/services/feedback/impl/listenbrainz/Utils.cpp index 6f9932d4..90057982 100644 --- a/src/libs/services/feedback/impl/listenbrainz/Utils.cpp +++ b/src/libs/services/feedback/impl/listenbrainz/Utils.cpp @@ -27,15 +27,18 @@ namespace lms::feedback::listenBrainz::utils { - std::optional getListenBrainzToken(db::Session& session, db::UserId userId) + std::string getListenBrainzToken(db::Session& session, db::UserId userId) { - auto transaction{ session.createReadTransaction() }; + std::string res; - const db::User::pointer user{ db::User::find(session, userId) }; - if (!user) - return std::nullopt; + { + auto transaction{ session.createReadTransaction() }; - return user->getListenBrainzToken(); + if (const db::User::pointer user{ db::User::find(session, userId) }) + res = std::string{ user->getListenBrainzToken() }; + } + + return res; } std::string parseValidateToken(std::string_view msgBody) diff --git a/src/libs/services/feedback/impl/listenbrainz/Utils.hpp b/src/libs/services/feedback/impl/listenbrainz/Utils.hpp index d2790cef..2b131a16 100644 --- a/src/libs/services/feedback/impl/listenbrainz/Utils.hpp +++ b/src/libs/services/feedback/impl/listenbrainz/Utils.hpp @@ -20,7 +20,7 @@ #pragma once #include "core/ILogger.hpp" -#include "core/UUID.hpp" + #include "database/objects/UserId.hpp" #define LOG(sev, message) LMS_LOG(FEEDBACK, sev, "[listenbrainz] " << message) @@ -32,6 +32,6 @@ namespace lms::db namespace lms::feedback::listenBrainz::utils { - std::optional getListenBrainzToken(db::Session& session, db::UserId userId); + std::string getListenBrainzToken(db::Session& session, db::UserId userId); std::string parseValidateToken(std::string_view msgBody); } // namespace lms::feedback::listenBrainz::utils diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp index 6895593d..62da3092 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.cpp @@ -291,34 +291,32 @@ namespace lms::scrobbling::listenBrainz return; } - const std::optional listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), listen.userId) }; - if (!listenBrainzToken) + const std::string listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), listen.userId) }; + if (listenBrainzToken.empty()) { LOG(DEBUG, "No listenbrainz token found: skipping"); return; } request.message.addBodyText(bodyText); - request.message.addHeader("Authorization", "Token " + std::string{ listenBrainzToken->getAsString() }); + request.message.addHeader("Authorization", "Token " + listenBrainzToken); request.message.addHeader("Content-Type", "application/json"); _client.sendPOSTRequest(std::move(request)); } bool ListensSynchronizer::saveListen(const TimedListen& listen, db::SyncState scrobblingState) { - using namespace db; - - Session& session{ _db.getTLSSession() }; + db::Session& session{ _db.getTLSSession() }; auto transaction{ session.createWriteTransaction() }; // TODO: unique only if needed db::Listen::pointer dbListen{ db::Listen::find(session, listen.userId, listen.trackId, db::ScrobblingBackend::ListenBrainz, listen.listenedAt) }; if (!dbListen) { - const User::pointer user{ User::find(session, listen.userId) }; + const db::User::pointer user{ db::User::find(session, listen.userId) }; if (!user) return false; - const Track::pointer track{ Track::find(session, listen.trackId) }; + const db::Track::pointer track{ db::Track::find(session, listen.trackId) }; if (!track) return false; @@ -464,8 +462,8 @@ namespace lms::scrobbling::listenBrainz { assert(context.listenBrainzUserName.empty()); - const std::optional listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), context.userId) }; - if (!listenBrainzToken) + const std::string listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), context.userId) }; + if (listenBrainzToken.empty()) { onSyncEnded(context); return; @@ -474,7 +472,7 @@ namespace lms::scrobbling::listenBrainz core::http::ClientGETRequestParameters request; request.priority = core::http::ClientRequestParameters::Priority::Low; request.relativeUrl = "/1/validate-token"; - request.headers = { { "Authorization", "Token " + std::string{ listenBrainzToken->getAsString() } } }; + request.headers = { { "Authorization", "Token " + listenBrainzToken } }; request.onSuccessFunc = [this, &context](const Wt::Http::Message& msg) { context.listenBrainzUserName = utils::parseValidateToken(msg.body()); if (context.listenBrainzUserName.empty()) diff --git a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp index 3bd41c2f..de8b4bbb 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/ListensSynchronizer.hpp @@ -55,7 +55,7 @@ namespace lms::scrobbling::listenBrainz private: void enqueListen(const Listen& listen, const Wt::WDateTime& timePoint); - bool saveListen(const TimedListen& listen, db::SyncState scrobblinState); + bool saveListen(const TimedListen& listen, db::SyncState scrobblingState); void enquePendingListens(); diff --git a/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp b/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp index 230f9df1..7a33db20 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/Utils.cpp @@ -27,15 +27,18 @@ namespace lms::scrobbling::listenBrainz::utils { - std::optional getListenBrainzToken(db::Session& session, db::UserId userId) + std::string getListenBrainzToken(db::Session& session, db::UserId userId) { - auto transaction{ session.createReadTransaction() }; + std::string res; - const db::User::pointer user{ db::User::find(session, userId) }; - if (!user) - return std::nullopt; + { + auto transaction{ session.createReadTransaction() }; - return user->getListenBrainzToken(); + if (const db::User::pointer user{ db::User::find(session, userId) }) + res = user->getListenBrainzToken(); + } + + return res; } std::string parseValidateToken(std::string_view msgBody) diff --git a/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp b/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp index 6bd75648..816f7e80 100644 --- a/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp +++ b/src/libs/services/scrobbling/impl/listenbrainz/Utils.hpp @@ -20,7 +20,7 @@ #pragma once #include "core/ILogger.hpp" -#include "core/UUID.hpp" + #include "database/objects/UserId.hpp" #define LOG(sev, message) LMS_LOG(SCROBBLING, sev, "[listenbrainz] " << message) @@ -32,6 +32,6 @@ namespace lms::db namespace lms::scrobbling::listenBrainz::utils { - std::optional getListenBrainzToken(db::Session& session, db::UserId userId); + std::string getListenBrainzToken(db::Session& session, db::UserId userId); std::string parseValidateToken(std::string_view msgBody); } // namespace lms::scrobbling::listenBrainz::utils diff --git a/src/lms/ui/SettingsView.cpp b/src/lms/ui/SettingsView.cpp index 36fe516b..158064a3 100644 --- a/src/lms/ui/SettingsView.cpp +++ b/src/lms/ui/SettingsView.cpp @@ -32,6 +32,8 @@ #include "core/IConfig.hpp" #include "core/Service.hpp" #include "core/String.hpp" +#include "core/UUID.hpp" + #include "database/Session.hpp" #include "database/Types.hpp" #include "database/objects/User.hpp" @@ -144,7 +146,7 @@ namespace lms::ui addField(ListenBrainzTokenField); setValidator(SubsonicTokenField, createUUIDValidator()); - setValidator(ListenBrainzTokenField, createUUIDValidator()); + setValidator(ListenBrainzTokenField, createMandatoryValidator()); if (_authPasswordService) { @@ -284,14 +286,14 @@ namespace lms::ui if (auto feedbackBackendRow{ _feedbackBackendModel->getRowFromString(valueText(FeedbackBackendField)) }) user.modify()->setFeedbackBackend(_feedbackBackendModel->getValue(*feedbackBackendRow)); - user.modify()->setListenBrainzToken(core::UUID::fromString(Wt::asString(value(ListenBrainzTokenField)).toUTF8())); + user.modify()->setListenBrainzToken(Wt::asString(value(ListenBrainzTokenField)).toUTF8()); } { if (auto scrobblingBackendRow{ _scrobblingBackendModel->getRowFromString(valueText(ScrobblingBackendField)) }) user.modify()->setScrobblingBackend(_scrobblingBackendModel->getValue(*scrobblingBackendRow)); - user.modify()->setListenBrainzToken(core::UUID::fromString(Wt::asString(value(ListenBrainzTokenField)).toUTF8())); + user.modify()->setListenBrainzToken(Wt::asString(value(ListenBrainzTokenField)).toUTF8()); } if (_authPasswordService && !valueText(PasswordField).empty()) @@ -390,8 +392,8 @@ namespace lms::ui if (auto scrobblingBackendRow{ _scrobblingBackendModel->getRowFromValue(user->getScrobblingBackend()) }) setValue(ScrobblingBackendField, _scrobblingBackendModel->getString(*scrobblingBackendRow)); - if (auto listenBrainzToken{ user->getListenBrainzToken() }) - setValue(ListenBrainzTokenField, Wt::WString::fromUTF8(std::string{ listenBrainzToken->getAsString() })); + if (const auto listenBrainzToken{ user->getListenBrainzToken() }; !listenBrainzToken.empty()) + setValue(ListenBrainzTokenField, Wt::WString::fromUTF8(std::string{ listenBrainzToken })); { const bool usesListenBrainz{ user->getScrobblingBackend() == db::ScrobblingBackend::ListenBrainz || user->getFeedbackBackend() == db::FeedbackBackend::ListenBrainz }; diff --git a/src/lms/ui/admin/UserView.cpp b/src/lms/ui/admin/UserView.cpp index 8ab44a40..85a0505d 100644 --- a/src/lms/ui/admin/UserView.cpp +++ b/src/lms/ui/admin/UserView.cpp @@ -30,6 +30,8 @@ #include "core/IConfig.hpp" #include "core/Service.hpp" #include "core/String.hpp" +#include "core/UUID.hpp" + #include "database/Session.hpp" #include "database/objects/User.hpp" #include "services/auth/IAuthTokenService.hpp"