From fcca2119a589091da3a72de573fbc771469f39ce Mon Sep 17 00:00:00 2001 From: Mateusz Skoczek Date: Thu, 28 Mar 2024 19:17:46 +0100 Subject: [PATCH] auth changes --- .../WatchIt.Database.Model/Account/Account.cs | 15 +- .../Account/AccountRefreshToken.cs | 57 + .../WatchIt.Database/DatabaseContext.cs | 2 + ...rNotRequiredAndDefaultNotAdmin.Designer.cs | 1297 ++++++++++++++++ ...003_GenderNotRequiredAndDefaultNotAdmin.cs | 77 + ...004_AccountDescriptionNullable.Designer.cs | 1296 ++++++++++++++++ ...4144605_0004_AccountDescriptionNullable.cs | 40 + ...0005_AccountRefreshTokensAdded.Designer.cs | 1331 ++++++++++++++++ ...24195235_0005_AccountRefreshTokensAdded.cs | 52 + ...006_AccountRefreshTokenChanges.Designer.cs | 1334 +++++++++++++++++ ...4205952_0006_AccountRefreshTokenChanges.cs | 39 + .../DatabaseContextModelSnapshot.cs | 49 +- .../Authenticate/AuthenticateRequest.cs | 26 + .../Authenticate/AuthenticateResponse.cs | 22 + .../Accounts/Register/RegisterRequest.cs | 27 + .../Accounts/Register/RegisterResponse.cs | 44 + .../WatchIt.Shared.Models/RequestResult.cs | 107 ++ .../RequestResultStatus.cs | 20 + .../WatchIt.Shared.Models.csproj | 18 + .../AccountsController.cs | 47 + .../WatchIt.WebAPI.Controllers.csproj | 18 + .../AccountsControllerService.cs | 88 ++ ...WatchIt.WebAPI.Services.Controllers.csproj | 20 + .../ConfigurationService.cs | 26 + .../Models/AccessToken.cs | 13 + .../Models/Authentication.cs | 16 + .../Models/ConfigurationData.cs | 13 + .../Models/RefreshToken.cs | 14 + ...bAPI.Services.Utility.Configuration.csproj | 13 + .../JWTService.cs | 131 ++ .../TokenNotExtendableException.cs | 13 + .../TokenNotFoundException.cs | 13 + ...WatchIt.WebAPI.Services.Utility.JWT.csproj | 21 + .../UserService.cs | 18 + ...atchIt.WebAPI.Services.Utility.User.csproj | 13 + .../Accounts/AuthenticateRequestValidator.cs | 26 + .../Accounts/RegisterRequestValidator.cs | 31 + .../CustomValidators.cs | 18 + .../WatchIt.WebAPI.Validators.csproj | 19 + WatchIt.sln | 59 +- WatchIt/Program.cs | 93 +- WatchIt/WatchIt.csproj | 13 + WatchIt/WebAPI/AccountsController.cs | 16 - WatchIt/appsettings.json | 20 +- genre.json | 18 - 45 files changed, 6588 insertions(+), 55 deletions(-) create mode 100644 WatchIt.Database/WatchIt.Database.Model/Account/AccountRefreshToken.cs create mode 100644 WatchIt.Database/WatchIt.Database/Migrations/20240324143239_0003_GenderNotRequiredAndDefaultNotAdmin.Designer.cs create mode 100644 WatchIt.Database/WatchIt.Database/Migrations/20240324143239_0003_GenderNotRequiredAndDefaultNotAdmin.cs create mode 100644 WatchIt.Database/WatchIt.Database/Migrations/20240324144605_0004_AccountDescriptionNullable.Designer.cs create mode 100644 WatchIt.Database/WatchIt.Database/Migrations/20240324144605_0004_AccountDescriptionNullable.cs create mode 100644 WatchIt.Database/WatchIt.Database/Migrations/20240324195235_0005_AccountRefreshTokensAdded.Designer.cs create mode 100644 WatchIt.Database/WatchIt.Database/Migrations/20240324195235_0005_AccountRefreshTokensAdded.cs create mode 100644 WatchIt.Database/WatchIt.Database/Migrations/20240324205952_0006_AccountRefreshTokenChanges.Designer.cs create mode 100644 WatchIt.Database/WatchIt.Database/Migrations/20240324205952_0006_AccountRefreshTokenChanges.cs create mode 100644 WatchIt.Shared/WatchIt.Shared.Models/Accounts/Authenticate/AuthenticateRequest.cs create mode 100644 WatchIt.Shared/WatchIt.Shared.Models/Accounts/Authenticate/AuthenticateResponse.cs create mode 100644 WatchIt.Shared/WatchIt.Shared.Models/Accounts/Register/RegisterRequest.cs create mode 100644 WatchIt.Shared/WatchIt.Shared.Models/Accounts/Register/RegisterResponse.cs create mode 100644 WatchIt.Shared/WatchIt.Shared.Models/RequestResult.cs create mode 100644 WatchIt.Shared/WatchIt.Shared.Models/RequestResultStatus.cs create mode 100644 WatchIt.Shared/WatchIt.Shared.Models/WatchIt.Shared.Models.csproj create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Controllers/AccountsController.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/AccountsControllerService.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.csproj create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/ConfigurationService.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/AccessToken.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/Authentication.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/ConfigurationData.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/RefreshToken.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/WatchIt.WebAPI.Services.Utility.Configuration.csproj create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/JWTService.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/TokenNotExtendableException.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/TokenNotFoundException.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/WatchIt.WebAPI.Services.Utility.JWT.csproj create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.User/UserService.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.User/WatchIt.WebAPI.Services.Utility.User.csproj create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Validators/Accounts/AuthenticateRequestValidator.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Validators/Accounts/RegisterRequestValidator.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Validators/CustomValidators.cs create mode 100644 WatchIt.WebAPI/WatchIt.WebAPI.Validators/WatchIt.WebAPI.Validators.csproj delete mode 100644 WatchIt/WebAPI/AccountsController.cs delete mode 100644 genre.json diff --git a/WatchIt.Database/WatchIt.Database.Model/Account/Account.cs b/WatchIt.Database/WatchIt.Database.Model/Account/Account.cs index 57ac65f..abf2064 100644 --- a/WatchIt.Database/WatchIt.Database.Model/Account/Account.cs +++ b/WatchIt.Database/WatchIt.Database.Model/Account/Account.cs @@ -22,8 +22,8 @@ namespace WatchIt.Database.Model.Account public long Id { get; set; } public string Username { get; set; } public string Email { get; set; } - public string Description { get; set; } - public short GenderId { get; set; } + public string? Description { get; set; } + public short? GenderId { get; set; } public Guid? ProfilePictureId { get; set; } public Guid? BackgroundPictureId { get; set; } public byte[] Password { get; set; } @@ -49,6 +49,8 @@ namespace WatchIt.Database.Model.Account public IEnumerable RatingMediaSeriesSeason { get; set; } public IEnumerable RatingMediaSeriesEpisode { get; set; } + public IEnumerable AccountRefreshTokens { get; set; } + #endregion @@ -76,10 +78,8 @@ namespace WatchIt.Database.Model.Account builder.HasOne(x => x.Gender) .WithMany() - .HasForeignKey(x => x.GenderId) - .IsRequired(); - builder.Property(x => x.GenderId) - .IsRequired(); + .HasForeignKey(x => x.GenderId); + builder.Property(x => x.GenderId); builder.HasOne(x => x.ProfilePicture) .WithOne(x => x.Account) @@ -104,7 +104,8 @@ namespace WatchIt.Database.Model.Account .IsRequired(); builder.Property(x => x.IsAdmin) - .IsRequired(); + .IsRequired() + .HasDefaultValue(false); builder.Property(x => x.CreationDate) .IsRequired() diff --git a/WatchIt.Database/WatchIt.Database.Model/Account/AccountRefreshToken.cs b/WatchIt.Database/WatchIt.Database.Model/Account/AccountRefreshToken.cs new file mode 100644 index 0000000..92aac22 --- /dev/null +++ b/WatchIt.Database/WatchIt.Database.Model/Account/AccountRefreshToken.cs @@ -0,0 +1,57 @@ +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WatchIt.Database.Model.Account +{ + public class AccountRefreshToken : IEntity + { + #region PROPERTIES + + public Guid Id { get; set; } + public long AccountId { get; set; } + public DateTime ExpirationDate { get; set; } + public bool IsExtendable { get; set; } + + #endregion + + + + #region NAVIGATION + + public Account Account { get; set; } + + #endregion + + + + #region PUBLIC METHODS + + static void IEntity.Build(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + builder.HasIndex(x => x.Id) + .IsUnique(); + builder.Property(x => x.Id) + .IsRequired(); + + builder.HasOne(x => x.Account) + .WithMany(x => x.AccountRefreshTokens) + .HasForeignKey(x => x.AccountId) + .IsRequired(); + builder.Property(x => x.AccountId) + .IsRequired(); + + builder.Property(x => x.ExpirationDate) + .IsRequired(); + + builder.Property(x => x.IsExtendable) + .IsRequired(); + } + + #endregion + } +} diff --git a/WatchIt.Database/WatchIt.Database/DatabaseContext.cs b/WatchIt.Database/WatchIt.Database/DatabaseContext.cs index b519f43..da01176 100644 --- a/WatchIt.Database/WatchIt.Database/DatabaseContext.cs +++ b/WatchIt.Database/WatchIt.Database/DatabaseContext.cs @@ -37,6 +37,7 @@ namespace WatchIt.Database // Account public virtual DbSet Accounts { get; set; } public virtual DbSet AccountProfilePictures { get; set; } + public virtual DbSet AccountRefreshTokens { get; set; } // Media public virtual DbSet Media { get; set; } @@ -87,6 +88,7 @@ namespace WatchIt.Database // Account EntityBuilder.Build(modelBuilder); EntityBuilder.Build(modelBuilder); + EntityBuilder.Build(modelBuilder); // Media EntityBuilder.Build(modelBuilder); diff --git a/WatchIt.Database/WatchIt.Database/Migrations/20240324143239_0003_GenderNotRequiredAndDefaultNotAdmin.Designer.cs b/WatchIt.Database/WatchIt.Database/Migrations/20240324143239_0003_GenderNotRequiredAndDefaultNotAdmin.Designer.cs new file mode 100644 index 0000000..e4bfd8b --- /dev/null +++ b/WatchIt.Database/WatchIt.Database/Migrations/20240324143239_0003_GenderNotRequiredAndDefaultNotAdmin.Designer.cs @@ -0,0 +1,1297 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using WatchIt.Database; + +#nullable disable + +namespace WatchIt.Database.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20240324143239_0003_GenderNotRequiredAndDefaultNotAdmin")] + partial class _0003_GenderNotRequiredAndDefaultNotAdmin + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BackgroundPictureId") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("GenderId") + .HasColumnType("smallint"); + + b.Property("IsAdmin") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("LastActive") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("LeftSalt") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("bytea"); + + b.Property("ProfilePictureId") + .HasColumnType("uuid"); + + b.Property("RightSalt") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("BackgroundPictureId"); + + b.HasIndex("GenderId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("ProfilePictureId") + .IsUnique(); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountProfilePicture", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("AccountProfilePictures"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Country", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Countries"); + + b.HasData( + new + { + Id = (short)1, + Name = "Afghanistan" + }, + new + { + Id = (short)2, + Name = "Albania" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Gender", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Genders"); + + b.HasData( + new + { + Id = (short)1, + Name = "Male" + }, + new + { + Id = (short)2, + Name = "Female" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Genres"); + + b.HasData( + new + { + Id = (short)1, + Name = "Comedy" + }, + new + { + Id = (short)2, + Name = "Thriller" + }, + new + { + Id = (short)3, + Name = "Horror" + }, + new + { + Id = (short)4, + Name = "Action" + }, + new + { + Id = (short)5, + Name = "Drama" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Length") + .HasColumnType("interval"); + + b.Property("MediaPosterImageId") + .HasColumnType("uuid"); + + b.Property("OriginalTitle") + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("ReleaseDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaPosterImageId") + .IsUnique(); + + b.ToTable("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaGenre", b => + { + b.Property("GenreId") + .HasColumnType("smallint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.HasKey("GenreId", "MediaId"); + + b.HasIndex("MediaId"); + + b.ToTable("MediaGenres"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaMovie", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Budget") + .HasColumnType("money"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaMovies"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("IsMediaBackground") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("IsUniversalBackground") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("MediaPhotoImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaPosterImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b => + { + b.Property("CountryId") + .HasColumnType("smallint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.HasKey("CountryId", "MediaId"); + + b.HasIndex("MediaId"); + + b.ToTable("MediaProductionCountrys"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("HasEnded") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaSeries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsSpecial") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("MediaSeriesSeasonId") + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesSeasonId"); + + b.ToTable("MediaSeriesEpisodes"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaSeriesId") + .HasColumnType("bigint"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesId"); + + b.ToTable("MediaSeriesSeasons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BirthDate") + .HasColumnType("date"); + + b.Property("DeathDate") + .HasColumnType("date"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("FullName") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("GenderId") + .HasColumnType("smallint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PersonPhotoId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GenderId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonPhotoId") + .IsUnique(); + + b.ToTable("Persons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("PersonActorRoleTypeId") + .HasColumnType("smallint"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.HasIndex("PersonActorRoleTypeId"); + + b.HasIndex("PersonId"); + + b.ToTable("PersonActorRoles"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRoleType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonActorRoleTypes"); + + b.HasData( + new + { + Id = (short)1, + Name = "Actor" + }, + new + { + Id = (short)2, + Name = "Supporting actor" + }, + new + { + Id = (short)3, + Name = "Voice actor" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("PersonCreatorRoleTypeId") + .HasColumnType("smallint"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.HasIndex("PersonCreatorRoleTypeId"); + + b.HasIndex("PersonId"); + + b.ToTable("PersonCreatorRoles"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRoleType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonCreatorRoleTypes"); + + b.HasData( + new + { + Id = (short)1, + Name = "Director" + }, + new + { + Id = (short)2, + Name = "Producer" + }, + new + { + Id = (short)3, + Name = "Screenwriter" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonPhotoImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonPhotoImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMedia", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("RatingsMedia"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaSeriesEpisodeId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesEpisodeId"); + + b.ToTable("RatingsMediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesSeason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaSeriesSeasonId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesSeasonId"); + + b.ToTable("RatingsMediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonActorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("PersonActorRoleId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonActorRoleId"); + + b.ToTable("RatingsPersonActorRole", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonCreatorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("PersonCreatorRoleId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonCreatorRoleId"); + + b.ToTable("RatingsPersonCreatorRole", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountMedia", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Date") + .ValueGeneratedOnAdd() + .HasColumnType("date") + .HasDefaultValueSql("now()"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("ViewCount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("ViewCountsMedia", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountPerson", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Date") + .ValueGeneratedOnAdd() + .HasColumnType("date") + .HasDefaultValueSql("now()"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.Property("ViewCount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonId"); + + b.ToTable("ViewCountsPerson", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaPhotoImage", "BackgroundPicture") + .WithMany() + .HasForeignKey("BackgroundPictureId"); + + b.HasOne("WatchIt.Database.Model.Common.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId"); + + b.HasOne("WatchIt.Database.Model.Account.AccountProfilePicture", "ProfilePicture") + .WithOne("Account") + .HasForeignKey("WatchIt.Database.Model.Account.Account", "ProfilePictureId"); + + b.Navigation("BackgroundPicture"); + + b.Navigation("Gender"); + + b.Navigation("ProfilePicture"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaMovie", null) + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeries", null) + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaPosterImage", "MediaPosterImage") + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "MediaPosterImageId"); + + b.Navigation("MediaPosterImage"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaGenre", b => + { + b.HasOne("WatchIt.Database.Model.Common.Genre", "Genre") + .WithMany("MediaGenres") + .HasForeignKey("GenreId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaGenres") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Genre"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImage", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaPhotoImages") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b => + { + b.HasOne("WatchIt.Database.Model.Common.Country", "Country") + .WithMany("MediaProductionCountries") + .HasForeignKey("CountryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaProductionCountries") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Country"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesSeason", "MediaSeriesSeason") + .WithMany("MediaSeriesEpisodes") + .HasForeignKey("MediaSeriesSeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaSeries", "MediaSeries") + .WithMany("MediaSeriesSeasons") + .HasForeignKey("MediaSeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaSeries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.HasOne("WatchIt.Database.Model.Common.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonPhotoImage", "PersonPhoto") + .WithOne("Person") + .HasForeignKey("WatchIt.Database.Model.Person.Person", "PersonPhotoId"); + + b.Navigation("Gender"); + + b.Navigation("PersonPhoto"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("PersonActorRoles") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonActorRoleType", "PersonActorRoleType") + .WithMany() + .HasForeignKey("PersonActorRoleTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("PersonActorRoles") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + + b.Navigation("Person"); + + b.Navigation("PersonActorRoleType"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("PersonCreatorRoles") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonCreatorRoleType", "PersonCreatorRoleType") + .WithMany() + .HasForeignKey("PersonCreatorRoleTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("PersonCreatorRoles") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + + b.Navigation("Person"); + + b.Navigation("PersonCreatorRoleType"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMedia", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMedia") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("RatingMedia") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesEpisode", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMediaSeriesEpisode") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesEpisode", "MediaSeriesEpisode") + .WithMany("RatingMediaSeriesEpisode") + .HasForeignKey("MediaSeriesEpisodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("MediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesSeason", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMediaSeriesSeason") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesSeason", "MediaSeriesSeason") + .WithMany("RatingMediaSeriesSeason") + .HasForeignKey("MediaSeriesSeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("MediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonActorRole", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingPersonActorRole") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonActorRole", "PersonActorRole") + .WithMany("RatingPersonActorRole") + .HasForeignKey("PersonActorRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("PersonActorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonCreatorRole", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingPersonCreatorRole") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonCreatorRole", "PersonCreatorRole") + .WithMany("RatingPersonCreatorRole") + .HasForeignKey("PersonCreatorRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("PersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountMedia", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("ViewCountsMedia") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountPerson", b => + { + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("ViewCountsPerson") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Person"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.Navigation("RatingMedia"); + + b.Navigation("RatingMediaSeriesEpisode"); + + b.Navigation("RatingMediaSeriesSeason"); + + b.Navigation("RatingPersonActorRole"); + + b.Navigation("RatingPersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountProfilePicture", b => + { + b.Navigation("Account") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Country", b => + { + b.Navigation("MediaProductionCountries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Genre", b => + { + b.Navigation("MediaGenres"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.Navigation("MediaGenres"); + + b.Navigation("MediaPhotoImages"); + + b.Navigation("MediaProductionCountries"); + + b.Navigation("PersonActorRoles"); + + b.Navigation("PersonCreatorRoles"); + + b.Navigation("RatingMedia"); + + b.Navigation("ViewCountsMedia"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaMovie", b => + { + b.Navigation("Media") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b => + { + b.Navigation("Media") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b => + { + b.Navigation("Media") + .IsRequired(); + + b.Navigation("MediaSeriesSeasons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.Navigation("RatingMediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.Navigation("MediaSeriesEpisodes"); + + b.Navigation("RatingMediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.Navigation("PersonActorRoles"); + + b.Navigation("PersonCreatorRoles"); + + b.Navigation("ViewCountsPerson"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.Navigation("RatingPersonActorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.Navigation("RatingPersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonPhotoImage", b => + { + b.Navigation("Person") + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WatchIt.Database/WatchIt.Database/Migrations/20240324143239_0003_GenderNotRequiredAndDefaultNotAdmin.cs b/WatchIt.Database/WatchIt.Database/Migrations/20240324143239_0003_GenderNotRequiredAndDefaultNotAdmin.cs new file mode 100644 index 0000000..9c843f9 --- /dev/null +++ b/WatchIt.Database/WatchIt.Database/Migrations/20240324143239_0003_GenderNotRequiredAndDefaultNotAdmin.cs @@ -0,0 +1,77 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace WatchIt.Database.Migrations +{ + /// + public partial class _0003_GenderNotRequiredAndDefaultNotAdmin : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Accounts_Genders_GenderId", + table: "Accounts"); + + migrationBuilder.AlterColumn( + name: "IsAdmin", + table: "Accounts", + type: "boolean", + nullable: false, + defaultValue: false, + oldClrType: typeof(bool), + oldType: "boolean"); + + migrationBuilder.AlterColumn( + name: "GenderId", + table: "Accounts", + type: "smallint", + nullable: true, + oldClrType: typeof(short), + oldType: "smallint"); + + migrationBuilder.AddForeignKey( + name: "FK_Accounts_Genders_GenderId", + table: "Accounts", + column: "GenderId", + principalTable: "Genders", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Accounts_Genders_GenderId", + table: "Accounts"); + + migrationBuilder.AlterColumn( + name: "IsAdmin", + table: "Accounts", + type: "boolean", + nullable: false, + oldClrType: typeof(bool), + oldType: "boolean", + oldDefaultValue: false); + + migrationBuilder.AlterColumn( + name: "GenderId", + table: "Accounts", + type: "smallint", + nullable: false, + defaultValue: (short)0, + oldClrType: typeof(short), + oldType: "smallint", + oldNullable: true); + + migrationBuilder.AddForeignKey( + name: "FK_Accounts_Genders_GenderId", + table: "Accounts", + column: "GenderId", + principalTable: "Genders", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/WatchIt.Database/WatchIt.Database/Migrations/20240324144605_0004_AccountDescriptionNullable.Designer.cs b/WatchIt.Database/WatchIt.Database/Migrations/20240324144605_0004_AccountDescriptionNullable.Designer.cs new file mode 100644 index 0000000..77f4446 --- /dev/null +++ b/WatchIt.Database/WatchIt.Database/Migrations/20240324144605_0004_AccountDescriptionNullable.Designer.cs @@ -0,0 +1,1296 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using WatchIt.Database; + +#nullable disable + +namespace WatchIt.Database.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20240324144605_0004_AccountDescriptionNullable")] + partial class _0004_AccountDescriptionNullable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BackgroundPictureId") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("GenderId") + .HasColumnType("smallint"); + + b.Property("IsAdmin") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("LastActive") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("LeftSalt") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("bytea"); + + b.Property("ProfilePictureId") + .HasColumnType("uuid"); + + b.Property("RightSalt") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("BackgroundPictureId"); + + b.HasIndex("GenderId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("ProfilePictureId") + .IsUnique(); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountProfilePicture", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("AccountProfilePictures"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Country", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Countries"); + + b.HasData( + new + { + Id = (short)1, + Name = "Afghanistan" + }, + new + { + Id = (short)2, + Name = "Albania" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Gender", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Genders"); + + b.HasData( + new + { + Id = (short)1, + Name = "Male" + }, + new + { + Id = (short)2, + Name = "Female" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Genres"); + + b.HasData( + new + { + Id = (short)1, + Name = "Comedy" + }, + new + { + Id = (short)2, + Name = "Thriller" + }, + new + { + Id = (short)3, + Name = "Horror" + }, + new + { + Id = (short)4, + Name = "Action" + }, + new + { + Id = (short)5, + Name = "Drama" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Length") + .HasColumnType("interval"); + + b.Property("MediaPosterImageId") + .HasColumnType("uuid"); + + b.Property("OriginalTitle") + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("ReleaseDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaPosterImageId") + .IsUnique(); + + b.ToTable("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaGenre", b => + { + b.Property("GenreId") + .HasColumnType("smallint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.HasKey("GenreId", "MediaId"); + + b.HasIndex("MediaId"); + + b.ToTable("MediaGenres"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaMovie", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Budget") + .HasColumnType("money"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaMovies"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("IsMediaBackground") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("IsUniversalBackground") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("MediaPhotoImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaPosterImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b => + { + b.Property("CountryId") + .HasColumnType("smallint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.HasKey("CountryId", "MediaId"); + + b.HasIndex("MediaId"); + + b.ToTable("MediaProductionCountrys"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("HasEnded") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaSeries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsSpecial") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("MediaSeriesSeasonId") + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesSeasonId"); + + b.ToTable("MediaSeriesEpisodes"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaSeriesId") + .HasColumnType("bigint"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesId"); + + b.ToTable("MediaSeriesSeasons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BirthDate") + .HasColumnType("date"); + + b.Property("DeathDate") + .HasColumnType("date"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("FullName") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("GenderId") + .HasColumnType("smallint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PersonPhotoId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GenderId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonPhotoId") + .IsUnique(); + + b.ToTable("Persons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("PersonActorRoleTypeId") + .HasColumnType("smallint"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.HasIndex("PersonActorRoleTypeId"); + + b.HasIndex("PersonId"); + + b.ToTable("PersonActorRoles"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRoleType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonActorRoleTypes"); + + b.HasData( + new + { + Id = (short)1, + Name = "Actor" + }, + new + { + Id = (short)2, + Name = "Supporting actor" + }, + new + { + Id = (short)3, + Name = "Voice actor" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("PersonCreatorRoleTypeId") + .HasColumnType("smallint"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.HasIndex("PersonCreatorRoleTypeId"); + + b.HasIndex("PersonId"); + + b.ToTable("PersonCreatorRoles"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRoleType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonCreatorRoleTypes"); + + b.HasData( + new + { + Id = (short)1, + Name = "Director" + }, + new + { + Id = (short)2, + Name = "Producer" + }, + new + { + Id = (short)3, + Name = "Screenwriter" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonPhotoImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonPhotoImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMedia", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("RatingsMedia"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaSeriesEpisodeId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesEpisodeId"); + + b.ToTable("RatingsMediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesSeason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaSeriesSeasonId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesSeasonId"); + + b.ToTable("RatingsMediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonActorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("PersonActorRoleId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonActorRoleId"); + + b.ToTable("RatingsPersonActorRole", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonCreatorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("PersonCreatorRoleId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonCreatorRoleId"); + + b.ToTable("RatingsPersonCreatorRole", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountMedia", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Date") + .ValueGeneratedOnAdd() + .HasColumnType("date") + .HasDefaultValueSql("now()"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("ViewCount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("ViewCountsMedia", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountPerson", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Date") + .ValueGeneratedOnAdd() + .HasColumnType("date") + .HasDefaultValueSql("now()"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.Property("ViewCount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonId"); + + b.ToTable("ViewCountsPerson", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaPhotoImage", "BackgroundPicture") + .WithMany() + .HasForeignKey("BackgroundPictureId"); + + b.HasOne("WatchIt.Database.Model.Common.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId"); + + b.HasOne("WatchIt.Database.Model.Account.AccountProfilePicture", "ProfilePicture") + .WithOne("Account") + .HasForeignKey("WatchIt.Database.Model.Account.Account", "ProfilePictureId"); + + b.Navigation("BackgroundPicture"); + + b.Navigation("Gender"); + + b.Navigation("ProfilePicture"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaMovie", null) + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeries", null) + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaPosterImage", "MediaPosterImage") + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "MediaPosterImageId"); + + b.Navigation("MediaPosterImage"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaGenre", b => + { + b.HasOne("WatchIt.Database.Model.Common.Genre", "Genre") + .WithMany("MediaGenres") + .HasForeignKey("GenreId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaGenres") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Genre"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImage", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaPhotoImages") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b => + { + b.HasOne("WatchIt.Database.Model.Common.Country", "Country") + .WithMany("MediaProductionCountries") + .HasForeignKey("CountryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaProductionCountries") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Country"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesSeason", "MediaSeriesSeason") + .WithMany("MediaSeriesEpisodes") + .HasForeignKey("MediaSeriesSeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaSeries", "MediaSeries") + .WithMany("MediaSeriesSeasons") + .HasForeignKey("MediaSeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaSeries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.HasOne("WatchIt.Database.Model.Common.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonPhotoImage", "PersonPhoto") + .WithOne("Person") + .HasForeignKey("WatchIt.Database.Model.Person.Person", "PersonPhotoId"); + + b.Navigation("Gender"); + + b.Navigation("PersonPhoto"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("PersonActorRoles") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonActorRoleType", "PersonActorRoleType") + .WithMany() + .HasForeignKey("PersonActorRoleTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("PersonActorRoles") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + + b.Navigation("Person"); + + b.Navigation("PersonActorRoleType"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("PersonCreatorRoles") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonCreatorRoleType", "PersonCreatorRoleType") + .WithMany() + .HasForeignKey("PersonCreatorRoleTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("PersonCreatorRoles") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + + b.Navigation("Person"); + + b.Navigation("PersonCreatorRoleType"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMedia", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMedia") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("RatingMedia") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesEpisode", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMediaSeriesEpisode") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesEpisode", "MediaSeriesEpisode") + .WithMany("RatingMediaSeriesEpisode") + .HasForeignKey("MediaSeriesEpisodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("MediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesSeason", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMediaSeriesSeason") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesSeason", "MediaSeriesSeason") + .WithMany("RatingMediaSeriesSeason") + .HasForeignKey("MediaSeriesSeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("MediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonActorRole", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingPersonActorRole") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonActorRole", "PersonActorRole") + .WithMany("RatingPersonActorRole") + .HasForeignKey("PersonActorRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("PersonActorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonCreatorRole", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingPersonCreatorRole") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonCreatorRole", "PersonCreatorRole") + .WithMany("RatingPersonCreatorRole") + .HasForeignKey("PersonCreatorRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("PersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountMedia", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("ViewCountsMedia") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountPerson", b => + { + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("ViewCountsPerson") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Person"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.Navigation("RatingMedia"); + + b.Navigation("RatingMediaSeriesEpisode"); + + b.Navigation("RatingMediaSeriesSeason"); + + b.Navigation("RatingPersonActorRole"); + + b.Navigation("RatingPersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountProfilePicture", b => + { + b.Navigation("Account") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Country", b => + { + b.Navigation("MediaProductionCountries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Genre", b => + { + b.Navigation("MediaGenres"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.Navigation("MediaGenres"); + + b.Navigation("MediaPhotoImages"); + + b.Navigation("MediaProductionCountries"); + + b.Navigation("PersonActorRoles"); + + b.Navigation("PersonCreatorRoles"); + + b.Navigation("RatingMedia"); + + b.Navigation("ViewCountsMedia"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaMovie", b => + { + b.Navigation("Media") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b => + { + b.Navigation("Media") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b => + { + b.Navigation("Media") + .IsRequired(); + + b.Navigation("MediaSeriesSeasons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.Navigation("RatingMediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.Navigation("MediaSeriesEpisodes"); + + b.Navigation("RatingMediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.Navigation("PersonActorRoles"); + + b.Navigation("PersonCreatorRoles"); + + b.Navigation("ViewCountsPerson"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.Navigation("RatingPersonActorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.Navigation("RatingPersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonPhotoImage", b => + { + b.Navigation("Person") + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WatchIt.Database/WatchIt.Database/Migrations/20240324144605_0004_AccountDescriptionNullable.cs b/WatchIt.Database/WatchIt.Database/Migrations/20240324144605_0004_AccountDescriptionNullable.cs new file mode 100644 index 0000000..db5b153 --- /dev/null +++ b/WatchIt.Database/WatchIt.Database/Migrations/20240324144605_0004_AccountDescriptionNullable.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace WatchIt.Database.Migrations +{ + /// + public partial class _0004_AccountDescriptionNullable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Description", + table: "Accounts", + type: "character varying(1000)", + maxLength: 1000, + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(1000)", + oldMaxLength: 1000); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Description", + table: "Accounts", + type: "character varying(1000)", + maxLength: 1000, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "character varying(1000)", + oldMaxLength: 1000, + oldNullable: true); + } + } +} diff --git a/WatchIt.Database/WatchIt.Database/Migrations/20240324195235_0005_AccountRefreshTokensAdded.Designer.cs b/WatchIt.Database/WatchIt.Database/Migrations/20240324195235_0005_AccountRefreshTokensAdded.Designer.cs new file mode 100644 index 0000000..eadf7d4 --- /dev/null +++ b/WatchIt.Database/WatchIt.Database/Migrations/20240324195235_0005_AccountRefreshTokensAdded.Designer.cs @@ -0,0 +1,1331 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using WatchIt.Database; + +#nullable disable + +namespace WatchIt.Database.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20240324195235_0005_AccountRefreshTokensAdded")] + partial class _0005_AccountRefreshTokensAdded + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BackgroundPictureId") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("GenderId") + .HasColumnType("smallint"); + + b.Property("IsAdmin") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("LastActive") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("LeftSalt") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("bytea"); + + b.Property("ProfilePictureId") + .HasColumnType("uuid"); + + b.Property("RightSalt") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("BackgroundPictureId"); + + b.HasIndex("GenderId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("ProfilePictureId") + .IsUnique(); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountProfilePicture", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("AccountProfilePictures"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountRefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("Lifetime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("AccountRefreshTokens"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Country", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Countries"); + + b.HasData( + new + { + Id = (short)1, + Name = "Afghanistan" + }, + new + { + Id = (short)2, + Name = "Albania" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Gender", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Genders"); + + b.HasData( + new + { + Id = (short)1, + Name = "Male" + }, + new + { + Id = (short)2, + Name = "Female" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Genres"); + + b.HasData( + new + { + Id = (short)1, + Name = "Comedy" + }, + new + { + Id = (short)2, + Name = "Thriller" + }, + new + { + Id = (short)3, + Name = "Horror" + }, + new + { + Id = (short)4, + Name = "Action" + }, + new + { + Id = (short)5, + Name = "Drama" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Length") + .HasColumnType("interval"); + + b.Property("MediaPosterImageId") + .HasColumnType("uuid"); + + b.Property("OriginalTitle") + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("ReleaseDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaPosterImageId") + .IsUnique(); + + b.ToTable("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaGenre", b => + { + b.Property("GenreId") + .HasColumnType("smallint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.HasKey("GenreId", "MediaId"); + + b.HasIndex("MediaId"); + + b.ToTable("MediaGenres"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaMovie", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Budget") + .HasColumnType("money"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaMovies"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("IsMediaBackground") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("IsUniversalBackground") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("MediaPhotoImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaPosterImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b => + { + b.Property("CountryId") + .HasColumnType("smallint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.HasKey("CountryId", "MediaId"); + + b.HasIndex("MediaId"); + + b.ToTable("MediaProductionCountrys"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("HasEnded") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaSeries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsSpecial") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("MediaSeriesSeasonId") + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesSeasonId"); + + b.ToTable("MediaSeriesEpisodes"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaSeriesId") + .HasColumnType("bigint"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesId"); + + b.ToTable("MediaSeriesSeasons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BirthDate") + .HasColumnType("date"); + + b.Property("DeathDate") + .HasColumnType("date"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("FullName") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("GenderId") + .HasColumnType("smallint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PersonPhotoId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GenderId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonPhotoId") + .IsUnique(); + + b.ToTable("Persons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("PersonActorRoleTypeId") + .HasColumnType("smallint"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.HasIndex("PersonActorRoleTypeId"); + + b.HasIndex("PersonId"); + + b.ToTable("PersonActorRoles"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRoleType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonActorRoleTypes"); + + b.HasData( + new + { + Id = (short)1, + Name = "Actor" + }, + new + { + Id = (short)2, + Name = "Supporting actor" + }, + new + { + Id = (short)3, + Name = "Voice actor" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("PersonCreatorRoleTypeId") + .HasColumnType("smallint"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.HasIndex("PersonCreatorRoleTypeId"); + + b.HasIndex("PersonId"); + + b.ToTable("PersonCreatorRoles"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRoleType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonCreatorRoleTypes"); + + b.HasData( + new + { + Id = (short)1, + Name = "Director" + }, + new + { + Id = (short)2, + Name = "Producer" + }, + new + { + Id = (short)3, + Name = "Screenwriter" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonPhotoImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonPhotoImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMedia", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("RatingsMedia"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaSeriesEpisodeId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesEpisodeId"); + + b.ToTable("RatingsMediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesSeason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaSeriesSeasonId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesSeasonId"); + + b.ToTable("RatingsMediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonActorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("PersonActorRoleId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonActorRoleId"); + + b.ToTable("RatingsPersonActorRole", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonCreatorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("PersonCreatorRoleId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonCreatorRoleId"); + + b.ToTable("RatingsPersonCreatorRole", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountMedia", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Date") + .ValueGeneratedOnAdd() + .HasColumnType("date") + .HasDefaultValueSql("now()"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("ViewCount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("ViewCountsMedia", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountPerson", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Date") + .ValueGeneratedOnAdd() + .HasColumnType("date") + .HasDefaultValueSql("now()"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.Property("ViewCount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonId"); + + b.ToTable("ViewCountsPerson", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaPhotoImage", "BackgroundPicture") + .WithMany() + .HasForeignKey("BackgroundPictureId"); + + b.HasOne("WatchIt.Database.Model.Common.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId"); + + b.HasOne("WatchIt.Database.Model.Account.AccountProfilePicture", "ProfilePicture") + .WithOne("Account") + .HasForeignKey("WatchIt.Database.Model.Account.Account", "ProfilePictureId"); + + b.Navigation("BackgroundPicture"); + + b.Navigation("Gender"); + + b.Navigation("ProfilePicture"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountRefreshToken", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("AccountRefreshTokens") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaMovie", null) + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeries", null) + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaPosterImage", "MediaPosterImage") + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "MediaPosterImageId"); + + b.Navigation("MediaPosterImage"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaGenre", b => + { + b.HasOne("WatchIt.Database.Model.Common.Genre", "Genre") + .WithMany("MediaGenres") + .HasForeignKey("GenreId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaGenres") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Genre"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImage", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaPhotoImages") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b => + { + b.HasOne("WatchIt.Database.Model.Common.Country", "Country") + .WithMany("MediaProductionCountries") + .HasForeignKey("CountryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaProductionCountries") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Country"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesSeason", "MediaSeriesSeason") + .WithMany("MediaSeriesEpisodes") + .HasForeignKey("MediaSeriesSeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaSeries", "MediaSeries") + .WithMany("MediaSeriesSeasons") + .HasForeignKey("MediaSeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaSeries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.HasOne("WatchIt.Database.Model.Common.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonPhotoImage", "PersonPhoto") + .WithOne("Person") + .HasForeignKey("WatchIt.Database.Model.Person.Person", "PersonPhotoId"); + + b.Navigation("Gender"); + + b.Navigation("PersonPhoto"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("PersonActorRoles") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonActorRoleType", "PersonActorRoleType") + .WithMany() + .HasForeignKey("PersonActorRoleTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("PersonActorRoles") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + + b.Navigation("Person"); + + b.Navigation("PersonActorRoleType"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("PersonCreatorRoles") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonCreatorRoleType", "PersonCreatorRoleType") + .WithMany() + .HasForeignKey("PersonCreatorRoleTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("PersonCreatorRoles") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + + b.Navigation("Person"); + + b.Navigation("PersonCreatorRoleType"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMedia", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMedia") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("RatingMedia") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesEpisode", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMediaSeriesEpisode") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesEpisode", "MediaSeriesEpisode") + .WithMany("RatingMediaSeriesEpisode") + .HasForeignKey("MediaSeriesEpisodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("MediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesSeason", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMediaSeriesSeason") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesSeason", "MediaSeriesSeason") + .WithMany("RatingMediaSeriesSeason") + .HasForeignKey("MediaSeriesSeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("MediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonActorRole", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingPersonActorRole") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonActorRole", "PersonActorRole") + .WithMany("RatingPersonActorRole") + .HasForeignKey("PersonActorRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("PersonActorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonCreatorRole", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingPersonCreatorRole") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonCreatorRole", "PersonCreatorRole") + .WithMany("RatingPersonCreatorRole") + .HasForeignKey("PersonCreatorRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("PersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountMedia", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("ViewCountsMedia") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountPerson", b => + { + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("ViewCountsPerson") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Person"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.Navigation("AccountRefreshTokens"); + + b.Navigation("RatingMedia"); + + b.Navigation("RatingMediaSeriesEpisode"); + + b.Navigation("RatingMediaSeriesSeason"); + + b.Navigation("RatingPersonActorRole"); + + b.Navigation("RatingPersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountProfilePicture", b => + { + b.Navigation("Account") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Country", b => + { + b.Navigation("MediaProductionCountries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Genre", b => + { + b.Navigation("MediaGenres"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.Navigation("MediaGenres"); + + b.Navigation("MediaPhotoImages"); + + b.Navigation("MediaProductionCountries"); + + b.Navigation("PersonActorRoles"); + + b.Navigation("PersonCreatorRoles"); + + b.Navigation("RatingMedia"); + + b.Navigation("ViewCountsMedia"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaMovie", b => + { + b.Navigation("Media") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b => + { + b.Navigation("Media") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b => + { + b.Navigation("Media") + .IsRequired(); + + b.Navigation("MediaSeriesSeasons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.Navigation("RatingMediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.Navigation("MediaSeriesEpisodes"); + + b.Navigation("RatingMediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.Navigation("PersonActorRoles"); + + b.Navigation("PersonCreatorRoles"); + + b.Navigation("ViewCountsPerson"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.Navigation("RatingPersonActorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.Navigation("RatingPersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonPhotoImage", b => + { + b.Navigation("Person") + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WatchIt.Database/WatchIt.Database/Migrations/20240324195235_0005_AccountRefreshTokensAdded.cs b/WatchIt.Database/WatchIt.Database/Migrations/20240324195235_0005_AccountRefreshTokensAdded.cs new file mode 100644 index 0000000..7e5f5cf --- /dev/null +++ b/WatchIt.Database/WatchIt.Database/Migrations/20240324195235_0005_AccountRefreshTokensAdded.cs @@ -0,0 +1,52 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace WatchIt.Database.Migrations +{ + /// + public partial class _0005_AccountRefreshTokensAdded : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AccountRefreshTokens", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + AccountId = table.Column(type: "bigint", nullable: false), + Lifetime = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AccountRefreshTokens", x => x.Id); + table.ForeignKey( + name: "FK_AccountRefreshTokens_Accounts_AccountId", + column: x => x.AccountId, + principalTable: "Accounts", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AccountRefreshTokens_AccountId", + table: "AccountRefreshTokens", + column: "AccountId"); + + migrationBuilder.CreateIndex( + name: "IX_AccountRefreshTokens_Id", + table: "AccountRefreshTokens", + column: "Id", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AccountRefreshTokens"); + } + } +} diff --git a/WatchIt.Database/WatchIt.Database/Migrations/20240324205952_0006_AccountRefreshTokenChanges.Designer.cs b/WatchIt.Database/WatchIt.Database/Migrations/20240324205952_0006_AccountRefreshTokenChanges.Designer.cs new file mode 100644 index 0000000..df17bdb --- /dev/null +++ b/WatchIt.Database/WatchIt.Database/Migrations/20240324205952_0006_AccountRefreshTokenChanges.Designer.cs @@ -0,0 +1,1334 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using WatchIt.Database; + +#nullable disable + +namespace WatchIt.Database.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20240324205952_0006_AccountRefreshTokenChanges")] + partial class _0006_AccountRefreshTokenChanges + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BackgroundPictureId") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(320) + .HasColumnType("character varying(320)"); + + b.Property("GenderId") + .HasColumnType("smallint"); + + b.Property("IsAdmin") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("LastActive") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.Property("LeftSalt") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("bytea"); + + b.Property("ProfilePictureId") + .HasColumnType("uuid"); + + b.Property("RightSalt") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("BackgroundPictureId"); + + b.HasIndex("GenderId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("ProfilePictureId") + .IsUnique(); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountProfilePicture", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("AccountProfilePictures"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountRefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("IsExtendable") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("AccountRefreshTokens"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Country", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Countries"); + + b.HasData( + new + { + Id = (short)1, + Name = "Afghanistan" + }, + new + { + Id = (short)2, + Name = "Albania" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Gender", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Genders"); + + b.HasData( + new + { + Id = (short)1, + Name = "Male" + }, + new + { + Id = (short)2, + Name = "Female" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("Genres"); + + b.HasData( + new + { + Id = (short)1, + Name = "Comedy" + }, + new + { + Id = (short)2, + Name = "Thriller" + }, + new + { + Id = (short)3, + Name = "Horror" + }, + new + { + Id = (short)4, + Name = "Action" + }, + new + { + Id = (short)5, + Name = "Drama" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Length") + .HasColumnType("interval"); + + b.Property("MediaPosterImageId") + .HasColumnType("uuid"); + + b.Property("OriginalTitle") + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("ReleaseDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaPosterImageId") + .IsUnique(); + + b.ToTable("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaGenre", b => + { + b.Property("GenreId") + .HasColumnType("smallint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.HasKey("GenreId", "MediaId"); + + b.HasIndex("MediaId"); + + b.ToTable("MediaGenres"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaMovie", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Budget") + .HasColumnType("money"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaMovies"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("IsMediaBackground") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("IsUniversalBackground") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("MediaPhotoImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaPosterImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b => + { + b.Property("CountryId") + .HasColumnType("smallint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.HasKey("CountryId", "MediaId"); + + b.HasIndex("MediaId"); + + b.ToTable("MediaProductionCountrys"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("HasEnded") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("MediaSeries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsSpecial") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); + + b.Property("MediaSeriesSeasonId") + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesSeasonId"); + + b.ToTable("MediaSeriesEpisodes"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaSeriesId") + .HasColumnType("bigint"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Number") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesId"); + + b.ToTable("MediaSeriesSeasons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BirthDate") + .HasColumnType("date"); + + b.Property("DeathDate") + .HasColumnType("date"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("FullName") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("GenderId") + .HasColumnType("smallint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("PersonPhotoId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("GenderId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonPhotoId") + .IsUnique(); + + b.ToTable("Persons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("PersonActorRoleTypeId") + .HasColumnType("smallint"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.HasIndex("PersonActorRoleTypeId"); + + b.HasIndex("PersonId"); + + b.ToTable("PersonActorRoles"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRoleType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonActorRoleTypes"); + + b.HasData( + new + { + Id = (short)1, + Name = "Actor" + }, + new + { + Id = (short)2, + Name = "Supporting actor" + }, + new + { + Id = (short)3, + Name = "Voice actor" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("PersonCreatorRoleTypeId") + .HasColumnType("smallint"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.HasIndex("PersonCreatorRoleTypeId"); + + b.HasIndex("PersonId"); + + b.ToTable("PersonCreatorRoles"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRoleType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonCreatorRoleTypes"); + + b.HasData( + new + { + Id = (short)1, + Name = "Director" + }, + new + { + Id = (short)2, + Name = "Producer" + }, + new + { + Id = (short)3, + Name = "Screenwriter" + }); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonPhotoImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasMaxLength(-1) + .HasColumnType("bytea"); + + b.Property("MimeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UploadDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasDefaultValueSql("now()"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("PersonPhotoImages"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMedia", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("RatingsMedia"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaSeriesEpisodeId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesEpisodeId"); + + b.ToTable("RatingsMediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesSeason", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("MediaSeriesSeasonId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaSeriesSeasonId"); + + b.ToTable("RatingsMediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonActorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("PersonActorRoleId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonActorRoleId"); + + b.ToTable("RatingsPersonActorRole", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonCreatorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("PersonCreatorRoleId") + .HasColumnType("uuid"); + + b.Property("Rating") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonCreatorRoleId"); + + b.ToTable("RatingsPersonCreatorRole", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountMedia", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Date") + .ValueGeneratedOnAdd() + .HasColumnType("date") + .HasDefaultValueSql("now()"); + + b.Property("MediaId") + .HasColumnType("bigint"); + + b.Property("ViewCount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("MediaId"); + + b.ToTable("ViewCountsMedia", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountPerson", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Date") + .ValueGeneratedOnAdd() + .HasColumnType("date") + .HasDefaultValueSql("now()"); + + b.Property("PersonId") + .HasColumnType("bigint"); + + b.Property("ViewCount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("PersonId"); + + b.ToTable("ViewCountsPerson", (string)null); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaPhotoImage", "BackgroundPicture") + .WithMany() + .HasForeignKey("BackgroundPictureId"); + + b.HasOne("WatchIt.Database.Model.Common.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId"); + + b.HasOne("WatchIt.Database.Model.Account.AccountProfilePicture", "ProfilePicture") + .WithOne("Account") + .HasForeignKey("WatchIt.Database.Model.Account.Account", "ProfilePictureId"); + + b.Navigation("BackgroundPicture"); + + b.Navigation("Gender"); + + b.Navigation("ProfilePicture"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountRefreshToken", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("AccountRefreshTokens") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaMovie", null) + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeries", null) + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaPosterImage", "MediaPosterImage") + .WithOne("Media") + .HasForeignKey("WatchIt.Database.Model.Media.Media", "MediaPosterImageId"); + + b.Navigation("MediaPosterImage"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaGenre", b => + { + b.HasOne("WatchIt.Database.Model.Common.Genre", "Genre") + .WithMany("MediaGenres") + .HasForeignKey("GenreId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaGenres") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Genre"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImage", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaPhotoImages") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b => + { + b.HasOne("WatchIt.Database.Model.Common.Country", "Country") + .WithMany("MediaProductionCountries") + .HasForeignKey("CountryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("MediaProductionCountries") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Country"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesSeason", "MediaSeriesSeason") + .WithMany("MediaSeriesEpisodes") + .HasForeignKey("MediaSeriesSeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.HasOne("WatchIt.Database.Model.Media.MediaSeries", "MediaSeries") + .WithMany("MediaSeriesSeasons") + .HasForeignKey("MediaSeriesId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("MediaSeries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.HasOne("WatchIt.Database.Model.Common.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonPhotoImage", "PersonPhoto") + .WithOne("Person") + .HasForeignKey("WatchIt.Database.Model.Person.Person", "PersonPhotoId"); + + b.Navigation("Gender"); + + b.Navigation("PersonPhoto"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("PersonActorRoles") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonActorRoleType", "PersonActorRoleType") + .WithMany() + .HasForeignKey("PersonActorRoleTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("PersonActorRoles") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + + b.Navigation("Person"); + + b.Navigation("PersonActorRoleType"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("PersonCreatorRoles") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonCreatorRoleType", "PersonCreatorRoleType") + .WithMany() + .HasForeignKey("PersonCreatorRoleTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("PersonCreatorRoles") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + + b.Navigation("Person"); + + b.Navigation("PersonCreatorRoleType"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMedia", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMedia") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("RatingMedia") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesEpisode", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMediaSeriesEpisode") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesEpisode", "MediaSeriesEpisode") + .WithMany("RatingMediaSeriesEpisode") + .HasForeignKey("MediaSeriesEpisodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("MediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingMediaSeriesSeason", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingMediaSeriesSeason") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Media.MediaSeriesSeason", "MediaSeriesSeason") + .WithMany("RatingMediaSeriesSeason") + .HasForeignKey("MediaSeriesSeasonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("MediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonActorRole", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingPersonActorRole") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonActorRole", "PersonActorRole") + .WithMany("RatingPersonActorRole") + .HasForeignKey("PersonActorRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("PersonActorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Rating.RatingPersonCreatorRole", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("RatingPersonCreatorRole") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("WatchIt.Database.Model.Person.PersonCreatorRole", "PersonCreatorRole") + .WithMany("RatingPersonCreatorRole") + .HasForeignKey("PersonCreatorRoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("PersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountMedia", b => + { + b.HasOne("WatchIt.Database.Model.Media.Media", "Media") + .WithMany("ViewCountsMedia") + .HasForeignKey("MediaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Media"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.ViewCount.ViewCountPerson", b => + { + b.HasOne("WatchIt.Database.Model.Person.Person", "Person") + .WithMany("ViewCountsPerson") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Person"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => + { + b.Navigation("AccountRefreshTokens"); + + b.Navigation("RatingMedia"); + + b.Navigation("RatingMediaSeriesEpisode"); + + b.Navigation("RatingMediaSeriesSeason"); + + b.Navigation("RatingPersonActorRole"); + + b.Navigation("RatingPersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountProfilePicture", b => + { + b.Navigation("Account") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Country", b => + { + b.Navigation("MediaProductionCountries"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Common.Genre", b => + { + b.Navigation("MediaGenres"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => + { + b.Navigation("MediaGenres"); + + b.Navigation("MediaPhotoImages"); + + b.Navigation("MediaProductionCountries"); + + b.Navigation("PersonActorRoles"); + + b.Navigation("PersonCreatorRoles"); + + b.Navigation("RatingMedia"); + + b.Navigation("ViewCountsMedia"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaMovie", b => + { + b.Navigation("Media") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b => + { + b.Navigation("Media") + .IsRequired(); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b => + { + b.Navigation("Media") + .IsRequired(); + + b.Navigation("MediaSeriesSeasons"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesEpisode", b => + { + b.Navigation("RatingMediaSeriesEpisode"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeriesSeason", b => + { + b.Navigation("MediaSeriesEpisodes"); + + b.Navigation("RatingMediaSeriesSeason"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.Person", b => + { + b.Navigation("PersonActorRoles"); + + b.Navigation("PersonCreatorRoles"); + + b.Navigation("ViewCountsPerson"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonActorRole", b => + { + b.Navigation("RatingPersonActorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonCreatorRole", b => + { + b.Navigation("RatingPersonCreatorRole"); + }); + + modelBuilder.Entity("WatchIt.Database.Model.Person.PersonPhotoImage", b => + { + b.Navigation("Person") + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WatchIt.Database/WatchIt.Database/Migrations/20240324205952_0006_AccountRefreshTokenChanges.cs b/WatchIt.Database/WatchIt.Database/Migrations/20240324205952_0006_AccountRefreshTokenChanges.cs new file mode 100644 index 0000000..c02ef15 --- /dev/null +++ b/WatchIt.Database/WatchIt.Database/Migrations/20240324205952_0006_AccountRefreshTokenChanges.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace WatchIt.Database.Migrations +{ + /// + public partial class _0006_AccountRefreshTokenChanges : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "Lifetime", + table: "AccountRefreshTokens", + newName: "ExpirationDate"); + + migrationBuilder.AddColumn( + name: "IsExtendable", + table: "AccountRefreshTokens", + type: "boolean", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsExtendable", + table: "AccountRefreshTokens"); + + migrationBuilder.RenameColumn( + name: "ExpirationDate", + table: "AccountRefreshTokens", + newName: "Lifetime"); + } + } +} diff --git a/WatchIt.Database/WatchIt.Database/Migrations/DatabaseContextModelSnapshot.cs b/WatchIt.Database/WatchIt.Database/Migrations/DatabaseContextModelSnapshot.cs index 73b70d5..186e9cc 100644 --- a/WatchIt.Database/WatchIt.Database/Migrations/DatabaseContextModelSnapshot.cs +++ b/WatchIt.Database/WatchIt.Database/Migrations/DatabaseContextModelSnapshot.cs @@ -39,7 +39,6 @@ namespace WatchIt.Database.Migrations .HasDefaultValueSql("now()"); b.Property("Description") - .IsRequired() .HasMaxLength(1000) .HasColumnType("character varying(1000)"); @@ -48,11 +47,13 @@ namespace WatchIt.Database.Migrations .HasMaxLength(320) .HasColumnType("character varying(320)"); - b.Property("GenderId") + b.Property("GenderId") .HasColumnType("smallint"); b.Property("IsAdmin") - .HasColumnType("boolean"); + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false); b.Property("LastActive") .ValueGeneratedOnAdd() @@ -126,6 +127,31 @@ namespace WatchIt.Database.Migrations b.ToTable("AccountProfilePictures"); }); + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountRefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("IsExtendable") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("AccountRefreshTokens"); + }); + modelBuilder.Entity("WatchIt.Database.Model.Common.Country", b => { b.Property("Id") @@ -891,9 +917,7 @@ namespace WatchIt.Database.Migrations b.HasOne("WatchIt.Database.Model.Common.Gender", "Gender") .WithMany() - .HasForeignKey("GenderId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + .HasForeignKey("GenderId"); b.HasOne("WatchIt.Database.Model.Account.AccountProfilePicture", "ProfilePicture") .WithOne("Account") @@ -906,6 +930,17 @@ namespace WatchIt.Database.Migrations b.Navigation("ProfilePicture"); }); + modelBuilder.Entity("WatchIt.Database.Model.Account.AccountRefreshToken", b => + { + b.HasOne("WatchIt.Database.Model.Account.Account", "Account") + .WithMany("AccountRefreshTokens") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + modelBuilder.Entity("WatchIt.Database.Model.Media.Media", b => { b.HasOne("WatchIt.Database.Model.Media.MediaMovie", null) @@ -1188,6 +1223,8 @@ namespace WatchIt.Database.Migrations modelBuilder.Entity("WatchIt.Database.Model.Account.Account", b => { + b.Navigation("AccountRefreshTokens"); + b.Navigation("RatingMedia"); b.Navigation("RatingMediaSeriesEpisode"); diff --git a/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Authenticate/AuthenticateRequest.cs b/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Authenticate/AuthenticateRequest.cs new file mode 100644 index 0000000..583f8d2 --- /dev/null +++ b/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Authenticate/AuthenticateRequest.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace WatchIt.Shared.Models.Accounts.Authenticate +{ + public class AuthenticateRequest + { + #region PROPERTIES + + [JsonPropertyName("username_or_email")] + public string UsernameOrEmail { get; set; } + + [JsonPropertyName("password")] + public string Password { get; set; } + + [JsonPropertyName("remember_me")] + public bool RememberMe { get; set; } + + #endregion + } +} diff --git a/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Authenticate/AuthenticateResponse.cs b/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Authenticate/AuthenticateResponse.cs new file mode 100644 index 0000000..0bd0636 --- /dev/null +++ b/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Authenticate/AuthenticateResponse.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace WatchIt.Shared.Models.Accounts.Authenticate +{ + public class AuthenticateResponse + { + #region PROPERTIES + + [JsonPropertyName("access_token")] + public required string AccessToken { get; init; } + + [JsonPropertyName("refresh_token")] + public required string RefreshToken { get; init; } + + #endregion + } +} diff --git a/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Register/RegisterRequest.cs b/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Register/RegisterRequest.cs new file mode 100644 index 0000000..f1cb25d --- /dev/null +++ b/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Register/RegisterRequest.cs @@ -0,0 +1,27 @@ +using FluentValidation; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace WatchIt.Shared.Models.Accounts.Register +{ + public class RegisterRequest + { + #region PROPERTIES + + [JsonPropertyName("username")] + public string Username { get; set; } + + [JsonPropertyName("email")] + public string Email { get; set; } + + [JsonPropertyName("password")] + public string Password { get; set; } + + #endregion + } +} diff --git a/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Register/RegisterResponse.cs b/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Register/RegisterResponse.cs new file mode 100644 index 0000000..43be31e --- /dev/null +++ b/WatchIt.Shared/WatchIt.Shared.Models/Accounts/Register/RegisterResponse.cs @@ -0,0 +1,44 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using WatchIt.Database.Model.Account; + +namespace WatchIt.Shared.Models.Accounts.Register +{ + public class RegisterResponse + { + #region PROPERTIES + + [JsonPropertyName("id")] + public required long Id { get; init; } + + [JsonPropertyName("username")] + public required string Username { get; init; } + + [JsonPropertyName("email")] + public required string Email { get; init; } + + [JsonPropertyName("creation_date")] + public required DateTime CreationDate { get; init; } + + #endregion + + + + #region CONVERTION + + public static implicit operator RegisterResponse(Account account) => new RegisterResponse + { + Id = account.Id, + Username = account.Username, + Email = account.Email, + CreationDate = account.CreationDate + }; + + #endregion + } +} diff --git a/WatchIt.Shared/WatchIt.Shared.Models/RequestResult.cs b/WatchIt.Shared/WatchIt.Shared.Models/RequestResult.cs new file mode 100644 index 0000000..7bab44e --- /dev/null +++ b/WatchIt.Shared/WatchIt.Shared.Models/RequestResult.cs @@ -0,0 +1,107 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +namespace WatchIt.Shared.Models +{ + public class RequestResult + { + #region PROPERTIES + + public RequestResultStatus Status { get; } + public IEnumerable ValidationMessages { get; init; } + + #endregion + + + + #region CONSTRUCTORS + + internal RequestResult(RequestResultStatus status) => Status = status; + + public static RequestResult Ok() => new RequestResult(RequestResultStatus.Ok); + public static RequestResult Ok() => new RequestResult(RequestResultStatus.Ok); + public static RequestResult Ok(T data) => new RequestResult(RequestResultStatus.Ok) { Data = data }; + public static RequestResult Created(string location, T resource) => new RequestResult(RequestResultStatus.Created) { NewResourceLocation = location, Data = resource }; + public static RequestResult NoContent() => new RequestResult(RequestResultStatus.NoContent); + public static RequestResult NoContent() => new RequestResult(RequestResultStatus.NoContent); + public static RequestResult BadRequest(params string[] validationErrors) => new RequestResult(RequestResultStatus.BadRequest) { ValidationMessages = validationErrors }; + public static RequestResult BadRequest(params string[] validationErrors) => new RequestResult(RequestResultStatus.BadRequest) { ValidationMessages = validationErrors }; + public static RequestResult Unauthorized(params string[] validationErrors) => new RequestResult(RequestResultStatus.Unauthorized) { ValidationMessages = validationErrors }; + public static RequestResult Unauthorized(params string[] validationErrors) => new RequestResult(RequestResultStatus.Unauthorized) { ValidationMessages = validationErrors }; + public static RequestResult Forbidden() => new RequestResult(RequestResultStatus.Forbidden); + public static RequestResult Forbidden() => new RequestResult(RequestResultStatus.Forbidden); + public static RequestResult NotFound() => new RequestResult(RequestResultStatus.NotFound); + public static RequestResult NotFound() => new RequestResult(RequestResultStatus.NotFound); + public static RequestResult Conflict() => new RequestResult(RequestResultStatus.Conflict); + public static RequestResult Conflict() => new RequestResult(RequestResultStatus.Conflict); + + #endregion + + + + #region CONVERSION + + public static implicit operator ActionResult(RequestResult result) => result.Status switch + { + RequestResultStatus.Ok => HandleOk(result), + RequestResultStatus.NoContent => HandleNoContent(), + RequestResultStatus.BadRequest => HandleBadRequest(result), + RequestResultStatus.Unauthorized => HandleUnauthorized(result), + RequestResultStatus.Forbidden => HandleForbidden(), + RequestResultStatus.NotFound => HandleNotFound(), + RequestResultStatus.Conflict => HandleConflict(), + }; + + protected static ActionResult HandleOk(RequestResult result) => new OkResult(); + protected static ActionResult HandleNoContent() => new NoContentResult(); + protected static ActionResult HandleBadRequest(RequestResult result) => new BadRequestObjectResult(result.ValidationMessages); + protected static ActionResult HandleUnauthorized(RequestResult result) => new UnauthorizedObjectResult(result.ValidationMessages); + protected static ActionResult HandleForbidden() => new ForbidResult(); + protected static ActionResult HandleNotFound() => new NotFoundResult(); + protected static ActionResult HandleConflict() => new ConflictResult(); + + #endregion + } + + public class RequestResult : RequestResult + { + #region PROPERTIES + + public T? Data { get; init; } + public string? NewResourceLocation { get; init; } + + #endregion + + + + #region CONSTRUCTORS + + internal RequestResult(RequestResultStatus type) : base(type) { } + + #endregion + + + + #region CONVERSION + + public static implicit operator ActionResult(RequestResult result) => result.Status switch + { + RequestResultStatus.Ok => HandleOk(result), + RequestResultStatus.Created => HandleCreated(result), + RequestResultStatus.NoContent => HandleNoContent(), + RequestResultStatus.BadRequest => HandleBadRequest(result), + RequestResultStatus.Unauthorized => HandleUnauthorized(result), + RequestResultStatus.Forbidden => HandleForbidden(), + RequestResultStatus.NotFound => HandleNotFound(), + RequestResultStatus.Conflict => HandleConflict(), + }; + + private static ActionResult HandleOk(RequestResult result) => result.Data is null ? new OkResult() : new OkObjectResult(result.Data); + private static ActionResult HandleCreated(RequestResult result) => new CreatedResult(result.NewResourceLocation, result.Data); + + #endregion + } +} diff --git a/WatchIt.Shared/WatchIt.Shared.Models/RequestResultStatus.cs b/WatchIt.Shared/WatchIt.Shared.Models/RequestResultStatus.cs new file mode 100644 index 0000000..3808ca5 --- /dev/null +++ b/WatchIt.Shared/WatchIt.Shared.Models/RequestResultStatus.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WatchIt.Shared.Models +{ + public enum RequestResultStatus + { + Ok = 200, + Created = 201, + NoContent = 204, + BadRequest = 400, + Unauthorized = 401, + Forbidden = 403, + NotFound = 404, + Conflict = 409, + } +} diff --git a/WatchIt.Shared/WatchIt.Shared.Models/WatchIt.Shared.Models.csproj b/WatchIt.Shared/WatchIt.Shared.Models/WatchIt.Shared.Models.csproj new file mode 100644 index 0000000..c5be2bb --- /dev/null +++ b/WatchIt.Shared/WatchIt.Shared.Models/WatchIt.Shared.Models.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/AccountsController.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/AccountsController.cs new file mode 100644 index 0000000..a592f2e --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/AccountsController.cs @@ -0,0 +1,47 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using WatchIt.Shared.Models.Accounts.Authenticate; +using WatchIt.Shared.Models.Accounts.Register; +using WatchIt.WebAPI.Services.Controllers; + +namespace WatchIt.WebAPI.Controllers +{ + [ApiController] + [Route("api/accounts")] + public class AccountsController(IAccountsControllerService accountsControllerService) : ControllerBase + { + #region METHODS + + [HttpPost] + [Route("register")] + [AllowAnonymous] + [ProducesResponseType(typeof(RegisterResponse), StatusCodes.Status201Created)] + [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] + public async Task Register([FromBody] RegisterRequest data) => await accountsControllerService.Register(data); + + [HttpPost] + [Route("authenticate")] + [AllowAnonymous] + [ProducesResponseType(typeof(AuthenticateResponse), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + public async Task Authenticate([FromBody] AuthenticateRequest data) => await accountsControllerService.Authenticate(data); + + [HttpPost] + [Route("authenticate-refresh")] + [Authorize(AuthenticationSchemes = "refresh")] + [ProducesResponseType(typeof(AuthenticateResponse), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + public async Task AuthenticateRefresh() => await accountsControllerService.AuthenticateRefresh(); + + + #endregion + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj new file mode 100644 index 0000000..54ffa42 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/AccountsControllerService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/AccountsControllerService.cs new file mode 100644 index 0000000..7d98976 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/AccountsControllerService.cs @@ -0,0 +1,88 @@ +using Microsoft.EntityFrameworkCore; +using SimpleToolkit.Extensions; +using System.Security.Cryptography; +using System.Text; +using WatchIt.Database; +using WatchIt.Database.Model.Account; +using WatchIt.Shared.Models; +using WatchIt.Shared.Models.Accounts.Authenticate; +using WatchIt.Shared.Models.Accounts.Register; +using WatchIt.WebAPI.Services.Utility.JWT; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace WatchIt.WebAPI.Services.Controllers +{ + public interface IAccountsControllerService + { + Task> Register(RegisterRequest data); + Task> Authenticate(AuthenticateRequest data); + Task> AuthenticateRefresh(); + } + + public class AccountsControllerService(IJWTService jwtService, DatabaseContext database) : IAccountsControllerService + { + #region PUBLIC METHODS + + public async Task> Register(RegisterRequest data) + { + string leftSalt = StringExtensions.CreateRandom(20); + string rightSalt = StringExtensions.CreateRandom(20); + byte[] hash = ComputeHash(data.Password, leftSalt, rightSalt); + + Account account = new Account + { + Username = data.Username, + Email = data.Email, + Password = hash, + LeftSalt = leftSalt, + RightSalt = rightSalt + }; + await database.Accounts.AddAsync(account); + await database.SaveChangesAsync(); + + return RequestResult.Created($"accounts/{account.Id}", account); + } + + public async Task> Authenticate(AuthenticateRequest data) + { + Account? account = await database.Accounts.FirstOrDefaultAsync(x => string.Equals(x.Email, data.UsernameOrEmail) || string.Equals(x.Username, data.UsernameOrEmail)); + if (account is null) + { + return RequestResult.Unauthorized("User does not exists"); + } + + byte[] hash = ComputeHash(data.Password, account.LeftSalt, account.RightSalt); + if (!Enumerable.SequenceEqual(hash, account.Password)) + { + return RequestResult.Unauthorized("Incorrect password"); + } + + Task refreshTokenTask = jwtService.CreateRefreshToken(account, true); + Task accessTokenTask = jwtService.CreateAccessToken(account); + await Task.WhenAll(refreshTokenTask, accessTokenTask); + + AuthenticateResponse response = new AuthenticateResponse + { + AccessToken = accessTokenTask.Result, + RefreshToken = refreshTokenTask.Result, + }; + + return RequestResult.Ok(response); + } + + public async Task> AuthenticateRefresh() + { + + } + + #endregion + + + + #region PRIVATE METHODS + + protected byte[] ComputeHash(string password, string leftSalt, string rightSalt) => SHA512.Create().ComputeHash(Encoding.UTF8.GetBytes($"{leftSalt}{password}{rightSalt}")); + + #endregion + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.csproj b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.csproj new file mode 100644 index 0000000..6c3b4fd --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/ConfigurationService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/ConfigurationService.cs new file mode 100644 index 0000000..88d3f95 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/ConfigurationService.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WatchIt.WebAPI.Services.Utility.Configuration.Models; + +namespace WatchIt.WebAPI.Services.Utility.Configuration +{ + public interface IConfigurationService + { + ConfigurationData Data { get; } + } + + + + public class ConfigurationService(IConfiguration configuration) : IConfigurationService + { + #region PROPERTIES + + public ConfigurationData Data => configuration.GetSection("WebAPI").Get()!; + + #endregion + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/AccessToken.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/AccessToken.cs new file mode 100644 index 0000000..0b65457 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/AccessToken.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WatchIt.WebAPI.Services.Utility.Configuration.Models +{ + public class AccessToken + { + public int Lifetime { get; set; } + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/Authentication.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/Authentication.cs new file mode 100644 index 0000000..f68baf5 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/Authentication.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WatchIt.WebAPI.Services.Utility.Configuration.Models +{ + public class Authentication + { + public string Key { get; set; } + public string Issuer { get; set; } + public RefreshToken RefreshToken { get; set; } + public AccessToken AccessToken { get; set; } + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/ConfigurationData.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/ConfigurationData.cs new file mode 100644 index 0000000..faf1bec --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/ConfigurationData.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WatchIt.WebAPI.Services.Utility.Configuration.Models +{ + public class ConfigurationData + { + public Authentication Authentication { get; set; } + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/RefreshToken.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/RefreshToken.cs new file mode 100644 index 0000000..542c115 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/Models/RefreshToken.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WatchIt.WebAPI.Services.Utility.Configuration.Models +{ + public class RefreshToken + { + public int Lifetime { get; set; } + public int ExtendedLifetime { get; set; } + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/WatchIt.WebAPI.Services.Utility.Configuration.csproj b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/WatchIt.WebAPI.Services.Utility.Configuration.csproj new file mode 100644 index 0000000..800b08f --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.Configuration/WatchIt.WebAPI.Services.Utility.Configuration.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/JWTService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/JWTService.cs new file mode 100644 index 0000000..e8afdc6 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/JWTService.cs @@ -0,0 +1,131 @@ +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Security.Principal; +using System.Text; +using System.Threading.Tasks; +using WatchIt.Database; +using WatchIt.Database.Model.Account; +using WatchIt.WebAPI.Services.Utility.Configuration; + +namespace WatchIt.WebAPI.Services.Utility.JWT +{ + public interface IJWTService + { + Task CreateAccessToken(Account account); + Task CreateRefreshToken(Account account, bool extendable); + Task ExtendRefreshToken(Account account, Guid id); + } + + + + public class JWTService(IConfigurationService configurationService, DatabaseContext database) : IJWTService + { + #region PUBLIC METHODS + + public async Task CreateRefreshToken(Account account, bool extendable) + { + int expirationMinutes = extendable ? configurationService.Data.Authentication.RefreshToken.ExtendedLifetime : configurationService.Data.Authentication.RefreshToken.Lifetime; + DateTime expirationDate = DateTime.UtcNow.AddMinutes(expirationMinutes); + Guid id = Guid.NewGuid(); + + AccountRefreshToken refreshToken = new AccountRefreshToken + { + Id = id, + AccountId = account.Id, + ExpirationDate = expirationDate, + IsExtendable = extendable + }; + database.AccountRefreshTokens.Add(refreshToken); + Task saveTask = database.SaveChangesAsync(); + + SecurityTokenDescriptor tokenDescriptor = CreateBaseSecurityTokenDescriptor(account, id, expirationDate); + tokenDescriptor.Audience = "refresh"; + tokenDescriptor.Subject.AddClaim(new Claim("extend", extendable.ToString())); + + string tokenString = TokenToString(tokenDescriptor); + + await saveTask; + + return tokenString; + } + + public async Task ExtendRefreshToken(Account account, Guid id) + { + AccountRefreshToken? token = account.AccountRefreshTokens.FirstOrDefault(x => x.Id == id); + if (token is null) + { + throw new TokenNotFoundException(); + } + if (!token.IsExtendable) + { + throw new TokenNotExtendableException(); + } + + int expirationMinutes = configurationService.Data.Authentication.RefreshToken.ExtendedLifetime; + DateTime expirationDate = DateTime.UtcNow.AddMinutes(expirationMinutes); + + token.ExpirationDate = expirationDate; + + Task saveTask = database.SaveChangesAsync(); + + SecurityTokenDescriptor tokenDescriptor = CreateBaseSecurityTokenDescriptor(account, id, expirationDate); + tokenDescriptor.Audience = "refresh"; + tokenDescriptor.Subject.AddClaim(new Claim("extend", bool.TrueString)); + + string tokenString = TokenToString(tokenDescriptor); + + await saveTask; + + return tokenString; + } + + public async Task CreateAccessToken(Account account) + { + DateTime lifetime = DateTime.Now.AddMinutes(configurationService.Data.Authentication.AccessToken.Lifetime); + Guid id = Guid.NewGuid(); + + SecurityTokenDescriptor tokenDescriptor = CreateBaseSecurityTokenDescriptor(account, id, lifetime); + tokenDescriptor.Audience = "access"; + tokenDescriptor.Subject.AddClaim(new Claim("admin", account.IsAdmin.ToString())); + + return TokenToString(tokenDescriptor); + } + + #endregion + + + + #region PRIVATE METHODS + + protected SecurityTokenDescriptor CreateBaseSecurityTokenDescriptor(Account account, Guid id, DateTime expirationTime) => new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity(new List + { + new Claim(JwtRegisteredClaimNames.Jti, id.ToString()), + new Claim(JwtRegisteredClaimNames.Sub, account.Id.ToString()), + new Claim(JwtRegisteredClaimNames.Email, account.Email), + new Claim(JwtRegisteredClaimNames.UniqueName, account.Username), + new Claim(JwtRegisteredClaimNames.Exp, expirationTime.ToString()), + }), + Expires = expirationTime, + Issuer = configurationService.Data.Authentication.Issuer, + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configurationService.Data.Authentication.Key)), SecurityAlgorithms.HmacSha512) + }; + + protected string TokenToString(SecurityTokenDescriptor tokenDescriptor) + { + System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler handler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler(); + handler.InboundClaimTypeMap.Clear(); + + SecurityToken token = handler.CreateToken(tokenDescriptor); + + return handler.WriteToken(token); + } + + #endregion + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/TokenNotExtendableException.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/TokenNotExtendableException.cs new file mode 100644 index 0000000..971cce2 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/TokenNotExtendableException.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WatchIt.WebAPI.Services.Utility.JWT +{ + public class TokenNotExtendableException : Exception + { + public TokenNotExtendableException() : base() { } + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/TokenNotFoundException.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/TokenNotFoundException.cs new file mode 100644 index 0000000..1e37897 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/TokenNotFoundException.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WatchIt.WebAPI.Services.Utility.JWT +{ + public class TokenNotFoundException : Exception + { + public TokenNotFoundException() : base() { } + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/WatchIt.WebAPI.Services.Utility.JWT.csproj b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/WatchIt.WebAPI.Services.Utility.JWT.csproj new file mode 100644 index 0000000..e3ca5ed --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.JWT/WatchIt.WebAPI.Services.Utility.JWT.csproj @@ -0,0 +1,21 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.User/UserService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.User/UserService.cs new file mode 100644 index 0000000..e0c8cd9 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.User/UserService.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WatchIt.WebAPI.Services.Utility.User +{ + public class UserService(IHttpContextAccessor accessor) + { + #region PUBLIC METHODS + + + + #endregion + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.User/WatchIt.WebAPI.Services.Utility.User.csproj b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.User/WatchIt.WebAPI.Services.Utility.User.csproj new file mode 100644 index 0000000..297920e --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Utility/WatchIt.WebAPI.Services.Utility.User/WatchIt.WebAPI.Services.Utility.User.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Validators/Accounts/AuthenticateRequestValidator.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Validators/Accounts/AuthenticateRequestValidator.cs new file mode 100644 index 0000000..7f2bdfb --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Validators/Accounts/AuthenticateRequestValidator.cs @@ -0,0 +1,26 @@ +using FluentValidation; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; +using WatchIt.Database; +using WatchIt.Shared.Models.Accounts.Authenticate; + +namespace WatchIt.WebAPI.Validators.Accounts +{ + public class AuthenticateRequestValidator : AbstractValidator + { + #region CONSTRUCTOR + + public AuthenticateRequestValidator(DatabaseContext database) + { + RuleFor(x => x.UsernameOrEmail).NotEmpty(); + RuleFor(x => x.Password).NotEmpty(); + } + + #endregion + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Validators/Accounts/RegisterRequestValidator.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Validators/Accounts/RegisterRequestValidator.cs new file mode 100644 index 0000000..ea90618 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Validators/Accounts/RegisterRequestValidator.cs @@ -0,0 +1,31 @@ +using FluentValidation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WatchIt.Database; +using WatchIt.Shared.Models.Accounts.Register; + +namespace WatchIt.WebAPI.Validators.Accounts +{ + public class RegisterRequestValidator : AbstractValidator + { + #region CONSTRUCTOR + + public RegisterRequestValidator(DatabaseContext database) + { + RuleFor(x => x.Username).MinimumLength(5) + .MaximumLength(50) + .CannotBeIn(database.Accounts, x => x.Username).WithMessage("Username was already used"); + RuleFor(x => x.Email).EmailAddress() + .CannotBeIn(database.Accounts, x => x.Email).WithMessage("Email was already used"); + RuleFor(x => x.Password).MinimumLength(8) + .Must(x => x.Any(c => Char.IsUpper(c))).WithMessage("Password must contain at least one uppercase letter.") + .Must(x => x.Any(c => Char.IsLower(c))).WithMessage("Password must contain at least one lowercase letter.") + .Must(x => x.Any(c => Char.IsDigit(c))).WithMessage("Password must contain at least one digit."); + } + + #endregion + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Validators/CustomValidators.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Validators/CustomValidators.cs new file mode 100644 index 0000000..76d157c --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Validators/CustomValidators.cs @@ -0,0 +1,18 @@ +using FluentValidation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WatchIt.WebAPI.Validators +{ + public static class CustomValidators + { + public static IRuleBuilderOptions CannotBeIn(this IRuleBuilder ruleBuilder, IEnumerable collection) => ruleBuilder.Must(x => !collection.Any(e => Equals(e, x))); + public static IRuleBuilderOptions CannotBeIn(this IRuleBuilder ruleBuilder, IEnumerable collection, Func propertyFunc) => ruleBuilder.Must(x => !collection.Select(propertyFunc).Any(e => Equals(e, x))); + public static IRuleBuilderOptions MustBeIn(this IRuleBuilder ruleBuilder, IEnumerable collection) => ruleBuilder.Must(x => collection.Any(e => Equals(e, x))); + public static IRuleBuilderOptions MustBeIn(this IRuleBuilder ruleBuilder, IEnumerable collection, Func propertyFunc) => ruleBuilder.Must(x => collection.Select(propertyFunc).Any(e => Equals(e, x))); + + } +} diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Validators/WatchIt.WebAPI.Validators.csproj b/WatchIt.WebAPI/WatchIt.WebAPI.Validators/WatchIt.WebAPI.Validators.csproj new file mode 100644 index 0000000..4498da0 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Validators/WatchIt.WebAPI.Validators.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + diff --git a/WatchIt.sln b/WatchIt.sln index e01b1b8..3e1cdfd 100644 --- a/WatchIt.sln +++ b/WatchIt.sln @@ -15,7 +15,27 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WatchIt.Database", "WatchIt EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WatchIt.Database.Model", "WatchIt.Database\WatchIt.Database.Model\WatchIt.Database.Model.csproj", "{46A294FF-F15F-4773-9E33-AFFC6DF2148C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Database.DataSeeding", "WatchIt.Database\WatchIt.Database.DataSeeding\WatchIt.Database.DataSeeding.csproj", "{EC685BDC-9C80-4D6D-94DA-F788976CD104}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WatchIt.Database.DataSeeding", "WatchIt.Database\WatchIt.Database.DataSeeding\WatchIt.Database.DataSeeding.csproj", "{EC685BDC-9C80-4D6D-94DA-F788976CD104}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WatchIt.WebAPI.Controllers", "WatchIt.WebAPI\WatchIt.WebAPI.Controllers\WatchIt.WebAPI.Controllers.csproj", "{F8EC5C47-9866-4065-AA8B-0441280BB1C9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WatchIt.Shared", "WatchIt.Shared", "{02132B7F-2055-4FA9-AA94-EDB92159AFF8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WatchIt.Shared.Models", "WatchIt.Shared\WatchIt.Shared.Models\WatchIt.Shared.Models.csproj", "{B3D90254-F594-4C15-B003-F828EEDA850A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WatchIt.WebAPI.Services", "WatchIt.WebAPI.Services", "{CD2FA54C-BAF5-41B2-B8C7-5C3EDED1B41A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WatchIt.WebAPI.Services.Controllers", "WatchIt.WebAPI\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.csproj", "{CE4669C8-E537-400A-A872-A32BD165F1AE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.WebAPI.Validators", "WatchIt.WebAPI\WatchIt.WebAPI.Validators\WatchIt.WebAPI.Validators.csproj", "{E7DE3C54-B199-4DF8-ADA0-46FE85AA059F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WatchIt.WebAPI.Services.Utility", "WatchIt.WebAPI.Services.Utility", "{70058164-43EB-47E5-8507-23D6A41A2581}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.WebAPI.Services.Utility.Configuration", "WatchIt.WebAPI\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Utility\WatchIt.WebAPI.Services.Utility.Configuration\WatchIt.WebAPI.Services.Utility.Configuration.csproj", "{9915A61F-A7CA-4F6F-A213-4B31BE81C3DF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.WebAPI.Services.Utility.JWT", "WatchIt.WebAPI\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Utility\WatchIt.WebAPI.Services.Utility.JWT\WatchIt.WebAPI.Services.Utility.JWT.csproj", "{68A3C906-7470-40A1-B9C3-2F8963AA7E44}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.WebAPI.Services.Utility.User", "WatchIt.WebAPI\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Utility\WatchIt.WebAPI.Services.Utility.User\WatchIt.WebAPI.Services.Utility.User.csproj", "{FA335A3A-BD57-472A-B3ED-43F18D9F31A6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -39,6 +59,34 @@ Global {EC685BDC-9C80-4D6D-94DA-F788976CD104}.Debug|Any CPU.Build.0 = Debug|Any CPU {EC685BDC-9C80-4D6D-94DA-F788976CD104}.Release|Any CPU.ActiveCfg = Release|Any CPU {EC685BDC-9C80-4D6D-94DA-F788976CD104}.Release|Any CPU.Build.0 = Release|Any CPU + {F8EC5C47-9866-4065-AA8B-0441280BB1C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8EC5C47-9866-4065-AA8B-0441280BB1C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8EC5C47-9866-4065-AA8B-0441280BB1C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8EC5C47-9866-4065-AA8B-0441280BB1C9}.Release|Any CPU.Build.0 = Release|Any CPU + {B3D90254-F594-4C15-B003-F828EEDA850A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B3D90254-F594-4C15-B003-F828EEDA850A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B3D90254-F594-4C15-B003-F828EEDA850A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B3D90254-F594-4C15-B003-F828EEDA850A}.Release|Any CPU.Build.0 = Release|Any CPU + {CE4669C8-E537-400A-A872-A32BD165F1AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE4669C8-E537-400A-A872-A32BD165F1AE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE4669C8-E537-400A-A872-A32BD165F1AE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE4669C8-E537-400A-A872-A32BD165F1AE}.Release|Any CPU.Build.0 = Release|Any CPU + {E7DE3C54-B199-4DF8-ADA0-46FE85AA059F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7DE3C54-B199-4DF8-ADA0-46FE85AA059F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7DE3C54-B199-4DF8-ADA0-46FE85AA059F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7DE3C54-B199-4DF8-ADA0-46FE85AA059F}.Release|Any CPU.Build.0 = Release|Any CPU + {9915A61F-A7CA-4F6F-A213-4B31BE81C3DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9915A61F-A7CA-4F6F-A213-4B31BE81C3DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9915A61F-A7CA-4F6F-A213-4B31BE81C3DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9915A61F-A7CA-4F6F-A213-4B31BE81C3DF}.Release|Any CPU.Build.0 = Release|Any CPU + {68A3C906-7470-40A1-B9C3-2F8963AA7E44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68A3C906-7470-40A1-B9C3-2F8963AA7E44}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68A3C906-7470-40A1-B9C3-2F8963AA7E44}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68A3C906-7470-40A1-B9C3-2F8963AA7E44}.Release|Any CPU.Build.0 = Release|Any CPU + {FA335A3A-BD57-472A-B3ED-43F18D9F31A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FA335A3A-BD57-472A-B3ED-43F18D9F31A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FA335A3A-BD57-472A-B3ED-43F18D9F31A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FA335A3A-BD57-472A-B3ED-43F18D9F31A6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -47,6 +95,15 @@ Global {8CDAA140-05FC-4EB7-A9F5-A85032C8FD2F} = {98C91E27-2C36-4C74-A80F-9ACD7F28BC54} {46A294FF-F15F-4773-9E33-AFFC6DF2148C} = {98C91E27-2C36-4C74-A80F-9ACD7F28BC54} {EC685BDC-9C80-4D6D-94DA-F788976CD104} = {98C91E27-2C36-4C74-A80F-9ACD7F28BC54} + {F8EC5C47-9866-4065-AA8B-0441280BB1C9} = {76B40EBF-8054-4A15-ABE8-141E1CCA6E4E} + {B3D90254-F594-4C15-B003-F828EEDA850A} = {02132B7F-2055-4FA9-AA94-EDB92159AFF8} + {CD2FA54C-BAF5-41B2-B8C7-5C3EDED1B41A} = {76B40EBF-8054-4A15-ABE8-141E1CCA6E4E} + {CE4669C8-E537-400A-A872-A32BD165F1AE} = {CD2FA54C-BAF5-41B2-B8C7-5C3EDED1B41A} + {E7DE3C54-B199-4DF8-ADA0-46FE85AA059F} = {76B40EBF-8054-4A15-ABE8-141E1CCA6E4E} + {70058164-43EB-47E5-8507-23D6A41A2581} = {CD2FA54C-BAF5-41B2-B8C7-5C3EDED1B41A} + {9915A61F-A7CA-4F6F-A213-4B31BE81C3DF} = {70058164-43EB-47E5-8507-23D6A41A2581} + {68A3C906-7470-40A1-B9C3-2F8963AA7E44} = {70058164-43EB-47E5-8507-23D6A41A2581} + {FA335A3A-BD57-472A-B3ED-43F18D9F31A6} = {70058164-43EB-47E5-8507-23D6A41A2581} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1D253492-C786-4DD9-80B5-7DE51D4D3304} diff --git a/WatchIt/Program.cs b/WatchIt/Program.cs index 3086beb..76e1439 100644 --- a/WatchIt/Program.cs +++ b/WatchIt/Program.cs @@ -1,5 +1,16 @@ +using FluentValidation; +using FluentValidation.AspNetCore; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Identity.Data; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using System.Reflection; +using System.Text; using WatchIt.Database; +using WatchIt.Shared.Models.Accounts.Register; +using WatchIt.WebAPI.Services.Controllers; +using WatchIt.WebAPI.Services.Utility.Configuration; +using WatchIt.WebAPI.Services.Utility.JWT; using WatchIt.Website; namespace WatchIt @@ -23,10 +34,7 @@ namespace WatchIt ConfigureLogging(); ConfigureDatabase(); ConfigureWebAPI(); - - // Add services to the container. - _builder.Services.AddRazorComponents() - .AddInteractiveServerComponents(); + ConfigureWebsite(); var app = _builder.Build(); @@ -85,11 +93,86 @@ namespace WatchIt protected static void ConfigureWebAPI() { - _builder.Services.AddControllers(); + _builder.Services.AddValidatorsFromAssembly(Assembly.Load("WatchIt.Shared.Models")); + + _builder.Services.AddAuthentication(x => + { + x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(x => + { + x.RequireHttpsMetadata = false; + x.SaveToken = true; + x.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_builder.Configuration.GetValue("WebAPI:Authentication:Key"))), + ValidateAudience = true, + ValidAudience = "access", + ValidIssuer = _builder.Configuration.GetValue("WebAPI:Authentication:Issuer"), + ValidateLifetime = true, + ClockSkew = TimeSpan.FromMinutes(1), + }; + x.Events = new JwtBearerEvents + { + OnAuthenticationFailed = context => + { + if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) + { + context.Response.Headers.Add("Token-Expired", "true"); + } + return Task.CompletedTask; + } + }; + }) + .AddJwtBearer("refresh", x => + { + x.RequireHttpsMetadata = false; + x.SaveToken = true; + x.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_builder.Configuration.GetValue("WebAPI:Authentication:Key"))), + ValidateAudience = true, + ValidIssuer = _builder.Configuration.GetValue("WebAPI:Authentication:Issuer"), + ValidAudience = "refresh", + ValidateLifetime = true, + ClockSkew = TimeSpan.FromMinutes(1) + }; + x.Events = new JwtBearerEvents + { + OnAuthenticationFailed = context => + { + if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) + { + context.Response.Headers.Add("Token-Expired", "true"); + } + return Task.CompletedTask; + } + }; + }); + _builder.Services.AddAuthorization(); + + _builder.Services.AddHttpContextAccessor(); + + _builder.Services.AddSingleton(); + _builder.Services.AddSingleton(); + + _builder.Services.AddSingleton(); + + _builder.Services.AddFluentValidationAutoValidation(); _builder.Services.AddEndpointsApiExplorer(); + _builder.Services.AddControllers(); _builder.Services.AddSwaggerGen(); } + protected static void ConfigureWebsite() + { + _builder.Services.AddRazorComponents() + .AddInteractiveServerComponents(); + } + #endregion } } diff --git a/WatchIt/WatchIt.csproj b/WatchIt/WatchIt.csproj index 8207f5d..75368ab 100644 --- a/WatchIt/WatchIt.csproj +++ b/WatchIt/WatchIt.csproj @@ -7,6 +7,11 @@ + + + + + all @@ -26,7 +31,15 @@ + + + + + + + + diff --git a/WatchIt/WebAPI/AccountsController.cs b/WatchIt/WebAPI/AccountsController.cs deleted file mode 100644 index c897fdf..0000000 --- a/WatchIt/WebAPI/AccountsController.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace WatchIt.WebAPI -{ - [ApiController] - [Route("api/accounts")] - public class AccountsController : ControllerBase - { - [HttpPost] - [Route("create-account")] - public async Task CreateAccount() - { - } - } -} diff --git a/WatchIt/appsettings.json b/WatchIt/appsettings.json index b01ad1d..5647fb9 100644 --- a/WatchIt/appsettings.json +++ b/WatchIt/appsettings.json @@ -1,12 +1,28 @@ { + "WebAPI": { + "Authentication": { + "Key": "testkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytest", + "Issuer": "WatchIt", + "RefreshToken": { + "Lifetime": 1440, + "ExtendedLifetime": 10080 + }, + "AccessToken": { + "Lifetime": 5 + } + } + }, + "Website": { + + }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*", "ConnectionStrings": { "Default": "Host=localhost;Database=watchit;Username=watchit;Password=Xdv2Etchavbuuho" - } + }, + "AllowedHosts": "*" } diff --git a/genre.json b/genre.json deleted file mode 100644 index acb126a..0000000 --- a/genre.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "Id": 1, - "Name": "Comedy" - }, - { - "Id": 2, - "Name": "Thriller" - }, - { - "Id": 3, - "Name": "Horror" - }, - { - "Id": 4, - "Name": "Action" - } -] \ No newline at end of file