mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Switch from int ids to guid
This commit is contained in:
parent
22348e1554
commit
070a94d87d
@ -18,7 +18,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Exceptions;
|
||||
@ -47,7 +46,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(int id, Include<T>? include = default);
|
||||
Task<T> Get(Guid id, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's slug.
|
||||
@ -73,7 +72,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault(int id, Include<T>? include = default);
|
||||
Task<T?> GetOrDefault(Guid id, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's slug or null if it is not found.
|
||||
@ -128,7 +127,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="ids">The list of items id.</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources mapped from ids.</returns>
|
||||
Task<ICollection<T>> FromIds(IList<int> ids, Include<T>? include = default);
|
||||
Task<ICollection<T>> FromIds(IList<Guid> ids, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource.
|
||||
@ -175,7 +174,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// </param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Patch(int id, Func<T, Task<bool>> patch);
|
||||
Task<T> Patch(Guid id, Func<T, Task<bool>> patch);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a resource has been edited.
|
||||
@ -196,7 +195,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="id">The ID of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete(int id);
|
||||
Task Delete(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's slug
|
||||
|
@ -16,11 +16,13 @@
|
||||
// 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;
|
||||
|
||||
namespace Kyoo.Models;
|
||||
|
||||
public class PartialResource
|
||||
{
|
||||
public int? Id { get; set; }
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
public string? Slug { get; set; }
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
// 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;
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <summary>
|
||||
@ -29,7 +31,7 @@ namespace Kyoo.Abstractions.Models
|
||||
public class PeopleRole : IResource
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug => ForPeople ? Show!.Slug : People.Slug;
|
||||
@ -43,7 +45,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The ID of the People playing the role.
|
||||
/// </summary>
|
||||
public int PeopleID { get; set; }
|
||||
public Guid PeopleID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The people that played this role.
|
||||
@ -53,14 +55,14 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The ID of the Show where the People playing in.
|
||||
/// </summary>
|
||||
public int? ShowID { get; set; }
|
||||
public Guid? ShowID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The show where the People played in.
|
||||
/// </summary>
|
||||
public Show? Show { get; set; }
|
||||
|
||||
public int? MovieID { get; set; }
|
||||
public Guid? MovieID { get; set; }
|
||||
|
||||
public Movie? Movie { get; set; }
|
||||
|
||||
|
@ -34,7 +34,7 @@ namespace Kyoo.Abstractions.Models
|
||||
public static Sort DefaultSort => new Sort<Collection>.By(nameof(Collection.Name));
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)] public string Slug { get; set; }
|
||||
|
@ -41,7 +41,7 @@ namespace Kyoo.Abstractions.Models
|
||||
);
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Id { get; set; }
|
||||
public Guid Id { get; set; } = Guid.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
[Computed]
|
||||
@ -90,7 +90,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The ID of the Show containing this episode.
|
||||
/// </summary>
|
||||
public int ShowId { get; set; }
|
||||
public Guid ShowId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The show that contains this episode.
|
||||
@ -100,7 +100,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The ID of the Season containing this episode.
|
||||
/// </summary>
|
||||
public int? SeasonId { get; set; }
|
||||
public Guid? SeasonId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The season that contains this episode.
|
||||
|
@ -16,6 +16,7 @@
|
||||
// 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;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
|
||||
@ -33,7 +34,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// You don't need to specify an ID manually when creating a new resource,
|
||||
/// this field is automatically assigned by the <see cref="IRepository{T}"/>.
|
||||
/// </remarks>
|
||||
public int Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A human-readable identifier that can be used instead of an ID.
|
||||
|
@ -34,7 +34,7 @@ namespace Kyoo.Abstractions.Models
|
||||
public static Sort DefaultSort => new Sort<Movie>.By(x => x.Name);
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
@ -118,7 +118,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The ID of the Studio that made this show.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public int? StudioId { get; set; }
|
||||
[SerializeIgnore] public Guid? StudioId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Studio that made this show.
|
||||
|
@ -16,6 +16,7 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
@ -35,7 +36,7 @@ namespace Kyoo.Abstractions.Models
|
||||
public static Sort DefaultSort => new Sort<People>.By(x => x.Name);
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
|
@ -36,7 +36,7 @@ namespace Kyoo.Abstractions.Models
|
||||
public static Sort DefaultSort => new Sort<Season>.By(x => x.SeasonNumber);
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Computed]
|
||||
@ -71,7 +71,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The ID of the Show containing this season.
|
||||
/// </summary>
|
||||
public int ShowId { get; set; }
|
||||
public Guid ShowId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The show that contains this season.
|
||||
|
@ -37,7 +37,7 @@ namespace Kyoo.Abstractions.Models
|
||||
public static Sort DefaultSort => new Sort<Show>.By(x => x.Name);
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
@ -121,7 +121,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The ID of the Studio that made this show.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public int? StudioId { get; set; }
|
||||
[SerializeIgnore] public Guid? StudioId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Studio that made this show.
|
||||
|
@ -16,6 +16,7 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
@ -33,7 +34,7 @@ namespace Kyoo.Abstractions.Models
|
||||
public static Sort DefaultSort => new Sort<Studio>.By(x => x.Name);
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
|
@ -34,7 +34,7 @@ namespace Kyoo.Abstractions.Models
|
||||
public static Sort DefaultSort => new Sort<User>.By(x => x.Username);
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
|
@ -100,7 +100,7 @@ public abstract record Filter<T> : Filter
|
||||
/// Internal filter used for keyset paginations to resume random sorts.
|
||||
/// The pseudo sql is md5(seed || table.id) = md5(seed || 'hardCodedId')
|
||||
/// </summary>
|
||||
public record EqRandom(string Seed, int ReferenceId) : Filter<T>;
|
||||
public record EqRandom(string Seed, Guid ReferenceId) : Filter<T>;
|
||||
|
||||
/// <summary>
|
||||
/// Internal filter used only in EF with hard coded lamdas (used for relations).
|
||||
|
@ -37,7 +37,7 @@ namespace Kyoo.Abstractions.Models.Utils
|
||||
/// <summary>
|
||||
/// The ID of the resource or null if the slug is specified.
|
||||
/// </summary>
|
||||
private readonly int? _id;
|
||||
private readonly Guid? _id;
|
||||
|
||||
/// <summary>
|
||||
/// The slug of the resource or null if the id is specified.
|
||||
@ -48,7 +48,7 @@ namespace Kyoo.Abstractions.Models.Utils
|
||||
/// Create a new <see cref="Identifier"/> for the given id.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource.</param>
|
||||
public Identifier(int id)
|
||||
public Identifier(Guid id)
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
@ -80,7 +80,7 @@ namespace Kyoo.Abstractions.Models.Utils
|
||||
/// );
|
||||
/// </code>
|
||||
/// </example>
|
||||
public T Match<T>(Func<int, T> idFunc, Func<string, T> slugFunc)
|
||||
public T Match<T>(Func<Guid, T> idFunc, Func<string, T> slugFunc)
|
||||
{
|
||||
return _id.HasValue
|
||||
? idFunc(_id.Value)
|
||||
@ -99,7 +99,7 @@ namespace Kyoo.Abstractions.Models.Utils
|
||||
/// identifier.Matcher<Season>(x => x.ShowID, x => x.Show.Slug)
|
||||
/// </code>
|
||||
/// </example>
|
||||
public Filter<T> Matcher<T>(Expression<Func<T, int>> idGetter,
|
||||
public Filter<T> Matcher<T>(Expression<Func<T, Guid>> idGetter,
|
||||
Expression<Func<T, string>> slugGetter)
|
||||
{
|
||||
ConstantExpression self = Expression.Constant(_id.HasValue ? _id.Value : _slug);
|
||||
@ -111,14 +111,14 @@ namespace Kyoo.Abstractions.Models.Utils
|
||||
|
||||
/// <summary>
|
||||
/// A matcher overload for nullable IDs. See
|
||||
/// <see cref="Matcher{T}(Expression{Func{T,int}},Expression{Func{T,string}})"/>
|
||||
/// <see cref="Matcher{T}(Expression{Func{T,Guid}},Expression{Func{T,string}})"/>
|
||||
/// for more details.
|
||||
/// </summary>
|
||||
/// <param name="idGetter">An expression to retrieve an ID from the type <typeparamref name="T"/>.</param>
|
||||
/// <param name="slugGetter">An expression to retrieve a slug from the type <typeparamref name="T"/>.</param>
|
||||
/// <typeparam name="T">The type to match against this identifier.</typeparam>
|
||||
/// <returns>An expression to match the type <typeparamref name="T"/> to this identifier.</returns>
|
||||
public Filter<T> Matcher<T>(Expression<Func<T, int?>> idGetter,
|
||||
public Filter<T> Matcher<T>(Expression<Func<T, Guid?>> idGetter,
|
||||
Expression<Func<T, string>> slugGetter)
|
||||
{
|
||||
ConstantExpression self = Expression.Constant(_id.HasValue ? _id.Value : _slug);
|
||||
@ -210,11 +210,11 @@ namespace Kyoo.Abstractions.Models.Utils
|
||||
/// <inheritdoc />
|
||||
public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
|
||||
{
|
||||
if (value is int id)
|
||||
if (value is Guid id)
|
||||
return new Identifier(id);
|
||||
if (value is not string slug)
|
||||
return base.ConvertFrom(context, culture, value)!;
|
||||
return int.TryParse(slug, out id)
|
||||
return Guid.TryParse(slug, out id)
|
||||
? new Identifier(id)
|
||||
: new Identifier(slug);
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
// 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;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
@ -31,7 +33,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <summary>
|
||||
/// Where to start? Using the given sort.
|
||||
/// </summary>
|
||||
public int? AfterID { get; set; }
|
||||
public Guid? AfterID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should the previous page be returned instead of the next?
|
||||
@ -54,7 +56,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="count">Set the <see cref="Limit"/> value</param>
|
||||
/// <param name="afterID">Set the <see cref="AfterID"/> value. If not specified, it will start from the start</param>
|
||||
/// <param name="reverse">Should the previous page be returned instead of the next?</param>
|
||||
public Pagination(int count, int? afterID = null, bool reverse = false)
|
||||
public Pagination(int count, Guid? afterID = null, bool reverse = false)
|
||||
{
|
||||
Limit = count;
|
||||
AfterID = afterID;
|
||||
|
@ -49,6 +49,6 @@ namespace Kyoo.Authentication
|
||||
/// <param name="refreshToken">The refresh token to validate.</param>
|
||||
/// <exception cref="SecurityTokenException">The given refresh token is not valid.</exception>
|
||||
/// <returns>The id of the token's user.</returns>
|
||||
int GetRefreshTokenUserID(string refreshToken);
|
||||
Guid GetRefreshTokenUserID(string refreshToken);
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
@ -61,7 +60,7 @@ namespace Kyoo.Authentication
|
||||
: string.Empty;
|
||||
List<Claim> claims = new()
|
||||
{
|
||||
new Claim(Claims.Id, user.Id.ToString(CultureInfo.InvariantCulture)),
|
||||
new Claim(Claims.Id, user.Id.ToString()),
|
||||
new Claim(Claims.Name, user.Username),
|
||||
new Claim(Claims.Permissions, permissions),
|
||||
new Claim(Claims.Type, "access")
|
||||
@ -85,7 +84,7 @@ namespace Kyoo.Authentication
|
||||
signingCredentials: credential,
|
||||
claims: new[]
|
||||
{
|
||||
new Claim(Claims.Id, user.Id.ToString(CultureInfo.InvariantCulture)),
|
||||
new Claim(Claims.Id, user.Id.ToString()),
|
||||
new Claim(Claims.Guid, Guid.NewGuid().ToString()),
|
||||
new Claim(Claims.Type, "refresh")
|
||||
},
|
||||
@ -96,7 +95,7 @@ namespace Kyoo.Authentication
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int GetRefreshTokenUserID(string refreshToken)
|
||||
public Guid GetRefreshTokenUserID(string refreshToken)
|
||||
{
|
||||
SymmetricSecurityKey key = new(Encoding.UTF8.GetBytes(_options.Secret));
|
||||
JwtSecurityTokenHandler tokenHandler = new();
|
||||
@ -120,7 +119,7 @@ namespace Kyoo.Authentication
|
||||
if (principal.Claims.First(x => x.Type == Claims.Type).Value != "refresh")
|
||||
throw new SecurityTokenException("Invalid token type. The token should be a refresh token.");
|
||||
Claim identifier = principal.Claims.First(x => x.Type == Claims.Id);
|
||||
if (int.TryParse(identifier.Value, out int id))
|
||||
if (Guid.TryParse(identifier.Value, out Guid id))
|
||||
return id;
|
||||
throw new SecurityTokenException("Token not associated to any user.");
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
@ -126,7 +127,7 @@ namespace Kyoo.Authentication.Views
|
||||
User user = request.ToUser();
|
||||
user.Permissions = _permissions.NewUser;
|
||||
// If no users exists, the new one will be an admin. Give it every permissions.
|
||||
if (await _users.GetOrDefault(1) == null)
|
||||
if ((await _users.GetAll(limit: new Pagination(1))).Any())
|
||||
user.Permissions = PermissionOption.Admin;
|
||||
try
|
||||
{
|
||||
@ -161,7 +162,7 @@ namespace Kyoo.Authentication.Views
|
||||
{
|
||||
try
|
||||
{
|
||||
int userId = _token.GetRefreshTokenUserID(token);
|
||||
Guid userId = _token.GetRefreshTokenUserID(token);
|
||||
User user = await _users.Get(userId);
|
||||
return new JwtToken(
|
||||
_token.CreateAccessToken(user, out TimeSpan expireIn),
|
||||
@ -196,7 +197,7 @@ namespace Kyoo.Authentication.Views
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(RequestError))]
|
||||
public async Task<ActionResult<User>> GetMe()
|
||||
{
|
||||
if (!int.TryParse(User.FindFirstValue(Claims.Id), out int userID))
|
||||
if (!Guid.TryParse(User.FindFirstValue(Claims.Id), out Guid userID))
|
||||
return Unauthorized(new RequestError("User not authenticated or token invalid."));
|
||||
try
|
||||
{
|
||||
@ -225,7 +226,7 @@ namespace Kyoo.Authentication.Views
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(RequestError))]
|
||||
public async Task<ActionResult<User>> EditMe(User user)
|
||||
{
|
||||
if (!int.TryParse(User.FindFirstValue(Claims.Id), out int userID))
|
||||
if (!Guid.TryParse(User.FindFirstValue(Claims.Id), out Guid userID))
|
||||
return Unauthorized(new RequestError("User not authenticated or token invalid."));
|
||||
try
|
||||
{
|
||||
@ -255,7 +256,7 @@ namespace Kyoo.Authentication.Views
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(RequestError))]
|
||||
public async Task<ActionResult<User>> PatchMe(PartialResource user)
|
||||
{
|
||||
if (!int.TryParse(User.FindFirstValue(Claims.Id), out int userID))
|
||||
if (!Guid.TryParse(User.FindFirstValue(Claims.Id), out Guid userID))
|
||||
return Unauthorized(new RequestError("User not authenticated or token invalid."));
|
||||
try
|
||||
{
|
||||
@ -285,7 +286,7 @@ namespace Kyoo.Authentication.Views
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(RequestError))]
|
||||
public async Task<ActionResult<User>> DeleteMe()
|
||||
{
|
||||
if (!int.TryParse(User.FindFirstValue(Claims.Id), out int userID))
|
||||
if (!Guid.TryParse(User.FindFirstValue(Claims.Id), out Guid userID))
|
||||
return Unauthorized(new RequestError("User not authenticated or token invalid."));
|
||||
try
|
||||
{
|
||||
|
@ -77,13 +77,13 @@ namespace Kyoo.Core.Controllers
|
||||
throw new ArgumentException("The collection's name must be set and not empty");
|
||||
}
|
||||
|
||||
public async Task AddMovie(int id, int movieId)
|
||||
public async Task AddMovie(Guid id, Guid movieId)
|
||||
{
|
||||
_database.AddLinks<Collection, Movie>(id, movieId);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task AddShow(int id, int showId)
|
||||
public async Task AddShow(Guid id, Guid showId)
|
||||
{
|
||||
_database.AddLinks<Collection, Show>(id, showId);
|
||||
await _database.SaveChangesAsync();
|
||||
|
@ -180,7 +180,7 @@ public static class DapperHelper
|
||||
FormattableString command,
|
||||
Dictionary<string, Type> config,
|
||||
Func<List<object?>, T> mapper,
|
||||
Func<int, Task<T>> get,
|
||||
Func<Guid, Task<T>> get,
|
||||
Include<T>? include,
|
||||
Filter<T>? filter,
|
||||
Sort<T>? sort,
|
||||
|
@ -46,7 +46,7 @@ public abstract class DapperRepository<T> : IRepository<T>
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<T> Get(int id, Include<T>? include = default)
|
||||
public virtual async Task<T> Get(Guid id, Include<T>? include = default)
|
||||
{
|
||||
T? ret = await GetOrDefault(id, include);
|
||||
if (ret == null)
|
||||
@ -74,13 +74,13 @@ public abstract class DapperRepository<T> : IRepository<T>
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<T>> FromIds(IList<int> ids, Include<T>? include = null)
|
||||
public Task<ICollection<T>> FromIds(IList<Guid> ids, Include<T>? include = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T?> GetOrDefault(int id, Include<T>? include = null)
|
||||
public Task<T?> GetOrDefault(Guid id, Include<T>? include = null)
|
||||
{
|
||||
return Database.QuerySingle<T>(
|
||||
Sql,
|
||||
@ -165,7 +165,7 @@ public abstract class DapperRepository<T> : IRepository<T>
|
||||
public Task<T> CreateIfNotExists(T obj) => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task Delete(int id) => throw new NotImplementedException();
|
||||
public Task Delete(Guid id) => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task Delete(string slug) => throw new NotImplementedException();
|
||||
@ -180,5 +180,5 @@ public abstract class DapperRepository<T> : IRepository<T>
|
||||
public Task<T> Edit(T edited) => throw new NotImplementedException();
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> Patch(int id, Func<T, Task<bool>> patch) => throw new NotImplementedException();
|
||||
public Task<T> Patch(Guid id, Func<T, Task<bool>> patch) => throw new NotImplementedException();
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ namespace Kyoo.Core.Controllers
|
||||
protected override async Task Validate(Episode resource)
|
||||
{
|
||||
await base.Validate(resource);
|
||||
if (resource.ShowId <= 0)
|
||||
if (resource.ShowId != Guid.Empty)
|
||||
{
|
||||
if (resource.Show == null)
|
||||
{
|
||||
|
@ -62,18 +62,12 @@ namespace Kyoo.Core.Controllers
|
||||
|
||||
protected override ILibraryItem Mapper(List<object?> items)
|
||||
{
|
||||
if (items[0] is Show show && show.Id != 0)
|
||||
if (items[0] is Show show && show.Id != Guid.Empty)
|
||||
return show;
|
||||
if (items[1] is Movie movie && movie.Id != 0)
|
||||
{
|
||||
movie.Id = -movie.Id;
|
||||
if (items[1] is Movie movie && movie.Id != Guid.Empty)
|
||||
return movie;
|
||||
}
|
||||
if (items[2] is Collection collection && collection.Id != 0)
|
||||
{
|
||||
collection.Id += 10_000;
|
||||
if (items[2] is Collection collection && collection.Id != Guid.Empty)
|
||||
return collection;
|
||||
}
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
|
||||
@ -82,7 +76,7 @@ namespace Kyoo.Core.Controllers
|
||||
{ }
|
||||
|
||||
public async Task<ICollection<ILibraryItem>> GetAllOfCollection(
|
||||
int collectionId,
|
||||
Guid collectionId,
|
||||
Filter<ILibraryItem>? filter = default,
|
||||
Sort<ILibraryItem>? sort = default,
|
||||
Include<ILibraryItem>? include = default,
|
||||
|
@ -119,10 +119,10 @@ namespace Kyoo.Core.Controllers
|
||||
|
||||
ParameterExpression x = Expression.Parameter(typeof(T), "x");
|
||||
|
||||
Expression EqRandomHandler(string seed, int refId)
|
||||
Expression EqRandomHandler(string seed, Guid refId)
|
||||
{
|
||||
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(Guid.ToString), null);
|
||||
Expression xrng = Expression.Call(concat, Expression.Constant(seed), id);
|
||||
Expression left = Expression.Call(typeof(DatabaseContext), nameof(DatabaseContext.MD5), null, xrng);
|
||||
Expression right = Expression.Call(typeof(DatabaseContext), nameof(DatabaseContext.MD5), null, Expression.Constant($"{seed}{refId}"));
|
||||
@ -179,7 +179,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="id">The ID of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The tracked resource with the given ID</returns>
|
||||
protected virtual async Task<T> GetWithTracking(int id)
|
||||
protected virtual async Task<T> GetWithTracking(Guid id)
|
||||
{
|
||||
T? ret = await Database.Set<T>().AsTracking().FirstOrDefaultAsync(x => x.Id == id);
|
||||
if (ret == null)
|
||||
@ -188,7 +188,7 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<T> Get(int id, Include<T>? include = default)
|
||||
public virtual async Task<T> Get(Guid id, Include<T>? include = default)
|
||||
{
|
||||
T? ret = await GetOrDefault(id, include);
|
||||
if (ret == null)
|
||||
@ -215,7 +215,7 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Task<T?> GetOrDefault(int id, Include<T>? include = default)
|
||||
public virtual Task<T?> GetOrDefault(Guid id, Include<T>? include = default)
|
||||
{
|
||||
return AddIncludes(Database.Set<T>(), include)
|
||||
.FirstOrDefaultAsync(x => x.Id == id);
|
||||
@ -247,7 +247,7 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<ICollection<T>> FromIds(IList<int> ids, Include<T>? include = default)
|
||||
public virtual async Task<ICollection<T>> FromIds(IList<Guid> ids, Include<T>? include = default)
|
||||
{
|
||||
return (
|
||||
await AddIncludes(Database.Set<T>(), include)
|
||||
@ -375,7 +375,7 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<T> Patch(int id, Func<T, Task<bool>> patch)
|
||||
public virtual async Task<T> Patch(Guid id, Func<T, Task<bool>> patch)
|
||||
{
|
||||
bool lazyLoading = Database.ChangeTracker.LazyLoadingEnabled;
|
||||
Database.ChangeTracker.LazyLoadingEnabled = false;
|
||||
@ -453,7 +453,7 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task Delete(int id)
|
||||
public virtual async Task Delete(Guid id)
|
||||
{
|
||||
T resource = await Get(id);
|
||||
await Delete(resource);
|
||||
|
@ -53,13 +53,10 @@ namespace Kyoo.Core.Controllers
|
||||
|
||||
protected override INews Mapper(List<object?> items)
|
||||
{
|
||||
if (items[0] is Episode episode && episode.Id != 0)
|
||||
if (items[0] is Episode episode && episode.Id != Guid.Empty)
|
||||
return episode;
|
||||
if (items[1] is Movie movie && movie.Id != 0)
|
||||
{
|
||||
movie.Id = -movie.Id;
|
||||
if (items[1] is Movie movie && movie.Id != Guid.Empty)
|
||||
return movie;
|
||||
}
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ namespace Kyoo.Core.Controllers
|
||||
protected override async Task Validate(Season resource)
|
||||
{
|
||||
await base.Validate(resource);
|
||||
if (resource.ShowId <= 0)
|
||||
if (resource.ShowId != Guid.Empty)
|
||||
{
|
||||
if (resource.Show == null)
|
||||
{
|
||||
|
@ -166,7 +166,7 @@ namespace Kyoo.Core.Api
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<T>> Edit([FromBody] T resource)
|
||||
{
|
||||
if (resource.Id > 0)
|
||||
if (resource.Id != null)
|
||||
return await Repository.Edit(resource);
|
||||
|
||||
T old = await Repository.Get(resource.Slug);
|
||||
|
@ -16,6 +16,7 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@ -75,11 +76,11 @@ namespace Kyoo.Core.Api
|
||||
[ProducesResponseType(StatusCodes.Status409Conflict)]
|
||||
public async Task<ActionResult> AddMovie(Identifier identifier, Identifier movie)
|
||||
{
|
||||
int collectionId = await identifier.Match(
|
||||
Guid collectionId = await identifier.Match(
|
||||
async id => (await _libraryManager.Collections.Get(id)).Id,
|
||||
async slug => (await _libraryManager.Collections.Get(slug)).Id
|
||||
);
|
||||
int movieId = await movie.Match(
|
||||
Guid movieId = await movie.Match(
|
||||
async id => (await _libraryManager.Movies.Get(id)).Id,
|
||||
async slug => (await _libraryManager.Movies.Get(slug)).Id
|
||||
);
|
||||
@ -106,11 +107,11 @@ namespace Kyoo.Core.Api
|
||||
[ProducesResponseType(StatusCodes.Status409Conflict)]
|
||||
public async Task<ActionResult> AddShow(Identifier identifier, Identifier show)
|
||||
{
|
||||
int collectionId = await identifier.Match(
|
||||
Guid collectionId = await identifier.Match(
|
||||
async id => (await _libraryManager.Collections.Get(id)).Id,
|
||||
async slug => (await _libraryManager.Collections.Get(slug)).Id
|
||||
);
|
||||
int showId = await show.Match(
|
||||
Guid showId = await show.Match(
|
||||
async id => (await _libraryManager.Shows.Get(id)).Id,
|
||||
async slug => (await _libraryManager.Shows.Get(slug)).Id
|
||||
);
|
||||
@ -144,7 +145,7 @@ namespace Kyoo.Core.Api
|
||||
[FromQuery] Pagination pagination,
|
||||
[FromQuery] Include<ILibraryItem>? fields)
|
||||
{
|
||||
int collectionId = await identifier.Match(
|
||||
Guid collectionId = await identifier.Match(
|
||||
id => Task.FromResult(id),
|
||||
async slug => (await _libraryManager.Collections.Get(slug)).Id
|
||||
);
|
||||
|
@ -68,12 +68,12 @@ public class MeiliSync
|
||||
return _client.Index(index).AddDocumentsAsync(new[] { item });
|
||||
}
|
||||
|
||||
private Task _Delete(string index, int id, string? kind = null)
|
||||
private Task _Delete(string index, Guid id, string? kind = null)
|
||||
{
|
||||
if (kind != null)
|
||||
{
|
||||
return _client.Index(index).DeleteOneDocumentAsync($"{kind}/{id}");
|
||||
}
|
||||
return _client.Index(index).DeleteOneDocumentAsync(id);
|
||||
return _client.Index(index).DeleteOneDocumentAsync(id.ToString());
|
||||
}
|
||||
}
|
||||
|
@ -74,35 +74,13 @@ public class SearchManager : ISearchManager
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<SearchPage<ILibraryItem>.SearchResult> SearchItems(string? query,
|
||||
/// <inheritdoc/>
|
||||
public Task<SearchPage<ILibraryItem>.SearchResult> SearchItems(string? query,
|
||||
Sort<ILibraryItem> sortBy,
|
||||
SearchPagination pagination,
|
||||
Include<ILibraryItem>? include = default)
|
||||
{
|
||||
// TODO: add filters and facets
|
||||
ISearchable<IdResource> res = await _client.Index("items").SearchAsync<IdResource>(query, new SearchQuery()
|
||||
{
|
||||
Sort = _GetSortsBy("items", sortBy),
|
||||
Limit = pagination?.Limit ?? 50,
|
||||
Offset = pagination?.Skip ?? 0,
|
||||
});
|
||||
|
||||
// Since library items's ID are still ints mapped from real items ids, we must map it here to match the db's value.
|
||||
// Look at the LibraryItemRepository's Mapper to understand what those magic numbers are.
|
||||
List<int> ids = res.Hits.Select(x => x.Kind switch
|
||||
{
|
||||
nameof(Show) => x.Id,
|
||||
nameof(Movie) => -x.Id,
|
||||
nameof(Collection) => x.Id + 10_000,
|
||||
_ => throw new InvalidOperationException("An unknown item kind was found in meilisearch"),
|
||||
}).ToList();
|
||||
|
||||
return new SearchPage<ILibraryItem>.SearchResult
|
||||
{
|
||||
Query = query,
|
||||
Items = await _libraryManager.LibraryItems
|
||||
.FromIds(ids, include),
|
||||
};
|
||||
return _Search("items", query, null, sortBy, pagination, include);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -152,7 +130,7 @@ public class SearchManager : ISearchManager
|
||||
|
||||
private class IdResource
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string? Kind { get; set; }
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ namespace Kyoo.Postgresql
|
||||
/// <param name="second">The ID of the second resource.</param>
|
||||
/// <typeparam name="T1">The first resource type of the relation. It is the owner of the second</typeparam>
|
||||
/// <typeparam name="T2">The second resource type of the relation. It is the contained resource.</typeparam>
|
||||
public void AddLinks<T1, T2>(int first, int second)
|
||||
public void AddLinks<T1, T2>(Guid first, Guid second)
|
||||
where T1 : class, IResource
|
||||
where T2 : class, IResource
|
||||
{
|
||||
|
@ -72,12 +72,6 @@ namespace Kyoo.Tests.Database
|
||||
KAssert.DeepEqual(TestSample.Get<T>(), value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetByFakeIdTest()
|
||||
{
|
||||
await Assert.ThrowsAsync<ItemNotFoundException>(() => _repository.Get(2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetByFakeSlugTest()
|
||||
{
|
||||
@ -105,18 +99,6 @@ namespace Kyoo.Tests.Database
|
||||
Assert.Equal(0, await _repository.GetCount());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public virtual async Task CreateTest()
|
||||
{
|
||||
await Assert.ThrowsAsync<DuplicatedItemException>(() => _repository.Create(TestSample.Get<T>()));
|
||||
await _repository.Delete(TestSample.Get<T>());
|
||||
|
||||
T expected = TestSample.Get<T>();
|
||||
expected.Id = 0;
|
||||
await _repository.Create(expected);
|
||||
KAssert.DeepEqual(expected, await _repository.Get(expected.Slug));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public virtual async Task CreateIfNotExistTest()
|
||||
{
|
||||
@ -135,7 +117,6 @@ namespace Kyoo.Tests.Database
|
||||
[Fact]
|
||||
public async Task GetOrDefaultTest()
|
||||
{
|
||||
Assert.Null(await _repository.GetOrDefault(56));
|
||||
Assert.Null(await _repository.GetOrDefault("non-existing"));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user