diff --git a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs index 7533f43e..2efd68bf 100644 --- a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs +++ b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs @@ -187,11 +187,11 @@ namespace Kyoo.Abstractions.Controllers /// The id of the resource to edit /// /// A method that will be called when you need to update every properties that you want to - /// persist. It can return false to abort the process via an ArgumentException + /// persist. /// /// If the item is not found /// The resource edited and completed by database's information (related items and so on) - Task Patch(Guid id, Func> patch); + Task Patch(Guid id, Func patch); /// /// Called when a resource has been edited. diff --git a/back/src/Kyoo.Abstractions/Models/PartialResource.cs b/back/src/Kyoo.Abstractions/Models/Patch.cs similarity index 54% rename from back/src/Kyoo.Abstractions/Models/PartialResource.cs rename to back/src/Kyoo.Abstractions/Models/Patch.cs index 9a9c436f..608b3f61 100644 --- a/back/src/Kyoo.Abstractions/Models/PartialResource.cs +++ b/back/src/Kyoo.Abstractions/Models/Patch.cs @@ -17,12 +17,30 @@ // along with Kyoo. If not, see . using System; +using System.Collections.Generic; +using System.Reflection; +using Kyoo.Abstractions.Models; +using Newtonsoft.Json.Linq; namespace Kyoo.Models; -public class PartialResource +public class Patch : Dictionary + where T : class, IResource { - public Guid? Id { get; set; } + public Guid? Id => this.GetValueOrDefault(nameof(IResource.Id))?.ToObject(); - public string? Slug { get; set; } + public string? Slug => this.GetValueOrDefault(nameof(IResource.Slug))?.ToObject(); + + public T Apply(T current) + { + foreach ((string property, JObject value) in this) + { + PropertyInfo prop = typeof(T).GetProperty( + property, + BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance + )!; + prop.SetValue(current, value.ToObject(prop.PropertyType)); + } + return current; + } } diff --git a/back/src/Kyoo.Authentication/Views/AuthApi.cs b/back/src/Kyoo.Authentication/Views/AuthApi.cs index e14b5889..11d9ac46 100644 --- a/back/src/Kyoo.Authentication/Views/AuthApi.cs +++ b/back/src/Kyoo.Authentication/Views/AuthApi.cs @@ -246,7 +246,7 @@ namespace Kyoo.Authentication.Views /// /// Edit only provided informations about the currently authenticated user. /// - /// The new data for the current user. + /// The new data for the current user. /// The currently authenticated user after modifications. /// The user is not authenticated. /// The given access token is invalid. @@ -255,14 +255,14 @@ namespace Kyoo.Authentication.Views [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(RequestError))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(RequestError))] - public async Task> PatchMe(PartialResource user) + public async Task> PatchMe([FromBody] Patch patch) { Guid userId = User.GetIdOrThrow(); try { - if (user.Id.HasValue && user.Id != userId) + if (patch.Id.HasValue && patch.Id != userId) throw new ArgumentException("Can't edit your user id."); - return await _users.Patch(userId, TryUpdateModelAsync); + return await _users.Patch(userId, patch.Apply); } catch (ItemNotFoundException) { diff --git a/back/src/Kyoo.Core/Controllers/Repositories/DapperRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/DapperRepository.cs index 2ef6eede..18f0677b 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/DapperRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/DapperRepository.cs @@ -217,5 +217,5 @@ public abstract class DapperRepository : IRepository public Task Edit(T edited) => throw new NotImplementedException(); /// - public Task Patch(Guid id, Func> patch) => throw new NotImplementedException(); + public Task Patch(Guid id, Func patch) => throw new NotImplementedException(); } diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs index 90ccb35b..38130e24 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs @@ -497,7 +497,7 @@ namespace Kyoo.Core.Controllers } /// - public virtual async Task Patch(Guid id, Func> patch) + public virtual async Task Patch(Guid id, Func patch) { bool lazyLoading = Database.ChangeTracker.LazyLoadingEnabled; Database.ChangeTracker.LazyLoadingEnabled = false; @@ -505,8 +505,7 @@ namespace Kyoo.Core.Controllers { T resource = await GetWithTracking(id); - if (!await patch(resource)) - throw new ArgumentException("Could not patch resource"); + resource = patch(resource); await Database.SaveChangesAsync(); await IRepository.OnResourceEdited(resource); diff --git a/back/src/Kyoo.Core/Views/Helper/CrudApi.cs b/back/src/Kyoo.Core/Views/Helper/CrudApi.cs index b1679313..38b68326 100644 --- a/back/src/Kyoo.Core/Views/Helper/CrudApi.cs +++ b/back/src/Kyoo.Core/Views/Helper/CrudApi.cs @@ -180,7 +180,7 @@ namespace Kyoo.Core.Api /// Edit only specified properties of an item. If the ID is specified it will be used to identify the resource. /// If not, the slug will be used to identify it. /// - /// The resource to patch. + /// The resource to patch. /// The edited resource. /// The resource in the request body is invalid. /// No item found with the specified ID (or slug). @@ -189,17 +189,17 @@ namespace Kyoo.Core.Api [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> Patch([FromBody] PartialResource resource) + public async Task> Patch([FromBody] Patch patch) { - if (resource.Id.HasValue) - return await Repository.Patch(resource.Id.Value, TryUpdateModelAsync); - if (resource.Slug == null) + if (patch.Id.HasValue) + return await Repository.Patch(patch.Id.Value, patch.Apply); + if (patch.Slug == null) throw new ArgumentException( "Either the Id or the slug of the resource has to be defined to edit it." ); - T old = await Repository.Get(resource.Slug); - return await Repository.Patch(old.Id, TryUpdateModelAsync); + T old = await Repository.Get(patch.Slug); + return await Repository.Patch(old.Id, patch.Apply); } ///