From f4af78817d5832c11ff96f365714917fad0db4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Fern=C3=A1ndez?= Date: Mon, 6 Sep 2021 21:05:21 +0200 Subject: [PATCH] Move model configuration to its own classes --- Jellyfin.Server.Implementations/JellyfinDb.cs | 94 +------------------ .../ModelConfiguration/ApiKeyConfiguration.cs | 22 +++++ ...stomItemDisplayPreferencesConfiguration.cs | 22 +++++ .../ModelConfiguration/DeviceConfiguration.cs | 30 ++++++ .../DeviceOptionsConfiguration.cs | 22 +++++ .../DisplayPreferencesConfiguration.cs | 29 ++++++ .../PermissionConfiguration.cs | 26 +++++ .../PreferenceConfiguration.cs | 23 +++++ .../ModelConfiguration/UserConfiguration.cs | 62 ++++++++++++ 9 files changed, 238 insertions(+), 92 deletions(-) create mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs create mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs create mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs create mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs create mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs create mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs create mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs create mode 100644 Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index 6f35a2c1c2..b176e14a61 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -153,100 +153,10 @@ namespace Jellyfin.Server.Implementations { modelBuilder.SetDefaultDateTimeKind(DateTimeKind.Utc); base.OnModelCreating(modelBuilder); - modelBuilder.HasDefaultSchema("jellyfin"); - // Collations - - modelBuilder.Entity() - .Property(user => user.Username) - .UseCollation("NOCASE"); - - // Delete behavior - - modelBuilder.Entity() - .HasOne(u => u.ProfileImage) - .WithOne() - .OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity() - .HasMany(u => u.Permissions) - .WithOne() - .HasForeignKey(p => p.UserId) - .OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity() - .HasMany(u => u.Preferences) - .WithOne() - .HasForeignKey(p => p.UserId) - .OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity() - .HasMany(u => u.AccessSchedules) - .WithOne() - .OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity() - .HasMany(u => u.DisplayPreferences) - .WithOne() - .OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity() - .HasMany(u => u.ItemDisplayPreferences) - .WithOne() - .OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity() - .HasMany(d => d.HomeSections) - .WithOne() - .OnDelete(DeleteBehavior.Cascade); - - // Indexes - - modelBuilder.Entity() - .HasIndex(entity => entity.AccessToken) - .IsUnique(); - - modelBuilder.Entity() - .HasIndex(entity => entity.Username) - .IsUnique(); - - modelBuilder.Entity() - .HasIndex(entity => new { entity.DeviceId, entity.DateLastActivity }); - - modelBuilder.Entity() - .HasIndex(entity => new { entity.AccessToken, entity.DateLastActivity }); - - modelBuilder.Entity() - .HasIndex(entity => new { entity.UserId, entity.DeviceId }); - - modelBuilder.Entity() - .HasIndex(entity => entity.DeviceId); - - modelBuilder.Entity() - .HasIndex(entity => entity.DeviceId) - .IsUnique(); - - modelBuilder.Entity() - .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client }) - .IsUnique(); - - modelBuilder.Entity() - .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client, entity.Key }) - .IsUnique(); - - // Used to get a user's permissions or a specific permission for a user. - // Also prevents multiple values being created for a user. - // Filtered over non-null user ids for when other entities (groups, API keys) get permissions - modelBuilder.Entity() - .HasIndex(p => new { p.UserId, p.Kind }) - .HasFilter("[UserId] IS NOT NULL") - .IsUnique(); - - modelBuilder.Entity() - .HasIndex(p => new { p.UserId, p.Kind }) - .HasFilter("[UserId] IS NOT NULL") - .IsUnique(); + // Configuration for each entity is in it's own class inside 'ModelConfiguratio'. + modelBuilder.ApplyConfigurationsFromAssembly(typeof(JellyfinDb).Assembly); } } } diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs new file mode 100644 index 0000000000..9067d3833d --- /dev/null +++ b/Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs @@ -0,0 +1,22 @@ +using Jellyfin.Data.Entities.Security; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the ApiKey entity. + /// + public class ApiKeyConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + // Indexes + + builder + .HasIndex(entity => entity.AccessToken) + .IsUnique(); + } + } +} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs new file mode 100644 index 0000000000..75d9ba529e --- /dev/null +++ b/Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs @@ -0,0 +1,22 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the CustomItemDisplayPreferences entity. + /// + public class CustomItemDisplayPreferencesConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + // Indexes + + builder + .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client, entity.Key }) + .IsUnique(); + } + } +} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs new file mode 100644 index 0000000000..5b4e711cc4 --- /dev/null +++ b/Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs @@ -0,0 +1,30 @@ +using Jellyfin.Data.Entities.Security; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the Device entity. + /// + public class DeviceConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + // Indexes + + builder + .HasIndex(entity => new { entity.DeviceId, entity.DateLastActivity }); + + builder + .HasIndex(entity => new { entity.AccessToken, entity.DateLastActivity }); + + builder + .HasIndex(entity => new { entity.UserId, entity.DeviceId }); + + builder + .HasIndex(entity => entity.DeviceId); + } + } +} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs new file mode 100644 index 0000000000..0db1944b58 --- /dev/null +++ b/Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs @@ -0,0 +1,22 @@ +using Jellyfin.Data.Entities.Security; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the DeviceOptions entity. + /// + public class DeviceOptionsConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + // Indexes + + builder + .HasIndex(entity => entity.DeviceId) + .IsUnique(); + } + } +} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs new file mode 100644 index 0000000000..807078803d --- /dev/null +++ b/Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs @@ -0,0 +1,29 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the DisplayPreferencesConfiguration entity. + /// + public class DisplayPreferencesConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + // Delete behaviour + + builder + .HasMany(d => d.HomeSections) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + // Indexes + + builder + .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client }) + .IsUnique(); + } + } +} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs new file mode 100644 index 0000000000..56e76d88dd --- /dev/null +++ b/Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs @@ -0,0 +1,26 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the Permission entity. + /// + public class PermissionConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + // Indexes + + // Used to get a user's permissions or a specific permission for a user. + // Also prevents multiple values being created for a user. + // Filtered over non-null user ids for when other entities (groups, API keys) get permissions + builder + .HasIndex(p => new { p.UserId, p.Kind }) + .HasFilter("[UserId] IS NOT NULL") + .IsUnique(); + } + } +} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs new file mode 100644 index 0000000000..3cd5f8afbe --- /dev/null +++ b/Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs @@ -0,0 +1,23 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the Permission entity. + /// + public class PreferenceConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + // Indexes + + builder + .HasIndex(p => new { p.UserId, p.Kind }) + .HasFilter("[UserId] IS NOT NULL") + .IsUnique(); + } + } +} diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs new file mode 100644 index 0000000000..ee88318048 --- /dev/null +++ b/Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs @@ -0,0 +1,62 @@ +using Jellyfin.Data.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Jellyfin.Server.Implementations.ModelConfiguration +{ + /// + /// FluentAPI configuration for the User entity. + /// + public class UserConfiguration : IEntityTypeConfiguration + { + /// + public void Configure(EntityTypeBuilder builder) + { + // Collations + + builder + .Property(user => user.Username) + .UseCollation("NOCASE"); + + // Delete behavior + + builder + .HasOne(u => u.ProfileImage) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasMany(u => u.Permissions) + .WithOne() + .HasForeignKey(p => p.UserId) + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasMany(u => u.Preferences) + .WithOne() + .HasForeignKey(p => p.UserId) + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasMany(u => u.AccessSchedules) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasMany(u => u.DisplayPreferences) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + builder + .HasMany(u => u.ItemDisplayPreferences) + .WithOne() + .OnDelete(DeleteBehavior.Cascade); + + // Indexes + + builder + .HasIndex(entity => entity.Username) + .IsUnique(); + } + } +}