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