Send pending listens that have not been successfully sent
This commit is contained in:
@@ -155,17 +155,24 @@ namespace Database
|
||||
return session.getDboSession().find<Listen>().where("id = ?").bind(id).resultValue();
|
||||
}
|
||||
|
||||
RangeResults<Listen::pointer>
|
||||
Listen::find(Session& session, UserId userId, Scrobbler scrobbler, Range range)
|
||||
RangeResults<ListenId>
|
||||
Listen::find(Session& session, const FindParameters& parameters)
|
||||
{
|
||||
session.checkSharedLocked();
|
||||
|
||||
auto query {session.getDboSession().find<Listen>()
|
||||
.where("user_id = ?").bind(userId)
|
||||
.where("scrobbler = ?").bind(scrobbler)
|
||||
.orderBy("date_time")};
|
||||
auto query {session.getDboSession().query<ListenId>("SELECT id FROM listen")
|
||||
.orderBy("date_time")};
|
||||
|
||||
return execQuery(query, range);
|
||||
if (parameters.user.isValid())
|
||||
query.where("user_id = ?").bind(parameters.user);
|
||||
|
||||
if (parameters.scrobbler)
|
||||
query.where("scrobbler = ?").bind(*parameters.scrobbler);
|
||||
|
||||
if (parameters.scrobblingState)
|
||||
query.where("scrobbling_state = ?").bind(*parameters.scrobblingState);
|
||||
|
||||
return execQuery(query, parameters.range);
|
||||
}
|
||||
|
||||
Listen::pointer
|
||||
|
||||
@@ -75,6 +75,13 @@ namespace Database::Migration
|
||||
Db& _db;
|
||||
};
|
||||
|
||||
static
|
||||
std::string
|
||||
dateTimeToDbFormat(const Wt::WDateTime& dateTime)
|
||||
{
|
||||
return dateTime.toString("yyyy'-'MM'-'dd'T'hh':'mm':'ss'.000'", false).toUTF8();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV5(Session& session)
|
||||
@@ -450,7 +457,7 @@ CREATE TABLE "starred_track" (
|
||||
// Can't migrate using class mapping as mapping may evolve in the future
|
||||
|
||||
// use time_t to avoid rounding issues later
|
||||
const Wt::WDateTime now {Wt::WDateTime::fromTime_t(Wt::WDateTime::currentDateTime().toTime_t())};
|
||||
const std::string now {dateTimeToDbFormat(Wt::WDateTime::fromTime_t(Wt::WDateTime::currentDateTime().toTime_t()))};
|
||||
|
||||
std::map<IdType::ValueType, Scrobbler> userScrobblers;
|
||||
auto getScrobbler {[&](IdType::ValueType userId)
|
||||
@@ -480,7 +487,7 @@ CREATE TABLE "starred_track" (
|
||||
session.getDboSession().execute("INSERT INTO " + newTableName + " ('version', 'scrobbler', 'date_time', '" + colName + "', 'user_id') VALUES (?, ?, ?, ?, ?)")
|
||||
.bind(0)
|
||||
.bind(getScrobbler(userId))
|
||||
.bind(now.toString().toUTF8())
|
||||
.bind(now)
|
||||
.bind(entryId)
|
||||
.bind(userId);
|
||||
}
|
||||
@@ -523,7 +530,7 @@ CREATE TABLE "listen" (
|
||||
{
|
||||
session.getDboSession().execute("INSERT INTO listen ('version', 'date_time', 'scrobbler', 'scrobbling_state', 'track_id', 'user_id') VALUES (?, ?, ?, ?, ?, ?)")
|
||||
.bind(0)
|
||||
.bind(dateTime.toString().toUTF8())
|
||||
.bind(dateTimeToDbFormat(dateTime))
|
||||
.bind(scrobbler)
|
||||
.bind(ScrobblingState::Synchronized) // consider sync is done to avoid duplicate submissions
|
||||
.bind(trackId)
|
||||
|
||||
@@ -44,13 +44,16 @@ User::getCount(Session& session)
|
||||
}
|
||||
|
||||
RangeResults<UserId>
|
||||
User::find(Session& session, Range range)
|
||||
User::find(Session& session, const FindParameters& params)
|
||||
{
|
||||
session.checkSharedLocked();
|
||||
|
||||
auto query {session.getDboSession().query<UserId>("SELECT id FROM user")};
|
||||
|
||||
return execQuery(query, range);
|
||||
if (params.scrobbler)
|
||||
query.where("scrobbler = ?").bind(*params.scrobbler);
|
||||
|
||||
return execQuery(query, params.range);
|
||||
}
|
||||
|
||||
User::pointer
|
||||
|
||||
@@ -44,11 +44,24 @@ class Listen : public Object<Listen, ListenId>
|
||||
Listen() = default;
|
||||
Listen(ObjectPtr<User> user, ObjectPtr<Track> track, Scrobbler scrobbler, const Wt::WDateTime& dateTime);
|
||||
|
||||
struct FindParameters
|
||||
{
|
||||
UserId user;
|
||||
std::optional<Scrobbler> scrobbler;
|
||||
std::optional<ScrobblingState> scrobblingState;
|
||||
Range range;
|
||||
|
||||
FindParameters& setUser(UserId _user) { user = _user; return *this; }
|
||||
FindParameters& setScrobbler(Scrobbler _scrobbler) { scrobbler = _scrobbler; return *this; }
|
||||
FindParameters& setScrobblingState(ScrobblingState _scrobblingState) { scrobblingState = _scrobblingState; return *this; }
|
||||
FindParameters& setRange(Range _range) {range = _range; return *this; }
|
||||
};
|
||||
|
||||
// Accessors
|
||||
static std::size_t getCount(Session& session);
|
||||
static pointer find(Session& session, ListenId id);
|
||||
static RangeResults<pointer> find(Session& session, UserId userId, Scrobbler scrobbler, Range = {});
|
||||
static pointer find(Session& session, UserId userId, TrackId trackId, Scrobbler scrobbler, const Wt::WDateTime& dateTime);
|
||||
static RangeResults<ListenId> find(Session& session, const FindParameters& parameters);
|
||||
|
||||
// Create
|
||||
static pointer create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track, Scrobbler scrobbler, const Wt::WDateTime& dateTime);
|
||||
@@ -88,8 +101,10 @@ class Listen : public Object<Listen, ListenId>
|
||||
const std::vector<ClusterId>& clusterIds,
|
||||
Range range = {});
|
||||
|
||||
ScrobblingState getScrobblingState() const { return _scrobblingState; }
|
||||
ObjectPtr<User> getUser() const { return _user; }
|
||||
ScrobblingState getScrobblingState() const { return _scrobblingState; }
|
||||
ObjectPtr<User> getUser() const { return _user; }
|
||||
ObjectPtr<Track> getTrack() const { return _track; }
|
||||
const Wt::WDateTime& getDateTime() const { return _dateTime; }
|
||||
|
||||
void setScrobblingState(ScrobblingState state) { _scrobblingState = state; }
|
||||
|
||||
|
||||
@@ -45,6 +45,15 @@ class User : public Object<User, UserId>
|
||||
std::string hash;
|
||||
};
|
||||
|
||||
struct FindParameters
|
||||
{
|
||||
std::optional<Scrobbler> scrobbler;
|
||||
Range range;
|
||||
|
||||
FindParameters& setScrobbler(Scrobbler _scrobbler) { scrobbler = _scrobbler; return *this; }
|
||||
FindParameters& setRange(Range _range) {range = _range; return *this; }
|
||||
};
|
||||
|
||||
static inline const std::size_t MinNameLength {3};
|
||||
static inline const std::size_t MaxNameLength {15};
|
||||
static inline const bool defaultSubsonicTranscodeEnable {true};
|
||||
@@ -63,7 +72,7 @@ class User : public Object<User, UserId>
|
||||
static std::size_t getCount(Session& session);
|
||||
static pointer find(Session& session, UserId id);
|
||||
static pointer find(Session& session, std::string_view loginName);
|
||||
static RangeResults<UserId> find(Session& session, Range range);
|
||||
static RangeResults<UserId> find(Session& session, const FindParameters& params);
|
||||
static pointer findDemoUser(Session& session);
|
||||
|
||||
// accessors
|
||||
|
||||
@@ -89,7 +89,7 @@ TEST_F(DatabaseFixture, SingleUser)
|
||||
{
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
EXPECT_TRUE(User::find(session, Range {}).results.empty());
|
||||
EXPECT_TRUE(User::find(session, User::FindParameters {}).results.empty());
|
||||
EXPECT_EQ(User::getCount(session), 0);
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ TEST_F(DatabaseFixture, SingleUser)
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
|
||||
EXPECT_EQ(User::find(session, Range {}).results.size(), 1);
|
||||
EXPECT_EQ(User::find(session, User::FindParameters {}).results.size(), 1);
|
||||
EXPECT_EQ(User::getCount(session), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,17 +66,28 @@ TEST_F(DatabaseFixture, Listen_get)
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
|
||||
auto listens {Listen::find(session, user->getId(), Scrobbler::ListenBrainz)};
|
||||
auto listens {Listen::find(session, Listen::FindParameters{}.setUser(user->getId()).setScrobbler(Scrobbler::ListenBrainz))};
|
||||
EXPECT_EQ(listens.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
|
||||
auto listens {Listen::find(session, user->getId(), Scrobbler::Internal)};
|
||||
EXPECT_EQ(listens.moreResults, false);
|
||||
ASSERT_EQ(listens.results.size(), 1);
|
||||
EXPECT_EQ(listens.results.front()->getId(), listen->getId());
|
||||
{
|
||||
auto listens {Listen::find(session, Listen::FindParameters{}.setUser(user->getId()).setScrobbler(Scrobbler::Internal))};
|
||||
EXPECT_EQ(listens.moreResults, false);
|
||||
ASSERT_EQ(listens.results.size(), 1);
|
||||
EXPECT_EQ(listens.results.front(), listen->getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto listens {Listen::find(session, Listen::FindParameters{}.setUser(user->getId()).setScrobbler(Scrobbler::Internal).setScrobblingState(ScrobblingState::PendingAdd))};
|
||||
EXPECT_EQ(listens.results.size(), 1);
|
||||
}
|
||||
{
|
||||
auto listens {Listen::find(session, Listen::FindParameters{}.setUser(user->getId()).setScrobbler(Scrobbler::Internal).setScrobblingState(ScrobblingState::Synchronized))};
|
||||
EXPECT_EQ(listens.results.size(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,11 +102,11 @@ TEST_F(DatabaseFixture, Listen_get_multi)
|
||||
{
|
||||
auto transaction {session.createSharedTransaction()};
|
||||
|
||||
auto listens {Listen::find(session, user->getId(), Scrobbler::Internal)};
|
||||
auto listens {Listen::find(session, Listen::FindParameters{}.setUser(user->getId()).setScrobbler(Scrobbler::Internal))};
|
||||
ASSERT_EQ(listens.results.size(), 3);
|
||||
EXPECT_EQ(listens.results[0]->getId(), listen1.getId());
|
||||
EXPECT_EQ(listens.results[1]->getId(), listen2.getId());
|
||||
EXPECT_EQ(listens.results[2]->getId(), listen3.getId());
|
||||
EXPECT_EQ(listens.results[0], listen1.getId());
|
||||
EXPECT_EQ(listens.results[1], listen2.getId());
|
||||
EXPECT_EQ(listens.results[2], listen3.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user