Removed UUID constraint on listenbrainz token, fixes #825

This commit is contained in:
emeric
2026-03-10 17:07:12 +01:00
parent 82468be9cc
commit 086cbea03e
10 changed files with 49 additions and 42 deletions
@@ -27,7 +27,6 @@
#include <Wt/WDateTime.h> #include <Wt/WDateTime.h>
#include "core/EnumSet.hpp" #include "core/EnumSet.hpp"
#include "core/UUID.hpp"
#include "database/Object.hpp" #include "database/Object.hpp"
#include "database/Types.hpp" #include "database/Types.hpp"
@@ -118,7 +117,7 @@ namespace lms::db
void setSubsonicArtistListMode(SubsonicArtistListMode mode) { _subsonicArtistListMode = mode; } void setSubsonicArtistListMode(SubsonicArtistListMode mode) { _subsonicArtistListMode = mode; }
void setFeedbackBackend(FeedbackBackend feedbackBackend) { _feedbackBackend = feedbackBackend; } void setFeedbackBackend(FeedbackBackend feedbackBackend) { _feedbackBackend = feedbackBackend; }
void setScrobblingBackend(ScrobblingBackend scrobblingBackend) { _scrobblingBackend = scrobblingBackend; } void setScrobblingBackend(ScrobblingBackend scrobblingBackend) { _scrobblingBackend = scrobblingBackend; }
void setListenBrainzToken(const std::optional<core::UUID>& MBID) { _listenbrainzToken = MBID ? MBID->getAsString() : ""; } void setListenBrainzToken(std::string_view token) { _listenbrainzToken = token; }
// read // read
bool isAdmin() const { return _type == UserType::ADMIN; } bool isAdmin() const { return _type == UserType::ADMIN; }
@@ -134,7 +133,7 @@ namespace lms::db
SubsonicArtistListMode getSubsonicArtistListMode() const { return _subsonicArtistListMode; } SubsonicArtistListMode getSubsonicArtistListMode() const { return _subsonicArtistListMode; }
FeedbackBackend getFeedbackBackend() const { return _feedbackBackend; } FeedbackBackend getFeedbackBackend() const { return _feedbackBackend; }
ScrobblingBackend getScrobblingBackend() const { return _scrobblingBackend; } ScrobblingBackend getScrobblingBackend() const { return _scrobblingBackend; }
std::optional<core::UUID> getListenBrainzToken() const { return core::UUID::fromString(_listenbrainzToken); } std::string_view getListenBrainzToken() const { return _listenbrainzToken; }
template<class Action> template<class Action>
void persist(Action& a) void persist(Action& a)
@@ -118,13 +118,13 @@ namespace lms::feedback::listenBrainz
return; return;
} }
const std::optional<core::UUID> listenBrainzToken{ starredTrack->getUser()->getListenBrainzToken() }; const std::string listenBrainzToken{ starredTrack->getUser()->getListenBrainzToken() };
if (!listenBrainzToken) if (listenBrainzToken.empty())
return; return;
core::http::ClientPOSTRequestParameters request; core::http::ClientPOSTRequestParameters request;
request.relativeUrl = "/1/feedback/recording-feedback"; 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; Wt::Json::Object root;
root["recording_mbid"] = Wt::Json::Value{ std::string{ recordingMBID->getAsString() } }; root["recording_mbid"] = Wt::Json::Value{ std::string{ recordingMBID->getAsString() } };
@@ -310,8 +310,8 @@ namespace lms::feedback::listenBrainz
{ {
assert(context.listenBrainzUserName.empty()); assert(context.listenBrainzUserName.empty());
const std::optional<core::UUID> listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), context.userId) }; const std::string listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), context.userId) };
if (!listenBrainzToken) if (listenBrainzToken.empty())
{ {
onSyncEnded(context); onSyncEnded(context);
return; return;
@@ -320,7 +320,7 @@ namespace lms::feedback::listenBrainz
core::http::ClientGETRequestParameters request; core::http::ClientGETRequestParameters request;
request.priority = core::http::ClientRequestParameters::Priority::Low; request.priority = core::http::ClientRequestParameters::Priority::Low;
request.relativeUrl = "/1/validate-token"; 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) { request.onSuccessFunc = [this, &context](const Wt::Http::Message& msg) {
context.listenBrainzUserName = utils::parseValidateToken(msg.body()); context.listenBrainzUserName = utils::parseValidateToken(msg.body());
if (context.listenBrainzUserName.empty()) if (context.listenBrainzUserName.empty())
@@ -27,15 +27,18 @@
namespace lms::feedback::listenBrainz::utils namespace lms::feedback::listenBrainz::utils
{ {
std::optional<core::UUID> 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) auto transaction{ session.createReadTransaction() };
return std::nullopt;
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) std::string parseValidateToken(std::string_view msgBody)
@@ -20,7 +20,7 @@
#pragma once #pragma once
#include "core/ILogger.hpp" #include "core/ILogger.hpp"
#include "core/UUID.hpp"
#include "database/objects/UserId.hpp" #include "database/objects/UserId.hpp"
#define LOG(sev, message) LMS_LOG(FEEDBACK, sev, "[listenbrainz] " << message) #define LOG(sev, message) LMS_LOG(FEEDBACK, sev, "[listenbrainz] " << message)
@@ -32,6 +32,6 @@ namespace lms::db
namespace lms::feedback::listenBrainz::utils namespace lms::feedback::listenBrainz::utils
{ {
std::optional<core::UUID> getListenBrainzToken(db::Session& session, db::UserId userId); std::string getListenBrainzToken(db::Session& session, db::UserId userId);
std::string parseValidateToken(std::string_view msgBody); std::string parseValidateToken(std::string_view msgBody);
} // namespace lms::feedback::listenBrainz::utils } // namespace lms::feedback::listenBrainz::utils
@@ -291,34 +291,32 @@ namespace lms::scrobbling::listenBrainz
return; return;
} }
const std::optional<core::UUID> listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), listen.userId) }; const std::string listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), listen.userId) };
if (!listenBrainzToken) if (listenBrainzToken.empty())
{ {
LOG(DEBUG, "No listenbrainz token found: skipping"); LOG(DEBUG, "No listenbrainz token found: skipping");
return; return;
} }
request.message.addBodyText(bodyText); 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"); request.message.addHeader("Content-Type", "application/json");
_client.sendPOSTRequest(std::move(request)); _client.sendPOSTRequest(std::move(request));
} }
bool ListensSynchronizer::saveListen(const TimedListen& listen, db::SyncState scrobblingState) bool ListensSynchronizer::saveListen(const TimedListen& listen, db::SyncState scrobblingState)
{ {
using namespace db; db::Session& session{ _db.getTLSSession() };
Session& session{ _db.getTLSSession() };
auto transaction{ session.createWriteTransaction() }; // TODO: unique only if needed 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) }; db::Listen::pointer dbListen{ db::Listen::find(session, listen.userId, listen.trackId, db::ScrobblingBackend::ListenBrainz, listen.listenedAt) };
if (!dbListen) if (!dbListen)
{ {
const User::pointer user{ User::find(session, listen.userId) }; const db::User::pointer user{ db::User::find(session, listen.userId) };
if (!user) if (!user)
return false; return false;
const Track::pointer track{ Track::find(session, listen.trackId) }; const db::Track::pointer track{ db::Track::find(session, listen.trackId) };
if (!track) if (!track)
return false; return false;
@@ -464,8 +462,8 @@ namespace lms::scrobbling::listenBrainz
{ {
assert(context.listenBrainzUserName.empty()); assert(context.listenBrainzUserName.empty());
const std::optional<core::UUID> listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), context.userId) }; const std::string listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), context.userId) };
if (!listenBrainzToken) if (listenBrainzToken.empty())
{ {
onSyncEnded(context); onSyncEnded(context);
return; return;
@@ -474,7 +472,7 @@ namespace lms::scrobbling::listenBrainz
core::http::ClientGETRequestParameters request; core::http::ClientGETRequestParameters request;
request.priority = core::http::ClientRequestParameters::Priority::Low; request.priority = core::http::ClientRequestParameters::Priority::Low;
request.relativeUrl = "/1/validate-token"; 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) { request.onSuccessFunc = [this, &context](const Wt::Http::Message& msg) {
context.listenBrainzUserName = utils::parseValidateToken(msg.body()); context.listenBrainzUserName = utils::parseValidateToken(msg.body());
if (context.listenBrainzUserName.empty()) if (context.listenBrainzUserName.empty())
@@ -55,7 +55,7 @@ namespace lms::scrobbling::listenBrainz
private: private:
void enqueListen(const Listen& listen, const Wt::WDateTime& timePoint); 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(); void enquePendingListens();
@@ -27,15 +27,18 @@
namespace lms::scrobbling::listenBrainz::utils namespace lms::scrobbling::listenBrainz::utils
{ {
std::optional<core::UUID> 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) auto transaction{ session.createReadTransaction() };
return std::nullopt;
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) std::string parseValidateToken(std::string_view msgBody)
@@ -20,7 +20,7 @@
#pragma once #pragma once
#include "core/ILogger.hpp" #include "core/ILogger.hpp"
#include "core/UUID.hpp"
#include "database/objects/UserId.hpp" #include "database/objects/UserId.hpp"
#define LOG(sev, message) LMS_LOG(SCROBBLING, sev, "[listenbrainz] " << message) #define LOG(sev, message) LMS_LOG(SCROBBLING, sev, "[listenbrainz] " << message)
@@ -32,6 +32,6 @@ namespace lms::db
namespace lms::scrobbling::listenBrainz::utils namespace lms::scrobbling::listenBrainz::utils
{ {
std::optional<core::UUID> getListenBrainzToken(db::Session& session, db::UserId userId); std::string getListenBrainzToken(db::Session& session, db::UserId userId);
std::string parseValidateToken(std::string_view msgBody); std::string parseValidateToken(std::string_view msgBody);
} // namespace lms::scrobbling::listenBrainz::utils } // namespace lms::scrobbling::listenBrainz::utils
+7 -5
View File
@@ -32,6 +32,8 @@
#include "core/IConfig.hpp" #include "core/IConfig.hpp"
#include "core/Service.hpp" #include "core/Service.hpp"
#include "core/String.hpp" #include "core/String.hpp"
#include "core/UUID.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/Types.hpp" #include "database/Types.hpp"
#include "database/objects/User.hpp" #include "database/objects/User.hpp"
@@ -144,7 +146,7 @@ namespace lms::ui
addField(ListenBrainzTokenField); addField(ListenBrainzTokenField);
setValidator(SubsonicTokenField, createUUIDValidator()); setValidator(SubsonicTokenField, createUUIDValidator());
setValidator(ListenBrainzTokenField, createUUIDValidator()); setValidator(ListenBrainzTokenField, createMandatoryValidator());
if (_authPasswordService) if (_authPasswordService)
{ {
@@ -284,14 +286,14 @@ namespace lms::ui
if (auto feedbackBackendRow{ _feedbackBackendModel->getRowFromString(valueText(FeedbackBackendField)) }) if (auto feedbackBackendRow{ _feedbackBackendModel->getRowFromString(valueText(FeedbackBackendField)) })
user.modify()->setFeedbackBackend(_feedbackBackendModel->getValue(*feedbackBackendRow)); 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)) }) if (auto scrobblingBackendRow{ _scrobblingBackendModel->getRowFromString(valueText(ScrobblingBackendField)) })
user.modify()->setScrobblingBackend(_scrobblingBackendModel->getValue(*scrobblingBackendRow)); 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()) if (_authPasswordService && !valueText(PasswordField).empty())
@@ -390,8 +392,8 @@ namespace lms::ui
if (auto scrobblingBackendRow{ _scrobblingBackendModel->getRowFromValue(user->getScrobblingBackend()) }) if (auto scrobblingBackendRow{ _scrobblingBackendModel->getRowFromValue(user->getScrobblingBackend()) })
setValue(ScrobblingBackendField, _scrobblingBackendModel->getString(*scrobblingBackendRow)); setValue(ScrobblingBackendField, _scrobblingBackendModel->getString(*scrobblingBackendRow));
if (auto listenBrainzToken{ user->getListenBrainzToken() }) if (const auto listenBrainzToken{ user->getListenBrainzToken() }; !listenBrainzToken.empty())
setValue(ListenBrainzTokenField, Wt::WString::fromUTF8(std::string{ listenBrainzToken->getAsString() })); setValue(ListenBrainzTokenField, Wt::WString::fromUTF8(std::string{ listenBrainzToken }));
{ {
const bool usesListenBrainz{ user->getScrobblingBackend() == db::ScrobblingBackend::ListenBrainz || user->getFeedbackBackend() == db::FeedbackBackend::ListenBrainz }; const bool usesListenBrainz{ user->getScrobblingBackend() == db::ScrobblingBackend::ListenBrainz || user->getFeedbackBackend() == db::FeedbackBackend::ListenBrainz };
+2
View File
@@ -30,6 +30,8 @@
#include "core/IConfig.hpp" #include "core/IConfig.hpp"
#include "core/Service.hpp" #include "core/Service.hpp"
#include "core/String.hpp" #include "core/String.hpp"
#include "core/UUID.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/objects/User.hpp" #include "database/objects/User.hpp"
#include "services/auth/IAuthTokenService.hpp" #include "services/auth/IAuthTokenService.hpp"