mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 12:14:46 -04:00
Use null safety
This commit is contained in:
parent
e13f9c6aa8
commit
8b102b083f
@ -249,7 +249,7 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// <param name="showID">The id of the show</param>
|
/// <param name="showID">The id of the show</param>
|
||||||
/// <param name="seasonNumber">The season's number</param>
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
/// <returns>The season found</returns>
|
/// <returns>The season found</returns>
|
||||||
Task<Season> GetOrDefault(int showID, int seasonNumber);
|
Task<Season?> GetOrDefault(int showID, int seasonNumber);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a season from it's show slug and it's seasonNumber or null if it is not found.
|
/// Get a season from it's show slug and it's seasonNumber or null if it is not found.
|
||||||
@ -257,7 +257,7 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// <param name="showSlug">The slug of the show</param>
|
/// <param name="showSlug">The slug of the show</param>
|
||||||
/// <param name="seasonNumber">The season's number</param>
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
/// <returns>The season found</returns>
|
/// <returns>The season found</returns>
|
||||||
Task<Season> GetOrDefault(string showSlug, int seasonNumber);
|
Task<Season?> GetOrDefault(string showSlug, int seasonNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -294,7 +294,7 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// <param name="seasonNumber">The season's number</param>
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
/// <param name="episodeNumber">The episode's number</param>
|
/// <param name="episodeNumber">The episode's number</param>
|
||||||
/// <returns>The episode found</returns>
|
/// <returns>The episode found</returns>
|
||||||
Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber);
|
Task<Episode?> GetOrDefault(int showID, int seasonNumber, int episodeNumber);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found.
|
/// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found.
|
||||||
@ -303,7 +303,7 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// <param name="seasonNumber">The season's number</param>
|
/// <param name="seasonNumber">The season's number</param>
|
||||||
/// <param name="episodeNumber">The episode's number</param>
|
/// <param name="episodeNumber">The episode's number</param>
|
||||||
/// <returns>The episode found</returns>
|
/// <returns>The episode found</returns>
|
||||||
Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
|
Task<Episode?> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a episode from it's showID and it's absolute number.
|
/// Get a episode from it's showID and it's absolute number.
|
||||||
|
@ -46,7 +46,7 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// <param name="desendant">
|
/// <param name="desendant">
|
||||||
/// If this is set to true, items will be sorted in descend order else, they will be sorted in ascendant order.
|
/// If this is set to true, items will be sorted in descend order else, they will be sorted in ascendant order.
|
||||||
/// </param>
|
/// </param>
|
||||||
public By(Expression<Func<T, object>> key, bool desendant = false)
|
public By(Expression<Func<T, object?>> key, bool desendant = false)
|
||||||
: this(Utility.GetPropertyName(key), desendant) { }
|
: this(Utility.GetPropertyName(key), desendant) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@ namespace Kyoo.Core.Controllers
|
|||||||
public class IdentifierRouteConstraint : IRouteConstraint
|
public class IdentifierRouteConstraint : IRouteConstraint
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool Match(HttpContext httpContext,
|
public bool Match(HttpContext? httpContext,
|
||||||
IRouter route,
|
IRouter? route,
|
||||||
string routeKey,
|
string routeKey,
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
RouteDirection routeDirection)
|
RouteDirection routeDirection)
|
||||||
|
@ -74,15 +74,15 @@ namespace Kyoo.Core.Controllers
|
|||||||
public LibraryManager(IEnumerable<IBaseRepository> repositories)
|
public LibraryManager(IEnumerable<IBaseRepository> repositories)
|
||||||
{
|
{
|
||||||
_repositories = repositories.ToArray();
|
_repositories = repositories.ToArray();
|
||||||
LibraryItemRepository = GetRepository<LibraryItem>() as ILibraryItemRepository;
|
LibraryItemRepository = (ILibraryItemRepository)GetRepository<LibraryItem>();
|
||||||
CollectionRepository = GetRepository<Collection>() as ICollectionRepository;
|
CollectionRepository = (ICollectionRepository)GetRepository<Collection>();
|
||||||
MovieRepository = GetRepository<Movie>() as IMovieRepository;
|
MovieRepository = (IMovieRepository)GetRepository<Movie>();
|
||||||
ShowRepository = GetRepository<Show>() as IShowRepository;
|
ShowRepository = (IShowRepository)GetRepository<Show>();
|
||||||
SeasonRepository = GetRepository<Season>() as ISeasonRepository;
|
SeasonRepository = (ISeasonRepository)GetRepository<Season>();
|
||||||
EpisodeRepository = GetRepository<Episode>() as IEpisodeRepository;
|
EpisodeRepository = (IEpisodeRepository)GetRepository<Episode>();
|
||||||
PeopleRepository = GetRepository<People>() as IPeopleRepository;
|
PeopleRepository = (IPeopleRepository)GetRepository<People>();
|
||||||
StudioRepository = GetRepository<Studio>() as IStudioRepository;
|
StudioRepository = (IStudioRepository)GetRepository<Studio>();
|
||||||
UserRepository = GetRepository<User>() as IUserRepository;
|
UserRepository = (IUserRepository)GetRepository<User>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -140,46 +140,46 @@ namespace Kyoo.Core.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<T> GetOrDefault<T>(int id)
|
public async Task<T?> GetOrDefault<T>(int id)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
return await GetRepository<T>().GetOrDefault(id);
|
return await GetRepository<T>().GetOrDefault(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<T> GetOrDefault<T>(string slug)
|
public async Task<T?> GetOrDefault<T>(string slug)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
return await GetRepository<T>().GetOrDefault(slug);
|
return await GetRepository<T>().GetOrDefault(slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where, Sort<T> sortBy)
|
public async Task<T?> GetOrDefault<T>(Expression<Func<T, bool>> where, Sort<T>? sortBy)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
return await GetRepository<T>().GetOrDefault(where, sortBy);
|
return await GetRepository<T>().GetOrDefault(where, sortBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<Season> GetOrDefault(int showID, int seasonNumber)
|
public async Task<Season?> GetOrDefault(int showID, int seasonNumber)
|
||||||
{
|
{
|
||||||
return await SeasonRepository.GetOrDefault(showID, seasonNumber);
|
return await SeasonRepository.GetOrDefault(showID, seasonNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<Season> GetOrDefault(string showSlug, int seasonNumber)
|
public async Task<Season?> GetOrDefault(string showSlug, int seasonNumber)
|
||||||
{
|
{
|
||||||
return await SeasonRepository.GetOrDefault(showSlug, seasonNumber);
|
return await SeasonRepository.GetOrDefault(showSlug, seasonNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber)
|
public async Task<Episode?> GetOrDefault(int showID, int seasonNumber, int episodeNumber)
|
||||||
{
|
{
|
||||||
return await EpisodeRepository.GetOrDefault(showID, seasonNumber, episodeNumber);
|
return await EpisodeRepository.GetOrDefault(showID, seasonNumber, episodeNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
|
public async Task<Episode?> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
|
||||||
{
|
{
|
||||||
return await EpisodeRepository.GetOrDefault(showSlug, seasonNumber, episodeNumber);
|
return await EpisodeRepository.GetOrDefault(showSlug, seasonNumber, episodeNumber);
|
||||||
}
|
}
|
||||||
@ -238,7 +238,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
|
||||||
object existingValue = obj.GetType()
|
object? existingValue = obj.GetType()
|
||||||
.GetProperties()
|
.GetProperties()
|
||||||
.FirstOrDefault(x => string.Equals(x.Name, memberName, StringComparison.InvariantCultureIgnoreCase))
|
.FirstOrDefault(x => string.Equals(x.Name, memberName, StringComparison.InvariantCultureIgnoreCase))
|
||||||
?.GetValue(obj);
|
?.GetValue(obj);
|
||||||
@ -248,11 +248,11 @@ namespace Kyoo.Core.Controllers
|
|||||||
return (obj, member: memberName) switch
|
return (obj, member: memberName) switch
|
||||||
{
|
{
|
||||||
(Collection c, nameof(Collection.Shows)) => ShowRepository
|
(Collection c, nameof(Collection.Shows)) => ShowRepository
|
||||||
.GetAll(x => x.Collections.Any(y => y.Id == obj.Id))
|
.GetAll(x => x.Collections!.Any(y => y.Id == obj.Id))
|
||||||
.Then(x => c.Shows = x),
|
.Then(x => c.Shows = x),
|
||||||
|
|
||||||
(Collection c, nameof(Collection.Movies)) => MovieRepository
|
(Collection c, nameof(Collection.Movies)) => MovieRepository
|
||||||
.GetAll(x => x.Collections.Any(y => y.Id == obj.Id))
|
.GetAll(x => x.Collections!.Any(y => y.Id == obj.Id))
|
||||||
.Then(x => c.Movies = x),
|
.Then(x => c.Movies = x),
|
||||||
|
|
||||||
|
|
||||||
@ -261,11 +261,11 @@ namespace Kyoo.Core.Controllers
|
|||||||
.Then(x => m.People = x),
|
.Then(x => m.People = x),
|
||||||
|
|
||||||
(Movie m, nameof(Movie.Collections)) => CollectionRepository
|
(Movie m, nameof(Movie.Collections)) => CollectionRepository
|
||||||
.GetAll(x => x.Movies.Any(y => y.Id == obj.Id))
|
.GetAll(x => x.Movies!.Any(y => y.Id == obj.Id))
|
||||||
.Then(x => m.Collections = x),
|
.Then(x => m.Collections = x),
|
||||||
|
|
||||||
(Movie m, nameof(Movie.Studio)) => StudioRepository
|
(Movie m, nameof(Movie.Studio)) => StudioRepository
|
||||||
.GetOrDefault(x => x.Movies.Any(y => y.Id == obj.Id))
|
.GetOrDefault(x => x.Movies!.Any(y => y.Id == obj.Id))
|
||||||
.Then(x =>
|
.Then(x =>
|
||||||
{
|
{
|
||||||
m.Studio = x;
|
m.Studio = x;
|
||||||
@ -278,21 +278,21 @@ namespace Kyoo.Core.Controllers
|
|||||||
.Then(x => s.People = x),
|
.Then(x => s.People = x),
|
||||||
|
|
||||||
(Show s, nameof(Show.Seasons)) => _SetRelation(s,
|
(Show s, nameof(Show.Seasons)) => _SetRelation(s,
|
||||||
SeasonRepository.GetAll(x => x.Show.Id == obj.Id),
|
SeasonRepository.GetAll(x => x.Show!.Id == obj.Id),
|
||||||
(x, y) => x.Seasons = y,
|
(x, y) => x.Seasons = y,
|
||||||
(x, y) => { x.Show = y; x.ShowId = y.Id; }),
|
(x, y) => { x.Show = y; x.ShowId = y.Id; }),
|
||||||
|
|
||||||
(Show s, nameof(Show.Episodes)) => _SetRelation(s,
|
(Show s, nameof(Show.Episodes)) => _SetRelation(s,
|
||||||
EpisodeRepository.GetAll(x => x.Show.Id == obj.Id),
|
EpisodeRepository.GetAll(x => x.Show!.Id == obj.Id),
|
||||||
(x, y) => x.Episodes = y,
|
(x, y) => x.Episodes = y,
|
||||||
(x, y) => { x.Show = y; x.ShowId = y.Id; }),
|
(x, y) => { x.Show = y; x.ShowId = y.Id; }),
|
||||||
|
|
||||||
(Show s, nameof(Show.Collections)) => CollectionRepository
|
(Show s, nameof(Show.Collections)) => CollectionRepository
|
||||||
.GetAll(x => x.Shows.Any(y => y.Id == obj.Id))
|
.GetAll(x => x.Shows!.Any(y => y.Id == obj.Id))
|
||||||
.Then(x => s.Collections = x),
|
.Then(x => s.Collections = x),
|
||||||
|
|
||||||
(Show s, nameof(Show.Studio)) => StudioRepository
|
(Show s, nameof(Show.Studio)) => StudioRepository
|
||||||
.GetOrDefault(x => x.Shows.Any(y => y.Id == obj.Id))
|
.GetOrDefault(x => x.Shows!.Any(y => y.Id == obj.Id))
|
||||||
.Then(x =>
|
.Then(x =>
|
||||||
{
|
{
|
||||||
s.Studio = x;
|
s.Studio = x;
|
||||||
@ -301,12 +301,12 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
|
|
||||||
(Season s, nameof(Season.Episodes)) => _SetRelation(s,
|
(Season s, nameof(Season.Episodes)) => _SetRelation(s,
|
||||||
EpisodeRepository.GetAll(x => x.Season.Id == obj.Id),
|
EpisodeRepository.GetAll(x => x.Season!.Id == obj.Id),
|
||||||
(x, y) => x.Episodes = y,
|
(x, y) => x.Episodes = y,
|
||||||
(x, y) => { x.Season = y; x.SeasonId = y.Id; }),
|
(x, y) => { x.Season = y; x.SeasonId = y.Id; }),
|
||||||
|
|
||||||
(Season s, nameof(Season.Show)) => ShowRepository
|
(Season s, nameof(Season.Show)) => ShowRepository
|
||||||
.GetOrDefault(x => x.Seasons.Any(y => y.Id == obj.Id))
|
.GetOrDefault(x => x.Seasons!.Any(y => y.Id == obj.Id))
|
||||||
.Then(x =>
|
.Then(x =>
|
||||||
{
|
{
|
||||||
s.Show = x;
|
s.Show = x;
|
||||||
@ -315,7 +315,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
|
|
||||||
(Episode e, nameof(Episode.Show)) => ShowRepository
|
(Episode e, nameof(Episode.Show)) => ShowRepository
|
||||||
.GetOrDefault(x => x.Episodes.Any(y => y.Id == obj.Id))
|
.GetOrDefault(x => x.Episodes!.Any(y => y.Id == obj.Id))
|
||||||
.Then(x =>
|
.Then(x =>
|
||||||
{
|
{
|
||||||
e.Show = x;
|
e.Show = x;
|
||||||
@ -323,7 +323,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
(Episode e, nameof(Episode.Season)) => SeasonRepository
|
(Episode e, nameof(Episode.Season)) => SeasonRepository
|
||||||
.GetOrDefault(x => x.Episodes.Any(y => y.Id == e.Id))
|
.GetOrDefault(x => x.Episodes!.Any(y => y.Id == e.Id))
|
||||||
.Then(x =>
|
.Then(x =>
|
||||||
{
|
{
|
||||||
e.Season = x;
|
e.Season = x;
|
||||||
@ -344,11 +344,11 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
|
|
||||||
(Studio s, nameof(Studio.Shows)) => ShowRepository
|
(Studio s, nameof(Studio.Shows)) => ShowRepository
|
||||||
.GetAll(x => x.Studio.Id == obj.Id)
|
.GetAll(x => x.Studio!.Id == obj.Id)
|
||||||
.Then(x => s.Shows = x),
|
.Then(x => s.Shows = x),
|
||||||
|
|
||||||
(Studio s, nameof(Studio.Movies)) => MovieRepository
|
(Studio s, nameof(Studio.Movies)) => MovieRepository
|
||||||
.GetAll(x => x.Studio.Id == obj.Id)
|
.GetAll(x => x.Studio!.Id == obj.Id)
|
||||||
.Then(x => s.Movies = x),
|
.Then(x => s.Movies = x),
|
||||||
|
|
||||||
|
|
||||||
@ -362,51 +362,51 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
|
public Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
|
||||||
Expression<Func<PeopleRole, bool>> where = null,
|
Expression<Func<PeopleRole, bool>>? where = null,
|
||||||
Sort<PeopleRole> sort = default,
|
Sort<PeopleRole>? sort = default,
|
||||||
Pagination limit = default)
|
Pagination? limit = default)
|
||||||
{
|
{
|
||||||
return PeopleRepository.GetFromShow(showID, where, sort, limit);
|
return PeopleRepository.GetFromShow(showID, where, sort, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<ICollection<PeopleRole>> GetPeopleFromShow(string showSlug,
|
public Task<ICollection<PeopleRole>> GetPeopleFromShow(string showSlug,
|
||||||
Expression<Func<PeopleRole, bool>> where = null,
|
Expression<Func<PeopleRole, bool>>? where = null,
|
||||||
Sort<PeopleRole> sort = default,
|
Sort<PeopleRole>? sort = default,
|
||||||
Pagination limit = default)
|
Pagination? limit = default)
|
||||||
{
|
{
|
||||||
return PeopleRepository.GetFromShow(showSlug, where, sort, limit);
|
return PeopleRepository.GetFromShow(showSlug, where, sort, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<ICollection<PeopleRole>> GetRolesFromPeople(int id,
|
public Task<ICollection<PeopleRole>> GetRolesFromPeople(int id,
|
||||||
Expression<Func<PeopleRole, bool>> where = null,
|
Expression<Func<PeopleRole, bool>>? where = null,
|
||||||
Sort<PeopleRole> sort = default,
|
Sort<PeopleRole>? sort = default,
|
||||||
Pagination limit = default)
|
Pagination? limit = default)
|
||||||
{
|
{
|
||||||
return PeopleRepository.GetFromPeople(id, where, sort, limit);
|
return PeopleRepository.GetFromPeople(id, where, sort, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<ICollection<PeopleRole>> GetRolesFromPeople(string slug,
|
public Task<ICollection<PeopleRole>> GetRolesFromPeople(string slug,
|
||||||
Expression<Func<PeopleRole, bool>> where = null,
|
Expression<Func<PeopleRole, bool>>? where = null,
|
||||||
Sort<PeopleRole> sort = default,
|
Sort<PeopleRole>? sort = default,
|
||||||
Pagination limit = default)
|
Pagination? limit = default)
|
||||||
{
|
{
|
||||||
return PeopleRepository.GetFromPeople(slug, where, sort, limit);
|
return PeopleRepository.GetFromPeople(slug, where, sort, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>> where = null,
|
public Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>>? where = null,
|
||||||
Sort<T> sort = default,
|
Sort<T>? sort = default,
|
||||||
Pagination limit = default)
|
Pagination? limit = default)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
return GetRepository<T>().GetAll(where, sort, limit);
|
return GetRepository<T>().GetAll(where, sort, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<int> GetCount<T>(Expression<Func<T, bool>> where = null)
|
public Task<int> GetCount<T>(Expression<Func<T, bool>>? where = null)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
return GetRepository<T>().GetCount(where);
|
return GetRepository<T>().GetCount(where);
|
||||||
|
@ -77,7 +77,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber)
|
public Task<Episode?> GetOrDefault(int showID, int seasonNumber, int episodeNumber)
|
||||||
{
|
{
|
||||||
return _database.Episodes.FirstOrDefaultAsync(x => x.ShowId == showID
|
return _database.Episodes.FirstOrDefaultAsync(x => x.ShowId == showID
|
||||||
&& x.SeasonNumber == seasonNumber
|
&& x.SeasonNumber == seasonNumber
|
||||||
@ -85,9 +85,9 @@ namespace Kyoo.Core.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
|
public Task<Episode?> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
|
||||||
{
|
{
|
||||||
return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
return _database.Episodes.FirstOrDefaultAsync(x => x.Show!.Slug == showSlug
|
||||||
&& x.SeasonNumber == seasonNumber
|
&& x.SeasonNumber == seasonNumber
|
||||||
&& x.EpisodeNumber == episodeNumber).Then(SetBackingImage);
|
&& x.EpisodeNumber == episodeNumber).Then(SetBackingImage);
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <inheritdoc />
|
/// <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);
|
Episode? ret = await GetOrDefault(showID, seasonNumber, episodeNumber);
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
throw new ItemNotFoundException($"No episode S{seasonNumber}E{episodeNumber} found on the show {showID}.");
|
throw new ItemNotFoundException($"No episode S{seasonNumber}E{episodeNumber} found on the show {showID}.");
|
||||||
return ret;
|
return ret;
|
||||||
@ -104,24 +104,30 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber)
|
public async Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber)
|
||||||
{
|
{
|
||||||
Episode ret = await GetOrDefault(showSlug, seasonNumber, episodeNumber);
|
Episode? ret = await GetOrDefault(showSlug, seasonNumber, episodeNumber);
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
throw new ItemNotFoundException($"No episode S{seasonNumber}E{episodeNumber} found on the show {showSlug}.");
|
throw new ItemNotFoundException($"No episode S{seasonNumber}E{episodeNumber} found on the show {showSlug}.");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<Episode> GetAbsolute(int showID, int absoluteNumber)
|
public async Task<Episode> GetAbsolute(int showID, int absoluteNumber)
|
||||||
{
|
{
|
||||||
return _database.Episodes.FirstOrDefaultAsync(x => x.ShowId == showID
|
Episode? ret = await _database.Episodes.FirstOrDefaultAsync(x => x.ShowId == showID
|
||||||
&& x.AbsoluteNumber == absoluteNumber).Then(SetBackingImage);
|
&& x.AbsoluteNumber == absoluteNumber).Then(SetBackingImage);
|
||||||
|
if (ret == null)
|
||||||
|
throw new ItemNotFoundException();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<Episode> GetAbsolute(string showSlug, int absoluteNumber)
|
public async Task<Episode> GetAbsolute(string showSlug, int absoluteNumber)
|
||||||
{
|
{
|
||||||
return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
Episode? ret = await _database.Episodes.FirstOrDefaultAsync(x => x.Show!.Slug == showSlug
|
||||||
&& x.AbsoluteNumber == absoluteNumber).Then(SetBackingImage);
|
&& x.AbsoluteNumber == absoluteNumber).Then(SetBackingImage);
|
||||||
|
if (ret == null)
|
||||||
|
throw new ItemNotFoundException();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -131,13 +137,13 @@ namespace Kyoo.Core.Controllers
|
|||||||
_database.Episodes
|
_database.Episodes
|
||||||
.Include(x => x.Show)
|
.Include(x => x.Show)
|
||||||
.Where(x => x.EpisodeNumber != null || x.AbsoluteNumber != null)
|
.Where(x => x.EpisodeNumber != null || x.AbsoluteNumber != null)
|
||||||
.Where(_database.Like<Episode>(x => x.Name, $"%{query}%"))
|
.Where(_database.Like<Episode>(x => x.Name!, $"%{query}%"))
|
||||||
)
|
)
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
foreach (Episode ep in ret)
|
foreach (Episode ep in ret)
|
||||||
{
|
{
|
||||||
ep.Show.Episodes = null;
|
ep.Show!.Episodes = null;
|
||||||
SetBackingImage(ep);
|
SetBackingImage(ep);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -152,7 +158,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
await _database.SaveChangesAsync(() =>
|
await _database.SaveChangesAsync(() =>
|
||||||
obj.SeasonNumber != null && obj.EpisodeNumber != null
|
obj.SeasonNumber != null && obj.EpisodeNumber != null
|
||||||
? Get(obj.ShowId, obj.SeasonNumber.Value, obj.EpisodeNumber.Value)
|
? Get(obj.ShowId, obj.SeasonNumber.Value, obj.EpisodeNumber.Value)
|
||||||
: GetAbsolute(obj.ShowId, obj.AbsoluteNumber.Value));
|
: GetAbsolute(obj.ShowId, obj.AbsoluteNumber!.Value));
|
||||||
OnResourceCreated(obj);
|
OnResourceCreated(obj);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <param name="query">The query to sort.</param>
|
/// <param name="query">The query to sort.</param>
|
||||||
/// <param name="sortBy">How to sort the query</param>
|
/// <param name="sortBy">How to sort the query</param>
|
||||||
/// <returns>The newly sorted query.</returns>
|
/// <returns>The newly sorted query.</returns>
|
||||||
protected IOrderedQueryable<T> Sort(IQueryable<T> query, Sort<T> sortBy = null)
|
protected IOrderedQueryable<T> Sort(IQueryable<T> query, Sort<T>? sortBy = null)
|
||||||
{
|
{
|
||||||
sortBy ??= DefaultSort;
|
sortBy ??= DefaultSort;
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
: (greaterThan ? Expression.GreaterThan : Expression.LessThan);
|
: (greaterThan ? Expression.GreaterThan : Expression.LessThan);
|
||||||
}
|
}
|
||||||
|
|
||||||
private record SortIndicator(string key, bool desc, string? seed);
|
private record SortIndicator(string Key, bool Desc, string? Seed);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a filter (where) expression on the query to skip everything before/after the referenceID.
|
/// Create a filter (where) expression on the query to skip everything before/after the referenceID.
|
||||||
@ -158,7 +158,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <param name="next">True if the following page should be returned, false for the previous.</param>
|
/// <param name="next">True if the following page should be returned, false for the previous.</param>
|
||||||
/// <returns>An expression ready to be added to a Where close of a sorted query to handle the AfterID</returns>
|
/// <returns>An expression ready to be added to a Where close of a sorted query to handle the AfterID</returns>
|
||||||
protected Expression<Func<T, bool>> KeysetPaginate(
|
protected Expression<Func<T, bool>> KeysetPaginate(
|
||||||
Sort<T> sort,
|
Sort<T>? sort,
|
||||||
T reference,
|
T reference,
|
||||||
bool next = true)
|
bool next = true)
|
||||||
{
|
{
|
||||||
@ -170,7 +170,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
void GetRandomSortKeys(string seed, out Expression left, out Expression right)
|
void GetRandomSortKeys(string seed, out Expression left, out Expression right)
|
||||||
{
|
{
|
||||||
MethodInfo concat = typeof(string).GetMethod(nameof(string.Concat), new[] { typeof(string), typeof(string) });
|
MethodInfo concat = typeof(string).GetMethod(nameof(string.Concat), new[] { typeof(string), typeof(string) })!;
|
||||||
Expression id = Expression.Call(Expression.Property(x, "ID"), nameof(int.ToString), null);
|
Expression id = Expression.Call(Expression.Property(x, "ID"), nameof(int.ToString), null);
|
||||||
Expression xrng = Expression.Call(concat, Expression.Constant(seed), id);
|
Expression xrng = Expression.Call(concat, Expression.Constant(seed), id);
|
||||||
right = Expression.Call(typeof(DatabaseContext), nameof(DatabaseContext.MD5), null, Expression.Constant($"{seed}{reference.Id}"));
|
right = Expression.Call(typeof(DatabaseContext), nameof(DatabaseContext.MD5), null, Expression.Constant($"{seed}{reference.Id}"));
|
||||||
@ -193,14 +193,14 @@ namespace Kyoo.Core.Controllers
|
|||||||
IEnumerable<SortIndicator> sorts = GetSortsBy(sort)
|
IEnumerable<SortIndicator> sorts = GetSortsBy(sort)
|
||||||
.Append(new SortIndicator("Id", false, null));
|
.Append(new SortIndicator("Id", false, null));
|
||||||
|
|
||||||
BinaryExpression filter = null;
|
BinaryExpression? filter = null;
|
||||||
List<SortIndicator> previousSteps = new();
|
List<SortIndicator> previousSteps = new();
|
||||||
// TODO: Add an outer query >= for perf
|
// TODO: Add an outer query >= for perf
|
||||||
// PERF: See https://use-the-index-luke.com/sql/partial-results/fetch-next-page#sb-equivalent-logic
|
// PERF: See https://use-the-index-luke.com/sql/partial-results/fetch-next-page#sb-equivalent-logic
|
||||||
foreach ((string key, bool desc, string? seed) in sorts)
|
foreach ((string key, bool desc, string? seed) in sorts)
|
||||||
{
|
{
|
||||||
BinaryExpression compare = null;
|
BinaryExpression? compare = null;
|
||||||
PropertyInfo property = key != "random"
|
PropertyInfo? property = key != "random"
|
||||||
? typeof(T).GetProperty(key)
|
? typeof(T).GetProperty(key)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
return Expression.Lambda<Func<T, bool>>(filter!, x);
|
return Expression.Lambda<Func<T, bool>>(filter!, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SetBackingImage(T obj)
|
protected void SetBackingImage(T? obj)
|
||||||
{
|
{
|
||||||
if (obj is not IThumbnails thumbs)
|
if (obj is not IThumbnails thumbs)
|
||||||
return;
|
return;
|
||||||
@ -298,7 +298,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <returns>The tracked resource with the given ID</returns>
|
/// <returns>The tracked resource with the given ID</returns>
|
||||||
protected virtual async Task<T> GetWithTracking(int id)
|
protected virtual async Task<T> GetWithTracking(int id)
|
||||||
{
|
{
|
||||||
T ret = await Database.Set<T>().AsTracking().FirstOrDefaultAsync(x => x.Id == id);
|
T? ret = await Database.Set<T>().AsTracking().FirstOrDefaultAsync(x => x.Id == id);
|
||||||
SetBackingImage(ret);
|
SetBackingImage(ret);
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
throw new ItemNotFoundException($"No {typeof(T).Name} found with the id {id}");
|
throw new ItemNotFoundException($"No {typeof(T).Name} found with the id {id}");
|
||||||
@ -308,7 +308,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual async Task<T> Get(int id)
|
public virtual async Task<T> Get(int id)
|
||||||
{
|
{
|
||||||
T ret = await GetOrDefault(id);
|
T? ret = await GetOrDefault(id);
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
throw new ItemNotFoundException($"No {typeof(T).Name} found with the id {id}");
|
throw new ItemNotFoundException($"No {typeof(T).Name} found with the id {id}");
|
||||||
return ret;
|
return ret;
|
||||||
@ -317,7 +317,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual async Task<T> Get(string slug)
|
public virtual async Task<T> Get(string slug)
|
||||||
{
|
{
|
||||||
T ret = await GetOrDefault(slug);
|
T? ret = await GetOrDefault(slug);
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
throw new ItemNotFoundException($"No {typeof(T).Name} found with the slug {slug}");
|
throw new ItemNotFoundException($"No {typeof(T).Name} found with the slug {slug}");
|
||||||
return ret;
|
return ret;
|
||||||
@ -326,20 +326,20 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual async Task<T> Get(Expression<Func<T, bool>> where)
|
public virtual async Task<T> Get(Expression<Func<T, bool>> where)
|
||||||
{
|
{
|
||||||
T ret = await GetOrDefault(where);
|
T? ret = await GetOrDefault(where);
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
throw new ItemNotFoundException($"No {typeof(T).Name} found with the given predicate.");
|
throw new ItemNotFoundException($"No {typeof(T).Name} found with the given predicate.");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual Task<T> GetOrDefault(int id)
|
public virtual Task<T?> GetOrDefault(int id)
|
||||||
{
|
{
|
||||||
return Database.Set<T>().FirstOrDefaultAsync(x => x.Id == id).Then(SetBackingImage);
|
return Database.Set<T>().FirstOrDefaultAsync(x => x.Id == id).Then(SetBackingImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual Task<T> GetOrDefault(string slug)
|
public virtual Task<T?> GetOrDefault(string slug)
|
||||||
{
|
{
|
||||||
if (slug == "random")
|
if (slug == "random")
|
||||||
return Database.Set<T>().OrderBy(x => EF.Functions.Random()).FirstOrDefaultAsync().Then(SetBackingImage);
|
return Database.Set<T>().OrderBy(x => EF.Functions.Random()).FirstOrDefaultAsync().Then(SetBackingImage);
|
||||||
@ -347,7 +347,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual Task<T> GetOrDefault(Expression<Func<T, bool>> where, Sort<T> sortBy = default)
|
public virtual Task<T?> GetOrDefault(Expression<Func<T, bool>> where, Sort<T>? sortBy = default)
|
||||||
{
|
{
|
||||||
return Sort(Database.Set<T>(), sortBy).FirstOrDefaultAsync(where).Then(SetBackingImage);
|
return Sort(Database.Set<T>(), sortBy).FirstOrDefaultAsync(where).Then(SetBackingImage);
|
||||||
}
|
}
|
||||||
@ -356,9 +356,9 @@ namespace Kyoo.Core.Controllers
|
|||||||
public abstract Task<ICollection<T>> Search(string query);
|
public abstract Task<ICollection<T>> Search(string query);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual async Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
|
public virtual async Task<ICollection<T>> GetAll(Expression<Func<T, bool>>? where = null,
|
||||||
Sort<T> sort = default,
|
Sort<T>? sort = default,
|
||||||
Pagination limit = default)
|
Pagination? limit = default)
|
||||||
{
|
{
|
||||||
return (await ApplyFilters(Database.Set<T>(), where, sort, limit))
|
return (await ApplyFilters(Database.Set<T>(), where, sort, limit))
|
||||||
.Select(SetBackingImageSelf).ToList();
|
.Select(SetBackingImageSelf).ToList();
|
||||||
@ -373,9 +373,9 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <param name="limit">Pagination information (where to start and how many to get)</param>
|
/// <param name="limit">Pagination information (where to start and how many to get)</param>
|
||||||
/// <returns>The filtered query</returns>
|
/// <returns>The filtered query</returns>
|
||||||
protected async Task<ICollection<T>> ApplyFilters(IQueryable<T> query,
|
protected async Task<ICollection<T>> ApplyFilters(IQueryable<T> query,
|
||||||
Expression<Func<T, bool>> where = null,
|
Expression<Func<T, bool>>? where = null,
|
||||||
Sort<T> sort = default,
|
Sort<T>? sort = default,
|
||||||
Pagination limit = default)
|
Pagination? limit = default)
|
||||||
{
|
{
|
||||||
query = Sort(query, sort);
|
query = Sort(query, sort);
|
||||||
if (where != null)
|
if (where != null)
|
||||||
@ -395,7 +395,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual Task<int> GetCount(Expression<Func<T, bool>> where = null)
|
public virtual Task<int> GetCount(Expression<Func<T, bool>>? where = null)
|
||||||
{
|
{
|
||||||
IQueryable<T> query = Database.Set<T>();
|
IQueryable<T> query = Database.Set<T>();
|
||||||
if (where != null)
|
if (where != null)
|
||||||
@ -411,11 +411,11 @@ namespace Kyoo.Core.Controllers
|
|||||||
{
|
{
|
||||||
await _thumbs.DownloadImages(thumbs);
|
await _thumbs.DownloadImages(thumbs);
|
||||||
if (thumbs.Poster != null)
|
if (thumbs.Poster != null)
|
||||||
Database.Entry(thumbs).Reference(x => x.Poster).TargetEntry.State = EntityState.Added;
|
Database.Entry(thumbs).Reference(x => x.Poster).TargetEntry!.State = EntityState.Added;
|
||||||
if (thumbs.Thumbnail != null)
|
if (thumbs.Thumbnail != null)
|
||||||
Database.Entry(thumbs).Reference(x => x.Thumbnail).TargetEntry.State = EntityState.Added;
|
Database.Entry(thumbs).Reference(x => x.Thumbnail).TargetEntry!.State = EntityState.Added;
|
||||||
if (thumbs.Logo != null)
|
if (thumbs.Logo != null)
|
||||||
Database.Entry(thumbs).Reference(x => x.Logo).TargetEntry.State = EntityState.Added;
|
Database.Entry(thumbs).Reference(x => x.Logo).TargetEntry!.State = EntityState.Added;
|
||||||
}
|
}
|
||||||
SetBackingImage(obj);
|
SetBackingImage(obj);
|
||||||
return obj;
|
return obj;
|
||||||
@ -444,7 +444,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
T old = await GetOrDefault(obj.Slug);
|
T? old = await GetOrDefault(obj.Slug);
|
||||||
if (old != null)
|
if (old != null)
|
||||||
return old;
|
return old;
|
||||||
|
|
||||||
@ -544,7 +544,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MethodInfo setter = typeof(T).GetProperty(nameof(resource.Slug))!.GetSetMethod();
|
MethodInfo? setter = typeof(T).GetProperty(nameof(resource.Slug))!.GetSetMethod();
|
||||||
if (setter != null)
|
if (setter != null)
|
||||||
setter.Invoke(resource, new object[] { resource.Slug + '!' });
|
setter.Invoke(resource, new object[] { resource.Slug + '!' });
|
||||||
else
|
else
|
||||||
|
@ -126,7 +126,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
if (changed.People != null)
|
if (changed.People != null)
|
||||||
{
|
{
|
||||||
await Database.Entry(resource).Collection(x => x.People).LoadAsync();
|
await Database.Entry(resource).Collection(x => x.People!).LoadAsync();
|
||||||
resource.People = changed.People;
|
resource.People = changed.People;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
{
|
{
|
||||||
foreach (PeopleRole role in resource.Roles)
|
foreach (PeopleRole role in resource.Roles)
|
||||||
{
|
{
|
||||||
role.Show = _database.LocalEntity<Show>(role.Show.Slug)
|
role.Show = _database.LocalEntity<Show>(role.Show!.Slug)
|
||||||
?? await _shows.Value.CreateIfNotExists(role.Show);
|
?? await _shows.Value.CreateIfNotExists(role.Show);
|
||||||
role.ShowID = role.Show.Id;
|
role.ShowID = role.Show.Id;
|
||||||
_database.Entry(role).State = EntityState.Added;
|
_database.Entry(role).State = EntityState.Added;
|
||||||
@ -109,7 +109,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
if (changed.Roles != null)
|
if (changed.Roles != null)
|
||||||
{
|
{
|
||||||
await Database.Entry(resource).Collection(x => x.Roles).LoadAsync();
|
await Database.Entry(resource).Collection(x => x.Roles!).LoadAsync();
|
||||||
resource.Roles = changed.Roles;
|
resource.Roles = changed.Roles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,9 +125,9 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<ICollection<PeopleRole>> GetFromShow(int showID,
|
public Task<ICollection<PeopleRole>> GetFromShow(int showID,
|
||||||
Expression<Func<PeopleRole, bool>> where = null,
|
Expression<Func<PeopleRole, bool>>? where = null,
|
||||||
Sort<PeopleRole> sort = default,
|
Sort<PeopleRole>? sort = default,
|
||||||
Pagination limit = default)
|
Pagination? limit = default)
|
||||||
{
|
{
|
||||||
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
||||||
// ICollection<PeopleRole> people = await ApplyFilters(_database.PeopleRoles
|
// ICollection<PeopleRole> people = await ApplyFilters(_database.PeopleRoles
|
||||||
@ -146,9 +146,9 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<ICollection<PeopleRole>> GetFromShow(string showSlug,
|
public Task<ICollection<PeopleRole>> GetFromShow(string showSlug,
|
||||||
Expression<Func<PeopleRole, bool>> where = null,
|
Expression<Func<PeopleRole, bool>>? where = null,
|
||||||
Sort<PeopleRole> sort = default,
|
Sort<PeopleRole>? sort = default,
|
||||||
Pagination limit = default)
|
Pagination? limit = default)
|
||||||
{
|
{
|
||||||
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
||||||
// ICollection<PeopleRole> people = await ApplyFilters(_database.PeopleRoles
|
// ICollection<PeopleRole> people = await ApplyFilters(_database.PeopleRoles
|
||||||
@ -169,9 +169,9 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<ICollection<PeopleRole>> GetFromPeople(int id,
|
public Task<ICollection<PeopleRole>> GetFromPeople(int id,
|
||||||
Expression<Func<PeopleRole, bool>> where = null,
|
Expression<Func<PeopleRole, bool>>? where = null,
|
||||||
Sort<PeopleRole> sort = default,
|
Sort<PeopleRole>? sort = default,
|
||||||
Pagination limit = default)
|
Pagination? limit = default)
|
||||||
{
|
{
|
||||||
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
||||||
// ICollection<PeopleRole> roles = await ApplyFilters(_database.PeopleRoles
|
// ICollection<PeopleRole> roles = await ApplyFilters(_database.PeopleRoles
|
||||||
@ -189,9 +189,9 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<ICollection<PeopleRole>> GetFromPeople(string slug,
|
public Task<ICollection<PeopleRole>> GetFromPeople(string slug,
|
||||||
Expression<Func<PeopleRole, bool>> where = null,
|
Expression<Func<PeopleRole, bool>>? where = null,
|
||||||
Sort<PeopleRole> sort = default,
|
Sort<PeopleRole>? sort = default,
|
||||||
Pagination limit = default)
|
Pagination? limit = default)
|
||||||
{
|
{
|
||||||
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
||||||
// ICollection<PeopleRole> roles = await ApplyFilters(_database.PeopleRoles
|
// ICollection<PeopleRole> roles = await ApplyFilters(_database.PeopleRoles
|
||||||
|
@ -71,7 +71,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<Season> Get(int showID, int seasonNumber)
|
public async Task<Season> Get(int showID, int seasonNumber)
|
||||||
{
|
{
|
||||||
Season ret = await GetOrDefault(showID, seasonNumber);
|
Season? ret = await GetOrDefault(showID, seasonNumber);
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
throw new ItemNotFoundException($"No season {seasonNumber} found for the show {showID}");
|
throw new ItemNotFoundException($"No season {seasonNumber} found for the show {showID}");
|
||||||
return ret;
|
return ret;
|
||||||
@ -80,23 +80,23 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<Season> Get(string showSlug, int seasonNumber)
|
public async Task<Season> Get(string showSlug, int seasonNumber)
|
||||||
{
|
{
|
||||||
Season ret = await GetOrDefault(showSlug, seasonNumber);
|
Season? ret = await GetOrDefault(showSlug, seasonNumber);
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
throw new ItemNotFoundException($"No season {seasonNumber} found for the show {showSlug}");
|
throw new ItemNotFoundException($"No season {seasonNumber} found for the show {showSlug}");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Task<Season> GetOrDefault(int showID, int seasonNumber)
|
public Task<Season?> GetOrDefault(int showID, int seasonNumber)
|
||||||
{
|
{
|
||||||
return _database.Seasons.FirstOrDefaultAsync(x => x.ShowId == showID
|
return _database.Seasons.FirstOrDefaultAsync(x => x.ShowId == showID
|
||||||
&& x.SeasonNumber == seasonNumber).Then(SetBackingImage);
|
&& x.SeasonNumber == seasonNumber).Then(SetBackingImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Task<Season> GetOrDefault(string showSlug, int seasonNumber)
|
public Task<Season?> GetOrDefault(string showSlug, int seasonNumber)
|
||||||
{
|
{
|
||||||
return _database.Seasons.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
return _database.Seasons.FirstOrDefaultAsync(x => x.Show!.Slug == showSlug
|
||||||
&& x.SeasonNumber == seasonNumber).Then(SetBackingImage);
|
&& x.SeasonNumber == seasonNumber).Then(SetBackingImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
{
|
{
|
||||||
return (await Sort(
|
return (await Sort(
|
||||||
_database.Seasons
|
_database.Seasons
|
||||||
.Where(_database.Like<Season>(x => x.Name, $"%{query}%"))
|
.Where(_database.Like<Season>(x => x.Name!, $"%{query}%"))
|
||||||
)
|
)
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync())
|
.ToListAsync())
|
||||||
|
@ -21,6 +21,7 @@ using System.Linq;
|
|||||||
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.Exceptions;
|
||||||
using Kyoo.Postgresql;
|
using Kyoo.Postgresql;
|
||||||
using Kyoo.Utils;
|
using Kyoo.Utils;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -129,17 +130,20 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
if (changed.People != null)
|
if (changed.People != null)
|
||||||
{
|
{
|
||||||
await Database.Entry(resource).Collection(x => x.People).LoadAsync();
|
await Database.Entry(resource).Collection(x => x.People!).LoadAsync();
|
||||||
resource.People = changed.People;
|
resource.People = changed.People;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<string> GetSlug(int showID)
|
public async Task<string> GetSlug(int showID)
|
||||||
{
|
{
|
||||||
return _database.Shows.Where(x => x.Id == showID)
|
string? ret = await _database.Shows.Where(x => x.Id == showID)
|
||||||
.Select(x => x.Slug)
|
.Select(x => x.Slug)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
|
if (ret == null)
|
||||||
|
throw new ItemNotFoundException();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -69,7 +69,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
await base.Create(obj);
|
await base.Create(obj);
|
||||||
_database.Entry(obj).State = EntityState.Added;
|
_database.Entry(obj).State = EntityState.Added;
|
||||||
if (obj.Logo != null)
|
if (obj.Logo != null)
|
||||||
_database.Entry(obj).Reference(x => x.Logo).TargetEntry.State = EntityState.Added;
|
_database.Entry(obj).Reference(x => x.Logo).TargetEntry!.State = EntityState.Added;
|
||||||
await _database.SaveChangesAsync(() => Get(obj.Slug));
|
await _database.SaveChangesAsync(() => Get(obj.Slug));
|
||||||
OnResourceCreated(obj);
|
OnResourceCreated(obj);
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -84,7 +84,7 @@ namespace Kyoo.Core
|
|||||||
options.InvalidModelStateResponseFactory = ctx =>
|
options.InvalidModelStateResponseFactory = ctx =>
|
||||||
{
|
{
|
||||||
string[] errors = ctx.ModelState
|
string[] errors = ctx.ModelState
|
||||||
.SelectMany(x => x.Value.Errors)
|
.SelectMany(x => x.Value!.Errors)
|
||||||
.Select(x => x.ErrorMessage)
|
.Select(x => x.ErrorMessage)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
return new BadRequestObjectResult(new RequestError(errors));
|
return new BadRequestObjectResult(new RequestError(errors));
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
// Kyoo - A portable and vast media library solution.
|
|
||||||
// Copyright (c) Kyoo.
|
|
||||||
//
|
|
||||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
|
||||||
//
|
|
||||||
// Kyoo is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// any later version.
|
|
||||||
//
|
|
||||||
// Kyoo is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Kyoo.Core
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A class containing helper methods.
|
|
||||||
/// </summary>
|
|
||||||
public static class Helper
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An helper method to get json content from an http server. This is a temporary thing and will probably be
|
|
||||||
/// replaced by a call to the function of the same name in the <c>System.Net.Http.Json</c> namespace when .net6
|
|
||||||
/// gets released.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="client">The http server to use.</param>
|
|
||||||
/// <param name="url">The url to retrieve</param>
|
|
||||||
/// <typeparam name="T">The type of object to convert</typeparam>
|
|
||||||
/// <returns>A T representing the json contained at the given url.</returns>
|
|
||||||
public static async Task<T> GetFromJsonAsync<T>(this HttpClient client, string url)
|
|
||||||
{
|
|
||||||
HttpResponseMessage ret = await client.GetAsync(url);
|
|
||||||
ret.EnsureSuccessStatusCode();
|
|
||||||
string content = await ret.Content.ReadAsStringAsync();
|
|
||||||
return JsonConvert.DeserializeObject<T>(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Kyoo.Core</AssemblyName>
|
<AssemblyName>Kyoo.Core</AssemblyName>
|
||||||
<RootNamespace>Kyoo.Core</RootNamespace>
|
<RootNamespace>Kyoo.Core</RootNamespace>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -48,9 +48,9 @@ namespace Kyoo.Core.Api
|
|||||||
/// <param name="right">The second parameter to compare.</param>
|
/// <param name="right">The second parameter to compare.</param>
|
||||||
/// <returns>A comparison expression compatible with strings</returns>
|
/// <returns>A comparison expression compatible with strings</returns>
|
||||||
public static BinaryExpression StringCompatibleExpression(
|
public static BinaryExpression StringCompatibleExpression(
|
||||||
[NotNull] Func<Expression, Expression, BinaryExpression> operand,
|
Func<Expression, Expression, BinaryExpression> operand,
|
||||||
[NotNull] Expression left,
|
Expression left,
|
||||||
[NotNull] Expression right)
|
Expression right)
|
||||||
{
|
{
|
||||||
if (left.Type != typeof(string))
|
if (left.Type != typeof(string))
|
||||||
return operand(left, right);
|
return operand(left, right);
|
||||||
@ -69,14 +69,14 @@ namespace Kyoo.Core.Api
|
|||||||
/// <typeparam name="T">The type to create filters for.</typeparam>
|
/// <typeparam name="T">The type to create filters for.</typeparam>
|
||||||
/// <exception cref="ArgumentException">A filter is invalid.</exception>
|
/// <exception cref="ArgumentException">A filter is invalid.</exception>
|
||||||
/// <returns>An expression representing the filters that can be used anywhere or compiled</returns>
|
/// <returns>An expression representing the filters that can be used anywhere or compiled</returns>
|
||||||
public static Expression<Func<T, bool>> ParseWhere<T>(Dictionary<string, string> where,
|
public static Expression<Func<T, bool>>? ParseWhere<T>(Dictionary<string, string>? where,
|
||||||
Expression<Func<T, bool>> defaultWhere = null)
|
Expression<Func<T, bool>>? defaultWhere = null)
|
||||||
{
|
{
|
||||||
if (where == null || where.Count == 0)
|
if (where == null || where.Count == 0)
|
||||||
return defaultWhere;
|
return defaultWhere;
|
||||||
|
|
||||||
ParameterExpression param = defaultWhere?.Parameters.First() ?? Expression.Parameter(typeof(T));
|
ParameterExpression param = defaultWhere?.Parameters.First() ?? Expression.Parameter(typeof(T));
|
||||||
Expression expression = defaultWhere?.Body;
|
Expression? expression = defaultWhere?.Body;
|
||||||
|
|
||||||
foreach ((string key, string desired) in where)
|
foreach ((string key, string desired) in where)
|
||||||
{
|
{
|
||||||
@ -91,17 +91,17 @@ namespace Kyoo.Core.Api
|
|||||||
value = desired.Substring(desired.IndexOf(':') + 1);
|
value = desired.Substring(desired.IndexOf(':') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyInfo property = typeof(T).GetProperty(key, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
|
PropertyInfo? property = typeof(T).GetProperty(key, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
|
||||||
if (property == null)
|
if (property == null)
|
||||||
throw new ArgumentException($"No filterable parameter with the name {key}.");
|
throw new ArgumentException($"No filterable parameter with the name {key}.");
|
||||||
MemberExpression propertyExpr = Expression.Property(param, property);
|
MemberExpression propertyExpr = Expression.Property(param, property);
|
||||||
|
|
||||||
ConstantExpression valueExpr = null;
|
ConstantExpression? valueExpr = null;
|
||||||
bool isList = typeof(IEnumerable).IsAssignableFrom(propertyExpr.Type) && propertyExpr.Type != typeof(string);
|
bool isList = typeof(IEnumerable).IsAssignableFrom(propertyExpr.Type) && propertyExpr.Type != typeof(string);
|
||||||
if (operand != "ctn" && !typeof(IResource).IsAssignableFrom(propertyExpr.Type) && !isList)
|
if (operand != "ctn" && !typeof(IResource).IsAssignableFrom(propertyExpr.Type) && !isList)
|
||||||
{
|
{
|
||||||
Type propertyType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
|
Type propertyType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
|
||||||
object val;
|
object? val;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
val = string.IsNullOrEmpty(value) || value.Equals("null", StringComparison.OrdinalIgnoreCase)
|
val = string.IsNullOrEmpty(value) || value.Equals("null", StringComparison.OrdinalIgnoreCase)
|
||||||
@ -110,7 +110,7 @@ namespace Kyoo.Core.Api
|
|||||||
}
|
}
|
||||||
catch (InvalidCastException)
|
catch (InvalidCastException)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Comparing two differents value's type.");
|
throw new ArgumentException("Comparing two different value's type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
valueExpr = Expression.Constant(val, property.PropertyType);
|
valueExpr = Expression.Constant(val, property.PropertyType);
|
||||||
@ -166,7 +166,7 @@ namespace Kyoo.Core.Api
|
|||||||
if (xProperty.Type == typeof(string))
|
if (xProperty.Type == typeof(string))
|
||||||
{
|
{
|
||||||
// x.PROPRETY.Contains(value);
|
// x.PROPRETY.Contains(value);
|
||||||
return Expression.Call(xProperty, typeof(string).GetMethod("Contains", new[] { typeof(string) }), Expression.Constant(value));
|
return Expression.Call(xProperty, typeof(string).GetMethod("Contains", new[] { typeof(string) })!, Expression.Constant(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// x.PROPERTY is either a List<> or a []
|
// x.PROPERTY is either a List<> or a []
|
||||||
@ -176,7 +176,8 @@ namespace Kyoo.Core.Api
|
|||||||
{
|
{
|
||||||
return Expression.Call(typeof(Enumerable), "Contains", new[] { inner }, xProperty, Expression.Constant(value));
|
return Expression.Call(typeof(Enumerable), "Contains", new[] { inner }, xProperty, Expression.Constant(value));
|
||||||
}
|
}
|
||||||
else if (inner.IsEnum && Enum.TryParse(inner, value, true, out object enumValue))
|
|
||||||
|
if (inner.IsEnum && Enum.TryParse(inner, value, true, out object? enumValue))
|
||||||
{
|
{
|
||||||
return Expression.Call(typeof(Enumerable), "Contains", new[] { inner }, xProperty, Expression.Constant(enumValue));
|
return Expression.Call(typeof(Enumerable), "Contains", new[] { inner }, xProperty, Expression.Constant(enumValue));
|
||||||
}
|
}
|
||||||
@ -185,7 +186,7 @@ namespace Kyoo.Core.Api
|
|||||||
throw new ArgumentException("Contain (ctn) not appliable for this property.");
|
throw new ArgumentException("Contain (ctn) not appliable for this property.");
|
||||||
|
|
||||||
// x => x.PROPERTY.Any(y => y.Slug == value)
|
// x => x.PROPERTY.Any(y => y.Slug == value)
|
||||||
Expression ret = null;
|
Expression? ret = null;
|
||||||
ParameterExpression y = Expression.Parameter(inner, "y");
|
ParameterExpression y = Expression.Parameter(inner, "y");
|
||||||
foreach (string val in value.Split(','))
|
foreach (string val in value.Split(','))
|
||||||
{
|
{
|
||||||
@ -197,7 +198,7 @@ namespace Kyoo.Core.Api
|
|||||||
else
|
else
|
||||||
ret = Expression.AndAlso(ret, iteration);
|
ret = Expression.AndAlso(ret, iteration);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
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;
|
||||||
@ -69,7 +70,7 @@ namespace Kyoo.Core.Api
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult<T>> Get(Identifier identifier)
|
public async Task<ActionResult<T>> Get(Identifier identifier)
|
||||||
{
|
{
|
||||||
T ret = await identifier.Match(
|
T? ret = await identifier.Match(
|
||||||
id => Repository.GetOrDefault(id),
|
id => Repository.GetOrDefault(id),
|
||||||
slug => Repository.GetOrDefault(slug)
|
slug => Repository.GetOrDefault(slug)
|
||||||
);
|
);
|
||||||
@ -235,7 +236,11 @@ namespace Kyoo.Core.Api
|
|||||||
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
|
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
|
||||||
public async Task<IActionResult> Delete([FromQuery] Dictionary<string, string> where)
|
public async Task<IActionResult> Delete([FromQuery] Dictionary<string, string> where)
|
||||||
{
|
{
|
||||||
await Repository.DeleteAll(ApiHelper.ParseWhere<T>(where));
|
Expression<Func<T, bool>>? w = ApiHelper.ParseWhere<T>(where);
|
||||||
|
if (w == null)
|
||||||
|
return BadRequest(new RequestError("Incule a filter to delete items, all items won't be deleted."));
|
||||||
|
|
||||||
|
await Repository.DeleteAll(w);
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,14 +59,14 @@ namespace Kyoo.Core.Api
|
|||||||
|
|
||||||
private async Task<IActionResult> _GetImage(Identifier identifier, string image, ImageQuality? quality)
|
private async Task<IActionResult> _GetImage(Identifier identifier, string image, ImageQuality? quality)
|
||||||
{
|
{
|
||||||
T resource = await identifier.Match(
|
T? resource = await identifier.Match(
|
||||||
id => Repository.GetOrDefault(id),
|
id => Repository.GetOrDefault(id),
|
||||||
slug => Repository.GetOrDefault(slug)
|
slug => Repository.GetOrDefault(slug)
|
||||||
);
|
);
|
||||||
if (resource == null)
|
if (resource == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
string path = _thumbs.GetImagePath(resource, image, quality ?? ImageQuality.High);
|
string path = _thumbs.GetImagePath(resource, image, quality ?? ImageQuality.High);
|
||||||
if (path == null || !System.IO.File.Exists(path))
|
if (!System.IO.File.Exists(path))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
if (!identifier.Match(id => false, slug => slug == "random"))
|
if (!identifier.Match(id => false, slug => slug == "random"))
|
||||||
|
@ -42,7 +42,7 @@ namespace Kyoo.Core.Api
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnActionExecuting(ActionExecutingContext context)
|
public override void OnActionExecuting(ActionExecutingContext context)
|
||||||
{
|
{
|
||||||
if (context.ActionArguments.TryGetValue("where", out object dic) && dic is Dictionary<string, string> where)
|
if (context.ActionArguments.TryGetValue("where", out object? dic) && dic is Dictionary<string, string> where)
|
||||||
{
|
{
|
||||||
Dictionary<string, string> nWhere = new(where, StringComparer.InvariantCultureIgnoreCase);
|
Dictionary<string, string> nWhere = new(where, StringComparer.InvariantCultureIgnoreCase);
|
||||||
nWhere.Remove("fields");
|
nWhere.Remove("fields");
|
||||||
@ -55,7 +55,7 @@ namespace Kyoo.Core.Api
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<string> fields = context.HttpContext.Request.Query["fields"]
|
List<string> fields = context.HttpContext.Request.Query["fields"]
|
||||||
.SelectMany(x => x.Split(','))
|
.SelectMany(x => x!.Split(','))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (context.ActionDescriptor is ControllerActionDescriptor descriptor)
|
if (context.ActionDescriptor is ControllerActionDescriptor descriptor)
|
||||||
@ -77,7 +77,7 @@ namespace Kyoo.Core.Api
|
|||||||
fields = fields
|
fields = fields
|
||||||
.Select(x =>
|
.Select(x =>
|
||||||
{
|
{
|
||||||
string property = properties
|
string? property = properties
|
||||||
.FirstOrDefault(y
|
.FirstOrDefault(y
|
||||||
=> string.Equals(x, y.Name, StringComparison.InvariantCultureIgnoreCase))
|
=> string.Equals(x, y.Name, StringComparison.InvariantCultureIgnoreCase))
|
||||||
?.Name;
|
?.Name;
|
||||||
@ -88,6 +88,7 @@ namespace Kyoo.Core.Api
|
|||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
|
.OfType<string>()
|
||||||
.ToList();
|
.ToList();
|
||||||
if (context.Result != null)
|
if (context.Result != null)
|
||||||
return;
|
return;
|
||||||
@ -111,12 +112,12 @@ namespace Kyoo.Core.Api
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ILibraryManager library = context.HttpContext.RequestServices.GetRequiredService<ILibraryManager>();
|
ILibraryManager library = context.HttpContext.RequestServices.GetRequiredService<ILibraryManager>();
|
||||||
ICollection<string> fields = (ICollection<string>)context.HttpContext.Items["fields"];
|
ICollection<string> fields = (ICollection<string>)context.HttpContext.Items["fields"]!;
|
||||||
Type pageType = Utility.GetGenericDefinition(result.DeclaredType, typeof(Page<>));
|
Type? pageType = Utility.GetGenericDefinition(result.DeclaredType, typeof(Page<>));
|
||||||
|
|
||||||
if (pageType != null)
|
if (pageType != null)
|
||||||
{
|
{
|
||||||
foreach (IResource resource in ((dynamic)result.Value).Items)
|
foreach (IResource resource in ((dynamic)result.Value!).Items)
|
||||||
{
|
{
|
||||||
foreach (string field in fields!)
|
foreach (string field in fields!)
|
||||||
await library.Load(resource, field);
|
await library.Load(resource, field);
|
||||||
@ -125,7 +126,7 @@ namespace Kyoo.Core.Api
|
|||||||
else if (result.DeclaredType.IsAssignableTo(typeof(IResource)))
|
else if (result.DeclaredType.IsAssignableTo(typeof(IResource)))
|
||||||
{
|
{
|
||||||
foreach (string field in fields!)
|
foreach (string field in fields!)
|
||||||
await library.Load((IResource)result.Value, field);
|
await library.Load((IResource)result.Value!, field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,16 +53,16 @@ namespace Kyoo.Core.Api
|
|||||||
{
|
{
|
||||||
JsonProperty property = base.CreateProperty(member, memberSerialization);
|
JsonProperty property = base.CreateProperty(member, memberSerialization);
|
||||||
|
|
||||||
LoadableRelationAttribute relation = member.GetCustomAttribute<LoadableRelationAttribute>();
|
LoadableRelationAttribute? relation = member.GetCustomAttribute<LoadableRelationAttribute>();
|
||||||
if (relation != null)
|
if (relation != null)
|
||||||
{
|
{
|
||||||
property.ShouldSerialize = _ =>
|
property.ShouldSerialize = _ =>
|
||||||
{
|
{
|
||||||
string resType = (string)_httpContextAccessor.HttpContext!.Items["ResourceType"];
|
string resType = (string)_httpContextAccessor.HttpContext!.Items["ResourceType"]!;
|
||||||
if (member.DeclaringType!.Name != resType)
|
if (member.DeclaringType!.Name != resType)
|
||||||
return false;
|
return false;
|
||||||
ICollection<string> fields = (ICollection<string>)_httpContextAccessor.HttpContext!.Items["fields"];
|
ICollection<string> fields = (ICollection<string>)_httpContextAccessor.HttpContext!.Items["fields"]!;
|
||||||
return fields!.Contains(member.Name);
|
return fields.Contains(member.Name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,10 +31,16 @@ namespace Kyoo.Core.Api
|
|||||||
public class PeopleRoleConverter : JsonConverter<PeopleRole>
|
public class PeopleRoleConverter : JsonConverter<PeopleRole>
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void WriteJson(JsonWriter writer, PeopleRole value, JsonSerializer serializer)
|
public override void WriteJson(JsonWriter writer, PeopleRole? value, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
ICollection<PeopleRole> oldPeople = value.Show?.People;
|
if (value == null)
|
||||||
ICollection<PeopleRole> oldRoles = value.People?.Roles;
|
{
|
||||||
|
writer.WriteNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ICollection<PeopleRole>? oldPeople = value.Show?.People;
|
||||||
|
ICollection<PeopleRole>? oldRoles = value.People?.Roles;
|
||||||
if (value.Show != null)
|
if (value.Show != null)
|
||||||
value.Show.People = null;
|
value.Show.People = null;
|
||||||
if (value.People != null)
|
if (value.People != null)
|
||||||
@ -54,7 +60,7 @@ namespace Kyoo.Core.Api
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override PeopleRole ReadJson(JsonReader reader,
|
public override PeopleRole ReadJson(JsonReader reader,
|
||||||
Type objectType,
|
Type objectType,
|
||||||
PeopleRole existingValue,
|
PeopleRole? existingValue,
|
||||||
bool hasExistingValue,
|
bool hasExistingValue,
|
||||||
JsonSerializer serializer)
|
JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
|
@ -85,7 +85,7 @@ namespace Kyoo.Core.Api
|
|||||||
[FromQuery] Dictionary<string, string> where,
|
[FromQuery] Dictionary<string, string> where,
|
||||||
[FromQuery] Pagination pagination)
|
[FromQuery] Pagination pagination)
|
||||||
{
|
{
|
||||||
Expression<Func<PeopleRole, bool>> whereQuery = ApiHelper.ParseWhere<PeopleRole>(where);
|
Expression<Func<PeopleRole, bool>>? whereQuery = ApiHelper.ParseWhere<PeopleRole>(where);
|
||||||
Sort<PeopleRole> sort = Sort<PeopleRole>.From(sortBy);
|
Sort<PeopleRole> sort = Sort<PeopleRole>.From(sortBy);
|
||||||
|
|
||||||
ICollection<PeopleRole> resources = await identifier.Match(
|
ICollection<PeopleRole> resources = await identifier.Match(
|
||||||
|
@ -83,7 +83,7 @@ namespace Kyoo.Core.Api
|
|||||||
[FromQuery] Pagination pagination)
|
[FromQuery] Pagination pagination)
|
||||||
{
|
{
|
||||||
ICollection<Show> resources = await _libraryManager.GetAll(
|
ICollection<Show> resources = await _libraryManager.GetAll(
|
||||||
ApiHelper.ParseWhere(where, identifier.Matcher<Show>(x => x.StudioId, x => x.Studio.Slug)),
|
ApiHelper.ParseWhere(where, identifier.Matcher<Show>(x => x.StudioId, x => x.Studio!.Slug)),
|
||||||
Sort<Show>.From(sortBy),
|
Sort<Show>.From(sortBy),
|
||||||
pagination
|
pagination
|
||||||
);
|
);
|
||||||
|
@ -84,7 +84,7 @@ namespace Kyoo.Core.Api
|
|||||||
[FromQuery] Pagination pagination)
|
[FromQuery] Pagination pagination)
|
||||||
{
|
{
|
||||||
ICollection<Show> resources = await _libraryManager.GetAll(
|
ICollection<Show> resources = await _libraryManager.GetAll(
|
||||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Show, Collection>(x => x.Collections)),
|
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Show, Collection>(x => x.Collections!)),
|
||||||
Sort<Show>.From(sortBy),
|
Sort<Show>.From(sortBy),
|
||||||
pagination
|
pagination
|
||||||
);
|
);
|
||||||
|
@ -73,7 +73,7 @@ namespace Kyoo.Core.Api
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult<Show>> GetShow(Identifier identifier)
|
public async Task<ActionResult<Show>> GetShow(Identifier identifier)
|
||||||
{
|
{
|
||||||
return await _libraryManager.Get(identifier.IsContainedIn<Show, Episode>(x => x.Episodes));
|
return await _libraryManager.Get(identifier.IsContainedIn<Show, Episode>(x => x.Episodes!));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -93,10 +93,10 @@ namespace Kyoo.Core.Api
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult<Season>> GetSeason(Identifier identifier)
|
public async Task<ActionResult<Season>> GetSeason(Identifier identifier)
|
||||||
{
|
{
|
||||||
Season ret = await _libraryManager.GetOrDefault(identifier.IsContainedIn<Season, Episode>(x => x.Episodes));
|
Season? ret = await _libraryManager.GetOrDefault(identifier.IsContainedIn<Season, Episode>(x => x.Episodes!));
|
||||||
if (ret != null)
|
if (ret != null)
|
||||||
return ret;
|
return ret;
|
||||||
Episode episode = await identifier.Match(
|
Episode? episode = await identifier.Match(
|
||||||
id => _libraryManager.GetOrDefault<Episode>(id),
|
id => _libraryManager.GetOrDefault<Episode>(id),
|
||||||
slug => _libraryManager.GetOrDefault<Episode>(slug)
|
slug => _libraryManager.GetOrDefault<Episode>(slug)
|
||||||
);
|
);
|
||||||
|
@ -108,7 +108,7 @@ namespace Kyoo.Core.Api
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult<Studio>> GetStudio(Identifier identifier)
|
public async Task<ActionResult<Studio>> GetStudio(Identifier identifier)
|
||||||
{
|
{
|
||||||
return await _libraryManager.Get(identifier.IsContainedIn<Studio, Movie>(x => x.Movies));
|
return await _libraryManager.Get(identifier.IsContainedIn<Studio, Movie>(x => x.Movies!));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -136,7 +136,7 @@ namespace Kyoo.Core.Api
|
|||||||
[FromQuery] Pagination pagination)
|
[FromQuery] Pagination pagination)
|
||||||
{
|
{
|
||||||
ICollection<Collection> resources = await _libraryManager.GetAll(
|
ICollection<Collection> resources = await _libraryManager.GetAll(
|
||||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Collection, Movie>(x => x.Movies)),
|
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Collection, Movie>(x => x.Movies!)),
|
||||||
Sort<Collection>.From(sortBy),
|
Sort<Collection>.From(sortBy),
|
||||||
pagination
|
pagination
|
||||||
);
|
);
|
||||||
|
@ -84,7 +84,7 @@ namespace Kyoo.Core.Api
|
|||||||
[FromQuery] Pagination pagination)
|
[FromQuery] Pagination pagination)
|
||||||
{
|
{
|
||||||
ICollection<Episode> resources = await _libraryManager.GetAll(
|
ICollection<Episode> resources = await _libraryManager.GetAll(
|
||||||
ApiHelper.ParseWhere(where, identifier.Matcher<Episode>(x => x.SeasonId, x => x.Season.Slug)),
|
ApiHelper.ParseWhere(where, identifier.Matcher<Episode>(x => x.SeasonId, x => x.Season!.Slug)),
|
||||||
Sort<Episode>.From(sortBy),
|
Sort<Episode>.From(sortBy),
|
||||||
pagination
|
pagination
|
||||||
);
|
);
|
||||||
@ -109,7 +109,7 @@ namespace Kyoo.Core.Api
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult<Show>> GetShow(Identifier identifier)
|
public async Task<ActionResult<Show>> GetShow(Identifier identifier)
|
||||||
{
|
{
|
||||||
Show ret = await _libraryManager.GetOrDefault(identifier.IsContainedIn<Show, Season>(x => x.Seasons));
|
Show? ret = await _libraryManager.GetOrDefault(identifier.IsContainedIn<Show, Season>(x => x.Seasons!));
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -86,7 +86,7 @@ namespace Kyoo.Core.Api
|
|||||||
[FromQuery] Pagination pagination)
|
[FromQuery] Pagination pagination)
|
||||||
{
|
{
|
||||||
ICollection<Season> resources = await _libraryManager.GetAll(
|
ICollection<Season> resources = await _libraryManager.GetAll(
|
||||||
ApiHelper.ParseWhere(where, identifier.Matcher<Season>(x => x.ShowId, x => x.Show.Slug)),
|
ApiHelper.ParseWhere(where, identifier.Matcher<Season>(x => x.ShowId, x => x.Show!.Slug)),
|
||||||
Sort<Season>.From(sortBy),
|
Sort<Season>.From(sortBy),
|
||||||
pagination
|
pagination
|
||||||
);
|
);
|
||||||
@ -121,7 +121,7 @@ namespace Kyoo.Core.Api
|
|||||||
[FromQuery] Pagination pagination)
|
[FromQuery] Pagination pagination)
|
||||||
{
|
{
|
||||||
ICollection<Episode> resources = await _libraryManager.GetAll(
|
ICollection<Episode> resources = await _libraryManager.GetAll(
|
||||||
ApiHelper.ParseWhere(where, identifier.Matcher<Episode>(x => x.ShowId, x => x.Show.Slug)),
|
ApiHelper.ParseWhere(where, identifier.Matcher<Episode>(x => x.ShowId, x => x.Show!.Slug)),
|
||||||
Sort<Episode>.From(sortBy),
|
Sort<Episode>.From(sortBy),
|
||||||
pagination
|
pagination
|
||||||
);
|
);
|
||||||
@ -155,7 +155,7 @@ namespace Kyoo.Core.Api
|
|||||||
[FromQuery] Dictionary<string, string> where,
|
[FromQuery] Dictionary<string, string> where,
|
||||||
[FromQuery] Pagination pagination)
|
[FromQuery] Pagination pagination)
|
||||||
{
|
{
|
||||||
Expression<Func<PeopleRole, bool>> whereQuery = ApiHelper.ParseWhere<PeopleRole>(where);
|
Expression<Func<PeopleRole, bool>>? whereQuery = ApiHelper.ParseWhere<PeopleRole>(where);
|
||||||
Sort<PeopleRole> sort = Sort<PeopleRole>.From(sortBy);
|
Sort<PeopleRole> sort = Sort<PeopleRole>.From(sortBy);
|
||||||
|
|
||||||
ICollection<PeopleRole> resources = await identifier.Match(
|
ICollection<PeopleRole> resources = await identifier.Match(
|
||||||
@ -180,7 +180,7 @@ namespace Kyoo.Core.Api
|
|||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult<Studio>> GetStudio(Identifier identifier)
|
public async Task<ActionResult<Studio>> GetStudio(Identifier identifier)
|
||||||
{
|
{
|
||||||
return await _libraryManager.Get(identifier.IsContainedIn<Studio, Show>(x => x.Shows));
|
return await _libraryManager.Get(identifier.IsContainedIn<Studio, Show>(x => x.Shows!));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -208,7 +208,7 @@ namespace Kyoo.Core.Api
|
|||||||
[FromQuery] Pagination pagination)
|
[FromQuery] Pagination pagination)
|
||||||
{
|
{
|
||||||
ICollection<Collection> resources = await _libraryManager.GetAll(
|
ICollection<Collection> resources = await _libraryManager.GetAll(
|
||||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Collection, Show>(x => x.Shows)),
|
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Collection, Show>(x => x.Shows!)),
|
||||||
Sort<Collection>.From(sortBy),
|
Sort<Collection>.From(sortBy),
|
||||||
pagination
|
pagination
|
||||||
);
|
);
|
||||||
|
@ -180,8 +180,8 @@ namespace Kyoo.Postgresql
|
|||||||
modelBuilder.Entity<T>()
|
modelBuilder.Entity<T>()
|
||||||
.Property(x => x.ExternalId)
|
.Property(x => x.ExternalId)
|
||||||
.HasConversion(
|
.HasConversion(
|
||||||
v => JsonSerializer.Serialize(v, (JsonSerializerOptions)null),
|
v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
|
||||||
v => JsonSerializer.Deserialize<Dictionary<string, MetadataId>>(v, (JsonSerializerOptions)null)
|
v => JsonSerializer.Deserialize<Dictionary<string, MetadataId>>(v, (JsonSerializerOptions?)null)!
|
||||||
)
|
)
|
||||||
.HasColumnType("json");
|
.HasColumnType("json");
|
||||||
}
|
}
|
||||||
@ -215,8 +215,8 @@ namespace Kyoo.Postgresql
|
|||||||
/// <typeparam name="T">The owning type of the relationship</typeparam>
|
/// <typeparam name="T">The owning type of the relationship</typeparam>
|
||||||
/// <typeparam name="T2">The owned type of the relationship</typeparam>
|
/// <typeparam name="T2">The owned type of the relationship</typeparam>
|
||||||
private void _HasManyToMany<T, T2>(ModelBuilder modelBuilder,
|
private void _HasManyToMany<T, T2>(ModelBuilder modelBuilder,
|
||||||
Expression<Func<T, IEnumerable<T2>>> firstNavigation,
|
Expression<Func<T, IEnumerable<T2>?>> firstNavigation,
|
||||||
Expression<Func<T2, IEnumerable<T>>> secondNavigation)
|
Expression<Func<T2, IEnumerable<T>?>> secondNavigation)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
where T2 : class, IResource
|
where T2 : class, IResource
|
||||||
{
|
{
|
||||||
@ -360,7 +360,7 @@ namespace Kyoo.Postgresql
|
|||||||
public T GetTemporaryObject<T>(T model)
|
public T GetTemporaryObject<T>(T model)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
T tmp = Set<T>().Local.FirstOrDefault(x => x.Id == model.Id);
|
T? tmp = Set<T>().Local.FirstOrDefault(x => x.Id == model.Id);
|
||||||
if (tmp != null)
|
if (tmp != null)
|
||||||
return tmp;
|
return tmp;
|
||||||
Entry(model).State = EntityState.Unchanged;
|
Entry(model).State = EntityState.Unchanged;
|
||||||
@ -509,8 +509,7 @@ namespace Kyoo.Postgresql
|
|||||||
/// <param name="slug">The slug of the resource to check</param>
|
/// <param name="slug">The slug of the resource to check</param>
|
||||||
/// <typeparam name="T">The type of entity to check</typeparam>
|
/// <typeparam name="T">The type of entity to check</typeparam>
|
||||||
/// <returns>The local entity representing the resource with the given slug if it exists or null.</returns>
|
/// <returns>The local entity representing the resource with the given slug if it exists or null.</returns>
|
||||||
[CanBeNull]
|
public T? LocalEntity<T>(string slug)
|
||||||
public T LocalEntity<T>(string slug)
|
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
return ChangeTracker.Entries<T>()
|
return ChangeTracker.Entries<T>()
|
||||||
|
@ -106,7 +106,7 @@ namespace Kyoo.Postgresql
|
|||||||
modelBuilder.HasPostgresEnum<Genre>();
|
modelBuilder.HasPostgresEnum<Genre>();
|
||||||
modelBuilder.HasPostgresEnum<ItemKind>();
|
modelBuilder.HasPostgresEnum<ItemKind>();
|
||||||
|
|
||||||
modelBuilder.HasDbFunction(typeof(DatabaseContext).GetMethod(nameof(MD5)))
|
modelBuilder.HasDbFunction(typeof(DatabaseContext).GetMethod(nameof(MD5))!)
|
||||||
.HasTranslation(args =>
|
.HasTranslation(args =>
|
||||||
new SqlFunctionExpression(
|
new SqlFunctionExpression(
|
||||||
"md5",
|
"md5",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user