Add documentation to episodes and show repositories

This commit is contained in:
Zoe Roux 2021-04-21 22:44:18 +02:00
parent 411eaa7aed
commit 6cc65d5aa8
5 changed files with 134 additions and 26 deletions

View File

@ -375,14 +375,6 @@ namespace Kyoo.Controllers
/// <exception cref="ItemNotFound">If the item is not found</exception> /// <exception cref="ItemNotFound">If the item is not found</exception>
/// <returns>The episode found</returns> /// <returns>The episode found</returns>
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber); Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
/// <summary>
/// Get a episode from it's season ID and it's episode number.
/// </summary>
/// <param name="seasonID">The ID of the season</param>
/// <param name="episodeNumber">The episode number</param>
/// <exception cref="ItemNotFound">If the item is not found</exception>
/// <returns>The episode found</returns>
Task<Episode> Get(int seasonID, int episodeNumber);
/// <summary> /// <summary>
/// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found. /// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found.

View File

@ -97,19 +97,19 @@ namespace Kyoo.Controllers
} }
/// <inheritdoc /> /// <inheritdoc />
public Task<T> GetOrDefault(int id) public virtual Task<T> GetOrDefault(int id)
{ {
return Database.Set<T>().FirstOrDefaultAsync(x => x.ID == id); return Database.Set<T>().FirstOrDefaultAsync(x => x.ID == id);
} }
/// <inheritdoc /> /// <inheritdoc />
public Task<T> GetOrDefault(string slug) public virtual Task<T> GetOrDefault(string slug)
{ {
return Database.Set<T>().FirstOrDefaultAsync(x => x.Slug == slug); return Database.Set<T>().FirstOrDefaultAsync(x => x.Slug == slug);
} }
/// <inheritdoc /> /// <inheritdoc />
public Task<T> GetOrDefault(Expression<Func<T, bool>> where) public virtual Task<T> GetOrDefault(Expression<Func<T, bool>> where)
{ {
return Database.Set<T>().FirstOrDefaultAsync(where); return Database.Set<T>().FirstOrDefaultAsync(where);
} }

View File

@ -5,21 +5,49 @@ using System.Linq.Expressions;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kyoo.Models; using Kyoo.Models;
using Kyoo.Models.Exceptions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers namespace Kyoo.Controllers
{ {
/// <summary>
/// A local repository to handle episodes.
/// </summary>
public class EpisodeRepository : LocalRepository<Episode>, IEpisodeRepository public class EpisodeRepository : LocalRepository<Episode>, IEpisodeRepository
{ {
/// <summary>
/// Has this instance been disposed and should not handle requests?
/// </summary>
private bool _disposed; private bool _disposed;
/// <summary>
/// The databse handle
/// </summary>
private readonly DatabaseContext _database; private readonly DatabaseContext _database;
/// <summary>
/// A provider repository to handle externalID creation and deletion
/// </summary>
private readonly IProviderRepository _providers; private readonly IProviderRepository _providers;
/// <summary>
/// A show repository to get show's slug from their ID and keep the slug in each episode.
/// </summary>
private readonly IShowRepository _shows; private readonly IShowRepository _shows;
/// <summary>
/// A track repository to handle creation and deletion of tracks related to the current episode.
/// </summary>
private readonly ITrackRepository _tracks; private readonly ITrackRepository _tracks;
/// <inheritdoc />
protected override Expression<Func<Episode, object>> DefaultSort => x => x.EpisodeNumber; protected override Expression<Func<Episode, object>> DefaultSort => x => x.EpisodeNumber;
public EpisodeRepository(DatabaseContext database, /// <summary>
/// Create a new <see cref="EpisodeRepository"/>.
/// </summary>
/// <param name="database">The database handle to use.</param>
/// <param name="providers">A provider repository</param>
/// <param name="shows">A show repository</param>
/// <param name="tracks">A track repository</param>
public EpisodeRepository(DatabaseContext database,
IProviderRepository providers, IProviderRepository providers,
IShowRepository shows, IShowRepository shows,
ITrackRepository tracks) ITrackRepository tracks)
@ -32,6 +60,7 @@ namespace Kyoo.Controllers
} }
/// <inheritdoc />
public override void Dispose() public override void Dispose()
{ {
if (_disposed) if (_disposed)
@ -43,6 +72,7 @@ namespace Kyoo.Controllers
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
/// <inheritdoc />
public override async ValueTask DisposeAsync() public override async ValueTask DisposeAsync()
{ {
if (_disposed) if (_disposed)
@ -53,7 +83,8 @@ namespace Kyoo.Controllers
await _shows.DisposeAsync(); await _shows.DisposeAsync();
} }
public override async Task<Episode> Get(int id) /// <inheritdoc />
public override async Task<Episode> GetOrDefault(int id)
{ {
Episode ret = await base.Get(id); Episode ret = await base.Get(id);
if (ret != null) if (ret != null)
@ -61,13 +92,14 @@ namespace Kyoo.Controllers
return ret; return ret;
} }
public override async Task<Episode> Get(string slug) /// <inheritdoc />
public override async Task<Episode> GetOrDefault(string slug)
{ {
Match match = Regex.Match(slug, @"(?<show>.*)-s(?<season>\d*)e(?<episode>\d*)"); Match match = Regex.Match(slug, @"(?<show>.*)-s(?<season>\d*)e(?<episode>\d*)");
if (match.Success) if (match.Success)
{ {
return await Get(match.Groups["show"].Value, return await GetOrDefault(match.Groups["show"].Value,
int.Parse(match.Groups["season"].Value), int.Parse(match.Groups["season"].Value),
int.Parse(match.Groups["episode"].Value)); int.Parse(match.Groups["episode"].Value));
} }
@ -78,7 +110,8 @@ namespace Kyoo.Controllers
return episode; return episode;
} }
public override async Task<Episode> Get(Expression<Func<Episode, bool>> predicate) /// <inheritdoc />
public override async Task<Episode> GetOrDefault(Expression<Func<Episode, bool>> predicate)
{ {
Episode ret = await base.Get(predicate); Episode ret = await base.Get(predicate);
if (ret != null) if (ret != null)
@ -86,7 +119,8 @@ namespace Kyoo.Controllers
return ret; return ret;
} }
public async Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber) /// <inheritdoc />
public async Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
{ {
Episode ret = await _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug Episode ret = await _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
&& x.SeasonNumber == seasonNumber && x.SeasonNumber == seasonNumber
@ -96,7 +130,26 @@ namespace Kyoo.Controllers
return ret; return ret;
} }
/// <inheritdoc />
public async Task<Episode> Get(int showID, int seasonNumber, int episodeNumber) public async Task<Episode> Get(int showID, int seasonNumber, int episodeNumber)
{
Episode ret = await GetOrDefault(showID, seasonNumber, episodeNumber);
if (ret == null)
throw new ItemNotFound($"No episode S{seasonNumber}E{episodeNumber} found on the show {showID}.");
return ret;
}
/// <inheritdoc />
public async Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber)
{
Episode ret = await GetOrDefault(showSlug, seasonNumber, episodeNumber);
if (ret == null)
throw new ItemNotFound($"No episode S{seasonNumber}E{episodeNumber} found on the show {showSlug}.");
return ret;
}
/// <inheritdoc />
public async Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber)
{ {
Episode ret = await _database.Episodes.FirstOrDefaultAsync(x => x.ShowID == showID Episode ret = await _database.Episodes.FirstOrDefaultAsync(x => x.ShowID == showID
&& x.SeasonNumber == seasonNumber && x.SeasonNumber == seasonNumber
@ -106,15 +159,7 @@ namespace Kyoo.Controllers
return ret; return ret;
} }
public async Task<Episode> Get(int seasonID, int episodeNumber) /// <inheritdoc />
{
Episode ret = await _database.Episodes.FirstOrDefaultAsync(x => x.SeasonID == seasonID
&& x.EpisodeNumber == episodeNumber);
if (ret != null)
ret.ShowSlug = await _shows.GetSlug(ret.ShowID);
return ret;
}
public async Task<Episode> GetAbsolute(int showID, int absoluteNumber) public async Task<Episode> GetAbsolute(int showID, int absoluteNumber)
{ {
Episode ret = await _database.Episodes.FirstOrDefaultAsync(x => x.ShowID == showID Episode ret = await _database.Episodes.FirstOrDefaultAsync(x => x.ShowID == showID
@ -124,6 +169,7 @@ namespace Kyoo.Controllers
return ret; return ret;
} }
/// <inheritdoc />
public async Task<Episode> GetAbsolute(string showSlug, int absoluteNumber) public async Task<Episode> GetAbsolute(string showSlug, int absoluteNumber)
{ {
Episode ret = await _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug Episode ret = await _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
@ -133,6 +179,7 @@ namespace Kyoo.Controllers
return ret; return ret;
} }
/// <inheritdoc />
public override async Task<ICollection<Episode>> Search(string query) public override async Task<ICollection<Episode>> Search(string query)
{ {
List<Episode> episodes = await _database.Episodes List<Episode> episodes = await _database.Episodes
@ -145,6 +192,7 @@ namespace Kyoo.Controllers
return episodes; return episodes;
} }
/// <inheritdoc />
public override async Task<ICollection<Episode>> GetAll(Expression<Func<Episode, bool>> where = null, public override async Task<ICollection<Episode>> GetAll(Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default) Pagination limit = default)
@ -155,6 +203,7 @@ namespace Kyoo.Controllers
return episodes; return episodes;
} }
/// <inheritdoc />
public override async Task<Episode> Create(Episode obj) public override async Task<Episode> Create(Episode obj)
{ {
await base.Create(obj); await base.Create(obj);
@ -164,6 +213,7 @@ namespace Kyoo.Controllers
return await ValidateTracks(obj); return await ValidateTracks(obj);
} }
/// <inheritdoc />
protected override async Task EditRelations(Episode resource, Episode changed, bool resetOld) protected override async Task EditRelations(Episode resource, Episode changed, bool resetOld)
{ {
if (resource.ShowID <= 0) if (resource.ShowID <= 0)
@ -185,6 +235,11 @@ namespace Kyoo.Controllers
await Validate(resource); await Validate(resource);
} }
/// <summary>
/// Set track's index and ensure that every tracks is well-formed.
/// </summary>
/// <param name="resource">The resource to fix.</param>
/// <returns>The <see cref="resource"/> parameter is returnned.</returns>
private async Task<Episode> ValidateTracks(Episode resource) private async Task<Episode> ValidateTracks(Episode resource)
{ {
resource.Tracks = await resource.Tracks.MapAsync((x, i) => resource.Tracks = await resource.Tracks.MapAsync((x, i) =>
@ -199,6 +254,7 @@ namespace Kyoo.Controllers
return resource; return resource;
} }
/// <inheritdoc />
protected override async Task Validate(Episode resource) protected override async Task Validate(Episode resource)
{ {
await base.Validate(resource); await base.Validate(resource);
@ -211,6 +267,7 @@ namespace Kyoo.Controllers
}).ToListAsync(); }).ToListAsync();
} }
/// <inheritdoc />
public override async Task Delete(Episode obj) public override async Task Delete(Episode obj)
{ {
if (obj == null) if (obj == null)

View File

@ -20,9 +20,21 @@ namespace Kyoo.Controllers
/// Has this instance been disposed and should not handle requests? /// Has this instance been disposed and should not handle requests?
/// </summary> /// </summary>
private bool _disposed; private bool _disposed;
/// <summary>
/// The database handle
/// </summary>
private readonly DatabaseContext _database; private readonly DatabaseContext _database;
/// <summary>
/// A provider repository to handle externalID creation and deletion
/// </summary>
private readonly IProviderRepository _providers; private readonly IProviderRepository _providers;
/// <summary>
/// A show repository to get show's slug from their ID and keep the slug in each episode.
/// </summary>
private readonly IShowRepository _shows; private readonly IShowRepository _shows;
/// <summary>
/// A lazilly loaded episode repository to handle deletion of episodes with the season.
/// </summary>
private readonly Lazy<IEpisodeRepository> _episodes; private readonly Lazy<IEpisodeRepository> _episodes;
/// <inheritdoc/> /// <inheritdoc/>

View File

@ -9,18 +9,56 @@ using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Controllers namespace Kyoo.Controllers
{ {
/// <summary>
/// A local repository to handle shows
/// </summary>
public class ShowRepository : LocalRepository<Show>, IShowRepository public class ShowRepository : LocalRepository<Show>, IShowRepository
{ {
/// <summary>
/// Has this instance been disposed and should not handle requests?
/// </summary>
private bool _disposed; private bool _disposed;
/// <summary>
/// The databse handle
/// </summary>
private readonly DatabaseContext _database; private readonly DatabaseContext _database;
/// <summary>
/// A studio repository to handle creation/validation of related studios.
/// </summary>
private readonly IStudioRepository _studios; private readonly IStudioRepository _studios;
/// <summary>
/// A people repository to handle creation/validation of related people.
/// </summary>
private readonly IPeopleRepository _people; private readonly IPeopleRepository _people;
/// <summary>
/// A genres repository to handle creation/validation of related genres.
/// </summary>
private readonly IGenreRepository _genres; private readonly IGenreRepository _genres;
/// <summary>
/// A provider repository to handle externalID creation and deletion
/// </summary>
private readonly IProviderRepository _providers; private readonly IProviderRepository _providers;
/// <summary>
/// A lazy loaded season repository to handle cascade deletion (seasons deletion whith it's show)
/// </summary>
private readonly Lazy<ISeasonRepository> _seasons; private readonly Lazy<ISeasonRepository> _seasons;
/// <summary>
/// A lazy loaded episode repository to handle cascade deletion (episode deletion whith it's show)
/// </summary>
private readonly Lazy<IEpisodeRepository> _episodes; private readonly Lazy<IEpisodeRepository> _episodes;
/// <inheritdoc />
protected override Expression<Func<Show, object>> DefaultSort => x => x.Title; protected override Expression<Func<Show, object>> DefaultSort => x => x.Title;
/// <summary>
/// Create a new <see cref="ShowRepository"/>.
/// </summary>
/// <param name="database">The database handle to use</param>
/// <param name="studios">A studio repository</param>
/// <param name="people">A people repository</param>
/// <param name="genres">A genres repository</param>
/// <param name="providers">A provider repository</param>
/// <param name="services">A service provider to lazilly request a season and an episode repository</param>
public ShowRepository(DatabaseContext database, public ShowRepository(DatabaseContext database,
IStudioRepository studios, IStudioRepository studios,
IPeopleRepository people, IPeopleRepository people,
@ -38,6 +76,7 @@ namespace Kyoo.Controllers
_episodes = new Lazy<IEpisodeRepository>(services.GetRequiredService<IEpisodeRepository>); _episodes = new Lazy<IEpisodeRepository>(services.GetRequiredService<IEpisodeRepository>);
} }
/// <inheritdoc />
public override void Dispose() public override void Dispose()
{ {
if (_disposed) if (_disposed)
@ -55,6 +94,7 @@ namespace Kyoo.Controllers
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
/// <inheritdoc />
public override async ValueTask DisposeAsync() public override async ValueTask DisposeAsync()
{ {
if (_disposed) if (_disposed)
@ -71,6 +111,7 @@ namespace Kyoo.Controllers
await _episodes.Value.DisposeAsync(); await _episodes.Value.DisposeAsync();
} }
/// <inheritdoc />
public override async Task<ICollection<Show>> Search(string query) public override async Task<ICollection<Show>> Search(string query)
{ {
query = $"%{query}%"; query = $"%{query}%";
@ -83,6 +124,7 @@ namespace Kyoo.Controllers
.ToListAsync(); .ToListAsync();
} }
/// <inheritdoc />
public override async Task<Show> Create(Show obj) public override async Task<Show> Create(Show obj)
{ {
await base.Create(obj); await base.Create(obj);
@ -94,6 +136,7 @@ namespace Kyoo.Controllers
return obj; return obj;
} }
/// <inheritdoc />
protected override async Task Validate(Show resource) protected override async Task Validate(Show resource)
{ {
await base.Validate(resource); await base.Validate(resource);
@ -119,6 +162,7 @@ namespace Kyoo.Controllers
}); });
} }
/// <inheritdoc />
protected override async Task EditRelations(Show resource, Show changed, bool resetOld) protected override async Task EditRelations(Show resource, Show changed, bool resetOld)
{ {
await Validate(changed); await Validate(changed);
@ -145,6 +189,7 @@ namespace Kyoo.Controllers
} }
} }
/// <inheritdoc />
public async Task AddShowLink(int showID, int? libraryID, int? collectionID) public async Task AddShowLink(int showID, int? libraryID, int? collectionID)
{ {
if (collectionID != null) if (collectionID != null)
@ -168,6 +213,7 @@ namespace Kyoo.Controllers
} }
} }
/// <inheritdoc />
public Task<string> GetSlug(int showID) public Task<string> GetSlug(int showID)
{ {
return _database.Shows.Where(x => x.ID == showID) return _database.Shows.Where(x => x.ID == showID)
@ -175,6 +221,7 @@ namespace Kyoo.Controllers
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
} }
/// <inheritdoc />
public override async Task Delete(Show obj) public override async Task Delete(Show obj)
{ {
if (obj == null) if (obj == null)