mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-06-02 13:14:29 -04:00
Rework patch apis
This commit is contained in:
parent
e668cdd89c
commit
fabafcb78b
@ -187,11 +187,11 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// <param name="id">The id of the resource to edit</param>
|
/// <param name="id">The id of the resource to edit</param>
|
||||||
/// <param name="patch">
|
/// <param name="patch">
|
||||||
/// A method that will be called when you need to update every properties that you want to
|
/// 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.
|
||||||
/// </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(Guid id, Func<T, Task<bool>> patch);
|
Task<T> Patch(Guid id, Func<T, T> patch);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when a resource has been edited.
|
/// Called when a resource has been edited.
|
||||||
|
@ -17,12 +17,30 @@
|
|||||||
// 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.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using Kyoo.Abstractions.Models;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Kyoo.Models;
|
namespace Kyoo.Models;
|
||||||
|
|
||||||
public class PartialResource
|
public class Patch<T> : Dictionary<string, JObject>
|
||||||
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
public Guid? Id { get; set; }
|
public Guid? Id => this.GetValueOrDefault(nameof(IResource.Id))?.ToObject<Guid>();
|
||||||
|
|
||||||
public string? Slug { get; set; }
|
public string? Slug => this.GetValueOrDefault(nameof(IResource.Slug))?.ToObject<string>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -246,7 +246,7 @@ namespace Kyoo.Authentication.Views
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Edit only provided informations about the currently authenticated user.
|
/// Edit only provided informations about the currently authenticated user.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="user">The new data for the current user.</param>
|
/// <param name="patch">The new data for the current user.</param>
|
||||||
/// <returns>The currently authenticated user after modifications.</returns>
|
/// <returns>The currently authenticated user after modifications.</returns>
|
||||||
/// <response code="401">The user is not authenticated.</response>
|
/// <response code="401">The user is not authenticated.</response>
|
||||||
/// <response code="403">The given access token is invalid.</response>
|
/// <response code="403">The given access token is invalid.</response>
|
||||||
@ -255,14 +255,14 @@ namespace Kyoo.Authentication.Views
|
|||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(RequestError))]
|
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(RequestError))]
|
||||||
[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([FromBody] Patch<User> patch)
|
||||||
{
|
{
|
||||||
Guid userId = User.GetIdOrThrow();
|
Guid userId = User.GetIdOrThrow();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (user.Id.HasValue && user.Id != userId)
|
if (patch.Id.HasValue && patch.Id != userId)
|
||||||
throw new ArgumentException("Can't edit your user id.");
|
throw new ArgumentException("Can't edit your user id.");
|
||||||
return await _users.Patch(userId, TryUpdateModelAsync);
|
return await _users.Patch(userId, patch.Apply);
|
||||||
}
|
}
|
||||||
catch (ItemNotFoundException)
|
catch (ItemNotFoundException)
|
||||||
{
|
{
|
||||||
|
@ -217,5 +217,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(Guid id, Func<T, Task<bool>> patch) => throw new NotImplementedException();
|
public Task<T> Patch(Guid id, Func<T, T> patch) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -497,7 +497,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual async Task<T> Patch(Guid id, Func<T, Task<bool>> patch)
|
public virtual async Task<T> Patch(Guid id, Func<T, T> patch)
|
||||||
{
|
{
|
||||||
bool lazyLoading = Database.ChangeTracker.LazyLoadingEnabled;
|
bool lazyLoading = Database.ChangeTracker.LazyLoadingEnabled;
|
||||||
Database.ChangeTracker.LazyLoadingEnabled = false;
|
Database.ChangeTracker.LazyLoadingEnabled = false;
|
||||||
@ -505,8 +505,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
{
|
{
|
||||||
T resource = await GetWithTracking(id);
|
T resource = await GetWithTracking(id);
|
||||||
|
|
||||||
if (!await patch(resource))
|
resource = patch(resource);
|
||||||
throw new ArgumentException("Could not patch resource");
|
|
||||||
|
|
||||||
await Database.SaveChangesAsync();
|
await Database.SaveChangesAsync();
|
||||||
await IRepository<T>.OnResourceEdited(resource);
|
await IRepository<T>.OnResourceEdited(resource);
|
||||||
|
@ -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.
|
/// 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.
|
/// If not, the slug will be used to identify it.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="resource">The resource to patch.</param>
|
/// <param name="patch">The resource to patch.</param>
|
||||||
/// <returns>The edited resource.</returns>
|
/// <returns>The edited resource.</returns>
|
||||||
/// <response code="400">The resource in the request body is invalid.</response>
|
/// <response code="400">The resource in the request body is invalid.</response>
|
||||||
/// <response code="404">No item found with the specified ID (or slug).</response>
|
/// <response code="404">No item found with the specified ID (or slug).</response>
|
||||||
@ -189,17 +189,17 @@ namespace Kyoo.Core.Api
|
|||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
|
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult<T>> Patch([FromBody] PartialResource resource)
|
public async Task<ActionResult<T>> Patch([FromBody] Patch<T> patch)
|
||||||
{
|
{
|
||||||
if (resource.Id.HasValue)
|
if (patch.Id.HasValue)
|
||||||
return await Repository.Patch(resource.Id.Value, TryUpdateModelAsync);
|
return await Repository.Patch(patch.Id.Value, patch.Apply);
|
||||||
if (resource.Slug == null)
|
if (patch.Slug == null)
|
||||||
throw new ArgumentException(
|
throw new ArgumentException(
|
||||||
"Either the Id or the slug of the resource has to be defined to edit it."
|
"Either the Id or the slug of the resource has to be defined to edit it."
|
||||||
);
|
);
|
||||||
|
|
||||||
T old = await Repository.Get(resource.Slug);
|
T old = await Repository.Get(patch.Slug);
|
||||||
return await Repository.Patch(old.Id, TryUpdateModelAsync);
|
return await Repository.Patch(old.Id, patch.Apply);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user