diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index 50c796de..00000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Testing -on: - push: - branches: - - master - - next - pull_request: - -jobs: - tests: - name: Back tests - runs-on: ubuntu-latest - container: mcr.microsoft.com/dotnet/sdk:7.0 - services: - postgres: - image: postgres - env: - POSTGRES_PASSWORD: postgres - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Build - run: | - cd back - dotnet build '-p:SkipTranscoder=true' -p:CopyLocalLockFileAssemblies=true - cp ./out/bin/Kyoo.Abstractions/Debug/net7.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll ./tests/Kyoo.Tests/bin/Debug/net7.0/ - - - name: Test - run: | - cd back - dotnet test --no-build '-p:CollectCoverage=true;CoverletOutputFormat=opencover' --logger "trx;LogFileName=TestOutputResults.xml" - env: - POSTGRES_HOST: postgres - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - - - name: Sanitize coverage output - if: ${{ always() }} - run: sed -i "s'$(pwd)/back'.'" back/tests/Kyoo.Tests/coverage.opencover.xml - - - name: Upload tests results - if: ${{ always() }} - uses: actions/upload-artifact@v4 - with: - name: results.xml - path: "**/TestOutputResults.xml" - - - name: Upload coverage report - if: ${{ always() }} - uses: actions/upload-artifact@v4 - with: - name: coverage.xml - path: "**/coverage.opencover.xml" diff --git a/back/Dockerfile b/back/Dockerfile index cc319474..3bfa1be5 100644 --- a/back/Dockerfile +++ b/back/Dockerfile @@ -12,7 +12,6 @@ COPY src/Kyoo.Host/Kyoo.Host.csproj src/Kyoo.Host/Kyoo.Host.csproj COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj -COPY tests/Kyoo.Tests/Kyoo.Tests.csproj tests/Kyoo.Tests/Kyoo.Tests.csproj RUN dotnet restore -a $TARGETARCH COPY . . diff --git a/back/Dockerfile.dev b/back/Dockerfile.dev index f17a571f..3400f1ef 100644 --- a/back/Dockerfile.dev +++ b/back/Dockerfile.dev @@ -12,7 +12,6 @@ COPY src/Kyoo.Host/Kyoo.Host.csproj src/Kyoo.Host/Kyoo.Host.csproj COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj -COPY tests/Kyoo.Tests/Kyoo.Tests.csproj tests/Kyoo.Tests/Kyoo.Tests.csproj RUN dotnet restore WORKDIR /kyoo diff --git a/back/Kyoo.sln b/back/Kyoo.sln index 49a66538..db805de4 100644 --- a/back/Kyoo.sln +++ b/back/Kyoo.sln @@ -7,12 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Postgresql", "src\Kyoo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Authentication", "src\Kyoo.Authentication\Kyoo.Authentication.csproj", "{7A841335-6523-47DB-9717-80AA7BD943FD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Tests", "tests\Kyoo.Tests\Kyoo.Tests.csproj", "{0C8AA7EA-E723-4532-852F-35AA4E8AFED5}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Swagger", "src\Kyoo.Swagger\Kyoo.Swagger.csproj", "{7D1A7596-73F6-4D35-842E-A5AD9C620596}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{FEAE1B0E-D797-470F-9030-0EF743575ECC}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host", "src\Kyoo.Host\Kyoo.Host.csproj", "{0938459E-2E2B-457F-8120-7D8CA93866A6}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Meilisearch", "src\Kyoo.Meilisearch\Kyoo.Meilisearch.csproj", "{F8E6018A-FD51-40EB-99FF-A26BA59F2762}" @@ -43,10 +39,6 @@ Global {6515380E-1E57-42DA-B6E3-E1C8A848818A}.Debug|Any CPU.Build.0 = Debug|Any CPU {6515380E-1E57-42DA-B6E3-E1C8A848818A}.Release|Any CPU.ActiveCfg = Release|Any CPU {6515380E-1E57-42DA-B6E3-E1C8A848818A}.Release|Any CPU.Build.0 = Release|Any CPU - {0C8AA7EA-E723-4532-852F-35AA4E8AFED5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0C8AA7EA-E723-4532-852F-35AA4E8AFED5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0C8AA7EA-E723-4532-852F-35AA4E8AFED5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0C8AA7EA-E723-4532-852F-35AA4E8AFED5}.Release|Any CPU.Build.0 = Release|Any CPU {2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Debug|Any CPU.Build.0 = Debug|Any CPU {2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -68,7 +60,4 @@ Global {F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Release|Any CPU.ActiveCfg = Release|Any CPU {F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {0C8AA7EA-E723-4532-852F-35AA4E8AFED5} = {FEAE1B0E-D797-470F-9030-0EF743575ECC} - EndGlobalSection EndGlobal diff --git a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs index ef5bd683..12bb63fe 100644 --- a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs +++ b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs @@ -68,11 +68,6 @@ namespace Kyoo.Abstractions.Controllers /// IRepository Episodes { get; } - /// - /// The repository that handle people. - /// - IRepository People { get; } - /// /// The repository that handle studios. /// diff --git a/back/src/Kyoo.Abstractions/Controllers/IPlugin.cs b/back/src/Kyoo.Abstractions/Controllers/IPlugin.cs index 5c1e1442..3363a4ff 100644 --- a/back/src/Kyoo.Abstractions/Controllers/IPlugin.cs +++ b/back/src/Kyoo.Abstractions/Controllers/IPlugin.cs @@ -19,7 +19,6 @@ using System; using System.Collections.Generic; using Autofac; -using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; namespace Kyoo.Abstractions.Controllers @@ -31,7 +30,6 @@ namespace Kyoo.Abstractions.Controllers /// You can inject services in the IPlugin constructor. /// You should only inject well known services like an ILogger, IConfiguration or IWebHostEnvironment. /// - [UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)] public interface IPlugin { /// diff --git a/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj b/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj index 2861264a..9613d37c 100644 --- a/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj +++ b/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj @@ -10,11 +10,9 @@ - - diff --git a/back/src/Kyoo.Abstractions/Models/Attributes/Serializer/DeserializeIgnoreAttribute.cs b/back/src/Kyoo.Abstractions/Models/Attributes/Serializer/DeserializeIgnoreAttribute.cs deleted file mode 100644 index 8b10ee87..00000000 --- a/back/src/Kyoo.Abstractions/Models/Attributes/Serializer/DeserializeIgnoreAttribute.cs +++ /dev/null @@ -1,28 +0,0 @@ -// 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; - -namespace Kyoo.Abstractions.Models.Attributes -{ - /// - /// Remove a property from the deserialization pipeline. The user can't input value for this property. - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public class DeserializeIgnoreAttribute : Attribute { } -} diff --git a/back/src/Kyoo.Abstractions/Models/Attributes/Serializer/SerializeIgnoreAttribute.cs b/back/src/Kyoo.Abstractions/Models/Attributes/Serializer/SerializeIgnoreAttribute.cs deleted file mode 100644 index 4a87d3f9..00000000 --- a/back/src/Kyoo.Abstractions/Models/Attributes/Serializer/SerializeIgnoreAttribute.cs +++ /dev/null @@ -1,28 +0,0 @@ -// 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; - -namespace Kyoo.Abstractions.Models.Attributes -{ - /// - /// Remove an property from the serialization pipeline. It will simply be skipped. - /// - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] - public class SerializeIgnoreAttribute : Attribute { } -} diff --git a/back/src/Kyoo.Abstractions/Models/Patch.cs b/back/src/Kyoo.Abstractions/Models/Patch.cs index 305a76fb..1eafe949 100644 --- a/back/src/Kyoo.Abstractions/Models/Patch.cs +++ b/back/src/Kyoo.Abstractions/Models/Patch.cs @@ -19,27 +19,27 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Text.Json; using Kyoo.Abstractions.Models; -using Newtonsoft.Json.Linq; namespace Kyoo.Models; -public class Patch : Dictionary +public class Patch : Dictionary where T : class, IResource { - public Guid? Id => this.GetValueOrDefault(nameof(IResource.Id))?.ToObject(); + public Guid? Id => this.GetValueOrDefault(nameof(IResource.Id))?.Deserialize(); - public string? Slug => this.GetValueOrDefault(nameof(IResource.Slug))?.ToObject(); + public string? Slug => this.GetValueOrDefault(nameof(IResource.Slug))?.Deserialize(); public T Apply(T current) { - foreach ((string property, JToken value) in this) + foreach ((string property, JsonDocument value) in this) { PropertyInfo prop = typeof(T).GetProperty( property, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance )!; - prop.SetValue(current, value.ToObject(prop.PropertyType)); + prop.SetValue(current, value.Deserialize(prop.PropertyType)); } return current; } diff --git a/back/src/Kyoo.Abstractions/Models/PeopleRole.cs b/back/src/Kyoo.Abstractions/Models/PeopleRole.cs deleted file mode 100644 index 96b52fe2..00000000 --- a/back/src/Kyoo.Abstractions/Models/PeopleRole.cs +++ /dev/null @@ -1,81 +0,0 @@ -// 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; - -namespace Kyoo.Abstractions.Models -{ - /// - /// A role a person played for a show. It can be an actor, musician, voice actor, director, writer... - /// - /// - /// This class is not serialized like other classes. - /// Based on the field, it is serialized like - /// a show with two extra fields ( and ). - /// - public class PeopleRole : IResource - { - /// - public Guid Id { get; set; } - - /// - public string Slug => ForPeople ? Show!.Slug : People.Slug; - - /// - /// Should this role be used as a Show substitute (the value is true) or - /// as a People substitute (the value is false). - /// - public bool ForPeople { get; set; } - - /// - /// The ID of the People playing the role. - /// - public Guid PeopleID { get; set; } - - /// - /// The people that played this role. - /// - public People People { get; set; } - - /// - /// The ID of the Show where the People playing in. - /// - public Guid? ShowID { get; set; } - - /// - /// The show where the People played in. - /// - public Show? Show { get; set; } - - public Guid? MovieID { get; set; } - - public Movie? Movie { get; set; } - - /// - /// The type of work the person has done for the show. - /// That can be something like "Actor", "Writer", "Music", "Voice Actor"... - /// - public string Type { get; set; } - - /// - /// The role the People played. - /// This is mostly used to inform witch character was played for actor and voice actors. - /// - public string Role { get; set; } - } -} diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs b/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs index 75f8b5d9..23dd12ba 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs @@ -19,10 +19,9 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models.Attributes; using Kyoo.Utils; -using Newtonsoft.Json; namespace Kyoo.Abstractions.Models { @@ -65,13 +64,13 @@ namespace Kyoo.Abstractions.Models /// /// The list of movies contained in this collection. /// - [SerializeIgnore] + [JsonIgnore] public ICollection? Movies { get; set; } /// /// The list of shows contained in this collection. /// - [SerializeIgnore] + [JsonIgnore] public ICollection? Shows { get; set; } /// diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs b/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs index 09a33b2d..d8325426 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs @@ -20,9 +20,9 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Text.Json.Serialization; using System.Text.RegularExpressions; using EntityFrameworkCore.Projectables; -using JetBrains.Annotations; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models.Attributes; @@ -60,7 +60,6 @@ namespace Kyoo.Abstractions.Models ); return GetSlug(ShowId.ToString(), SeasonNumber, EpisodeNumber, AbsoluteNumber); } - [UsedImplicitly] private set { Match match = Regex.Match(value, @"(?.+)-s(?\d+)e(?\d+)"); @@ -90,7 +89,7 @@ namespace Kyoo.Abstractions.Models /// /// The slug of the Show that contain this episode. If this is not set, this episode is ill-formed. /// - [SerializeIgnore] + [JsonIgnore] public string? ShowSlug { private get; set; } /// @@ -249,7 +248,7 @@ namespace Kyoo.Abstractions.Models || (x.SeasonNumber == SeasonNumber && x.EpisodeNumber > EpisodeNumber) ); - [SerializeIgnore] + [JsonIgnore] public ICollection? Watched { get; set; } /// diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs index b590c98d..aed090b1 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IThumbnails.cs @@ -20,8 +20,8 @@ using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Globalization; +using System.Text.Json.Serialization; using Kyoo.Abstractions.Models.Attributes; -using Newtonsoft.Json; namespace Kyoo.Abstractions.Models { diff --git a/back/src/Kyoo.Abstractions/Models/Resources/JwtToken.cs b/back/src/Kyoo.Abstractions/Models/Resources/JwtToken.cs index d2c8eacd..1342dc07 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/JwtToken.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/JwtToken.cs @@ -18,7 +18,6 @@ using System; using System.Text.Json.Serialization; -using Newtonsoft.Json; namespace Kyoo.Abstractions.Models; @@ -36,21 +35,18 @@ public class JwtToken(string accessToken, string refreshToken, TimeSpan expireIn /// /// The type of this token (always a Bearer). /// - [JsonProperty("token_type")] [JsonPropertyName("token_type")] public string TokenType => "Bearer"; /// /// The access token used to authorize requests. /// - [JsonProperty("access_token")] [JsonPropertyName("access_token")] public string AccessToken { get; set; } = accessToken; /// /// The refresh token used to retrieve a new access/refresh token when the access token has expired. /// - [JsonProperty("refresh_token")] [JsonPropertyName("refresh_token")] public string RefreshToken { get; set; } = refreshToken; @@ -58,14 +54,12 @@ public class JwtToken(string accessToken, string refreshToken, TimeSpan expireIn /// When the access token will expire. After this time, the refresh token should be used to retrieve. /// a new token.cs /// - [JsonProperty("expire_in")] [JsonPropertyName("expire_in")] public TimeSpan ExpireIn => ExpireAt.Subtract(DateTime.UtcNow); /// /// The exact date at which the access token will expire. /// - [JsonProperty("expire_at")] [JsonPropertyName("expire_at")] public DateTime ExpireAt { get; set; } = DateTime.UtcNow + expireIn; } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs index bdab427e..257ddcb8 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs @@ -21,11 +21,11 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; +using System.Text.Json.Serialization; using EntityFrameworkCore.Projectables; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models.Attributes; using Kyoo.Utils; -using Newtonsoft.Json; namespace Kyoo.Abstractions.Models { @@ -36,7 +36,6 @@ namespace Kyoo.Abstractions.Models : IQuery, IResource, IMetadata, - IOnMerge, IThumbnails, IAddedDate, ILibraryItem, @@ -119,11 +118,11 @@ namespace Kyoo.Abstractions.Models /// public Image? Logo { get; set; } - [SerializeIgnore] + [JsonIgnore] [Column("air_date")] public DateTime? StartAir => AirDate; - [SerializeIgnore] + [JsonIgnore] [Column("air_date")] public DateTime? EndAir => AirDate; @@ -138,7 +137,7 @@ namespace Kyoo.Abstractions.Models /// /// The ID of the Studio that made this show. /// - [SerializeIgnore] + [JsonIgnore] public Guid? StudioId { get; set; } /// @@ -147,15 +146,10 @@ namespace Kyoo.Abstractions.Models [LoadableRelation(nameof(StudioId))] public Studio? Studio { get; set; } - // /// - // /// The list of people that made this show. - // /// - // [SerializeIgnore] public ICollection? People { get; set; } - /// /// The list of collections that contains this show. /// - [SerializeIgnore] + [JsonIgnore] public ICollection? Collections { get; set; } /// @@ -164,7 +158,7 @@ namespace Kyoo.Abstractions.Models public VideoLinks Links => new() { Direct = $"/movie/{Slug}/direct", Hls = $"/movie/{Slug}/master.m3u8", }; - [SerializeIgnore] + [JsonIgnore] public ICollection? Watched { get; set; } /// @@ -180,16 +174,6 @@ namespace Kyoo.Abstractions.Models // There is a global query filter to filter by user so we just need to do single. private MovieWatchStatus? _WatchStatus => Watched!.FirstOrDefault(); - /// - public void OnMerge(object merged) - { - // if (People != null) - // { - // foreach (PeopleRole link in People) - // link.Movie = this; - // } - } - public Movie() { } [JsonConstructor] diff --git a/back/src/Kyoo.Abstractions/Models/Resources/People.cs b/back/src/Kyoo.Abstractions/Models/Resources/People.cs deleted file mode 100644 index 336b7e6b..00000000 --- a/back/src/Kyoo.Abstractions/Models/Resources/People.cs +++ /dev/null @@ -1,80 +0,0 @@ -// 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.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models.Attributes; -using Kyoo.Utils; -using Newtonsoft.Json; - -namespace Kyoo.Abstractions.Models -{ - /// - /// An actor, voice actor, writer, animator, somebody who worked on a . - /// - [Table("people")] - public class People : IQuery, IResource, IMetadata, IThumbnails - { - public static Sort DefaultSort => new Sort.By(x => x.Name); - - /// - public Guid Id { get; set; } - - /// - [MaxLength(256)] - public string Slug { get; set; } - - /// - /// The name of this person. - /// - public string Name { get; set; } - - /// - public Image? Poster { get; set; } - - /// - public Image? Thumbnail { get; set; } - - /// - public Image? Logo { get; set; } - - /// - public Dictionary ExternalId { get; set; } = new(); - - /// - /// The list of roles this person has played in. See for more information. - /// - [SerializeIgnore] - public ICollection? Roles { get; set; } - - public People() { } - - [JsonConstructor] - public People(string name) - { - if (name != null) - { - Slug = Utility.ToSlug(name); - Name = name; - } - } - } -} diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Season.cs b/back/src/Kyoo.Abstractions/Models/Resources/Season.cs index df0ae10d..64c3cfe2 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Season.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Season.cs @@ -20,9 +20,9 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; using System.Text.RegularExpressions; using EntityFrameworkCore.Projectables; -using JetBrains.Annotations; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models.Attributes; @@ -49,8 +49,6 @@ namespace Kyoo.Abstractions.Models return $"{ShowId}-s{SeasonNumber}"; return $"{ShowSlug ?? Show?.Slug}-s{SeasonNumber}"; } - [UsedImplicitly] - [NotNull] private set { Match match = Regex.Match(value, @"(?.+)-s(?\d+)"); @@ -67,7 +65,7 @@ namespace Kyoo.Abstractions.Models /// /// The slug of the Show that contain this episode. If this is not set, this season is ill-formed. /// - [SerializeIgnore] + [JsonIgnore] public string? ShowSlug { private get; set; } /// @@ -124,7 +122,7 @@ namespace Kyoo.Abstractions.Models /// /// The list of episodes that this season contains. /// - [SerializeIgnore] + [JsonIgnore] public ICollection? Episodes { get; set; } /// diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs index 6da2fe34..a9c8b832 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs @@ -21,11 +21,11 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; +using System.Text.Json.Serialization; using EntityFrameworkCore.Projectables; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models.Attributes; using Kyoo.Utils; -using Newtonsoft.Json; namespace Kyoo.Abstractions.Models { @@ -119,7 +119,7 @@ namespace Kyoo.Abstractions.Models /// public string? Trailer { get; set; } - [SerializeIgnore] + [JsonIgnore] [Column("start_air")] public DateTime? AirDate => StartAir; @@ -129,7 +129,6 @@ namespace Kyoo.Abstractions.Models /// /// The ID of the Studio that made this show. /// - [SerializeIgnore] public Guid? StudioId { get; set; } /// @@ -138,15 +137,10 @@ namespace Kyoo.Abstractions.Models [LoadableRelation(nameof(StudioId))] public Studio? Studio { get; set; } - // /// - // /// The list of people that made this show. - // /// - // [SerializeIgnore] public ICollection? People { get; set; } - /// /// The different seasons in this show. If this is a movie, this list is always null or empty. /// - [SerializeIgnore] + [JsonIgnore] public ICollection? Seasons { get; set; } /// @@ -154,13 +148,13 @@ namespace Kyoo.Abstractions.Models /// If this is a movie, there will be a unique episode (with the seasonNumber and episodeNumber set to null). /// Having an episode is necessary to store metadata and tracks. /// - [SerializeIgnore] + [JsonIgnore] public ICollection? Episodes { get; set; } /// /// The list of collections that contains this show. /// - [SerializeIgnore] + [JsonIgnore] public ICollection? Collections { get; set; } /// @@ -213,7 +207,7 @@ namespace Kyoo.Abstractions.Models private int _EpisodesCount => Episodes!.Count; - [SerializeIgnore] + [JsonIgnore] public ICollection? Watched { get; set; } /// @@ -232,11 +226,6 @@ namespace Kyoo.Abstractions.Models /// public void OnMerge(object merged) { - // if (People != null) - // { - // foreach (PeopleRole link in People) - // link.Show = this; - // } if (Seasons != null) { foreach (Season season in Seasons) diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs b/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs index 2f4eef3d..4f9f69f2 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Studio.cs @@ -19,10 +19,9 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models.Attributes; using Kyoo.Utils; -using Newtonsoft.Json; namespace Kyoo.Abstractions.Models { @@ -48,13 +47,13 @@ namespace Kyoo.Abstractions.Models /// /// The list of shows that are made by this studio. /// - [SerializeIgnore] + [JsonIgnore] public ICollection? Shows { get; set; } /// /// The list of movies that are made by this studio. /// - [SerializeIgnore] + [JsonIgnore] public ICollection? Movies { get; set; } /// diff --git a/back/src/Kyoo.Abstractions/Models/Resources/User.cs b/back/src/Kyoo.Abstractions/Models/Resources/User.cs index 6afeccb8..027d086d 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/User.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/User.cs @@ -19,10 +19,9 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models.Attributes; using Kyoo.Utils; -using Newtonsoft.Json; namespace Kyoo.Abstractions.Models { @@ -53,7 +52,7 @@ namespace Kyoo.Abstractions.Models /// /// The user password (hashed, it can't be read like that). The hashing format is implementation defined. /// - [SerializeIgnore] + [JsonIgnore] public string? Password { get; set; } /// diff --git a/back/src/Kyoo.Abstractions/Models/Resources/WatchStatus.cs b/back/src/Kyoo.Abstractions/Models/Resources/WatchStatus.cs index bc67f0bd..38b73cbd 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/WatchStatus.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/WatchStatus.cs @@ -17,6 +17,7 @@ // along with Kyoo. If not, see . using System; +using System.Text.Json.Serialization; using Kyoo.Abstractions.Models.Attributes; namespace Kyoo.Abstractions.Models @@ -56,25 +57,23 @@ namespace Kyoo.Abstractions.Models /// /// The ID of the user that started watching this episode. /// - [SerializeIgnore] public Guid UserId { get; set; } /// /// The user that started watching this episode. /// - [SerializeIgnore] + [JsonIgnore] public User User { get; set; } /// /// The ID of the movie started. /// - [SerializeIgnore] public Guid MovieId { get; set; } /// /// The started. /// - [SerializeIgnore] + [JsonIgnore] public Movie Movie { get; set; } /// @@ -113,25 +112,23 @@ namespace Kyoo.Abstractions.Models /// /// The ID of the user that started watching this episode. /// - [SerializeIgnore] public Guid UserId { get; set; } /// /// The user that started watching this episode. /// - [SerializeIgnore] + [JsonIgnore] public User User { get; set; } /// /// The ID of the episode started. /// - [SerializeIgnore] public Guid? EpisodeId { get; set; } /// /// The started. /// - [SerializeIgnore] + [JsonIgnore] public Episode Episode { get; set; } /// @@ -170,25 +167,23 @@ namespace Kyoo.Abstractions.Models /// /// The ID of the user that started watching this episode. /// - [SerializeIgnore] public Guid UserId { get; set; } /// /// The user that started watching this episode. /// - [SerializeIgnore] + [JsonIgnore] public User User { get; set; } /// /// The ID of the show started. /// - [SerializeIgnore] public Guid ShowId { get; set; } /// /// The started. /// - [SerializeIgnore] + [JsonIgnore] public Show Show { get; set; } /// @@ -212,7 +207,6 @@ namespace Kyoo.Abstractions.Models /// /// The ID of the episode started. /// - [SerializeIgnore] public Guid? NextEpisodeId { get; set; } /// diff --git a/back/src/Kyoo.Abstractions/Models/Utils/RequestError.cs b/back/src/Kyoo.Abstractions/Models/Utils/RequestError.cs index beca21d5..7c512237 100644 --- a/back/src/Kyoo.Abstractions/Models/Utils/RequestError.cs +++ b/back/src/Kyoo.Abstractions/Models/Utils/RequestError.cs @@ -18,7 +18,6 @@ using System; using System.Linq; -using JetBrains.Annotations; namespace Kyoo.Abstractions.Models.Utils { diff --git a/back/src/Kyoo.Abstractions/Utility/EnumerableExtensions.cs b/back/src/Kyoo.Abstractions/Utility/EnumerableExtensions.cs index f75626c2..f0ae5ffe 100644 --- a/back/src/Kyoo.Abstractions/Utility/EnumerableExtensions.cs +++ b/back/src/Kyoo.Abstractions/Utility/EnumerableExtensions.cs @@ -18,7 +18,6 @@ using System; using System.Collections.Generic; -using JetBrains.Annotations; namespace Kyoo.Utils { @@ -34,7 +33,6 @@ namespace Kyoo.Utils /// The action to execute is the list is empty /// The type of items inside the list /// The iterator proxied, there is no dual iterations. - [LinqTunnel] public static IEnumerable IfEmpty(this IEnumerable self, Action action) { static IEnumerable Generator(IEnumerable self, Action action) diff --git a/back/src/Kyoo.Abstractions/Utility/Merger.cs b/back/src/Kyoo.Abstractions/Utility/Merger.cs index d440e759..d60b2ae5 100644 --- a/back/src/Kyoo.Abstractions/Utility/Merger.cs +++ b/back/src/Kyoo.Abstractions/Utility/Merger.cs @@ -20,7 +20,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; -using JetBrains.Annotations; using Kyoo.Abstractions.Models.Attributes; namespace Kyoo.Utils @@ -44,7 +43,6 @@ namespace Kyoo.Utils /// A dictionary with the missing elements of /// set to those of . /// - [ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)] public static IDictionary? CompleteDictionaries( IDictionary? first, IDictionary? second, @@ -87,11 +85,7 @@ namespace Kyoo.Utils /// /// Fields of T will be completed /// - public static T Complete( - T first, - T? second, - [InstantHandle] Func? where = null - ) + public static T Complete(T first, T? second, Func? where = null) { if (second == null) return first; diff --git a/back/src/Kyoo.Abstractions/Utility/Utility.cs b/back/src/Kyoo.Abstractions/Utility/Utility.cs index 86e7f42f..933149ae 100644 --- a/back/src/Kyoo.Abstractions/Utility/Utility.cs +++ b/back/src/Kyoo.Abstractions/Utility/Utility.cs @@ -22,10 +22,8 @@ using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; -using System.Runtime.ExceptionServices; using System.Text; using System.Text.RegularExpressions; -using JetBrains.Annotations; namespace Kyoo.Utils { @@ -232,7 +230,6 @@ namespace Kyoo.Utils /// /// No method match the given constraints. /// The method handle of the matching method. - [PublicAPI] public static MethodInfo GetMethod( Type type, BindingFlags flag, diff --git a/back/src/Kyoo.Authentication/Kyoo.Authentication.csproj b/back/src/Kyoo.Authentication/Kyoo.Authentication.csproj index b273ee03..83a794b7 100644 --- a/back/src/Kyoo.Authentication/Kyoo.Authentication.csproj +++ b/back/src/Kyoo.Authentication/Kyoo.Authentication.csproj @@ -7,7 +7,6 @@ - diff --git a/back/src/Kyoo.Core/Controllers/LibraryManager.cs b/back/src/Kyoo.Core/Controllers/LibraryManager.cs index e86e4cad..74ccfa4c 100644 --- a/back/src/Kyoo.Core/Controllers/LibraryManager.cs +++ b/back/src/Kyoo.Core/Controllers/LibraryManager.cs @@ -38,7 +38,6 @@ namespace Kyoo.Core.Controllers IRepository showRepository, IRepository seasonRepository, IRepository episodeRepository, - IRepository peopleRepository, IRepository studioRepository, IRepository userRepository ) @@ -51,7 +50,6 @@ namespace Kyoo.Core.Controllers Shows = showRepository; Seasons = seasonRepository; Episodes = episodeRepository; - People = peopleRepository; Studios = studioRepository; Users = userRepository; @@ -64,7 +62,6 @@ namespace Kyoo.Core.Controllers Shows, Seasons, Episodes, - People, Studios, Users }; @@ -94,9 +91,6 @@ namespace Kyoo.Core.Controllers /// public IRepository Episodes { get; } - /// - public IRepository People { get; } - /// public IRepository Studios { get; } diff --git a/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs index 52e0f2ee..327dd906 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs @@ -42,29 +42,15 @@ namespace Kyoo.Core.Controllers /// private readonly IRepository _studios; - /// - /// A people repository to handle creation/validation of related people. - /// - private readonly IRepository _people; - - /// - /// Create a new . - /// - /// The database handle to use - /// A studio repository - /// A people repository - /// The thumbnail manager used to store images. public MovieRepository( DatabaseContext database, IRepository studios, - IRepository people, IThumbnailsManager thumbs ) : base(database, thumbs) { _database = database; _studios = studios; - _people = people; } /// @@ -98,17 +84,6 @@ namespace Kyoo.Core.Controllers resource.Studio = await _studios.CreateIfNotExists(resource.Studio); resource.StudioId = resource.Studio.Id; } - - // if (resource.People != null) - // { - // foreach (PeopleRole role in resource.People) - // { - // role.People = _database.LocalEntity(role.People.Slug) - // ?? await _people.CreateIfNotExists(role.People); - // role.PeopleID = role.People.Id; - // _database.Entry(role).State = EntityState.Added; - // } - // } } /// @@ -121,12 +96,6 @@ namespace Kyoo.Core.Controllers await Database.Entry(resource).Reference(x => x.Studio).LoadAsync(); resource.Studio = changed.Studio; } - - // if (changed.People != null) - // { - // await Database.Entry(resource).Collection(x => x.People!).LoadAsync(); - // resource.People = changed.People; - // } } /// diff --git a/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs deleted file mode 100644 index ab143315..00000000 --- a/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs +++ /dev/null @@ -1,206 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Utils; -using Kyoo.Postgresql; -using Kyoo.Utils; -using Microsoft.EntityFrameworkCore; - -namespace Kyoo.Core.Controllers -{ - /// - /// A local repository to handle people. - /// - public class PeopleRepository : LocalRepository - { - /// - /// The database handle - /// - private readonly DatabaseContext _database; - - /// - /// A lazy loaded show repository to validate requests from shows. - /// - private readonly Lazy> _shows; - - /// - /// Create a new - /// - /// The database handle - /// A lazy loaded show repository - /// The thumbnail manager used to store images. - public PeopleRepository( - DatabaseContext database, - Lazy> shows, - IThumbnailsManager thumbs - ) - : base(database, thumbs) - { - _database = database; - _shows = shows; - } - - /// - public override Task> Search( - string query, - Include? include = default - ) - { - throw new NotImplementedException(); - // return await AddIncludes(_database.People, include) - // .Where(x => EF.Functions.ILike(x.Name, $"%{query}%")) - // .Take(20) - // .ToListAsync(); - } - - /// - public override async Task Create(People obj) - { - await base.Create(obj); - _database.Entry(obj).State = EntityState.Added; - await _database.SaveChangesAsync(() => Get(obj.Slug)); - await IRepository.OnResourceCreated(obj); - return obj; - } - - /// - protected override async Task Validate(People resource) - { - await base.Validate(resource); - - if (resource.Roles != null) - { - foreach (PeopleRole role in resource.Roles) - { - role.Show = - _database.LocalEntity(role.Show!.Slug) - ?? await _shows.Value.CreateIfNotExists(role.Show); - role.ShowID = role.Show.Id; - _database.Entry(role).State = EntityState.Added; - } - } - } - - /// - protected override async Task EditRelations(People resource, People changed) - { - await Validate(changed); - - if (changed.Roles != null) - { - await Database.Entry(resource).Collection(x => x.Roles!).LoadAsync(); - resource.Roles = changed.Roles; - } - } - - /// - public override async Task Delete(People obj) - { - _database.Entry(obj).State = EntityState.Deleted; - obj.Roles.ForEach(x => _database.Entry(x).State = EntityState.Deleted); - await _database.SaveChangesAsync(); - await base.Delete(obj); - } - - // /// - // public Task> GetFromShow(int showID, - // Expression>? where = null, - // Sort? sort = default, - // Pagination? limit = default) - // { - // ICollection people = await ApplyFilters(_database.PeopleRoles - // .Where(x => x.ShowID == showID) - // .Include(x => x.People), - // x => x.People.Name, - // where, - // sort, - // limit); - // if (!people.Any() && await _shows.Value.GetOrDefault(showID) == null) - // throw new ItemNotFoundException(); - // foreach (PeopleRole role in people) - // role.ForPeople = true; - // return people; - // } - - // /// - // public Task> GetFromShow(string showSlug, - // Expression>? where = null, - // Sort? sort = default, - // Pagination? limit = default) - // { - // ICollection people = await ApplyFilters(_database.PeopleRoles - // .Where(x => x.Show.Slug == showSlug) - // .Include(x => x.People) - // .Include(x => x.Show), - // id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id), - // x => x.People.Name, - // where, - // sort, - // limit); - // if (!people.Any() && await _shows.Value.GetOrDefault(showSlug) == null) - // throw new ItemNotFoundException(); - // foreach (PeopleRole role in people) - // role.ForPeople = true; - // return people; - // } - - // /// - // public Task> GetFromPeople(int id, - // Expression>? where = null, - // Sort? sort = default, - // Pagination? limit = default) - // { - // ICollection roles = await ApplyFilters(_database.PeopleRoles - // .Where(x => x.PeopleID == id) - // .Include(x => x.Show), - // y => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == y), - // x => x.Show.Title, - // where, - // sort, - // limit); - // if (!roles.Any() && await GetOrDefault(id) == null) - // throw new ItemNotFoundException(); - // return roles; - // } - - // /// - // public Task> GetFromPeople(string slug, - // Expression>? where = null, - // Sort? sort = default, - // Pagination? limit = default) - // { - // ICollection roles = await ApplyFilters(_database.PeopleRoles - // .Where(x => x.People.Slug == slug) - // .Include(x => x.Show), - // id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id), - // x => x.Show.Title, - // where, - // sort, - // limit); - // if (!roles.Any() && await GetOrDefault(slug) == null) - // throw new ItemNotFoundException(); - // return roles; - // } - } -} diff --git a/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs index e6e4c3d4..5bc8e194 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs @@ -43,29 +43,15 @@ namespace Kyoo.Core.Controllers /// private readonly IRepository _studios; - /// - /// A people repository to handle creation/validation of related people. - /// - private readonly IRepository _people; - - /// - /// Create a new . - /// - /// The database handle to use - /// A studio repository - /// A people repository - /// The thumbnail manager used to store images. public ShowRepository( DatabaseContext database, IRepository studios, - IRepository people, IThumbnailsManager thumbs ) : base(database, thumbs) { _database = database; _studios = studios; - _people = people; } /// @@ -99,17 +85,6 @@ namespace Kyoo.Core.Controllers resource.Studio = await _studios.CreateIfNotExists(resource.Studio); resource.StudioId = resource.Studio.Id; } - - // if (resource.People != null) - // { - // foreach (PeopleRole role in resource.People) - // { - // role.People = _database.LocalEntity(role.People.Slug) - // ?? await _people.CreateIfNotExists(role.People); - // role.PeopleID = role.People.Id; - // _database.Entry(role).State = EntityState.Added; - // } - // } } /// @@ -122,12 +97,6 @@ namespace Kyoo.Core.Controllers await Database.Entry(resource).Reference(x => x.Studio).LoadAsync(); resource.Studio = changed.Studio; } - - // if (changed.People != null) - // { - // await Database.Entry(resource).Collection(x => x.People!).LoadAsync(); - // resource.People = changed.People; - // } } /// diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs index d343bd72..6a0c36f3 100644 --- a/back/src/Kyoo.Core/CoreModule.cs +++ b/back/src/Kyoo.Core/CoreModule.cs @@ -19,6 +19,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; using AspNetCore.Proxy; using Autofac; using Kyoo.Abstractions; @@ -30,10 +32,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using JsonOptions = Kyoo.Core.Api.JsonOptions; namespace Kyoo.Core { @@ -66,7 +64,6 @@ namespace Kyoo.Core builder.RegisterRepository(); builder.RegisterRepository(); builder.RegisterRepository(); - builder.RegisterRepository(); builder.RegisterRepository(); builder.RegisterRepository().As(); builder.RegisterRepository(); @@ -87,7 +84,6 @@ namespace Kyoo.Core public void Configure(IServiceCollection services) { services.AddHttpContextAccessor(); - services.AddTransient, JsonOptions>(); services .AddMvcCore(options => @@ -97,10 +93,14 @@ namespace Kyoo.Core options.ModelBinderProviders.Insert(0, new IncludeBinder.Provider()); options.ModelBinderProviders.Insert(0, new FilterBinder.Provider()); }) - .AddNewtonsoftJson(x => + .AddJsonOptions(x => { - x.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; - x.SerializerSettings.Converters.Add(new StringEnumConverter()); + x.JsonSerializerOptions.TypeInfoResolver = new WithKindResolver() + { + Modifiers = { WithKindResolver.HandleLoadableFields } + }; + x.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + x.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; }) .AddDataAnnotations() .AddControllersAsServices() diff --git a/back/src/Kyoo.Core/Kyoo.Core.csproj b/back/src/Kyoo.Core/Kyoo.Core.csproj index 783954ce..91fabccd 100644 --- a/back/src/Kyoo.Core/Kyoo.Core.csproj +++ b/back/src/Kyoo.Core/Kyoo.Core.csproj @@ -12,8 +12,6 @@ - - diff --git a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonOptions.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonOptions.cs deleted file mode 100644 index 5da2d274..00000000 --- a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonOptions.cs +++ /dev/null @@ -1,56 +0,0 @@ -// 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 Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Options; - -namespace Kyoo.Core.Api -{ - /// - /// The custom options of newtonsoft json. This simply add the and set - /// the . It is on a separate class to use dependency injection. - /// - public class JsonOptions : IConfigureOptions - { - /// - /// The http context accessor given to the . - /// - private readonly IHttpContextAccessor _httpContextAccessor; - - /// - /// Create a new . - /// - /// - /// The http context accessor given to the . - /// - public JsonOptions(IHttpContextAccessor httpContextAccessor) - { - _httpContextAccessor = httpContextAccessor; - } - - /// - public void Configure(MvcNewtonsoftJsonOptions options) - { - options.SerializerSettings.ContractResolver = new JsonSerializerContract( - _httpContextAccessor - ); - options.SerializerSettings.Converters.Add(new PeopleRoleConverter()); - } - } -} diff --git a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs index 10248071..b3f5b0c7 100644 --- a/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs +++ b/back/src/Kyoo.Core/Views/Helper/Serializers/JsonSerializerContract.cs @@ -1,129 +1,69 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. +// // 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 . // -// See AUTHORS.md and LICENSE file in the project root for full license information. +// using System; +// using System.Collections.Generic; +// using System.Linq; +// using System.Net.Http.Formatting; +// using System.Reflection; +// using Kyoo.Abstractions.Models; +// using Kyoo.Abstractions.Models.Attributes; +// using Microsoft.AspNetCore.Http; +// using static System.Text.Json.JsonNamingPolicy; // -// 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. +// namespace Kyoo.Core.Api +// { +// /// +// /// A custom json serializer that respects and +// /// . It also handle via the +// /// fields query parameter and items. +// /// +// public class JsonSerializerContract(IHttpContextAccessor? httpContextAccessor, MediaTypeFormatter formatter) +// : JsonContractResolver(formatter) +// { +// /// +// protected override JsonProperty CreateProperty( +// MemberInfo member, +// MemberSerialization memberSerialization +// ) +// { +// JsonProperty property = base.CreateProperty(member, memberSerialization); // -// 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.Collections.Generic; -using System.Linq; -using System.Reflection; -using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Attributes; -using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using static System.Text.Json.JsonNamingPolicy; - -namespace Kyoo.Core.Api -{ - /// - /// A custom json serializer that respects and - /// . It also handle via the - /// fields query parameter and items. - /// - public class JsonSerializerContract : CamelCasePropertyNamesContractResolver - { - /// - /// The http context accessor used to retrieve the fields query parameter as well as the type of - /// resource currently serializing. - /// - private readonly IHttpContextAccessor _httpContextAccessor; - - /// - /// Create a new . - /// - /// The http context accessor to use. - public JsonSerializerContract(IHttpContextAccessor httpContextAccessor) - { - _httpContextAccessor = httpContextAccessor; - } - - /// - protected override JsonProperty CreateProperty( - MemberInfo member, - MemberSerialization memberSerialization - ) - { - JsonProperty property = base.CreateProperty(member, memberSerialization); - - LoadableRelationAttribute? relation = - member.GetCustomAttribute(); - if (relation != null) - { - property.ShouldSerialize = _ => - { - if ( - _httpContextAccessor.HttpContext!.Items["fields"] - is not ICollection fields - ) - return false; - return fields.Contains(member.Name); - }; - } - - if (member.GetCustomAttribute() != null) - property.ShouldSerialize = _ => false; - if (member.GetCustomAttribute() != null) - property.ShouldDeserialize = _ => false; - return property; - } - - protected override IList CreateProperties( - Type type, - MemberSerialization memberSerialization - ) - { - IList properties = base.CreateProperties(type, memberSerialization); - - if ( - properties.All(x => x.PropertyName != "kind") - && type.IsAssignableTo(typeof(IResource)) - ) - { - properties.Add( - new JsonProperty() - { - DeclaringType = type, - PropertyName = "kind", - UnderlyingName = "kind", - PropertyType = typeof(string), - ValueProvider = new FixedValueProvider(CamelCase.ConvertName(type.Name)), - Readable = true, - Writable = false, - TypeNameHandling = TypeNameHandling.None, - } - ); - } - - return properties; - } - - public class FixedValueProvider : IValueProvider - { - private readonly object _value; - - public FixedValueProvider(object value) - { - _value = value; - } - - public object GetValue(object target) => _value; - - public void SetValue(object target, object? value) => - throw new NotImplementedException(); - } - } -} +// LoadableRelationAttribute? relation = +// member.GetCustomAttribute(); +// if (relation != null) +// { +// if (httpContextAccessor != null) +// { +// property.ShouldSerialize = _ => +// { +// if ( +// httpContextAccessor.HttpContext!.Items["fields"] +// is not ICollection fields +// ) +// return false; +// return fields.Contains(member.Name); +// }; +// } +// else +// property.ShouldSerialize = _ => true; +// } +// return property; +// } +// } +// } diff --git a/back/src/Kyoo.Core/Views/Helper/Serializers/PeopleRoleConverter.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/PeopleRoleConverter.cs deleted file mode 100644 index 773a8d9b..00000000 --- a/back/src/Kyoo.Core/Views/Helper/Serializers/PeopleRoleConverter.cs +++ /dev/null @@ -1,76 +0,0 @@ -// 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.Collections.Generic; -using Kyoo.Abstractions.Models; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Kyoo.Core.Api -{ - /// - /// A custom role's convertor to inline the person or the show depending on the value of - /// . - /// - public class PeopleRoleConverter : JsonConverter - { - /// - public override void WriteJson( - JsonWriter writer, - PeopleRole? value, - JsonSerializer serializer - ) - { - // if (value == null) - // { - // writer.WriteNull(); - // return; - // } - // - // ICollection? oldPeople = value.Show?.People; - // ICollection? oldRoles = value.People?.Roles; - // if (value.Show != null) - // value.Show.People = null; - // if (value.People != null) - // value.People.Roles = null; - // - // JObject obj = JObject.FromObject((value.ForPeople ? value.People : value.Show)!, serializer); - // obj.Add("role", value.Role); - // obj.Add("type", value.Type); - // obj.WriteTo(writer); - // - // if (value.Show != null) - // value.Show.People = oldPeople; - // if (value.People != null) - // value.People.Roles = oldRoles; - } - - /// - public override PeopleRole ReadJson( - JsonReader reader, - Type objectType, - PeopleRole? existingValue, - bool hasExistingValue, - JsonSerializer serializer - ) - { - throw new NotImplementedException(); - } - } -} diff --git a/back/src/Kyoo.Core/Views/Helper/Serializers/WithKindResolver.cs b/back/src/Kyoo.Core/Views/Helper/Serializers/WithKindResolver.cs new file mode 100644 index 00000000..0cf61131 --- /dev/null +++ b/back/src/Kyoo.Core/Views/Helper/Serializers/WithKindResolver.cs @@ -0,0 +1,99 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization.Metadata; +using Kyoo.Abstractions.Models; +using Kyoo.Abstractions.Models.Attributes; +using Microsoft.AspNetCore.Http; +using static System.Text.Json.JsonNamingPolicy; + +namespace Kyoo.Core.Api; + +public class WithKindResolver : DefaultJsonTypeInfoResolver +{ + public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) + { + JsonTypeInfo jsonTypeInfo = base.GetTypeInfo(type, options); + + if (jsonTypeInfo.Type.GetCustomAttribute() != null) + { + jsonTypeInfo.PolymorphismOptions = new() + { + TypeDiscriminatorPropertyName = "kind", + IgnoreUnrecognizedTypeDiscriminators = true, + DerivedTypes = { }, + }; + IEnumerable derived = AppDomain + .CurrentDomain.GetAssemblies() + .SelectMany(s => s.GetTypes()) + .Where(p => type.IsAssignableFrom(p) && p.IsClass); + foreach (Type der in derived) + { + jsonTypeInfo.PolymorphismOptions.DerivedTypes.Add( + new JsonDerivedType(der, CamelCase.ConvertName(der.Name)) + ); + } + } + else if ( + jsonTypeInfo.Type.IsAssignableTo(typeof(IResource)) + && jsonTypeInfo.Properties.All(x => x.Name != "kind") + ) + { + jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions + { + TypeDiscriminatorPropertyName = "kind", + IgnoreUnrecognizedTypeDiscriminators = true, + DerivedTypes = + { + new JsonDerivedType( + jsonTypeInfo.Type, + CamelCase.ConvertName(jsonTypeInfo.Type.Name) + ), + }, + }; + } + + return jsonTypeInfo; + } + + private static readonly IHttpContextAccessor _accessor = new HttpContextAccessor(); + + public static void HandleLoadableFields(JsonTypeInfo info) + { + foreach (JsonPropertyInfo prop in info.Properties) + { + object[] attributes = + prop.AttributeProvider?.GetCustomAttributes(typeof(LoadableRelationAttribute), true) + ?? Array.Empty(); + if (attributes.FirstOrDefault() is not LoadableRelationAttribute relation) + continue; + prop.ShouldSerialize = (_, _) => + { + if (_accessor?.HttpContext?.Items["fields"] is not ICollection fields) + return false; + return fields.Contains(prop.Name, StringComparer.InvariantCultureIgnoreCase); + }; + } + } +} diff --git a/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs b/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs deleted file mode 100644 index 7cbf0cfc..00000000 --- a/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs +++ /dev/null @@ -1,90 +0,0 @@ -// 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 Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Attributes; -using Kyoo.Abstractions.Models.Permissions; -using Microsoft.AspNetCore.Mvc; -using static Kyoo.Abstractions.Models.Utils.Constants; - -namespace Kyoo.Core.Api -{ - /// - /// Information about one or multiple staff member. - /// - [Route("staff")] - [Route("people", Order = AlternativeRoute)] - [ApiController] - [PartialPermission(nameof(People))] - [ApiDefinition("Staff", Group = MetadataGroup)] - public class StaffApi : CrudThumbsApi - { - /// - /// The library manager used to modify or retrieve information in the data store. - /// - private readonly ILibraryManager _libraryManager; - - /// - /// Create a new . - /// - /// - /// The library manager used to modify or retrieve information about the data store. - /// - /// The thumbnail manager used to retrieve images paths. - public StaffApi(ILibraryManager libraryManager, IThumbnailsManager thumbs) - : base(libraryManager.People, thumbs) - { - _libraryManager = libraryManager; - } - - // /// - // /// Get roles - // /// - // /// - // /// List the roles in witch this person has played, written or worked in a way. - // /// - // /// The ID or slug of the person. - // /// A key to sort roles by. - // /// An optional list of filters. - // /// The number of roles to return. - // /// A page of roles. - // /// The filters or the sort parameters are invalid. - // /// No person with the given ID or slug could be found. - // [HttpGet("{identifier:id}/roles")] - // [HttpGet("{identifier:id}/role", Order = AlternativeRoute)] - // [PartialPermission(Kind.Read)] - // [ProducesResponseType(StatusCodes.Status200OK)] - // [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - // [ProducesResponseType(StatusCodes.Status404NotFound)] - // public async Task>> GetRoles(Identifier identifier, - // [FromQuery] Sort sortBy, - // [FromQuery] Dictionary where, - // [FromQuery] Pagination pagination) - // { - // Expression>? whereQuery = ApiHelper.ParseWhere(where); - // - // ICollection resources = await identifier.Match( - // id => _libraryManager.GetRolesFromPeople(id, whereQuery, sortBy, pagination), - // slug => _libraryManager.GetRolesFromPeople(slug, whereQuery, sortBy, pagination) - // ); - // - // return Page(resources, pagination.Limit); - // } - } -} diff --git a/back/src/Kyoo.Core/Views/Resources/MovieApi.cs b/back/src/Kyoo.Core/Views/Resources/MovieApi.cs index b148f85d..f83d92cc 100644 --- a/back/src/Kyoo.Core/Views/Resources/MovieApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/MovieApi.cs @@ -43,40 +43,6 @@ namespace Kyoo.Core.Api public class MovieApi(ILibraryManager libraryManager, IThumbnailsManager thumbs) : TranscoderApi(libraryManager.Movies, thumbs) { - // /// - // /// Get staff - // /// - // /// - // /// List staff members that made this show. - // /// - // /// The ID or slug of the . - // /// A key to sort staff members by. - // /// An optional list of filters. - // /// The number of people to return. - // /// A page of people. - // /// The filters or the sort parameters are invalid. - // /// No show with the given ID or slug could be found. - // [HttpGet("{identifier:id}/staff")] - // [HttpGet("{identifier:id}/people", Order = AlternativeRoute)] - // [PartialPermission(Kind.Read)] - // [ProducesResponseType(StatusCodes.Status200OK)] - // [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - // [ProducesResponseType(StatusCodes.Status404NotFound)] - // public async Task>> GetPeople(Identifier identifier, - // [FromQuery] string sortBy, - // [FromQuery] Dictionary where, - // [FromQuery] Pagination pagination) - // { - // Expression> whereQuery = ApiHelper.ParseWhere(where); - // Sort sort = Sort.From(sortBy); - // - // ICollection resources = await identifier.Match( - // id => _libraryManager.GetPeopleFromShow(id, whereQuery, sort, pagination), - // slug => _libraryManager.GetPeopleFromShow(slug, whereQuery, sort, pagination) - // ); - // return Page(resources, pagination.Limit); - // } - /// /// Get studio that made the show /// diff --git a/back/src/Kyoo.Core/Views/Resources/ShowApi.cs b/back/src/Kyoo.Core/Views/Resources/ShowApi.cs index f0dc5122..96da58c2 100644 --- a/back/src/Kyoo.Core/Views/Resources/ShowApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/ShowApi.cs @@ -146,41 +146,6 @@ namespace Kyoo.Core.Api return Page(resources, pagination.Limit); } - // /// - // /// Get staff - // /// - // /// - // /// List staff members that made this show. - // /// - // /// The ID or slug of the . - // /// A key to sort staff members by. - // /// An optional list of filters. - // /// The number of people to return. - // /// The aditional fields to include in the result. - // /// A page of people. - // /// The filters or the sort parameters are invalid. - // /// No show with the given ID or slug could be found. - // [HttpGet("{identifier:id}/staff")] - // [HttpGet("{identifier:id}/people", Order = AlternativeRoute)] - // [PartialPermission(Kind.Read)] - // [ProducesResponseType(StatusCodes.Status200OK)] - // [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - // [ProducesResponseType(StatusCodes.Status404NotFound)] - // public async Task>> GetPeople(Identifier identifier, - // [FromQuery] Sort sortBy, - // [FromQuery] Dictionary where, - // [FromQuery] Pagination pagination, - // [FromQuery] Include fields) - // { - // Expression>? whereQuery = ApiHelper.ParseWhere(where); - // - // ICollection resources = await identifier.Match( - // id => _libraryManager.GetPeopleFromShow(id, whereQuery, sortBy, pagination), - // slug => _libraryManager.GetPeopleFromShow(slug, whereQuery, sortBy, pagination) - // ); - // return Page(resources, pagination.Limit); - // } - /// /// Get studio that made the show /// diff --git a/back/src/Kyoo.Host/Program.cs b/back/src/Kyoo.Host/Program.cs index 730553f0..2217b0f7 100644 --- a/back/src/Kyoo.Host/Program.cs +++ b/back/src/Kyoo.Host/Program.cs @@ -17,7 +17,6 @@ // along with Kyoo. If not, see . using System.Threading.Tasks; -using Kyoo.Host; using Microsoft.AspNetCore.Hosting; namespace Kyoo.Host diff --git a/back/src/Kyoo.Postgresql/DatabaseContext.cs b/back/src/Kyoo.Postgresql/DatabaseContext.cs index 8f728ce6..6d40001a 100644 --- a/back/src/Kyoo.Postgresql/DatabaseContext.cs +++ b/back/src/Kyoo.Postgresql/DatabaseContext.cs @@ -78,11 +78,6 @@ namespace Kyoo.Postgresql /// public DbSet Episodes { get; set; } - // /// - // /// All people of Kyoo. See . - // /// - // public DbSet People { get; set; } - /// /// All studios of Kyoo. See . /// @@ -93,11 +88,6 @@ namespace Kyoo.Postgresql /// public DbSet Users { get; set; } - // /// - // /// All people's role. See . - // /// - // public DbSet PeopleRoles { get; set; } - public DbSet MovieWatchStatus { get; set; } public DbSet ShowWatchStatus { get; set; } @@ -275,8 +265,6 @@ namespace Kyoo.Postgresql .Ignore(x => x.PreviousEpisode) .Ignore(x => x.NextEpisode); - // modelBuilder.Entity() - // .Ignore(x => x.ForPeople); modelBuilder .Entity() .HasMany(x => x.Seasons) @@ -312,14 +300,12 @@ namespace Kyoo.Postgresql _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); - // _HasMetadata(modelBuilder); _HasMetadata(modelBuilder); _HasImages(modelBuilder); _HasImages(modelBuilder); _HasImages(modelBuilder); _HasImages(modelBuilder); - // _HasImages(modelBuilder); _HasImages(modelBuilder); _HasAddedDate(modelBuilder); @@ -382,9 +368,6 @@ namespace Kyoo.Postgresql modelBuilder.Entity().Ignore(x => x.WatchStatus); modelBuilder.Entity().HasIndex(x => x.Slug).IsUnique(); - // modelBuilder.Entity() - // .HasIndex(x => x.Slug) - // .IsUnique(); modelBuilder.Entity().HasIndex(x => x.Slug).IsUnique(); modelBuilder.Entity().HasIndex(x => x.Slug).IsUnique(); modelBuilder.Entity().HasIndex(x => x.Slug).IsUnique(); diff --git a/back/src/Kyoo.Postgresql/Utils/JsonTypeHandler.cs b/back/src/Kyoo.Postgresql/Utils/JsonTypeHandler.cs index 1eff28a2..e9655389 100644 --- a/back/src/Kyoo.Postgresql/Utils/JsonTypeHandler.cs +++ b/back/src/Kyoo.Postgresql/Utils/JsonTypeHandler.cs @@ -17,7 +17,7 @@ // along with Kyoo. If not, see . using System.Data; -using Newtonsoft.Json; +using System.Text.Json; using Npgsql; using NpgsqlTypes; using static Dapper.SqlMapper; @@ -30,13 +30,13 @@ public class JsonTypeHandler : TypeHandler public override T? Parse(object value) { if (value is string str) - return JsonConvert.DeserializeObject(str); + return JsonSerializer.Deserialize(str); return default; } public override void SetValue(IDbDataParameter parameter, T? value) { - parameter.Value = JsonConvert.SerializeObject(value); + parameter.Value = JsonSerializer.Serialize(value); ((NpgsqlParameter)parameter).NpgsqlDbType = NpgsqlDbType.Jsonb; } } diff --git a/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs b/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs deleted file mode 100644 index d95f76e8..00000000 --- a/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs +++ /dev/null @@ -1,132 +0,0 @@ -// 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.Collections.Generic; -using System.Data.Common; -using System.Linq; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Core; -using Kyoo.Core.Controllers; -using Kyoo.Postgresql; -using Microsoft.Extensions.DependencyInjection; -using Moq; -using Xunit.Abstractions; - -namespace Kyoo.Tests.Database -{ - public class RepositoryActivator : IDisposable, IAsyncDisposable - { - public TestContext Context { get; } - public ILibraryManager LibraryManager { get; } - - private readonly List _databases = new(); - - private readonly IBaseRepository[] _repositories; - - public RepositoryActivator(ITestOutputHelper output, PostgresFixture postgres = null) - { - Context = new PostgresTestContext(postgres, output); - - Mock thumbs = new(); - CollectionRepository collection = new(_NewContext(), thumbs.Object); - StudioRepository studio = new(_NewContext(), thumbs.Object); - PeopleRepository people = - new( - _NewContext(), - new Lazy>(() => LibraryManager.Shows), - thumbs.Object - ); - MovieRepository movies = new(_NewContext(), studio, people, thumbs.Object); - ShowRepository show = new(_NewContext(), studio, people, thumbs.Object); - SeasonRepository season = new(_NewContext(), thumbs.Object); - LibraryItemRepository libraryItem = new(_NewConnection(), new(null)); - EpisodeRepository episode = new(_NewContext(), show, thumbs.Object); - UserRepository user = - new(_NewContext(), _NewConnection(), new(null), thumbs.Object, new()); - - _repositories = new IBaseRepository[] - { - libraryItem, - collection, - movies, - show, - season, - episode, - people, - studio, - user - }; - - ServiceCollection container = new(); - container.AddScoped((_) => _NewContext()); - CoreModule.Services = container.BuildServiceProvider(); - - LibraryManager = new LibraryManager( - libraryItem, - null, - null, - collection, - movies, - show, - season, - episode, - people, - studio, - user - ); - } - - public IRepository GetRepository() - where T : class, IResource, IQuery - { - return _repositories.First(x => x.RepositoryType == typeof(T)) as IRepository; - } - - private DatabaseContext _NewContext() - { - DatabaseContext context = Context.New(); - _databases.Add(context); - return context; - } - - private DbConnection _NewConnection() - { - DbConnection context = Context.NewConnection(); - _databases.Add(context); - return context; - } - - public void Dispose() - { - foreach (IDisposable context in _databases) - context.Dispose(); - Context.Dispose(); - GC.SuppressFinalize(this); - } - - public async ValueTask DisposeAsync() - { - foreach (IAsyncDisposable context in _databases) - await context.DisposeAsync(); - await Context.DisposeAsync(); - } - } -} diff --git a/back/tests/Kyoo.Tests/Database/RepositoryTests.cs b/back/tests/Kyoo.Tests/Database/RepositoryTests.cs deleted file mode 100644 index 8ec486c1..00000000 --- a/back/tests/Kyoo.Tests/Database/RepositoryTests.cs +++ /dev/null @@ -1,114 +0,0 @@ -// 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.Linq; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Exceptions; -using Kyoo.Postgresql; -using Xunit; - -namespace Kyoo.Tests.Database -{ - public abstract class RepositoryTests : IDisposable, IAsyncDisposable - where T : class, IResource, IQuery - { - protected readonly RepositoryActivator Repositories; - private readonly IRepository _repository; - - protected RepositoryTests(RepositoryActivator repositories) - { - Repositories = repositories; - _repository = Repositories.GetRepository(); - } - - public void Dispose() - { - Repositories.Dispose(); - GC.SuppressFinalize(this); - } - - public ValueTask DisposeAsync() - { - return Repositories.DisposeAsync(); - } - - [Fact] - public async Task FillTest() - { - await using DatabaseContext database = Repositories.Context.New(); - - Assert.Equal(1, database.Shows.Count()); - } - - [Fact] - public async Task GetByIdTest() - { - T value = await _repository.Get(TestSample.Get().Id); - KAssert.DeepEqual(TestSample.Get(), value); - } - - [Fact] - public async Task GetBySlugTest() - { - T value = await _repository.Get(TestSample.Get().Slug); - KAssert.DeepEqual(TestSample.Get(), value); - } - - [Fact] - public async Task GetByFakeSlugTest() - { - await Assert.ThrowsAsync(() => _repository.Get("non-existent")); - } - - [Fact] - public async Task DeleteByIdTest() - { - await _repository.Delete(TestSample.Get().Id); - Assert.Equal(0, await _repository.GetCount()); - } - - [Fact] - public async Task DeleteBySlugTest() - { - await _repository.Delete(TestSample.Get().Slug); - Assert.Equal(0, await _repository.GetCount()); - } - - [Fact] - public async Task DeleteByValueTest() - { - await _repository.Delete(TestSample.Get()); - Assert.Equal(0, await _repository.GetCount()); - } - - // [Fact] - // public async Task EditNonExistingTest() - // { - // await Assert.ThrowsAsync(() => _repository.Edit(new T { Id = 56 })); - // } - - [Fact] - public async Task GetOrDefaultTest() - { - Assert.Null(await _repository.GetOrDefault("non-existing")); - } - } -} diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/CollectionsTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/CollectionsTests.cs deleted file mode 100644 index 616807b3..00000000 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/CollectionsTests.cs +++ /dev/null @@ -1,158 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Postgresql; -using Microsoft.EntityFrameworkCore; -using Xunit; -using Xunit.Abstractions; - -namespace Kyoo.Tests.Database -{ - namespace PostgreSQL - { - [Collection(nameof(Postgresql))] - public class CollectionTests : ACollectionTests - { - public CollectionTests(PostgresFixture postgres, ITestOutputHelper output) - : base(new RepositoryActivator(output, postgres)) { } - } - } - - public abstract class ACollectionTests : RepositoryTests - { - private readonly IRepository _repository; - - protected ACollectionTests(RepositoryActivator repositories) - : base(repositories) - { - _repository = Repositories.LibraryManager.Collections; - } - - [Fact] - public async Task CreateWithEmptySlugTest() - { - Collection collection = TestSample.GetNew(); - collection.Slug = string.Empty; - await Assert.ThrowsAsync(() => _repository.Create(collection)); - } - - [Fact] - public async Task CreateWithNumberSlugTest() - { - Collection collection = TestSample.GetNew(); - collection.Slug = "2"; - Collection ret = await _repository.Create(collection); - Assert.Equal("2!", ret.Slug); - } - - [Fact] - public async Task CreateWithExternalIdTest() - { - Collection collection = TestSample.GetNew(); - collection.ExternalId = new Dictionary - { - ["1"] = new() { Link = "link", DataId = "id" }, - ["2"] = new() { Link = "new-provider-link", DataId = "new-id" } - }; - await _repository.Create(collection); - - Collection retrieved = await _repository.Get(2.AsGuid()); - Assert.Equal(2, retrieved.ExternalId.Count); - KAssert.DeepEqual(collection.ExternalId.First(), retrieved.ExternalId.First()); - KAssert.DeepEqual(collection.ExternalId.Last(), retrieved.ExternalId.Last()); - } - - [Fact] - public async Task EditTest() - { - Collection value = await _repository.Get(TestSample.Get().Slug); - value.Name = "New Title"; - value.Poster = new Image("new-poster"); - await _repository.Edit(value); - - await using DatabaseContext database = Repositories.Context.New(); - Collection retrieved = await database.Collections.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - - [Fact] - public async Task EditMetadataTest() - { - Collection value = await _repository.Get(TestSample.Get().Slug); - value.ExternalId = new Dictionary - { - ["test"] = new() { Link = "link", DataId = "id" }, - }; - await _repository.Edit(value); - - await using DatabaseContext database = Repositories.Context.New(); - Collection retrieved = await database.Collections.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - - [Fact] - public async Task AddMetadataTest() - { - Collection value = await _repository.Get(TestSample.Get().Slug); - value.ExternalId = new Dictionary - { - ["toto"] = new() { Link = "link", DataId = "id" }, - }; - await _repository.Edit(value); - - { - await using DatabaseContext database = Repositories.Context.New(); - Collection retrieved = await database.Collections.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - - value.ExternalId.Add("test", new MetadataId { Link = "link", DataId = "id" }); - await _repository.Edit(value); - - { - await using DatabaseContext database = Repositories.Context.New(); - Collection retrieved = await database.Collections.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - } - - [Theory] - [InlineData("test")] - [InlineData("super")] - [InlineData("title")] - [InlineData("TiTlE")] - [InlineData("SuPeR")] - public async Task SearchTest(string query) - { - Collection value = new() { Slug = "super-test", Name = "This is a test title", }; - await _repository.Create(value); - ICollection ret = await _repository.Search(query); - KAssert.DeepEqual(value, ret.First()); - } - } -} diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/EpisodeTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/EpisodeTests.cs deleted file mode 100644 index 9c9e976a..00000000 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/EpisodeTests.cs +++ /dev/null @@ -1,329 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Exceptions; -using Kyoo.Postgresql; -using Microsoft.EntityFrameworkCore; -using Xunit; -using Xunit.Abstractions; - -namespace Kyoo.Tests.Database -{ - namespace PostgreSQL - { - [Collection(nameof(Postgresql))] - public class EpisodeTests : AEpisodeTests - { - public EpisodeTests(PostgresFixture postgres, ITestOutputHelper output) - : base(new RepositoryActivator(output, postgres)) { } - } - } - - public abstract class AEpisodeTests : RepositoryTests - { - private readonly IRepository _repository; - - protected AEpisodeTests(RepositoryActivator repositories) - : base(repositories) - { - _repository = repositories.LibraryManager.Episodes; - } - - [Fact] - public async Task SlugEditTest() - { - Episode episode = await _repository.Get(1.AsGuid()); - Assert.Equal($"{TestSample.Get().Slug}-s1e1", episode.Slug); - await Repositories.LibraryManager.Shows.Patch( - episode.ShowId, - (x) => - { - x.Slug = "new-slug"; - return x; - } - ); - episode = await _repository.Get(1.AsGuid()); - Assert.Equal("new-slug-s1e1", episode.Slug); - } - - [Fact] - public async Task SeasonNumberEditTest() - { - Episode episode = await _repository.Get(1.AsGuid()); - Assert.Equal($"{TestSample.Get().Slug}-s1e1", episode.Slug); - episode = await _repository.Patch( - 1.AsGuid(), - (x) => - { - x.SeasonNumber = 2; - return x; - } - ); - Assert.Equal($"{TestSample.Get().Slug}-s2e1", episode.Slug); - episode = await _repository.Get(1.AsGuid()); - Assert.Equal($"{TestSample.Get().Slug}-s2e1", episode.Slug); - } - - [Fact] - public async Task EpisodeNumberEditTest() - { - Episode episode = await _repository.Get(1.AsGuid()); - Assert.Equal($"{TestSample.Get().Slug}-s1e1", episode.Slug); - episode = await Repositories.LibraryManager.Episodes.Patch( - episode.Id, - (x) => - { - x.EpisodeNumber = 2; - return x; - } - ); - Assert.Equal($"{TestSample.Get().Slug}-s1e2", episode.Slug); - episode = await _repository.Get(1.AsGuid()); - Assert.Equal($"{TestSample.Get().Slug}-s1e2", episode.Slug); - } - - [Fact] - public async Task EpisodeCreationSlugTest() - { - Episode model = TestSample.Get(); - model.Id = 0.AsGuid(); - model.ShowId = TestSample.Get().Id; - model.SeasonNumber = 2; - model.EpisodeNumber = 4; - Episode episode = await _repository.Create(model); - Assert.Equal($"{TestSample.Get().Slug}-s2e4", episode.Slug); - } - - [Fact] - public void AbsoluteSlugTest() - { - Assert.Equal( - $"{TestSample.Get().Slug}-{TestSample.GetAbsoluteEpisode().AbsoluteNumber}", - TestSample.GetAbsoluteEpisode().Slug - ); - } - - [Fact] - public async Task EpisodeCreationAbsoluteSlugTest() - { - Episode episode = await _repository.Create(TestSample.GetAbsoluteEpisode()); - Assert.Equal( - $"{TestSample.Get().Slug}-{TestSample.GetAbsoluteEpisode().AbsoluteNumber}", - episode.Slug - ); - } - - [Fact] - public async Task SlugEditAbsoluteTest() - { - Episode episode = await _repository.Create(TestSample.GetAbsoluteEpisode()); - await Repositories.LibraryManager.Shows.Patch( - episode.ShowId, - (x) => - { - x.Slug = "new-slug"; - return x; - } - ); - episode = await _repository.Get(2.AsGuid()); - Assert.Equal($"new-slug-3", episode.Slug); - } - - [Fact] - public async Task AbsoluteNumberEditTest() - { - await _repository.Create(TestSample.GetAbsoluteEpisode()); - Episode episode = await _repository.Patch( - 2.AsGuid(), - (x) => - { - x.AbsoluteNumber = 56; - return x; - } - ); - Assert.Equal($"{TestSample.Get().Slug}-56", episode.Slug); - episode = await _repository.Get(2.AsGuid()); - Assert.Equal($"{TestSample.Get().Slug}-56", episode.Slug); - } - - [Fact] - public async Task AbsoluteToNormalEditTest() - { - await _repository.Create(TestSample.GetAbsoluteEpisode()); - Episode episode = await _repository.Patch( - 2.AsGuid(), - (x) => - { - x.SeasonNumber = 1; - x.EpisodeNumber = 2; - return x; - } - ); - Assert.Equal($"{TestSample.Get().Slug}-s1e2", episode.Slug); - episode = await _repository.Get(2.AsGuid()); - Assert.Equal($"{TestSample.Get().Slug}-s1e2", episode.Slug); - } - - [Fact] - public async Task NormalToAbsoluteEditTest() - { - Episode episode = await _repository.Get(1.AsGuid()); - episode.SeasonNumber = null; - episode.AbsoluteNumber = 12; - episode = await _repository.Edit(episode); - Assert.Equal($"{TestSample.Get().Slug}-12", episode.Slug); - episode = await _repository.Get(1.AsGuid()); - Assert.Equal($"{TestSample.Get().Slug}-12", episode.Slug); - } - - [Fact] - public async Task CreateWithExternalIdTest() - { - Episode value = TestSample.GetNew(); - value.ExternalId = new Dictionary - { - ["2"] = new() { Link = "link", DataId = "id" }, - ["3"] = new() { Link = "new-provider-link", DataId = "new-id" } - }; - await _repository.Create(value); - - Episode retrieved = await _repository.Get(2.AsGuid()); - Assert.Equal(2, retrieved.ExternalId.Count); - KAssert.DeepEqual(value.ExternalId.First(), retrieved.ExternalId.First()); - KAssert.DeepEqual(value.ExternalId.Last(), retrieved.ExternalId.Last()); - } - - [Fact] - public async Task EditTest() - { - Episode value = await _repository.Get(TestSample.Get().Slug); - value.Name = "New Title"; - value.Poster = new Image("poster"); - await _repository.Edit(value); - - await using DatabaseContext database = Repositories.Context.New(); - Episode retrieved = await database.Episodes.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - - [Fact] - public async Task EditMetadataTest() - { - Episode value = await _repository.Get(TestSample.Get().Slug); - value.ExternalId = new Dictionary - { - ["1"] = new() { Link = "link", DataId = "id" }, - }; - await _repository.Edit(value); - - await using DatabaseContext database = Repositories.Context.New(); - Episode retrieved = await database.Episodes.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - - [Fact] - public async Task AddMetadataTest() - { - Episode value = await _repository.Get(TestSample.Get().Slug); - value.ExternalId = new Dictionary - { - ["toto"] = new() { Link = "link", DataId = "id" }, - }; - await _repository.Edit(value); - - { - await using DatabaseContext database = Repositories.Context.New(); - Episode retrieved = await database.Episodes.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - - value.ExternalId.Add("test", new MetadataId { Link = "link", DataId = "id" }); - await _repository.Edit(value); - - { - await using DatabaseContext database = Repositories.Context.New(); - Episode retrieved = await database.Episodes.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - } - - [Theory] - [InlineData("test")] - [InlineData("super")] - [InlineData("title")] - [InlineData("TiTlE")] - [InlineData("SuPeR")] - public async Task SearchTest(string query) - { - Episode value = TestSample.Get(); - value.Id = 0.AsGuid(); - value.Name = "This is a test super title"; - value.EpisodeNumber = 56; - await _repository.Create(value); - ICollection ret = await _repository.Search(query); - KAssert.DeepEqual(value, ret.First()); - } - - [Fact] - public async Task CreateTest() - { - await Assert.ThrowsAsync( - () => _repository.Create(TestSample.Get()) - ); - await _repository.Delete(TestSample.Get()); - - Episode expected = TestSample.Get(); - expected.Id = 0.AsGuid(); - expected.ShowId = ( - await Repositories.LibraryManager.Shows.Create(TestSample.Get()) - ).Id; - expected.SeasonId = ( - await Repositories.LibraryManager.Seasons.Create(TestSample.Get()) - ).Id; - await _repository.Create(expected); - KAssert.DeepEqual(expected, await _repository.Get(expected.Slug)); - } - - [Fact] - public async Task CreateIfNotExistTest() - { - Episode expected = TestSample.Get(); - KAssert.DeepEqual( - expected, - await _repository.CreateIfNotExists(TestSample.Get()) - ); - await _repository.Delete(TestSample.Get()); - expected.ShowId = ( - await Repositories.LibraryManager.Shows.Create(TestSample.Get()) - ).Id; - expected.SeasonId = ( - await Repositories.LibraryManager.Seasons.Create(TestSample.Get()) - ).Id; - KAssert.DeepEqual(expected, await _repository.CreateIfNotExists(expected)); - } - } -} diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/SanityTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/SanityTests.cs deleted file mode 100644 index cc2b00a3..00000000 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/SanityTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -// 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.Diagnostics.CodeAnalysis; -using Kyoo.Abstractions.Models; -using Xunit; - -namespace Kyoo.Tests.Database -{ - public class GlobalTests - { - [Fact] - [SuppressMessage("ReSharper", "EqualExpressionComparison")] - public void SampleTest() - { - Assert.False(ReferenceEquals(TestSample.Get(), TestSample.Get())); - } - } -} diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/SeasonTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/SeasonTests.cs deleted file mode 100644 index 68d672cf..00000000 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/SeasonTests.cs +++ /dev/null @@ -1,183 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Postgresql; -using Microsoft.EntityFrameworkCore; -using Xunit; -using Xunit.Abstractions; - -namespace Kyoo.Tests.Database -{ - namespace PostgreSQL - { - [Collection(nameof(Postgresql))] - public class SeasonTests : ASeasonTests - { - public SeasonTests(PostgresFixture postgres, ITestOutputHelper output) - : base(new RepositoryActivator(output, postgres)) { } - } - } - - public abstract class ASeasonTests : RepositoryTests - { - private readonly IRepository _repository; - - protected ASeasonTests(RepositoryActivator repositories) - : base(repositories) - { - _repository = Repositories.LibraryManager.Seasons; - } - - [Fact] - public async Task SlugEditTest() - { - Season season = await _repository.Get(1.AsGuid()); - Assert.Equal("anohana-s1", season.Slug); - await Repositories.LibraryManager.Shows.Patch( - season.ShowId, - (x) => - { - x.Slug = "new-slug"; - return x; - } - ); - season = await _repository.Get(1.AsGuid()); - Assert.Equal("new-slug-s1", season.Slug); - } - - [Fact] - public async Task SeasonNumberEditTest() - { - Season season = await _repository.Get(1.AsGuid()); - Assert.Equal("anohana-s1", season.Slug); - await _repository.Patch( - season.Id, - (x) => - { - x.SeasonNumber = 2; - return x; - } - ); - season = await _repository.Get(1.AsGuid()); - Assert.Equal("anohana-s2", season.Slug); - } - - [Fact] - public async Task SeasonCreationSlugTest() - { - Season season = await _repository.Create( - new Season { ShowId = TestSample.Get().Id, SeasonNumber = 2 } - ); - Assert.Equal($"{TestSample.Get().Slug}-s2", season.Slug); - } - - [Fact] - public async Task CreateWithExternalIdTest() - { - Season season = TestSample.GetNew(); - season.ExternalId = new Dictionary - { - ["2"] = new() { Link = "link", DataId = "id" }, - ["1"] = new() { Link = "new-provider-link", DataId = "new-id" } - }; - await _repository.Create(season); - - Season retrieved = await _repository.Get(2.AsGuid()); - Assert.Equal(2, retrieved.ExternalId.Count); - KAssert.DeepEqual(season.ExternalId.First(), retrieved.ExternalId.First()); - KAssert.DeepEqual(season.ExternalId.Last(), retrieved.ExternalId.Last()); - } - - [Fact] - public async Task EditTest() - { - Season value = await _repository.Get(TestSample.Get().Slug); - value.Name = "New Title"; - value.Poster = new Image("test"); - await _repository.Edit(value); - - await using DatabaseContext database = Repositories.Context.New(); - Season retrieved = await database.Seasons.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - - [Fact] - public async Task EditMetadataTest() - { - Season value = await _repository.Get(TestSample.Get().Slug); - value.ExternalId = new Dictionary - { - ["toto"] = new() { Link = "link", DataId = "id" }, - }; - await _repository.Edit(value); - - await using DatabaseContext database = Repositories.Context.New(); - Season retrieved = await database.Seasons.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - - [Fact] - public async Task AddMetadataTest() - { - Season value = await _repository.Get(TestSample.Get().Slug); - value.ExternalId = new Dictionary - { - ["1"] = new() { Link = "link", DataId = "id" }, - }; - await _repository.Edit(value); - - { - await using DatabaseContext database = Repositories.Context.New(); - Season retrieved = await database.Seasons.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - - value.ExternalId.Add("toto", new MetadataId { Link = "link", DataId = "id" }); - await _repository.Edit(value); - - { - await using DatabaseContext database = Repositories.Context.New(); - Season retrieved = await database.Seasons.FirstAsync(); - - KAssert.DeepEqual(value, retrieved); - } - } - - [Theory] - [InlineData("test")] - [InlineData("super")] - [InlineData("title")] - [InlineData("TiTlE")] - [InlineData("SuPeR")] - public async Task SearchTest(string query) - { - Season value = new() { Name = "This is a test super title", ShowId = 1.AsGuid() }; - await _repository.Create(value); - ICollection ret = await _repository.Search(query); - KAssert.DeepEqual(value, ret.First()); - } - } -} diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/ShowTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/ShowTests.cs deleted file mode 100644 index c9050174..00000000 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/ShowTests.cs +++ /dev/null @@ -1,297 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Postgresql; -using Kyoo.Utils; -using Microsoft.EntityFrameworkCore; -using Xunit; -using Xunit.Abstractions; - -namespace Kyoo.Tests.Database -{ - namespace PostgreSQL - { - [Collection(nameof(Postgresql))] - public class ShowTests : AShowTests - { - public ShowTests(PostgresFixture postgres, ITestOutputHelper output) - : base(new RepositoryActivator(output, postgres)) { } - } - } - - public abstract class AShowTests : RepositoryTests - { - private readonly IRepository _repository; - - protected AShowTests(RepositoryActivator repositories) - : base(repositories) - { - _repository = Repositories.LibraryManager.Shows; - } - - [Fact] - public async Task EditTest() - { - Show value = await _repository.Get(TestSample.Get().Slug); - value.Name = "New Title"; - Show edited = await _repository.Edit(value); - KAssert.DeepEqual(value, edited); - - await using DatabaseContext database = Repositories.Context.New(); - Show show = await database.Shows.FirstAsync(); - - KAssert.DeepEqual(show, value); - } - - [Fact] - public async Task EditGenreTest() - { - Show value = await _repository.Get(TestSample.Get().Slug); - value.Genres = new List { Genre.Action }; - Show edited = await _repository.Edit(value); - - Assert.Equal(value.Slug, edited.Slug); - Assert.Equal(value.Genres, edited.Genres); - - await using DatabaseContext database = Repositories.Context.New(); - Show show = await database.Shows.FirstAsync(); - - Assert.Equal(value.Slug, show.Slug); - Assert.Equal(value.Genres, show.Genres); - } - - [Fact] - public async Task AddGenreTest() - { - Show value = await _repository.Get(TestSample.Get().Slug); - value.Genres.Add(Genre.Drama); - Show edited = await _repository.Edit(value); - - Assert.Equal(value.Slug, edited.Slug); - Assert.Equal(value.Genres, edited.Genres); - - await using DatabaseContext database = Repositories.Context.New(); - Show show = await database.Shows.FirstAsync(); - - Assert.Equal(value.Slug, show.Slug); - Assert.Equal(value.Genres, show.Genres); - } - - [Fact] - public async Task EditStudioTest() - { - Show value = await _repository.Get(TestSample.Get().Slug); - value.Studio = new Studio("studio"); - Show edited = await _repository.Edit(value); - - Assert.Equal(value.Slug, edited.Slug); - Assert.Equal("studio", edited.Studio!.Slug); - - await using DatabaseContext database = Repositories.Context.New(); - Show show = await database.Shows.Include(x => x.Studio).FirstAsync(); - - Assert.Equal(value.Slug, show.Slug); - Assert.Equal("studio", show.Studio!.Slug); - } - - [Fact] - public async Task EditAliasesTest() - { - Show value = await _repository.Get(TestSample.Get().Slug); - value.Aliases = new List() { "NiceNewAlias", "SecondAlias" }; - Show edited = await _repository.Edit(value); - - Assert.Equal(value.Slug, edited.Slug); - Assert.Equal(value.Aliases, edited.Aliases); - - await using DatabaseContext database = Repositories.Context.New(); - Show show = await database.Shows.FirstAsync(); - - Assert.Equal(value.Slug, show.Slug); - Assert.Equal(value.Aliases, show.Aliases); - } - - // [Fact] - // public async Task EditPeopleTest() - // { - // Show value = await _repository.Get(TestSample.Get().Slug); - // value.People = new[] - // { - // new PeopleRole - // { - // Show = value, - // People = TestSample.Get(), - // ForPeople = false, - // Type = "Actor", - // Role = "NiceCharacter" - // } - // }; - // Show edited = await _repository.Edit(value); - // - // Assert.Equal(value.Slug, edited.Slug); - // Assert.Equal(edited.People!.First().ShowID, value.Id); - // Assert.Equal( - // value.People.Select(x => new { x.Role, x.Slug, x.People.Name }), - // edited.People.Select(x => new { x.Role, x.Slug, x.People.Name })); - // - // await using DatabaseContext database = Repositories.Context.New(); - // Show show = await database.Shows - // .Include(x => x.People) - // .ThenInclude(x => x.People) - // .FirstAsync(); - // - // Assert.Equal(value.Slug, show.Slug); - // Assert.Equal( - // value.People.Select(x => new { x.Role, x.Slug, x.People.Name }), - // show.People!.Select(x => new { x.Role, x.Slug, x.People.Name })); - // } - - [Fact] - public async Task EditExternalIDsTest() - { - Show value = await _repository.Get(TestSample.Get().Slug); - value.ExternalId = new Dictionary() - { - ["test"] = new() { DataId = "1234" } - }; - Show edited = await _repository.Edit(value); - - Assert.Equal(value.Slug, edited.Slug); - KAssert.DeepEqual(value.ExternalId, edited.ExternalId); - - await using DatabaseContext database = Repositories.Context.New(); - Show show = await database.Shows.FirstAsync(); - - Assert.Equal(value.Slug, show.Slug); - KAssert.DeepEqual(value.ExternalId, show.ExternalId); - } - - [Fact] - public async Task CreateWithRelationsTest() - { - Show expected = TestSample.Get(); - expected.Id = 0.AsGuid(); - expected.Slug = "created-relation-test"; - expected.ExternalId = new Dictionary - { - ["test"] = new() { DataId = "ID" } - }; - expected.Genres = new List() { Genre.Action }; - // expected.People = new[] - // { - // new PeopleRole - // { - // People = TestSample.Get(), - // Show = expected, - // ForPeople = false, - // Role = "actor", - // Type = "actor" - // } - // }; - expected.Studio = new Studio("studio"); - Show created = await _repository.Create(expected); - KAssert.DeepEqual(expected, created); - - await using DatabaseContext context = Repositories.Context.New(); - Show retrieved = await context - .Shows - // .Include(x => x.People) - // .ThenInclude(x => x.People) - .Include(x => x.Studio) - .FirstAsync(x => x.Id == created.Id); - // retrieved.People.ForEach(x => - // { - // x.Show = null; - // x.People.Roles = null; - // x.People.Poster = null; - // x.People.Thumbnail = null; - // x.People.Logo = null; - // }); - retrieved.Studio!.Shows = null; - // expected.People.ForEach(x => - // { - // x.Show = null; - // x.People.Roles = null; - // x.People.Poster = null; - // x.People.Thumbnail = null; - // x.People.Logo = null; - // }); - - KAssert.DeepEqual(retrieved, expected); - } - - [Fact] - public async Task CreateWithExternalID() - { - Show expected = TestSample.Get(); - expected.Id = 0.AsGuid(); - expected.Slug = "created-relation-test"; - expected.ExternalId = new Dictionary - { - ["test"] = new() { DataId = "ID" } - }; - Show created = await _repository.Create(expected); - KAssert.DeepEqual(expected, created); - await using DatabaseContext context = Repositories.Context.New(); - Show retrieved = await context.Shows.FirstAsync(x => x.Id == created.Id); - KAssert.DeepEqual(expected, retrieved); - Assert.Single(retrieved.ExternalId); - Assert.Equal("ID", retrieved.ExternalId["test"].DataId); - } - - [Fact] - public async Task SlugDuplicationTest() - { - Show test = TestSample.Get(); - test.Id = 0.AsGuid(); - test.Slug = "300"; - Show created = await _repository.Create(test); - Assert.Equal("300!", created.Slug); - } - - [Theory] - [InlineData("test")] - [InlineData("super")] - [InlineData("title")] - [InlineData("TiTlE")] - [InlineData("SuPeR")] - public async Task SearchTest(string query) - { - Show value = new() { Slug = "super-test", Name = "This is a test title?" }; - await _repository.Create(value); - ICollection ret = await _repository.Search(query); - KAssert.DeepEqual(value, ret.First()); - } - - [Fact] - public async Task DeleteShowWithEpisodeAndSeason() - { - Show show = TestSample.Get(); - Assert.Equal(1, await _repository.GetCount()); - await _repository.Delete(show); - Assert.Equal(0, await Repositories.LibraryManager.Shows.GetCount()); - Assert.Equal(0, await Repositories.LibraryManager.Seasons.GetCount()); - Assert.Equal(0, await Repositories.LibraryManager.Episodes.GetCount()); - } - } -} diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/StudioTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/StudioTests.cs deleted file mode 100644 index 678d4202..00000000 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/StudioTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -// 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.Diagnostics.CodeAnalysis; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Xunit; -using Xunit.Abstractions; - -namespace Kyoo.Tests.Database -{ - namespace PostgreSQL - { - [Collection(nameof(Postgresql))] - public class StudioTests : AStudioTests - { - public StudioTests(PostgresFixture postgres, ITestOutputHelper output) - : base(new RepositoryActivator(output, postgres)) { } - } - } - - public abstract class AStudioTests : RepositoryTests - { - [SuppressMessage("ReSharper", "NotAccessedField.Local")] - private readonly IRepository _repository; - - protected AStudioTests(RepositoryActivator repositories) - : base(repositories) - { - _repository = Repositories.LibraryManager.Studios; - } - } -} diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/UserTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/UserTests.cs deleted file mode 100644 index 5fe797dd..00000000 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/UserTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -// 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.Diagnostics.CodeAnalysis; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Xunit; -using Xunit.Abstractions; - -namespace Kyoo.Tests.Database -{ - namespace PostgreSQL - { - [Collection(nameof(Postgresql))] - public class UserTests : AUserTests - { - public UserTests(PostgresFixture postgres, ITestOutputHelper output) - : base(new RepositoryActivator(output, postgres)) { } - } - } - - public abstract class AUserTests : RepositoryTests - { - [SuppressMessage("ReSharper", "NotAccessedField.Local")] - private readonly IRepository _repository; - - protected AUserTests(RepositoryActivator repositories) - : base(repositories) - { - _repository = Repositories.LibraryManager.Users; - } - } -} diff --git a/back/tests/Kyoo.Tests/Database/TestContext.cs b/back/tests/Kyoo.Tests/Database/TestContext.cs deleted file mode 100644 index 0e750b26..00000000 --- a/back/tests/Kyoo.Tests/Database/TestContext.cs +++ /dev/null @@ -1,174 +0,0 @@ -// 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.Data.Common; -using System.Threading.Tasks; -using Kyoo.Postgresql; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using Npgsql; -using Xunit; -using Xunit.Abstractions; - -namespace Kyoo.Tests -{ - [CollectionDefinition(nameof(Postgresql))] - public class PostgresCollection : ICollectionFixture { } - - public sealed class PostgresFixture : IDisposable - { - private readonly DbContextOptions _options; - - public string Template { get; } - - public string Connection => PostgresTestContext.GetConnectionString(Template); - - public PostgresFixture() - { - string id = Guid.NewGuid().ToString().Replace('-', '_'); - Template = $"kyoo_template_{id}"; - - _options = new DbContextOptionsBuilder().UseNpgsql(Connection).Options; - - using PostgresContext context = new(_options, null); - context.Database.Migrate(); - - using NpgsqlConnection conn = (NpgsqlConnection)context.Database.GetDbConnection(); - conn.Open(); - conn.ReloadTypes(); - - TestSample.FillDatabase(context); - conn.Close(); - } - - public void Dispose() - { - using PostgresContext context = new(_options, null); - context.Database.EnsureDeleted(); - } - } - - public sealed class PostgresTestContext : TestContext - { - private readonly string _database; - private readonly DbContextOptions _context; - - public PostgresTestContext(PostgresFixture template, ITestOutputHelper output) - { - string id = Guid.NewGuid().ToString().Replace('-', '_'); - _database = $"kyoo_test_{id}"; - - using (NpgsqlConnection connection = new(template.Connection)) - { - connection.Open(); - using NpgsqlCommand cmd = - new( - $"CREATE DATABASE {_database} WITH TEMPLATE {template.Template}", - connection - ); - cmd.ExecuteNonQuery(); - } - - _context = new DbContextOptionsBuilder() - .UseNpgsql(GetConnectionString(_database)) - .UseLoggerFactory( - LoggerFactory.Create(x => - { - x.ClearProviders(); - x.AddXunit(output); - }) - ) - .EnableSensitiveDataLogging() - .EnableDetailedErrors() - .Options; - } - - public static string GetConnectionString(string database) - { - string server = Environment.GetEnvironmentVariable("POSTGRES_HOST") ?? "127.0.0.1"; - string port = Environment.GetEnvironmentVariable("POSTGRES_PORT") ?? "5432"; - string username = Environment.GetEnvironmentVariable("POSTGRES_USER") ?? "KyooUser"; - string password = - Environment.GetEnvironmentVariable("POSTGRES_PASSWORD") ?? "KyooPassword"; - return $"Server={server};Port={port};Database={database};User ID={username};Password={password};Include Error Detail=true"; - } - - public override void Dispose() - { - using DatabaseContext db = New(); - db.Database.EnsureDeleted(); - } - - public override async ValueTask DisposeAsync() - { - await using DatabaseContext db = New(); - await db.Database.EnsureDeletedAsync(); - } - - public override DatabaseContext New() - { - return new PostgresContext(_context, null); - } - - public override DbConnection NewConnection() - { - return new NpgsqlConnection(GetConnectionString(_database)); - } - } - - /// - /// Class responsible to fill and create in memory databases for unit tests. - /// - public abstract class TestContext : IDisposable, IAsyncDisposable - { - /// - /// Add an arbitrary data to the test context. - /// - public void Add(T obj) - where T : class - { - using DatabaseContext context = New(); - context.Set().Add(obj); - context.SaveChanges(); - } - - /// - /// Add an arbitrary data to the test context. - /// - public async Task AddAsync(T obj) - where T : class - { - await using DatabaseContext context = New(); - await context.Set().AddAsync(obj); - await context.SaveChangesAsync(); - } - - /// - /// Get a new database context connected to a in memory Sqlite database. - /// - /// A valid DatabaseContext - public abstract DatabaseContext New(); - - public abstract DbConnection NewConnection(); - - public abstract void Dispose(); - - public abstract ValueTask DisposeAsync(); - } -} diff --git a/back/tests/Kyoo.Tests/Database/TestSample.cs b/back/tests/Kyoo.Tests/Database/TestSample.cs deleted file mode 100644 index e4728b46..00000000 --- a/back/tests/Kyoo.Tests/Database/TestSample.cs +++ /dev/null @@ -1,290 +0,0 @@ -// 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.Collections.Generic; -using Kyoo.Abstractions.Models; -using Kyoo.Postgresql; - -namespace Kyoo.Tests -{ - public static class TestSample - { - private static readonly Dictionary> NewSamples = - new() - { - { - typeof(Collection), - () => - new Collection - { - Id = 2.AsGuid(), - Slug = "new-collection", - Name = "New Collection", - Overview = "A collection created by new sample", - Thumbnail = new Image("thumbnail") - } - }, - { - typeof(Show), - () => - new Show - { - Id = 2.AsGuid(), - Slug = "new-show", - Name = "New Show", - Overview = "overview", - Status = Status.Planned, - StartAir = new DateTime(2011, 1, 1).ToUniversalTime(), - EndAir = new DateTime(2011, 1, 1).ToUniversalTime(), - Poster = new Image("Poster"), - Logo = new Image("Logo"), - Thumbnail = new Image("Thumbnail"), - Studio = null - } - }, - { - typeof(Season), - () => - new Season - { - Id = 2.AsGuid(), - ShowId = 1.AsGuid(), - ShowSlug = Get().Slug, - Name = "New season", - Overview = "New overview", - EndDate = new DateTime(2000, 10, 10).ToUniversalTime(), - SeasonNumber = 2, - StartDate = new DateTime(2010, 10, 10).ToUniversalTime(), - Logo = new Image("logo") - } - }, - { - typeof(Episode), - () => - new Episode - { - Id = 2.AsGuid(), - ShowId = 1.AsGuid(), - ShowSlug = Get().Slug, - SeasonId = 1.AsGuid(), - SeasonNumber = Get().SeasonNumber, - EpisodeNumber = 3, - AbsoluteNumber = 4, - Path = "/episode-path", - Name = "New Episode Title", - ReleaseDate = new DateTime(2000, 10, 10).ToUniversalTime(), - Overview = "new episode overview", - Logo = new Image("new episode logo") - } - }, - { - typeof(People), - () => - new People - { - Id = 2.AsGuid(), - Slug = "new-person-name", - Name = "New person name", - Logo = new Image("Old Logo"), - Poster = new Image("Old poster") - } - } - }; - - private static readonly Dictionary> Samples = - new() - { - { - typeof(Collection), - () => - new Collection - { - Id = 1.AsGuid(), - Slug = "collection", - Name = "Collection", - Overview = "A nice collection for tests", - Poster = new Image("Poster") - } - }, - { - typeof(Show), - () => - new Show - { - Id = 1.AsGuid(), - Slug = "anohana", - Name = "Anohana: The Flower We Saw That Day", - Aliases = new List - { - "Ano Hi Mita Hana no Namae o Bokutachi wa Mada Shiranai.", - "AnoHana", - "We Still Don't Know the Name of the Flower We Saw That Day." - }, - Overview = - "When Yadomi Jinta was a child, he was a central piece in a group of close friends. " - + "In time, however, these childhood friends drifted apart, and when they became high " - + "school students, they had long ceased to think of each other as friends.", - Status = Status.Finished, - StudioId = 1.AsGuid(), - StartAir = new DateTime(2011, 1, 1).ToUniversalTime(), - EndAir = new DateTime(2011, 1, 1).ToUniversalTime(), - Poster = new Image("Poster"), - Logo = new Image("Logo"), - Thumbnail = new Image("Thumbnail"), - Studio = null - } - }, - { - typeof(Season), - () => - new Season - { - Id = 1.AsGuid(), - ShowSlug = "anohana", - ShowId = 1.AsGuid(), - SeasonNumber = 1, - Name = "Season 1", - Overview = "The first season", - StartDate = new DateTime(2020, 06, 05).ToUniversalTime(), - EndDate = new DateTime(2020, 07, 05).ToUniversalTime(), - Poster = new Image("Poster"), - Logo = new Image("Logo"), - Thumbnail = new Image("Thumbnail") - } - }, - { - typeof(Episode), - () => - new Episode - { - Id = 1.AsGuid(), - ShowSlug = "anohana", - ShowId = 1.AsGuid(), - SeasonId = 1.AsGuid(), - SeasonNumber = 1, - EpisodeNumber = 1, - AbsoluteNumber = 1, - Path = "/home/kyoo/anohana-s1e1", - Poster = new Image("Poster"), - Logo = new Image("Logo"), - Thumbnail = new Image("Thumbnail"), - Name = "Episode 1", - Overview = "Summary of the first episode", - ReleaseDate = new DateTime(2020, 06, 05).ToUniversalTime() - } - }, - { - typeof(People), - () => - new People - { - Id = 1.AsGuid(), - Slug = "the-actor", - Name = "The Actor", - Poster = new Image("Poster"), - Logo = new Image("Logo"), - Thumbnail = new Image("Thumbnail") - } - }, - { - typeof(Studio), - () => - new Studio - { - Id = 1.AsGuid(), - Slug = "hyper-studio", - Name = "Hyper studio", - } - }, - { - typeof(User), - () => - new User - { - Id = 1.AsGuid(), - Slug = "user", - Username = "User", - Email = "user@im-a-user.com", - Password = "MD5-encoded", - Permissions = new[] { "overall.read" } - } - } - }; - - public static T Get() - { - return (T)Samples[typeof(T)](); - } - - public static T GetNew() - { - return (T)NewSamples[typeof(T)](); - } - - public static void FillDatabase(DatabaseContext context) - { - Collection collection = Get(); - context.Collections.Add(collection); - - Show show = Get(); - context.Shows.Add(show); - - Season season = Get(); - season.Show = show; - context.Seasons.Add(season); - - Episode episode = Get(); - episode.Show = show; - episode.Season = season; - context.Episodes.Add(episode); - - Studio studio = Get(); - studio.Shows = new List { show }; - context.Studios.Add(studio); - - People people = Get(); - // context.People.Add(people); - - User user = Get(); - context.Users.Add(user); - - context.SaveChanges(); - } - - public static Episode GetAbsoluteEpisode() - { - return new() - { - Id = 2.AsGuid(), - ShowSlug = "anohana", - ShowId = 1.AsGuid(), - SeasonNumber = null, - EpisodeNumber = null, - AbsoluteNumber = 3, - Path = "/home/kyoo/anohana-3", - Poster = new Image("Poster"), - Logo = new Image("Logo"), - Thumbnail = new Image("Thumbnail"), - Name = "Episode 3", - Overview = "Summary of the third absolute episode", - ReleaseDate = new DateTime(2020, 06, 05).ToUniversalTime() - }; - } - } -} diff --git a/back/tests/Kyoo.Tests/KAssert.cs b/back/tests/Kyoo.Tests/KAssert.cs deleted file mode 100644 index 81ea8b51..00000000 --- a/back/tests/Kyoo.Tests/KAssert.cs +++ /dev/null @@ -1,85 +0,0 @@ -// 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.Security.Cryptography; -using FluentAssertions; -using JetBrains.Annotations; -using Kyoo.Abstractions.Models; -using Xunit.Sdk; - -namespace Kyoo.Tests -{ - /// - /// Custom assertions used by Kyoo's tests. - /// - public static class KAssert - { - /// - /// Check if every property of the item is equal to the other's object. - /// - /// The value to check against - /// The value to check - /// The type to check - [AssertionMethod] - public static void DeepEqual(T expected, T value) - { - if (expected is IAddedDate ea && value is IAddedDate va) - { - ea.AddedDate = DateTime.UnixEpoch; - va.AddedDate = DateTime.UnixEpoch; - } - value.Should().BeEquivalentTo(expected); - } - - /// - /// Explicitly fail a test. - /// - [AssertionMethod] - public static void Fail() - { - throw new XunitException("Explicit fail"); - } - - /// - /// Explicitly fail a test. - /// - /// The message that will be seen in the test report - [AssertionMethod] - public static void Fail(string message) - { - throw new XunitException(message); - } - - public static Guid AsGuid(this string src) - { - // Use MD5 since (1) it's faster then SHA and (2) it's already 16 bytes which matches the Guid - return string.IsNullOrWhiteSpace(src) - ? Guid.Empty - : new Guid(MD5.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(src))); - } - - public static Guid AsGuid(this int src) - { - // Use MD5 since (1) it's faster then SHA and (2) it's already 16 bytes which matches the Guid - return src == 0 - ? Guid.Empty - : new Guid(MD5.Create().ComputeHash(BitConverter.GetBytes(src))); - } - } -} diff --git a/back/tests/Kyoo.Tests/Kyoo.Tests.csproj b/back/tests/Kyoo.Tests/Kyoo.Tests.csproj deleted file mode 100644 index 3f9fcde1..00000000 --- a/back/tests/Kyoo.Tests/Kyoo.Tests.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - net7.0 - default - - false - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - diff --git a/back/tests/Kyoo.Tests/Utility/EnumerableTests.cs b/back/tests/Kyoo.Tests/Utility/EnumerableTests.cs deleted file mode 100644 index 69aeb3ae..00000000 --- a/back/tests/Kyoo.Tests/Utility/EnumerableTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -// 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.Linq; -using Kyoo.Utils; -using Xunit; - -namespace Kyoo.Tests.Utility -{ - public class EnumerableTests - { - [Fact] - public void IfEmptyTest() - { - int[] list = { 1, 2, 3, 4 }; - list = list.IfEmpty(() => KAssert.Fail("Empty action should not be triggered.")) - .ToArray(); - list = Array.Empty(); - Assert.Throws( - () => list.IfEmpty(() => throw new ArgumentException()).ToList() - ); - Assert.Empty(list.IfEmpty(() => { })); - } - } -} diff --git a/back/tests/Kyoo.Tests/Utility/MergerTests.cs b/back/tests/Kyoo.Tests/Utility/MergerTests.cs deleted file mode 100644 index 2e214e5d..00000000 --- a/back/tests/Kyoo.Tests/Utility/MergerTests.cs +++ /dev/null @@ -1,145 +0,0 @@ -// 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.Collections.Generic; -using JetBrains.Annotations; -using Kyoo.Abstractions.Models; -using Kyoo.Utils; -using Xunit; - -namespace Kyoo.Tests.Utility -{ - public class MergerTests - { - [Fact] - public void CompleteTest() - { - Studio genre = new() { Name = "merged" }; - Studio genre2 = new() { Name = "test", Id = 5.AsGuid(), }; - Studio ret = Merger.Complete(genre, genre2); - Assert.True(ReferenceEquals(genre, ret)); - Assert.Equal(5.AsGuid(), ret.Id); - Assert.Equal("test", genre.Name); - Assert.Null(genre.Slug); - } - - [Fact] - public void CompleteDictionaryTest() - { - Collection collection = new() { Name = "merged", }; - Collection collection2 = new() { Id = 5.AsGuid(), Name = "test", }; - Collection ret = Merger.Complete(collection, collection2); - Assert.True(ReferenceEquals(collection, ret)); - Assert.Equal(5.AsGuid(), ret.Id); - Assert.Equal("test", ret.Name); - Assert.Null(ret.Slug); - } - - [Fact] - public void CompleteDictionaryOutParam() - { - Dictionary first = new() { ["logo"] = "logo", ["poster"] = "poster" }; - Dictionary second = - new() { ["poster"] = "new-poster", ["thumbnail"] = "thumbnails" }; - IDictionary ret = Merger.CompleteDictionaries( - first, - second, - out bool changed - ); - Assert.True(changed); - Assert.Equal(3, ret.Count); - Assert.Equal("new-poster", ret["poster"]); - Assert.Equal("thumbnails", ret["thumbnail"]); - Assert.Equal("logo", ret["logo"]); - } - - [Fact] - public void CompleteDictionaryEqualTest() - { - Dictionary first = new() { ["poster"] = "poster" }; - Dictionary second = new() { ["poster"] = "new-poster", }; - IDictionary ret = Merger.CompleteDictionaries( - first, - second, - out bool changed - ); - Assert.True(changed); - Assert.Single(ret); - Assert.Equal("new-poster", ret["poster"]); - } - - private class TestMergeSetter - { - public Dictionary Backing; - - [UsedImplicitly] - public Dictionary Dictionary - { - get => Backing; - set - { - Backing = value; - KAssert.Fail(); - } - } - } - - [Fact] - public void CompleteDictionaryNoChangeNoSetTest() - { - TestMergeSetter first = new() { Backing = new Dictionary { [2] = 3 } }; - TestMergeSetter second = new() { Backing = new Dictionary() }; - Merger.Complete(first, second); - // This should no call the setter of first so the test should pass. - } - - [Fact] - public void CompleteDictionaryNullValue() - { - Dictionary first = new() { ["logo"] = "logo", ["poster"] = null }; - Dictionary second = - new() { ["poster"] = "new-poster", ["thumbnail"] = "thumbnails" }; - IDictionary ret = Merger.CompleteDictionaries( - first, - second, - out bool changed - ); - Assert.True(changed); - Assert.Equal(3, ret.Count); - Assert.Equal("new-poster", ret["poster"]); - Assert.Equal("thumbnails", ret["thumbnail"]); - Assert.Equal("logo", ret["logo"]); - } - - [Fact] - public void CompleteDictionaryNullValueNoChange() - { - Dictionary first = new() { ["logo"] = "logo", ["poster"] = null }; - Dictionary second = new() { ["poster"] = null, }; - IDictionary ret = Merger.CompleteDictionaries( - first, - second, - out bool changed - ); - Assert.False(changed); - Assert.Equal(2, ret.Count); - Assert.Null(ret["poster"]); - Assert.Equal("logo", ret["logo"]); - } - } -} diff --git a/back/tests/Kyoo.Tests/Utility/UtilityTests.cs b/back/tests/Kyoo.Tests/Utility/UtilityTests.cs deleted file mode 100644 index 137591e5..00000000 --- a/back/tests/Kyoo.Tests/Utility/UtilityTests.cs +++ /dev/null @@ -1,96 +0,0 @@ -// 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.Linq.Expressions; -using System.Reflection; -using Kyoo.Abstractions.Models; -using Xunit; -using KUtility = Kyoo.Utils.Utility; - -namespace Kyoo.Tests.Utility -{ - public class UtilityTests - { - [Fact] - public void IsPropertyExpression_Tests() - { - Expression> member = x => x.Id; - Expression> memberCast = x => x.Id; - - Assert.True(KUtility.IsPropertyExpression(member)); - Assert.True(KUtility.IsPropertyExpression(memberCast)); - - Expression> call = x => x.ToString(); - Assert.False(KUtility.IsPropertyExpression(call)); - } - - [Fact] - public void GetPropertyName_Test() - { - Expression> member = x => x.Id; - Expression> memberCast = x => x.Id; - - Assert.Equal("Id", KUtility.GetPropertyName(member)); - Assert.Equal("Id", KUtility.GetPropertyName(memberCast)); - } - - [Fact] - public void GetMethodTest() - { - MethodInfo method = KUtility.GetMethod( - typeof(UtilityTests), - BindingFlags.Instance | BindingFlags.Public, - nameof(GetMethodTest), - Array.Empty(), - Array.Empty() - ); - Assert.Equal(MethodBase.GetCurrentMethod(), method); - } - - [Fact] - public void GetMethodInvalidGenericsTest() - { - Assert.Throws( - () => - KUtility.GetMethod( - typeof(UtilityTests), - BindingFlags.Instance | BindingFlags.Public, - nameof(GetMethodTest), - new[] { typeof(KUtility) }, - Array.Empty() - ) - ); - } - - [Fact] - public void GetMethodInvalidParamsTest() - { - Assert.Throws( - () => - KUtility.GetMethod( - typeof(UtilityTests), - BindingFlags.Instance | BindingFlags.Public, - nameof(GetMethodTest), - Array.Empty(), - new object[] { this } - ) - ); - } - } -} diff --git a/front/apps/web/src/pages/_app.tsx b/front/apps/web/src/pages/_app.tsx index a606bcbd..b553e409 100755 --- a/front/apps/web/src/pages/_app.tsx +++ b/front/apps/web/src/pages/_app.tsx @@ -210,37 +210,40 @@ App.getInitialProps = async (ctx: AppContext) => { if (typeof window !== "undefined") return { pageProps: superjson.serialize(appProps.pageProps) }; - const getUrl = Component.getFetchUrls; - const getLayoutUrl = - Component.getLayout && "Layout" in Component.getLayout - ? Component.getLayout.Layout.getFetchUrls - : Component.getLayout?.getFetchUrls; - const urls: QueryIdentifier[] = [ - ...(getUrl ? getUrl(ctx.router.query as any, items) : []), - ...(getLayoutUrl ? getLayoutUrl(ctx.router.query as any, items) : []), - // always include server info for guest permissions. - { path: ["info"], parser: ServerInfoP }, - ]; + try { + const getUrl = Component.getFetchUrls; + const getLayoutUrl = + Component.getLayout && "Layout" in Component.getLayout + ? Component.getLayout.Layout.getFetchUrls + : Component.getLayout?.getFetchUrls; + const urls: QueryIdentifier[] = [ + ...(getUrl ? getUrl(ctx.router.query as any, items) : []), + ...(getLayoutUrl ? getLayoutUrl(ctx.router.query as any, items) : []), + // always include server info for guest permissions. + { path: ["info"], parser: ServerInfoP }, + ]; - setSsrApiUrl(); + setSsrApiUrl(); - const account = readCookie(ctx.ctx.req?.headers.cookie, "account", AccountP); - if (account) urls.push({ path: ["auth", "me"], parser: UserP }); - const [authToken, token, error] = await getTokenWJ(account); - if (error) appProps.pageProps.ssrError = error; - else { - const client = (await fetchQuery(urls, authToken))!; - appProps.pageProps.queryState = dehydrate(client); - if (account) { - appProps.pageProps.token = token; - appProps.pageProps.account = { - ...client.getQueryData(["auth", "me"]), - ...account, - }; + const account = readCookie(ctx.ctx.req?.headers.cookie, "account", AccountP); + if (account) urls.push({ path: ["auth", "me"], parser: UserP }); + const [authToken, token, error] = await getTokenWJ(account); + if (error) appProps.pageProps.ssrError = error; + else { + const client = (await fetchQuery(urls, authToken))!; + appProps.pageProps.queryState = dehydrate(client); + if (account) { + appProps.pageProps.token = token; + appProps.pageProps.account = { + ...client.getQueryData(["auth", "me"]), + ...account, + }; + } } + appProps.pageProps.theme = readCookie(ctx.ctx.req?.headers.cookie, "theme") ?? "auto"; + } catch (e) { + console.error("SSR error, disabling it."); } - appProps.pageProps.theme = readCookie(ctx.ctx.req?.headers.cookie, "theme") ?? "auto"; - return { pageProps: superjson.serialize(appProps.pageProps) }; }; diff --git a/front/packages/models/src/account-internal.ts b/front/packages/models/src/account-internal.ts index 79a4ebe2..b8d4be89 100644 --- a/front/packages/models/src/account-internal.ts +++ b/front/packages/models/src/account-internal.ts @@ -62,8 +62,7 @@ export const readCookie = ( } if (c.indexOf(name) == 0) { const str = c.substring(name.length, c.length); - const ret = JSON.parse(str); - return parser ? parser.parse(ret) : ret; + return parser ? parser.parse(JSON.parse(str)) : str; } } return null; diff --git a/front/translations/fr.json b/front/translations/fr.json index 4186d7c3..016f7163 100644 --- a/front/translations/fr.json +++ b/front/translations/fr.json @@ -68,7 +68,7 @@ "more": "Plus", "expand": "Développer", "collapse": "Replier", - "edit": "Changer", + "edit": "Modifier", "or": "OU", "loading": "Chargement en cours" }, @@ -125,7 +125,7 @@ }, "password": { "label": "Mot de passe", - "description": "Changer de mot de passe", + "description": "Modifier votre mot de passe", "oldPassword": "Ancien mot de passe", "newPassword": "Nouveau mot de passe" }