diff --git a/back/src/Kyoo.Abstractions/Models/LibraryItem.cs b/back/src/Kyoo.Abstractions/Models/LibraryItem.cs index fb3a24e4..a57fb191 100644 --- a/back/src/Kyoo.Abstractions/Models/LibraryItem.cs +++ b/back/src/Kyoo.Abstractions/Models/LibraryItem.cs @@ -45,7 +45,7 @@ namespace Kyoo.Abstractions.Models Collection } - public class LibraryItem : IResource, IThumbnails, IMetadata + public class LibraryItem : IResource, IThumbnails, IMetadata, IAddedDate { /// public int Id { get; set; } @@ -110,6 +110,9 @@ namespace Kyoo.Abstractions.Models /// public DateTime? AirDate { get; set; } + /// + public DateTime AddedDate { get; set; } + /// public Image? Poster { get; set; } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs b/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs index 63a04eef..a5d6fef8 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Collection.cs @@ -16,6 +16,7 @@ // 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 Kyoo.Abstractions.Models.Attributes; @@ -27,7 +28,7 @@ namespace Kyoo.Abstractions.Models /// /// A class representing collections of . /// - public class Collection : IResource, IMetadata, IThumbnails + public class Collection : IResource, IMetadata, IThumbnails, IAddedDate { /// public int Id { get; set; } @@ -45,6 +46,9 @@ namespace Kyoo.Abstractions.Models /// public string? Overview { get; set; } + /// + public DateTime AddedDate { get; set; } + /// public Image? Poster { get; set; } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs b/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs index d5a49da7..40ddfedf 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Episode.cs @@ -29,7 +29,7 @@ namespace Kyoo.Abstractions.Models /// /// A class to represent a single show's episode. /// - public class Episode : IResource, IMetadata, IThumbnails + public class Episode : IResource, IMetadata, IThumbnails, IAddedDate { /// public int Id { get; set; } @@ -138,6 +138,9 @@ namespace Kyoo.Abstractions.Models /// public DateTime? ReleaseDate { get; set; } + /// + public DateTime AddedDate { get; set; } + /// public Image? Poster { get; set; } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IAddedDate.cs b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IAddedDate.cs new file mode 100644 index 00000000..be2af353 --- /dev/null +++ b/back/src/Kyoo.Abstractions/Models/Resources/Interfaces/IAddedDate.cs @@ -0,0 +1,33 @@ +// 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 +{ + /// + /// An interface applied to resources. + /// + public interface IAddedDate + { + /// + /// The date at which this resource was added to kyoo. + /// + public DateTime AddedDate { get; set; } + } +} diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs index 850bc3fc..a102a93c 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Movie.cs @@ -29,7 +29,7 @@ namespace Kyoo.Abstractions.Models /// /// A series or a movie. /// - public class Movie : IResource, IMetadata, IOnMerge, IThumbnails + public class Movie : IResource, IMetadata, IOnMerge, IThumbnails, IAddedDate { /// public int Id { get; set; } @@ -83,6 +83,9 @@ namespace Kyoo.Abstractions.Models /// public DateTime? AirDate { get; set; } + /// + public DateTime AddedDate { get; set; } + /// public Image? Poster { get; set; } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Season.cs b/back/src/Kyoo.Abstractions/Models/Resources/Season.cs index 6cd21c3c..9d28c4ad 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Season.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Season.cs @@ -29,7 +29,7 @@ namespace Kyoo.Abstractions.Models /// /// A season of a . /// - public class Season : IResource, IMetadata, IThumbnails + public class Season : IResource, IMetadata, IThumbnails, IAddedDate { /// public int Id { get; set; } @@ -95,6 +95,9 @@ namespace Kyoo.Abstractions.Models /// public DateTime? StartDate { get; set; } + /// + public DateTime AddedDate { get; set; } + /// /// The ending date of this season. /// diff --git a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs index aeba5c68..9345d66a 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/Show.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/Show.cs @@ -29,7 +29,7 @@ namespace Kyoo.Abstractions.Models /// /// A series or a movie. /// - public class Show : IResource, IMetadata, IOnMerge, IThumbnails + public class Show : IResource, IMetadata, IOnMerge, IThumbnails, IAddedDate { /// public int Id { get; set; } @@ -84,6 +84,9 @@ namespace Kyoo.Abstractions.Models /// public DateTime? EndAir { get; set; } + /// + public DateTime AddedDate { get; set; } + /// public Image? Poster { get; set; } diff --git a/back/src/Kyoo.Abstractions/Models/Resources/User.cs b/back/src/Kyoo.Abstractions/Models/Resources/User.cs index aa484e3f..17fde619 100644 --- a/back/src/Kyoo.Abstractions/Models/Resources/User.cs +++ b/back/src/Kyoo.Abstractions/Models/Resources/User.cs @@ -28,7 +28,7 @@ namespace Kyoo.Abstractions.Models /// /// A single user of the app. /// - public class User : IResource + public class User : IResource, IAddedDate { /// public int Id { get; set; } @@ -58,6 +58,9 @@ namespace Kyoo.Abstractions.Models /// public string[] Permissions { get; set; } = Array.Empty(); + /// + public DateTime AddedDate { get; set; } + /// /// A logo is a small image representing the resource. /// diff --git a/back/src/Kyoo.Postgresql/DatabaseContext.cs b/back/src/Kyoo.Postgresql/DatabaseContext.cs index 46605074..23437565 100644 --- a/back/src/Kyoo.Postgresql/DatabaseContext.cs +++ b/back/src/Kyoo.Postgresql/DatabaseContext.cs @@ -190,6 +190,14 @@ namespace Kyoo.Postgresql .OwnsOne(x => x.Logo); } + private static void _HasAddedDate(ModelBuilder modelBuilder) + where T : class, IAddedDate + { + modelBuilder.Entity() + .Property(x => x.AddedDate) + .HasDefaultValueSql("now() at time zone 'utc'"); + } + /// /// Create a many to many relationship between the two entities. /// The resulting relationship will have an available method. @@ -285,6 +293,14 @@ namespace Kyoo.Postgresql _HasImages(modelBuilder); _HasImages(modelBuilder); + _HasAddedDate(modelBuilder); + _HasAddedDate(modelBuilder); + _HasAddedDate(modelBuilder); + _HasAddedDate(modelBuilder); + _HasAddedDate(modelBuilder); + _HasAddedDate(modelBuilder); + _HasAddedDate(modelBuilder); + modelBuilder.Entity().OwnsOne(x => x.Logo); modelBuilder.Entity() diff --git a/back/src/Kyoo.Postgresql/Migrations/20230907201814_added_date.Designer.cs b/back/src/Kyoo.Postgresql/Migrations/20230907201814_added_date.Designer.cs new file mode 100644 index 00000000..2f012a1a --- /dev/null +++ b/back/src/Kyoo.Postgresql/Migrations/20230907201814_added_date.Designer.cs @@ -0,0 +1,1548 @@ +// +using System; +using System.Collections.Generic; +using Kyoo.Abstractions.Models; +using Kyoo.Postgresql; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Kyoo.Postgresql.Migrations +{ + [DbContext(typeof(PostgresContext))] + [Migration("20230907201814_added_date")] + partial class AddedDate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "genre", new[] { "action", "adventure", "animation", "comedy", "crime", "documentary", "drama", "family", "fantasy", "history", "horror", "music", "mystery", "romance", "science_fiction", "thriller", "war", "western" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "item_kind", new[] { "show", "movie", "collection" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "status", new[] { "unknown", "finished", "airing", "planned" }); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Collection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.HasKey("Id") + .HasName("pk_collections"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_collections_slug"); + + b.ToTable("collections", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Episode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AbsoluteNumber") + .HasColumnType("integer") + .HasColumnName("absolute_number"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("EpisodeNumber") + .HasColumnType("integer") + .HasColumnName("episode_number"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("ReleaseDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("release_date"); + + b.Property("SeasonId") + .HasColumnType("integer") + .HasColumnName("season_id"); + + b.Property("SeasonNumber") + .HasColumnType("integer") + .HasColumnName("season_number"); + + b.Property("ShowId") + .HasColumnType("integer") + .HasColumnName("show_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.HasKey("Id") + .HasName("pk_episodes"); + + b.HasIndex("SeasonId") + .HasDatabaseName("ix_episodes_season_id"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_episodes_slug"); + + b.HasIndex("ShowId", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber") + .IsUnique() + .HasDatabaseName("ix_episodes_show_id_season_number_episode_number_absolute_numb"); + + b.ToTable("episodes", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("AirDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("air_date"); + + b.Property("Aliases") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("aliases"); + + b.Property("EndAir") + .HasColumnType("timestamp with time zone") + .HasColumnName("end_air"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Genres") + .IsRequired() + .HasColumnType("genre[]") + .HasColumnName("genres"); + + b.Property("Kind") + .HasColumnType("item_kind") + .HasColumnName("kind"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Path") + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartAir") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_air"); + + b.Property("Status") + .HasColumnType("status") + .HasColumnName("status"); + + b.Property("Tagline") + .HasColumnType("text") + .HasColumnName("tagline"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("tags"); + + b.Property("Trailer") + .HasColumnType("text") + .HasColumnName("trailer"); + + b.HasKey("Id") + .HasName("pk_library_items"); + + b.ToTable("library_items", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("AirDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("air_date"); + + b.Property("Aliases") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("aliases"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Genres") + .IsRequired() + .HasColumnType("genre[]") + .HasColumnName("genres"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("Status") + .HasColumnType("status") + .HasColumnName("status"); + + b.Property("StudioID") + .HasColumnType("integer") + .HasColumnName("studio_id"); + + b.Property("Tagline") + .HasColumnType("text") + .HasColumnName("tagline"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("tags"); + + b.Property("Trailer") + .HasColumnType("text") + .HasColumnName("trailer"); + + b.HasKey("Id") + .HasName("pk_movies"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_movies_slug"); + + b.HasIndex("StudioID") + .HasDatabaseName("ix_movies_studio_id"); + + b.ToTable("movies", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.HasKey("Id") + .HasName("pk_people"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_people_slug"); + + b.ToTable("people", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.PeopleRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("MovieID") + .HasColumnType("integer") + .HasColumnName("movie_id"); + + b.Property("PeopleID") + .HasColumnType("integer") + .HasColumnName("people_id"); + + b.Property("Role") + .IsRequired() + .HasColumnType("text") + .HasColumnName("role"); + + b.Property("ShowID") + .HasColumnType("integer") + .HasColumnName("show_id"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_people_roles"); + + b.HasIndex("MovieID") + .HasDatabaseName("ix_people_roles_movie_id"); + + b.HasIndex("PeopleID") + .HasDatabaseName("ix_people_roles_people_id"); + + b.HasIndex("ShowID") + .HasDatabaseName("ix_people_roles_show_id"); + + b.ToTable("people_roles", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Season", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("end_date"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("SeasonNumber") + .HasColumnType("integer") + .HasColumnName("season_number"); + + b.Property("ShowId") + .HasColumnType("integer") + .HasColumnName("show_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_date"); + + b.HasKey("Id") + .HasName("pk_seasons"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_seasons_slug"); + + b.HasIndex("ShowId", "SeasonNumber") + .IsUnique() + .HasDatabaseName("ix_seasons_show_id_season_number"); + + b.ToTable("seasons", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Show", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property>("Aliases") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("aliases"); + + b.Property("EndAir") + .HasColumnType("timestamp with time zone") + .HasColumnName("end_air"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property>("Genres") + .IsRequired() + .HasColumnType("genre[]") + .HasColumnName("genres"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Overview") + .HasColumnType("text") + .HasColumnName("overview"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartAir") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_air"); + + b.Property("Status") + .HasColumnType("status") + .HasColumnName("status"); + + b.Property("StudioId") + .HasColumnType("integer") + .HasColumnName("studio_id"); + + b.Property("Tagline") + .HasColumnType("text") + .HasColumnName("tagline"); + + b.Property>("Tags") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("tags"); + + b.Property("Trailer") + .HasColumnType("text") + .HasColumnName("trailer"); + + b.HasKey("Id") + .HasName("pk_shows"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_shows_slug"); + + b.HasIndex("StudioId") + .HasDatabaseName("ix_shows_studio_id"); + + b.ToTable("shows", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Studio", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.HasKey("Id") + .HasName("pk_studios"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_studios_slug"); + + b.ToTable("studios", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("Password") + .IsRequired() + .HasColumnType("text") + .HasColumnName("password"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("permissions"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_users"); + + b.HasIndex("Slug") + .IsUnique() + .HasDatabaseName("ix_users_slug"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.WatchedEpisode", b => + { + b.Property("UserID") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.Property("EpisodeID") + .HasColumnType("integer") + .HasColumnName("episode_id"); + + b.Property("WatchedPercentage") + .HasColumnType("integer") + .HasColumnName("watched_percentage"); + + b.HasKey("UserID", "EpisodeID") + .HasName("pk_watched_episode"); + + b.HasIndex("EpisodeID") + .HasDatabaseName("ix_watched_episode_episode_id"); + + b.ToTable("watched_episode", (string)null); + }); + + modelBuilder.Entity("ShowUser", b => + { + b.Property("UsersId") + .HasColumnType("integer") + .HasColumnName("users_id"); + + b.Property("WatchedId") + .HasColumnType("integer") + .HasColumnName("watched_id"); + + b.HasKey("UsersId", "WatchedId") + .HasName("pk_link_user_show"); + + b.HasIndex("WatchedId") + .HasDatabaseName("ix_link_user_show_watched_id"); + + b.ToTable("link_user_show", (string)null); + }); + + modelBuilder.Entity("link_collection_movie", b => + { + b.Property("collection_id") + .HasColumnType("integer") + .HasColumnName("collection_id"); + + b.Property("movie_id") + .HasColumnType("integer") + .HasColumnName("movie_id"); + + b.HasKey("collection_id", "movie_id") + .HasName("pk_link_collection_movie"); + + b.HasIndex("movie_id") + .HasDatabaseName("ix_link_collection_movie_movie_id"); + + b.ToTable("link_collection_movie", (string)null); + }); + + modelBuilder.Entity("link_collection_show", b => + { + b.Property("collection_id") + .HasColumnType("integer") + .HasColumnName("collection_id"); + + b.Property("show_id") + .HasColumnType("integer") + .HasColumnName("show_id"); + + b.HasKey("collection_id", "show_id") + .HasName("pk_link_collection_show"); + + b.HasIndex("show_id") + .HasDatabaseName("ix_link_collection_show_show_id"); + + b.ToTable("link_collection_show", (string)null); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Collection", b => + { + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("CollectionId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("CollectionId"); + + b1.ToTable("collections"); + + b1.WithOwner() + .HasForeignKey("CollectionId") + .HasConstraintName("fk_collections_collections_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("CollectionId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("CollectionId"); + + b1.ToTable("collections"); + + b1.WithOwner() + .HasForeignKey("CollectionId") + .HasConstraintName("fk_collections_collections_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("CollectionId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("CollectionId"); + + b1.ToTable("collections"); + + b1.WithOwner() + .HasForeignKey("CollectionId") + .HasConstraintName("fk_collections_collections_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Episode", b => + { + b.HasOne("Kyoo.Abstractions.Models.Season", "Season") + .WithMany("Episodes") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_episodes_seasons_season_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", "Show") + .WithMany("Episodes") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_episodes_shows_show_id"); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("EpisodeId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + b1.WithOwner() + .HasForeignKey("EpisodeId") + .HasConstraintName("fk_episodes_episodes_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("EpisodeId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + b1.WithOwner() + .HasForeignKey("EpisodeId") + .HasConstraintName("fk_episodes_episodes_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("EpisodeId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + b1.WithOwner() + .HasForeignKey("EpisodeId") + .HasConstraintName("fk_episodes_episodes_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Season"); + + b.Navigation("Show"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.LibraryItem", b => + { + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("LibraryItemId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("LibraryItemId"); + + b1.ToTable("library_items"); + + b1.WithOwner() + .HasForeignKey("LibraryItemId") + .HasConstraintName("fk_library_items_library_items_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => + { + b.HasOne("Kyoo.Abstractions.Models.Studio", "Studio") + .WithMany("Movies") + .HasForeignKey("StudioID") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_movies_studios_studio_id"); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("MovieId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + b1.WithOwner() + .HasForeignKey("MovieId") + .HasConstraintName("fk_movies_movies_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("MovieId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + b1.WithOwner() + .HasForeignKey("MovieId") + .HasConstraintName("fk_movies_movies_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("MovieId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + b1.WithOwner() + .HasForeignKey("MovieId") + .HasConstraintName("fk_movies_movies_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Studio"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => + { + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("PeopleId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("PeopleId"); + + b1.ToTable("people"); + + b1.WithOwner() + .HasForeignKey("PeopleId") + .HasConstraintName("fk_people_people_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("PeopleId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("PeopleId"); + + b1.ToTable("people"); + + b1.WithOwner() + .HasForeignKey("PeopleId") + .HasConstraintName("fk_people_people_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("PeopleId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("PeopleId"); + + b1.ToTable("people"); + + b1.WithOwner() + .HasForeignKey("PeopleId") + .HasConstraintName("fk_people_people_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.PeopleRole", b => + { + b.HasOne("Kyoo.Abstractions.Models.Movie", "Movie") + .WithMany("People") + .HasForeignKey("MovieID") + .HasConstraintName("fk_people_roles_movies_movie_id"); + + b.HasOne("Kyoo.Abstractions.Models.People", "People") + .WithMany("Roles") + .HasForeignKey("PeopleID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_people_roles_people_people_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", "Show") + .WithMany("People") + .HasForeignKey("ShowID") + .HasConstraintName("fk_people_roles_shows_show_id"); + + b.Navigation("Movie"); + + b.Navigation("People"); + + b.Navigation("Show"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Season", b => + { + b.HasOne("Kyoo.Abstractions.Models.Show", "Show") + .WithMany("Seasons") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_seasons_shows_show_id"); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("SeasonId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + b1.WithOwner() + .HasForeignKey("SeasonId") + .HasConstraintName("fk_seasons_seasons_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("SeasonId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + b1.WithOwner() + .HasForeignKey("SeasonId") + .HasConstraintName("fk_seasons_seasons_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("SeasonId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + b1.WithOwner() + .HasForeignKey("SeasonId") + .HasConstraintName("fk_seasons_seasons_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Show"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Show", b => + { + b.HasOne("Kyoo.Abstractions.Models.Studio", "Studio") + .WithMany("Shows") + .HasForeignKey("StudioId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_shows_studios_studio_id"); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("ShowId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + b1.WithOwner() + .HasForeignKey("ShowId") + .HasConstraintName("fk_shows_shows_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Poster", b1 => + { + b1.Property("ShowId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + b1.WithOwner() + .HasForeignKey("ShowId") + .HasConstraintName("fk_shows_shows_id"); + }); + + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Thumbnail", b1 => + { + b1.Property("ShowId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + b1.WithOwner() + .HasForeignKey("ShowId") + .HasConstraintName("fk_shows_shows_id"); + }); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Studio"); + + b.Navigation("Thumbnail"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.User", b => + { + b.OwnsOne("Kyoo.Abstractions.Models.Image", "Logo", b1 => + { + b1.Property("UserId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("UserId"); + + b1.ToTable("users"); + + b1.WithOwner() + .HasForeignKey("UserId") + .HasConstraintName("fk_users_users_id"); + }); + + b.Navigation("Logo"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.WatchedEpisode", b => + { + b.HasOne("Kyoo.Abstractions.Models.Episode", "Episode") + .WithMany() + .HasForeignKey("EpisodeID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_watched_episode_episodes_episode_id"); + + b.HasOne("Kyoo.Abstractions.Models.User", null) + .WithMany("CurrentlyWatching") + .HasForeignKey("UserID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_watched_episode_users_user_id"); + + b.Navigation("Episode"); + }); + + modelBuilder.Entity("ShowUser", b => + { + b.HasOne("Kyoo.Abstractions.Models.User", null) + .WithMany() + .HasForeignKey("UsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_user_show_users_users_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", null) + .WithMany() + .HasForeignKey("WatchedId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_user_show_shows_watched_id"); + }); + + modelBuilder.Entity("link_collection_movie", b => + { + b.HasOne("Kyoo.Abstractions.Models.Collection", null) + .WithMany() + .HasForeignKey("collection_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_movie_collections_collection_id"); + + b.HasOne("Kyoo.Abstractions.Models.Movie", null) + .WithMany() + .HasForeignKey("movie_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_movie_movies_movie_id"); + }); + + modelBuilder.Entity("link_collection_show", b => + { + b.HasOne("Kyoo.Abstractions.Models.Collection", null) + .WithMany() + .HasForeignKey("collection_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_show_collections_collection_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", null) + .WithMany() + .HasForeignKey("show_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_show_shows_show_id"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Movie", b => + { + b.Navigation("People"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.People", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Season", b => + { + b.Navigation("Episodes"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Show", b => + { + b.Navigation("Episodes"); + + b.Navigation("People"); + + b.Navigation("Seasons"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.Studio", b => + { + b.Navigation("Movies"); + + b.Navigation("Shows"); + }); + + modelBuilder.Entity("Kyoo.Abstractions.Models.User", b => + { + b.Navigation("CurrentlyWatching"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/back/src/Kyoo.Postgresql/Migrations/20230907201814_added_date.cs b/back/src/Kyoo.Postgresql/Migrations/20230907201814_added_date.cs new file mode 100644 index 00000000..2834ef4a --- /dev/null +++ b/back/src/Kyoo.Postgresql/Migrations/20230907201814_added_date.cs @@ -0,0 +1,139 @@ +// 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 Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Kyoo.Postgresql.Migrations +{ + /// + public partial class AddedDate : Items + { + public static void CreateItemView(MigrationBuilder migrationBuilder) + { + // language=PostgreSQL + migrationBuilder.Sql(@" + CREATE VIEW library_items AS + SELECT + s.id, s.slug, s.name, s.tagline, s.aliases, s.overview, s.tags, s.genres, s.status, + s.start_air, s.end_air, s.poster_source, s.poster_blurhash, s.thumbnail_source, s.thumbnail_blurhash, + s.logo_source, s.logo_blurhash, s.trailer, s.external_id, s.start_air AS air_date, NULL as path, + 'show'::item_kind AS kind, added_date + FROM shows AS s + UNION ALL + SELECT + -m.id, m.slug, m.name, m.tagline, m.aliases, m.overview, m.tags, m.genres, m.status, + m.air_date as start_air, m.air_date as end_air, m.poster_source, m.poster_blurhash, m.thumbnail_source, + m.thumbnail_blurhash, m.logo_source, m.logo_blurhash, m.trailer, m.external_id, m.air_date, m.path, + 'movie'::item_kind AS kind, added_date + FROM movies AS m + UNION ALL + SELECT + c.id + 10000 AS id, c.slug, c.name, NULL as tagline, NULL as alises, c.overview, NULL AS tags, NULL AS genres, 'unknown'::status AS status, + NULL AS start_air, NULL AS end_air, c.poster_source, c.poster_blurhash, c.thumbnail_source, + c.thumbnail_blurhash, c.logo_source, c.logo_blurhash, NULL as trailer, c.external_id, NULL AS air_date, NULL as path, + 'collection'::item_kind AS kind, added_date + FROM collections AS c + "); + } + + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + base.Down(migrationBuilder); + + migrationBuilder.AddColumn( + name: "added_date", + table: "users", + type: "timestamp with time zone", + nullable: false, + defaultValueSql: "now() at time zone 'utc'"); + + migrationBuilder.AddColumn( + name: "added_date", + table: "shows", + type: "timestamp with time zone", + nullable: false, + defaultValueSql: "now() at time zone 'utc'"); + + migrationBuilder.AddColumn( + name: "added_date", + table: "seasons", + type: "timestamp with time zone", + nullable: false, + defaultValueSql: "now() at time zone 'utc'"); + + migrationBuilder.AddColumn( + name: "added_date", + table: "movies", + type: "timestamp with time zone", + nullable: false, + defaultValueSql: "now() at time zone 'utc'"); + + migrationBuilder.AddColumn( + name: "added_date", + table: "episodes", + type: "timestamp with time zone", + nullable: false, + defaultValueSql: "now() at time zone 'utc'"); + + migrationBuilder.AddColumn( + name: "added_date", + table: "collections", + type: "timestamp with time zone", + nullable: false, + defaultValueSql: "now() at time zone 'utc'"); + + CreateItemView(migrationBuilder); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + base.Down(migrationBuilder); + + migrationBuilder.DropColumn( + name: "added_date", + table: "users"); + + migrationBuilder.DropColumn( + name: "added_date", + table: "shows"); + + migrationBuilder.DropColumn( + name: "added_date", + table: "seasons"); + + migrationBuilder.DropColumn( + name: "added_date", + table: "movies"); + + migrationBuilder.DropColumn( + name: "added_date", + table: "episodes"); + + migrationBuilder.DropColumn( + name: "added_date", + table: "collections"); + + base.Up(migrationBuilder); + } + } +} diff --git a/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs b/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs index 5ac1b0cd..b6e422b8 100644 --- a/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs +++ b/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs @@ -1,5 +1,6 @@ // using System; +using System.Collections.Generic; using Kyoo.Abstractions.Models; using Kyoo.Postgresql; using Microsoft.EntityFrameworkCore; @@ -35,6 +36,12 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + b.Property("ExternalId") .IsRequired() .HasColumnType("json") @@ -78,6 +85,12 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("integer") .HasColumnName("absolute_number"); + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + b.Property("EpisodeNumber") .HasColumnType("integer") .HasColumnName("episode_number"); @@ -104,7 +117,7 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("release_date"); - b.Property("SeasonID") + b.Property("SeasonId") .HasColumnType("integer") .HasColumnName("season_id"); @@ -112,7 +125,7 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("integer") .HasColumnName("season_number"); - b.Property("ShowID") + b.Property("ShowId") .HasColumnType("integer") .HasColumnName("show_id"); @@ -125,14 +138,14 @@ namespace Kyoo.Postgresql.Migrations b.HasKey("Id") .HasName("pk_episodes"); - b.HasIndex("SeasonID") + b.HasIndex("SeasonId") .HasDatabaseName("ix_episodes_season_id"); b.HasIndex("Slug") .IsUnique() .HasDatabaseName("ix_episodes_slug"); - b.HasIndex("ShowID", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber") + b.HasIndex("ShowId", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber") .IsUnique() .HasDatabaseName("ix_episodes_show_id_season_number_episode_number_absolute_numb"); @@ -148,6 +161,12 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + b.Property("AirDate") .HasColumnType("timestamp with time zone") .HasColumnName("air_date"); @@ -171,6 +190,10 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("genre[]") .HasColumnName("genres"); + b.Property("Kind") + .HasColumnType("item_kind") + .HasColumnName("kind"); + b.Property("Name") .IsRequired() .HasColumnType("text") @@ -181,7 +204,6 @@ namespace Kyoo.Postgresql.Migrations .HasColumnName("overview"); b.Property("Path") - .IsRequired() .HasColumnType("text") .HasColumnName("path"); @@ -227,6 +249,12 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + b.Property("AirDate") .HasColumnType("timestamp with time zone") .HasColumnName("air_date"); @@ -390,6 +418,12 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + b.Property("EndDate") .HasColumnType("timestamp with time zone") .HasColumnName("end_date"); @@ -411,7 +445,7 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("integer") .HasColumnName("season_number"); - b.Property("ShowID") + b.Property("ShowId") .HasColumnType("integer") .HasColumnName("show_id"); @@ -432,7 +466,7 @@ namespace Kyoo.Postgresql.Migrations .IsUnique() .HasDatabaseName("ix_seasons_slug"); - b.HasIndex("ShowID", "SeasonNumber") + b.HasIndex("ShowId", "SeasonNumber") .IsUnique() .HasDatabaseName("ix_seasons_show_id_season_number"); @@ -448,7 +482,13 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("Aliases") + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property>("Aliases") .IsRequired() .HasColumnType("text[]") .HasColumnName("aliases"); @@ -462,7 +502,7 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("json") .HasColumnName("external_id"); - b.Property("Genres") + b.Property>("Genres") .IsRequired() .HasColumnType("genre[]") .HasColumnName("genres"); @@ -490,7 +530,7 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("status") .HasColumnName("status"); - b.Property("StudioID") + b.Property("StudioId") .HasColumnType("integer") .HasColumnName("studio_id"); @@ -498,7 +538,7 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("text") .HasColumnName("tagline"); - b.Property("Tags") + b.Property>("Tags") .IsRequired() .HasColumnType("text[]") .HasColumnName("tags"); @@ -514,7 +554,7 @@ namespace Kyoo.Postgresql.Migrations .IsUnique() .HasDatabaseName("ix_shows_slug"); - b.HasIndex("StudioID") + b.HasIndex("StudioId") .HasDatabaseName("ix_shows_studio_id"); b.ToTable("shows", (string)null); @@ -564,6 +604,12 @@ namespace Kyoo.Postgresql.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + b.Property("Email") .IsRequired() .HasColumnType("text") @@ -771,13 +817,13 @@ namespace Kyoo.Postgresql.Migrations { b.HasOne("Kyoo.Abstractions.Models.Season", "Season") .WithMany("Episodes") - .HasForeignKey("SeasonID") + .HasForeignKey("SeasonId") .OnDelete(DeleteBehavior.Cascade) .HasConstraintName("fk_episodes_seasons_season_id"); b.HasOne("Kyoo.Abstractions.Models.Show", "Show") .WithMany("Episodes") - .HasForeignKey("ShowID") + .HasForeignKey("ShowId") .OnDelete(DeleteBehavior.Cascade) .IsRequired() .HasConstraintName("fk_episodes_shows_show_id"); @@ -1170,7 +1216,7 @@ namespace Kyoo.Postgresql.Migrations { b.HasOne("Kyoo.Abstractions.Models.Show", "Show") .WithMany("Seasons") - .HasForeignKey("ShowID") + .HasForeignKey("ShowId") .OnDelete(DeleteBehavior.Cascade) .IsRequired() .HasConstraintName("fk_seasons_shows_show_id"); @@ -1266,7 +1312,7 @@ namespace Kyoo.Postgresql.Migrations { b.HasOne("Kyoo.Abstractions.Models.Studio", "Studio") .WithMany("Shows") - .HasForeignKey("StudioID") + .HasForeignKey("StudioId") .OnDelete(DeleteBehavior.SetNull) .HasConstraintName("fk_shows_studios_studio_id");