diff --git a/back/src/Kyoo.Abstractions/Models/Utils/Include.cs b/back/src/Kyoo.Abstractions/Models/Utils/Include.cs index 6cedf16c..36a44360 100644 --- a/back/src/Kyoo.Abstractions/Models/Utils/Include.cs +++ b/back/src/Kyoo.Abstractions/Models/Utils/Include.cs @@ -16,33 +16,33 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . +using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq; using System.Reflection; using Kyoo.Abstractions.Models.Attributes; namespace Kyoo.Abstractions.Models.Utils; public class Include - where T : IResource { - public string[] Fields { get; private init; } + public ICollection Fields { get; private init; } = ArraySegment.Empty; - public static Include From(string fields) + public static Include From(string? fields) { if (string.IsNullOrEmpty(fields)) - return new(); + return new Include(); - string[] values = fields.Split(','); - foreach (string field in values) + return new Include { - PropertyInfo? prop = typeof(T).GetProperty(field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); - if (prop?.GetCustomAttribute() == null) - throw new ValidationException($"No loadable relation with the name {field}."); - } - - return new() - { - Fields = values, + Fields = fields.Split(',').Select(x => + { + PropertyInfo? prop = typeof(T).GetProperty(x, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); + if (prop?.GetCustomAttribute() == null) + throw new ValidationException($"No loadable relation with the name {x}."); + return prop.Name; + }).ToArray() }; } } diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs index 7748c1c9..fcf16594 100644 --- a/back/src/Kyoo.Core/CoreModule.cs +++ b/back/src/Kyoo.Core/CoreModule.cs @@ -71,6 +71,7 @@ namespace Kyoo.Core { options.Filters.Add(); options.ModelBinderProviders.Insert(0, new SortBinder.Provider()); + options.ModelBinderProviders.Insert(0, new IncludeBinder.Provider()); }) .AddNewtonsoftJson(x => { diff --git a/back/src/Kyoo.Core/Views/Helper/IncludeBinder.cs b/back/src/Kyoo.Core/Views/Helper/IncludeBinder.cs new file mode 100644 index 00000000..2be993ce --- /dev/null +++ b/back/src/Kyoo.Core/Views/Helper/IncludeBinder.cs @@ -0,0 +1,60 @@ +// Kyoo - A portable and vast media library solution. +// Copyright (c) Kyoo. +// +// See AUTHORS.md and LICENSE file in the project root for full license information. +// +// Kyoo is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// Kyoo is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Kyoo. If not, see . + +using System; +using System.Reflection; +using System.Threading.Tasks; +using Kyoo.Abstractions.Models.Utils; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; + +namespace Kyoo.Core.Api; + +public class IncludeBinder : IModelBinder +{ + private readonly Random _rng = new(); + + public Task BindModelAsync(ModelBindingContext bindingContext) + { + ValueProviderResult fields = bindingContext.ValueProvider.GetValue(bindingContext.FieldName); + try + { + object include = bindingContext.ModelType.GetMethod(nameof(Include.From))! + .Invoke(null, new object?[] { fields.FirstValue })!; + bindingContext.Result = ModelBindingResult.Success(include); + return Task.CompletedTask; + } + catch (TargetInvocationException ex) + { + throw ex.InnerException!; + } + } + + public class Provider : IModelBinderProvider + { + public IModelBinder GetBinder(ModelBinderProviderContext context) + { + if (context.Metadata.ModelType.Name == "Include`1") + { + return new BinderTypeModelBinder(typeof(IncludeBinder)); + } + + return null!; + } + } +}