Update watch list code to use guids

This commit is contained in:
Zoe Roux 2023-11-29 02:42:45 +01:00
parent b9932383c6
commit 4139362677
7 changed files with 89 additions and 136 deletions

View File

@ -35,82 +35,23 @@ public interface IWatchStatusRepository
// /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> // /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
// public delegate Task ResourceEventHandler(T resource); // public delegate Task ResourceEventHandler(T resource);
/// <summary> Task<MovieWatchStatus?> GetMovieStatus(Guid movieId, Guid userId);
/// Get the watch status of a movie
/// </summary> Task<MovieWatchStatus?> SetMovieStatus(Guid movieId, Guid userId, WatchStatus status, int? watchedTime);
/// <param name="where">The movie selector.</param>
/// <param name="userId">The id of the user.</param> Task DeleteMovieStatus(Guid movieId, Guid userId);
/// <returns>The movie's status</returns>
Task<MovieWatchStatus?> GetMovieStatus(Expression<Func<Movie, bool>> where, int userId); Task<ShowWatchStatus?> GetShowStatus(Guid showId, Guid userId);
Task<ShowWatchStatus?> SetShowStatus(Guid showId, Guid userId, WatchStatus status);
Task DeleteShowStatus(Guid showId, Guid userId);
Task<EpisodeWatchStatus?> GetEpisodeStatus(Guid episodeId, Guid userId);
/// <summary>
/// Set the watch status of a movie
/// </summary>
/// <param name="movieId">The id of the movie.</param>
/// <param name="userId">The id of the user.</param>
/// <param name="status">The new status.</param>
/// <param name="watchedTime">Where the user has stopped watching. Only usable if Status /// <param name="watchedTime">Where the user has stopped watching. Only usable if Status
/// is <see cref="WatchStatus.Watching"/></param> /// is <see cref="WatchStatus.Watching"/></param>
/// <returns>The movie's status</returns> Task<EpisodeWatchStatus?> SetEpisodeStatus(Guid episodeId, Guid userId, WatchStatus status, int? watchedTime);
Task<MovieWatchStatus?> SetMovieStatus(int movieId, int userId, WatchStatus status, int? watchedTime);
/// <summary> Task DeleteEpisodeStatus(Guid episodeId, Guid userId);
/// Delete the watch status of a movie.
/// </summary>
/// <param name="where">The movie selector.</param>
/// <param name="userId">The id of the user.</param>
/// <returns>Nothing.</returns>
Task DeleteMovieStatus(Expression<Func<Movie, bool>> where, int userId);
/// <summary>
/// Get the watch status of a show.
/// </summary>
/// <param name="where">The show selector.</param>
/// <param name="userId">The id of the user.</param>
/// <returns>The show's status</returns>
Task<ShowWatchStatus?> GetShowStatus(Expression<Func<Show, bool>> where, int userId);
/// <summary>
/// Set the watch status of a show.
/// </summary>
/// <param name="showId">The id of the movie.</param>
/// <param name="userId">The id of the user.</param>
/// <param name="status">The new status.</param>
/// <returns>The shows's status</returns>
Task<ShowWatchStatus?> SetShowStatus(int showId, int userId, WatchStatus status);
/// <summary>
/// Delete the watch status of a show.
/// </summary>
/// <param name="where">The show selector.</param>
/// <param name="userId">The id of the user.</param>
/// <returns>Nothing.</returns>
Task DeleteShowStatus(Expression<Func<Show, bool>> where, int userId);
/// <summary>
/// Get the watch status of an episode.
/// </summary>
/// <param name="where">The episode selector.</param>
/// <param name="userId">The id of the user.</param>
/// <returns>The episode's status</returns>
Task<EpisodeWatchStatus?> GetEpisodeStatus(Expression<Func<Episode, bool>> where, int userId);
/// <summary>
/// Set the watch status of an episode.
/// </summary>
/// <param name="episodeId">The id of the episode.</param>
/// <param name="userId">The id of the user.</param>
/// <param name="status">The new status.</param>
/// <param name="watchedTime">Where the user has stopped watching. Only usable if Status
/// is <see cref="WatchStatus.Watching"/></param>
/// <returns>The episode's status</returns>
Task<EpisodeWatchStatus?> SetEpisodeStatus(int episodeId, int userId, WatchStatus status, int? watchedTime);
/// <summary>
/// Delete the watch status of an episode.
/// </summary>
/// <param name="where">The episode selector.</param>
/// <param name="userId">The id of the user.</param>
/// <returns>Nothing.</returns>
Task DeleteEpisodeStatus(Expression<Func<Episode, bool>> where, int userId);
} }

View File

@ -294,10 +294,20 @@ public static class DapperHelper
Func<List<object?>, T> mapper, Func<List<object?>, T> mapper,
Include<T>? include, Include<T>? include,
Filter<T>? filter, Filter<T>? filter,
Sort<T>? sort = null) Sort<T>? sort = null,
bool reverse = false)
where T : class, IResource, IQuery where T : class, IResource, IQuery
{ {
ICollection<T> ret = await db.Query<T>(command, config, mapper, null!, include, filter, sort, new Pagination(1)); ICollection<T> ret = await db.Query<T>(
command,
config,
mapper,
get: null!,
include,
filter,
sort,
new Pagination(1, reverse: reverse)
);
return ret.FirstOrDefault(); return ret.FirstOrDefault();
} }

View File

@ -128,7 +128,10 @@ public abstract class DapperRepository<T> : IRepository<T>
} }
/// <inheritdoc /> /// <inheritdoc />
public Task<T?> GetOrDefault(Filter<T>? filter, Include<T>? include = null, Sort<T>? sortBy = null) public Task<T?> GetOrDefault(Filter<T>? filter,
Include<T>? include = null,
Sort<T>? sortBy = null,
bool reverse = false)
{ {
return Database.QuerySingle<T>( return Database.QuerySingle<T>(
Sql, Sql,

View File

@ -23,6 +23,7 @@ using System.Linq.Expressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Utils;
using Kyoo.Postgresql; using Kyoo.Postgresql;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -57,18 +58,15 @@ public class WatchStatusRepository : IWatchStatusRepository
} }
/// <inheritdoc /> /// <inheritdoc />
public Task<MovieWatchStatus?> GetMovieStatus(Expression<Func<Movie, bool>> where, int userId) public Task<MovieWatchStatus?> GetMovieStatus(Guid movieId, Guid userId)
{ {
return _database.MovieWatchStatus.FirstOrDefaultAsync(x => return _database.MovieWatchStatus.FirstOrDefaultAsync(x => x.MovieId == movieId && x.UserId == userId);
x.Movie == _database.Movies.FirstOrDefault(where)
&& x.UserId == userId
);
} }
/// <inheritdoc /> /// <inheritdoc />
public async Task<MovieWatchStatus?> SetMovieStatus( public async Task<MovieWatchStatus?> SetMovieStatus(
int movieId, Guid movieId,
int userId, Guid userId,
WatchStatus status, WatchStatus status,
int? watchedTime) int? watchedTime)
{ {
@ -105,28 +103,24 @@ public class WatchStatusRepository : IWatchStatusRepository
/// <inheritdoc /> /// <inheritdoc />
public async Task DeleteMovieStatus( public async Task DeleteMovieStatus(
Expression<Func<Movie, bool>> where, Guid movieId,
int userId) Guid userId)
{ {
await _database.MovieWatchStatus await _database.MovieWatchStatus
.Where(x => x.Movie == _database.Movies.FirstOrDefault(where) .Where(x => x.MovieId == movieId && x.UserId == userId)
&& x.UserId == userId)
.ExecuteDeleteAsync(); .ExecuteDeleteAsync();
} }
/// <inheritdoc /> /// <inheritdoc />
public Task<ShowWatchStatus?> GetShowStatus(Expression<Func<Show, bool>> where, int userId) public Task<ShowWatchStatus?> GetShowStatus(Guid showId, Guid userId)
{ {
return _database.ShowWatchStatus.FirstOrDefaultAsync(x => return _database.ShowWatchStatus.FirstOrDefaultAsync(x => x.ShowId == showId && x.UserId == userId);
x.Show == _database.Shows.FirstOrDefault(where)
&& x.UserId == userId
);
} }
/// <inheritdoc /> /// <inheritdoc />
public async Task<ShowWatchStatus?> SetShowStatus( public async Task<ShowWatchStatus?> SetShowStatus(
int showId, Guid showId,
int userId, Guid userId,
WatchStatus status) WatchStatus status)
{ {
int unseenEpisodeCount = await _database.Episodes int unseenEpisodeCount = await _database.Episodes
@ -143,9 +137,11 @@ public class WatchStatusRepository : IWatchStatusRepository
Status = status, Status = status,
NextEpisode = status == WatchStatus.Watching NextEpisode = status == WatchStatus.Watching
? await _episodes.GetOrDefault( ? await _episodes.GetOrDefault(
where: x => x.ShowId == showId new Filter<Episode>.Lambda(
&& (x.WatchStatus!.Status == WatchStatus.Watching x => x.ShowId == showId
|| x.WatchStatus.Status == WatchStatus.Completed), && (x.WatchStatus!.Status == WatchStatus.Watching
|| x.WatchStatus.Status == WatchStatus.Completed)
),
reverse: true reverse: true
) )
: null, : null,
@ -160,32 +156,27 @@ public class WatchStatusRepository : IWatchStatusRepository
/// <inheritdoc /> /// <inheritdoc />
public async Task DeleteShowStatus( public async Task DeleteShowStatus(
Expression<Func<Show, bool>> where, Guid showId,
int userId) Guid userId)
{ {
await _database.ShowWatchStatus await _database.ShowWatchStatus
.Where(x => x.Show == _database.Shows.FirstOrDefault(where) .Where(x => x.ShowId == showId && x.UserId == userId)
&& x.UserId == userId)
.ExecuteDeleteAsync(); .ExecuteDeleteAsync();
await _database.EpisodeWatchStatus await _database.EpisodeWatchStatus
.Where(x => x.Episode.Show == _database.Shows.FirstOrDefault(where) .Where(x => x.Episode.ShowId == showId && x.UserId == userId)
&& x.UserId == userId)
.ExecuteDeleteAsync(); .ExecuteDeleteAsync();
} }
/// <inheritdoc /> /// <inheritdoc />
public Task<EpisodeWatchStatus?> GetEpisodeStatus(Expression<Func<Episode, bool>> where, int userId) public Task<EpisodeWatchStatus?> GetEpisodeStatus(Guid episodeId, Guid userId)
{ {
return _database.EpisodeWatchStatus.FirstOrDefaultAsync(x => return _database.EpisodeWatchStatus.FirstOrDefaultAsync(x => x.EpisodeId == episodeId && x.UserId == userId);
x.Episode == _database.Episodes.FirstOrDefault(where)
&& x.UserId == userId
);
} }
/// <inheritdoc /> /// <inheritdoc />
public async Task<EpisodeWatchStatus?> SetEpisodeStatus( public async Task<EpisodeWatchStatus?> SetEpisodeStatus(
int episodeId, Guid episodeId,
int userId, Guid userId,
WatchStatus status, WatchStatus status,
int? watchedTime) int? watchedTime)
{ {
@ -224,12 +215,11 @@ public class WatchStatusRepository : IWatchStatusRepository
/// <inheritdoc /> /// <inheritdoc />
public async Task DeleteEpisodeStatus( public async Task DeleteEpisodeStatus(
Expression<Func<Episode, bool>> where, Guid episodeId,
int userId) Guid userId)
{ {
await _database.EpisodeWatchStatus await _database.EpisodeWatchStatus
.Where(x => x.Episode == _database.Episodes.FirstOrDefault(where) .Where(x => x.EpisodeId == episodeId && x.UserId == userId)
&& x.UserId == userId)
.ExecuteDeleteAsync(); .ExecuteDeleteAsync();
} }
} }

View File

@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>. // along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models;
@ -128,10 +129,11 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<EpisodeWatchStatus?> GetWatchStatus(Identifier identifier) public async Task<EpisodeWatchStatus?> GetWatchStatus(Identifier identifier)
{ {
return await _libraryManager.WatchStatus.GetEpisodeStatus( Guid id = await identifier.Match(
identifier.IsSame<Episode>(), id => Task.FromResult(id),
User.GetId()!.Value async slug => (await _libraryManager.Episodes.Get(slug)).Id
); );
return await _libraryManager.WatchStatus.GetEpisodeStatus(id, User.GetId()!.Value);
} }
/// <summary> /// <summary>
@ -156,7 +158,7 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<EpisodeWatchStatus?> SetWatchStatus(Identifier identifier, WatchStatus status, int? watchedTime) public async Task<EpisodeWatchStatus?> SetWatchStatus(Identifier identifier, WatchStatus status, int? watchedTime)
{ {
int id = await identifier.Match( Guid id = await identifier.Match(
id => Task.FromResult(id), id => Task.FromResult(id),
async slug => (await _libraryManager.Episodes.Get(slug)).Id async slug => (await _libraryManager.Episodes.Get(slug)).Id
); );
@ -185,10 +187,11 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task DeleteWatchStatus(Identifier identifier) public async Task DeleteWatchStatus(Identifier identifier)
{ {
await _libraryManager.WatchStatus.DeleteEpisodeStatus( Guid id = await identifier.Match(
identifier.IsSame<Episode>(), id => Task.FromResult(id),
User.GetId()!.Value async slug => (await _libraryManager.Episodes.Get(slug)).Id
); );
await _libraryManager.WatchStatus.DeleteEpisodeStatus(id, User.GetId()!.Value);
} }
} }
} }

View File

@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>. // along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -169,10 +170,11 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<MovieWatchStatus?> GetWatchStatus(Identifier identifier) public async Task<MovieWatchStatus?> GetWatchStatus(Identifier identifier)
{ {
return await _libraryManager.WatchStatus.GetMovieStatus( Guid id = await identifier.Match(
identifier.IsSame<Movie>(), id => Task.FromResult(id),
User.GetId()!.Value async slug => (await _libraryManager.Movies.Get(slug)).Id
); );
return await _libraryManager.WatchStatus.GetMovieStatus(id, User.GetId()!.Value);
} }
/// <summary> /// <summary>
@ -198,7 +200,7 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<MovieWatchStatus?> SetWatchStatus(Identifier identifier, WatchStatus status, int? watchedTime) public async Task<MovieWatchStatus?> SetWatchStatus(Identifier identifier, WatchStatus status, int? watchedTime)
{ {
int id = await identifier.Match( Guid id = await identifier.Match(
id => Task.FromResult(id), id => Task.FromResult(id),
async slug => (await _libraryManager.Movies.Get(slug)).Id async slug => (await _libraryManager.Movies.Get(slug)).Id
); );
@ -227,10 +229,11 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task DeleteWatchStatus(Identifier identifier) public async Task DeleteWatchStatus(Identifier identifier)
{ {
await _libraryManager.WatchStatus.DeleteMovieStatus( Guid id = await identifier.Match(
identifier.IsSame<Movie>(), id => Task.FromResult(id),
User.GetId()!.Value async slug => (await _libraryManager.Movies.Get(slug)).Id
); );
await _libraryManager.WatchStatus.DeleteMovieStatus(id, User.GetId()!.Value);
} }
} }
} }

View File

@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>. // along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -246,10 +247,11 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ShowWatchStatus?> GetWatchStatus(Identifier identifier) public async Task<ShowWatchStatus?> GetWatchStatus(Identifier identifier)
{ {
return await _libraryManager.WatchStatus.GetShowStatus( Guid id = await identifier.Match(
identifier.IsSame<Show>(), id => Task.FromResult(id),
User.GetId()!.Value async slug => (await _libraryManager.Shows.Get(slug)).Id
); );
return await _libraryManager.WatchStatus.GetShowStatus(id, User.GetId()!.Value);
} }
/// <summary> /// <summary>
@ -273,7 +275,7 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ShowWatchStatus?> SetWatchStatus(Identifier identifier, WatchStatus status) public async Task<ShowWatchStatus?> SetWatchStatus(Identifier identifier, WatchStatus status)
{ {
int id = await identifier.Match( Guid id = await identifier.Match(
id => Task.FromResult(id), id => Task.FromResult(id),
async slug => (await _libraryManager.Shows.Get(slug)).Id async slug => (await _libraryManager.Shows.Get(slug)).Id
); );
@ -301,10 +303,11 @@ namespace Kyoo.Core.Api
[ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task DeleteWatchStatus(Identifier identifier) public async Task DeleteWatchStatus(Identifier identifier)
{ {
await _libraryManager.WatchStatus.DeleteShowStatus( Guid id = await identifier.Match(
identifier.IsSame<Show>(), id => Task.FromResult(id),
User.GetId()!.Value async slug => (await _libraryManager.Shows.Get(slug)).Id
); );
await _libraryManager.WatchStatus.DeleteShowStatus(id, User.GetId()!.Value);
} }
} }
} }