diff --git a/Kyoo.Common/Kyoo.Common.csproj b/Kyoo.Common/Kyoo.Common.csproj index ac43b9a0..b24abadc 100644 --- a/Kyoo.Common/Kyoo.Common.csproj +++ b/Kyoo.Common/Kyoo.Common.csproj @@ -16,7 +16,6 @@ - diff --git a/Kyoo.Common/Models/Attributes/MergeAttributes.cs b/Kyoo.Common/Models/Attributes/MergeAttributes.cs index 399f5389..1944c89b 100644 --- a/Kyoo.Common/Models/Attributes/MergeAttributes.cs +++ b/Kyoo.Common/Models/Attributes/MergeAttributes.cs @@ -8,4 +8,7 @@ namespace Kyoo.Models.Attributes { void OnMerge(object merged); } + + public class JsonReadOnly : Attribute { } + public class JsonIgnore : JsonReadOnly { } } \ No newline at end of file diff --git a/Kyoo.Common/Models/MetadataID.cs b/Kyoo.Common/Models/MetadataID.cs index 649ec157..945e578b 100644 --- a/Kyoo.Common/Models/MetadataID.cs +++ b/Kyoo.Common/Models/MetadataID.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Kyoo.Models.Attributes; namespace Kyoo.Models { diff --git a/Kyoo.Common/Models/PeopleRole.cs b/Kyoo.Common/Models/PeopleRole.cs index 678ae7e7..54fe48cb 100644 --- a/Kyoo.Common/Models/PeopleRole.cs +++ b/Kyoo.Common/Models/PeopleRole.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; -using Newtonsoft.Json; +using Kyoo.Models.Attributes; namespace Kyoo.Models { diff --git a/Kyoo.Common/Models/Resources/Collection.cs b/Kyoo.Common/Models/Resources/Collection.cs index bfe02e7b..2e8c85bc 100644 --- a/Kyoo.Common/Models/Resources/Collection.cs +++ b/Kyoo.Common/Models/Resources/Collection.cs @@ -1,5 +1,5 @@ -using Newtonsoft.Json; -using System.Collections.Generic; +using System.Collections.Generic; +using Kyoo.Models.Attributes; namespace Kyoo.Models { diff --git a/Kyoo.Common/Models/Resources/Episode.cs b/Kyoo.Common/Models/Resources/Episode.cs index f32a03ef..79229631 100644 --- a/Kyoo.Common/Models/Resources/Episode.cs +++ b/Kyoo.Common/Models/Resources/Episode.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; using Kyoo.Models.Attributes; diff --git a/Kyoo.Common/Models/Resources/Genre.cs b/Kyoo.Common/Models/Resources/Genre.cs index 3b34abb0..947a2866 100644 --- a/Kyoo.Common/Models/Resources/Genre.cs +++ b/Kyoo.Common/Models/Resources/Genre.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Newtonsoft.Json; +using Kyoo.Models.Attributes; namespace Kyoo.Models { diff --git a/Kyoo.Common/Models/Resources/Library.cs b/Kyoo.Common/Models/Resources/Library.cs index 80f8d0ef..dfb17da7 100644 --- a/Kyoo.Common/Models/Resources/Library.cs +++ b/Kyoo.Common/Models/Resources/Library.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Newtonsoft.Json; +using Kyoo.Models.Attributes; namespace Kyoo.Models { diff --git a/Kyoo.Common/Models/Resources/People.cs b/Kyoo.Common/Models/Resources/People.cs index 8a97a918..44c1ad63 100644 --- a/Kyoo.Common/Models/Resources/People.cs +++ b/Kyoo.Common/Models/Resources/People.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json; +using Kyoo.Models.Attributes; namespace Kyoo.Models { @@ -12,7 +11,7 @@ namespace Kyoo.Models public string Poster { get; set; } public virtual IEnumerable ExternalIDs { get; set; } - [JsonIgnore] public virtual IEnumerable Roles { get; set; } + [JsonReadOnly] public virtual IEnumerable Roles { get; set; } public People() {} diff --git a/Kyoo.Common/Models/Resources/ProviderID.cs b/Kyoo.Common/Models/Resources/ProviderID.cs index 387376fa..49e19774 100644 --- a/Kyoo.Common/Models/Resources/ProviderID.cs +++ b/Kyoo.Common/Models/Resources/ProviderID.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Kyoo.Models.Attributes; namespace Kyoo.Models { diff --git a/Kyoo.Common/Models/Resources/Season.cs b/Kyoo.Common/Models/Resources/Season.cs index 761fa2af..b0deac23 100644 --- a/Kyoo.Common/Models/Resources/Season.cs +++ b/Kyoo.Common/Models/Resources/Season.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Newtonsoft.Json; +using Kyoo.Models.Attributes; namespace Kyoo.Models { diff --git a/Kyoo.Common/Models/Resources/Show.cs b/Kyoo.Common/Models/Resources/Show.cs index 1f519c38..4e1705c1 100644 --- a/Kyoo.Common/Models/Resources/Show.cs +++ b/Kyoo.Common/Models/Resources/Show.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Kyoo.Models.Attributes; @@ -29,9 +28,9 @@ namespace Kyoo.Models [JsonIgnore] public int? StudioID { get; set; } - [JsonIgnore] public virtual Studio Studio { get; set; } - [JsonIgnore] public virtual IEnumerable Genres { get; set; } - [JsonIgnore] public virtual IEnumerable People { get; set; } + [JsonReadOnly] public virtual Studio Studio { get; set; } + [JsonReadOnly] public virtual IEnumerable Genres { get; set; } + [JsonReadOnly] public virtual IEnumerable People { get; set; } [JsonIgnore] public virtual IEnumerable Seasons { get; set; } [JsonIgnore] public virtual IEnumerable Episodes { get; set; } [JsonIgnore] public virtual IEnumerable Libraries { get; set; } diff --git a/Kyoo.Common/Models/Resources/Studio.cs b/Kyoo.Common/Models/Resources/Studio.cs index a101c394..1bbb6014 100644 --- a/Kyoo.Common/Models/Resources/Studio.cs +++ b/Kyoo.Common/Models/Resources/Studio.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Newtonsoft.Json; +using Kyoo.Models.Attributes; namespace Kyoo.Models { diff --git a/Kyoo.Common/Models/Resources/Track.cs b/Kyoo.Common/Models/Resources/Track.cs index 486c684a..62e4792a 100644 --- a/Kyoo.Common/Models/Resources/Track.cs +++ b/Kyoo.Common/Models/Resources/Track.cs @@ -1,8 +1,8 @@ using Kyoo.Models.Watch; -using Newtonsoft.Json; using System.Globalization; using System.Linq; using System.Runtime.InteropServices; +using Kyoo.Models.Attributes; namespace Kyoo.Models { diff --git a/Kyoo.Common/Models/WatchItem.cs b/Kyoo.Common/Models/WatchItem.cs index 40b03c16..a86f5490 100644 --- a/Kyoo.Common/Models/WatchItem.cs +++ b/Kyoo.Common/Models/WatchItem.cs @@ -1,10 +1,10 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Kyoo.Controllers; +using Kyoo.Models.Attributes; using Kyoo.Models.Watch; using PathIO = System.IO.Path; diff --git a/Kyoo.Common/Utility.cs b/Kyoo.Common/Utility.cs index ee978f43..4aa13f0f 100644 --- a/Kyoo.Common/Utility.cs +++ b/Kyoo.Common/Utility.cs @@ -112,9 +112,13 @@ namespace Kyoo object defaultValue = property.PropertyType.IsValueType ? Activator.CreateInstance(property.PropertyType) : null; - + if (value?.Equals(defaultValue) == false) + { + if (value is IEnumerable enumerable && !(value is string)) + value = RunGenericMethod(typeof(Enumerable), "ToList", GetEnumerableType(enumerable), value); property.SetValue(first, value); + } } if (first is IOnMerge merge) diff --git a/Kyoo.CommonAPI/JsonSerializer.cs b/Kyoo.CommonAPI/JsonSerializer.cs index 829475c3..4e0c6bbe 100644 --- a/Kyoo.CommonAPI/JsonSerializer.cs +++ b/Kyoo.CommonAPI/JsonSerializer.cs @@ -3,11 +3,11 @@ using System.Buffers; using System.Collections.Generic; using System.Reflection; using Kyoo.Models; +using Kyoo.Models.Attributes; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; @@ -24,7 +24,8 @@ namespace Kyoo.Controllers _forceSerialize = new Dictionary>(); } - public JsonPropertySelector(Dictionary> ignored, Dictionary> forceSerialize) + public JsonPropertySelector(Dictionary> ignored, + Dictionary> forceSerialize = null) { _ignored = ignored ?? new Dictionary>(); _forceSerialize = forceSerialize ?? new Dictionary>(); @@ -58,15 +59,20 @@ namespace Kyoo.Controllers { JsonProperty property = base.CreateProperty(member, memberSerialization); - if (IsIgnored(property.DeclaringType, property.PropertyName)) + if (IsSerializationForced(property.DeclaringType, property.PropertyName)) + { + property.ShouldSerialize = i => true; + property.Ignored = false; + } + else if (IsIgnored(property.DeclaringType, property.PropertyName)) { property.ShouldSerialize = i => false; property.Ignored = true; } - else if (IsSerializationForced(property.DeclaringType, property.PropertyName)) + else { - property.ShouldSerialize = i => true; - property.Ignored = false; + property.ShouldSerialize = i => member.GetCustomAttribute(true) == null; + property.ShouldDeserialize = i => member.GetCustomAttribute(true) == null; } return property; } @@ -89,7 +95,7 @@ namespace Kyoo.Controllers }) }, context.HttpContext.RequestServices.GetRequiredService>(), - context.HttpContext.RequestServices.GetRequiredService>().Value)); + new MvcOptions())); } } } diff --git a/Kyoo.CommonAPI/LocalRepository.cs b/Kyoo.CommonAPI/LocalRepository.cs index f7876131..b06b4f01 100644 --- a/Kyoo.CommonAPI/LocalRepository.cs +++ b/Kyoo.CommonAPI/LocalRepository.cs @@ -10,6 +10,7 @@ using Kyoo.CommonApi; using Kyoo.Models; using Kyoo.Models.Exceptions; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; namespace Kyoo.Controllers { @@ -142,18 +143,30 @@ namespace Kyoo.Controllers { if (edited == null) throw new ArgumentNullException(nameof(edited)); - - T old = await Get(edited.Slug); - if (old == null) - throw new ItemNotFound($"No resource found with the slug {edited.Slug}."); - - if (resetOld) - Utility.Nullify(old); - Utility.Merge(old, edited); - await Validate(old); - await Database.SaveChangesAsync(); - return old; + Database.ChangeTracker.LazyLoadingEnabled = false; + try + { + T old = await Get(edited.ID); + + if (old == null) + throw new ItemNotFound($"No resource found with the ID {edited.ID}."); + + if (resetOld) + Utility.Nullify(old); + Utility.Complete(old, edited); + await Validate(old); + // TODO should fix this, new links & deleted links should be kept. + // TODO The changetracker has trash values now & values can't be listed before the validation (exception is thrown) + foreach (EntityEntry x in Database.ChangeTracker.Entries().Where(x => x.Entity != old)) + x.State = EntityState.Detached; + await Database.SaveChangesAsync(); + return old; + } + finally + { + Database.ChangeTracker.LazyLoadingEnabled = true; + } } protected virtual Task Validate(T resource) diff --git a/Kyoo/Kyoo.csproj b/Kyoo/Kyoo.csproj index 76fff030..32b3148f 100644 --- a/Kyoo/Kyoo.csproj +++ b/Kyoo/Kyoo.csproj @@ -16,6 +16,7 @@ Anonymus-Raccoon https://github.com/AnonymusRaccoon/Kyoo Kyoo.Program + default diff --git a/Kyoo/Models/Resources/CollectionDE.cs b/Kyoo/Models/Resources/CollectionDE.cs index 8cafc83f..3f330c26 100644 --- a/Kyoo/Models/Resources/CollectionDE.cs +++ b/Kyoo/Models/Resources/CollectionDE.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Linq; using Kyoo.Models.Attributes; -using Newtonsoft.Json; namespace Kyoo.Models { diff --git a/Kyoo/Models/Resources/GenreDE.cs b/Kyoo/Models/Resources/GenreDE.cs index 03443d66..fa44e3b5 100644 --- a/Kyoo/Models/Resources/GenreDE.cs +++ b/Kyoo/Models/Resources/GenreDE.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Linq; using Kyoo.Models.Attributes; -using Newtonsoft.Json; namespace Kyoo.Models { diff --git a/Kyoo/Models/Resources/LibraryDE.cs b/Kyoo/Models/Resources/LibraryDE.cs index 3ddc6cd6..f2521904 100644 --- a/Kyoo/Models/Resources/LibraryDE.cs +++ b/Kyoo/Models/Resources/LibraryDE.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Linq; using Kyoo.Models.Attributes; -using Newtonsoft.Json; namespace Kyoo.Models { diff --git a/Kyoo/Models/Resources/ShowDE.cs b/Kyoo/Models/Resources/ShowDE.cs index 31d68100..010b33f6 100644 --- a/Kyoo/Models/Resources/ShowDE.cs +++ b/Kyoo/Models/Resources/ShowDE.cs @@ -1,16 +1,12 @@ using System.Collections.Generic; using System.Linq; using Kyoo.Models.Attributes; -using Newtonsoft.Json; - - -// TODO Remove every [JsonIgnore] tag from here once the serializer knows which property should be serialized. namespace Kyoo.Models { public class ShowDE : Show { - [JsonIgnore] [NotMergable] public virtual ICollection GenreLinks { get; set; } + [JsonReadOnly] [NotMergable] public virtual ICollection GenreLinks { get; set; } [ExpressionRewrite(nameof(GenreLinks), nameof(GenreLink.Genre))] public override IEnumerable Genres { @@ -18,7 +14,7 @@ namespace Kyoo.Models set => GenreLinks = value?.Select(x => new GenreLink(this, x)).ToList(); } - [JsonIgnore] [NotMergable] public virtual ICollection LibraryLinks { get; set; } + [JsonReadOnly] [NotMergable] public virtual ICollection LibraryLinks { get; set; } [ExpressionRewrite(nameof(LibraryLinks), nameof(LibraryLink.Library))] public override IEnumerable Libraries { @@ -26,7 +22,7 @@ namespace Kyoo.Models set => LibraryLinks = value?.Select(x => new LibraryLink(x, this)).ToList(); } - [JsonIgnore] [NotMergable] public virtual ICollection CollectionLinks { get; set; } + [JsonReadOnly] [NotMergable] public virtual ICollection CollectionLinks { get; set; } [ExpressionRewrite(nameof(CollectionLinks), nameof(CollectionLink.Collection))] public override IEnumerable Collections { diff --git a/Kyoo/Program.cs b/Kyoo/Program.cs index f04f5f57..dfda8f1e 100644 --- a/Kyoo/Program.cs +++ b/Kyoo/Program.cs @@ -1,5 +1,4 @@ using System; -using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; diff --git a/Kyoo/Startup.cs b/Kyoo/Startup.cs index 7c30527b..4e6cc6e5 100644 --- a/Kyoo/Startup.cs +++ b/Kyoo/Startup.cs @@ -40,7 +40,8 @@ namespace Kyoo configuration.RootPath = "wwwroot"; }); - services.AddControllers().AddNewtonsoftJson(); + services.AddControllers() + .AddNewtonsoftJson(x => x.SerializerSettings.ContractResolver = new JsonPropertySelector()); services.AddHttpClient(); services.AddDbContext(options => diff --git a/Kyoo/Views/WebClient b/Kyoo/Views/WebClient index 42af654d..f2ee4854 160000 --- a/Kyoo/Views/WebClient +++ b/Kyoo/Views/WebClient @@ -1 +1 @@ -Subproject commit 42af654da4f4ec45945336e6f1085d9bda8ed773 +Subproject commit f2ee4854ab7531cb8cf38ed9fd3d2b97d1d04a97