aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Server.Implementations')
-rw-r--r--Jellyfin.Server.Implementations/JellyfinDb.cs94
-rw-r--r--Jellyfin.Server.Implementations/JellyfinDbProvider.cs14
-rw-r--r--Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs20
-rw-r--r--Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs20
-rw-r--r--Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs28
-rw-r--r--Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs20
-rw-r--r--Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs25
-rw-r--r--Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs24
-rw-r--r--Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs21
-rw-r--r--Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs56
10 files changed, 228 insertions, 94 deletions
diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs
index 6f35a2c1c..dc4f53913 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<User>()
- .Property(user => user.Username)
- .UseCollation("NOCASE");
-
- // Delete behavior
-
- modelBuilder.Entity<User>()
- .HasOne(u => u.ProfileImage)
- .WithOne()
- .OnDelete(DeleteBehavior.Cascade);
-
- modelBuilder.Entity<User>()
- .HasMany(u => u.Permissions)
- .WithOne()
- .HasForeignKey(p => p.UserId)
- .OnDelete(DeleteBehavior.Cascade);
-
- modelBuilder.Entity<User>()
- .HasMany(u => u.Preferences)
- .WithOne()
- .HasForeignKey(p => p.UserId)
- .OnDelete(DeleteBehavior.Cascade);
-
- modelBuilder.Entity<User>()
- .HasMany(u => u.AccessSchedules)
- .WithOne()
- .OnDelete(DeleteBehavior.Cascade);
-
- modelBuilder.Entity<User>()
- .HasMany(u => u.DisplayPreferences)
- .WithOne()
- .OnDelete(DeleteBehavior.Cascade);
-
- modelBuilder.Entity<User>()
- .HasMany(u => u.ItemDisplayPreferences)
- .WithOne()
- .OnDelete(DeleteBehavior.Cascade);
-
- modelBuilder.Entity<DisplayPreferences>()
- .HasMany(d => d.HomeSections)
- .WithOne()
- .OnDelete(DeleteBehavior.Cascade);
-
- // Indexes
-
- modelBuilder.Entity<ApiKey>()
- .HasIndex(entity => entity.AccessToken)
- .IsUnique();
-
- modelBuilder.Entity<User>()
- .HasIndex(entity => entity.Username)
- .IsUnique();
-
- modelBuilder.Entity<Device>()
- .HasIndex(entity => new { entity.DeviceId, entity.DateLastActivity });
-
- modelBuilder.Entity<Device>()
- .HasIndex(entity => new { entity.AccessToken, entity.DateLastActivity });
-
- modelBuilder.Entity<Device>()
- .HasIndex(entity => new { entity.UserId, entity.DeviceId });
-
- modelBuilder.Entity<Device>()
- .HasIndex(entity => entity.DeviceId);
-
- modelBuilder.Entity<DeviceOptions>()
- .HasIndex(entity => entity.DeviceId)
- .IsUnique();
-
- modelBuilder.Entity<DisplayPreferences>()
- .HasIndex(entity => new { entity.UserId, entity.ItemId, entity.Client })
- .IsUnique();
-
- modelBuilder.Entity<CustomItemDisplayPreferences>()
- .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<Permission>()
- .HasIndex(p => new { p.UserId, p.Kind })
- .HasFilter("[UserId] IS NOT NULL")
- .IsUnique();
-
- modelBuilder.Entity<Preference>()
- .HasIndex(p => new { p.UserId, p.Kind })
- .HasFilter("[UserId] IS NOT NULL")
- .IsUnique();
+ // Configuration for each entity is in it's own class inside 'ModelConfiguration'.
+ modelBuilder.ApplyConfigurationsFromAssembly(typeof(JellyfinDb).Assembly);
}
}
}
diff --git a/Jellyfin.Server.Implementations/JellyfinDbProvider.cs b/Jellyfin.Server.Implementations/JellyfinDbProvider.cs
index 486be6053..c2c5198d1 100644
--- a/Jellyfin.Server.Implementations/JellyfinDbProvider.cs
+++ b/Jellyfin.Server.Implementations/JellyfinDbProvider.cs
@@ -1,8 +1,10 @@
using System;
using System.IO;
+using System.Linq;
using MediaBrowser.Common.Configuration;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
namespace Jellyfin.Server.Implementations
{
@@ -13,19 +15,27 @@ namespace Jellyfin.Server.Implementations
{
private readonly IServiceProvider _serviceProvider;
private readonly IApplicationPaths _appPaths;
+ private readonly ILogger<JellyfinDbProvider> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="JellyfinDbProvider"/> class.
/// </summary>
/// <param name="serviceProvider">The application's service provider.</param>
/// <param name="appPaths">The application paths.</param>
- public JellyfinDbProvider(IServiceProvider serviceProvider, IApplicationPaths appPaths)
+ /// <param name="logger">The logger.</param>
+ public JellyfinDbProvider(IServiceProvider serviceProvider, IApplicationPaths appPaths, ILogger<JellyfinDbProvider> logger)
{
_serviceProvider = serviceProvider;
_appPaths = appPaths;
+ _logger = logger;
using var jellyfinDb = CreateContext();
- jellyfinDb.Database.Migrate();
+ if (jellyfinDb.Database.GetPendingMigrations().Any())
+ {
+ _logger.LogInformation("There are pending EFCore migrations in the database. Applying... (This may take a while, do not stop Jellyfin)");
+ jellyfinDb.Database.Migrate();
+ _logger.LogInformation("EFCore migrations applied successfully");
+ }
}
/// <summary>
diff --git a/Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs b/Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs
new file mode 100644
index 000000000..3f19b6986
--- /dev/null
+++ b/Jellyfin.Server.Implementations/ModelConfiguration/ApiKeyConfiguration.cs
@@ -0,0 +1,20 @@
+using Jellyfin.Data.Entities.Security;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+ /// <summary>
+ /// FluentAPI configuration for the ApiKey entity.
+ /// </summary>
+ public class ApiKeyConfiguration : IEntityTypeConfiguration<ApiKey>
+ {
+ /// <inheritdoc/>
+ public void Configure(EntityTypeBuilder<ApiKey> builder)
+ {
+ 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 000000000..779aec986
--- /dev/null
+++ b/Jellyfin.Server.Implementations/ModelConfiguration/CustomItemDisplayPreferencesConfiguration.cs
@@ -0,0 +1,20 @@
+using Jellyfin.Data.Entities;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+ /// <summary>
+ /// FluentAPI configuration for the CustomItemDisplayPreferences entity.
+ /// </summary>
+ public class CustomItemDisplayPreferencesConfiguration : IEntityTypeConfiguration<CustomItemDisplayPreferences>
+ {
+ /// <inheritdoc/>
+ public void Configure(EntityTypeBuilder<CustomItemDisplayPreferences> builder)
+ {
+ 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 000000000..a750b65c0
--- /dev/null
+++ b/Jellyfin.Server.Implementations/ModelConfiguration/DeviceConfiguration.cs
@@ -0,0 +1,28 @@
+using Jellyfin.Data.Entities.Security;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+ /// <summary>
+ /// FluentAPI configuration for the Device entity.
+ /// </summary>
+ public class DeviceConfiguration : IEntityTypeConfiguration<Device>
+ {
+ /// <inheritdoc/>
+ public void Configure(EntityTypeBuilder<Device> builder)
+ {
+ 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 000000000..038afd752
--- /dev/null
+++ b/Jellyfin.Server.Implementations/ModelConfiguration/DeviceOptionsConfiguration.cs
@@ -0,0 +1,20 @@
+using Jellyfin.Data.Entities.Security;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+ /// <summary>
+ /// FluentAPI configuration for the DeviceOptions entity.
+ /// </summary>
+ public class DeviceOptionsConfiguration : IEntityTypeConfiguration<DeviceOptions>
+ {
+ /// <inheritdoc/>
+ public void Configure(EntityTypeBuilder<DeviceOptions> builder)
+ {
+ 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 000000000..9b437861b
--- /dev/null
+++ b/Jellyfin.Server.Implementations/ModelConfiguration/DisplayPreferencesConfiguration.cs
@@ -0,0 +1,25 @@
+using Jellyfin.Data.Entities;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+ /// <summary>
+ /// FluentAPI configuration for the DisplayPreferencesConfiguration entity.
+ /// </summary>
+ public class DisplayPreferencesConfiguration : IEntityTypeConfiguration<DisplayPreferences>
+ {
+ /// <inheritdoc/>
+ public void Configure(EntityTypeBuilder<DisplayPreferences> builder)
+ {
+ builder
+ .HasMany(d => d.HomeSections)
+ .WithOne()
+ .OnDelete(DeleteBehavior.Cascade);
+
+ 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 000000000..240e284c0
--- /dev/null
+++ b/Jellyfin.Server.Implementations/ModelConfiguration/PermissionConfiguration.cs
@@ -0,0 +1,24 @@
+using Jellyfin.Data.Entities;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+ /// <summary>
+ /// FluentAPI configuration for the Permission entity.
+ /// </summary>
+ public class PermissionConfiguration : IEntityTypeConfiguration<Permission>
+ {
+ /// <inheritdoc/>
+ public void Configure(EntityTypeBuilder<Permission> builder)
+ {
+ // 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 000000000..49c869c6a
--- /dev/null
+++ b/Jellyfin.Server.Implementations/ModelConfiguration/PreferenceConfiguration.cs
@@ -0,0 +1,21 @@
+using Jellyfin.Data.Entities;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+ /// <summary>
+ /// FluentAPI configuration for the Permission entity.
+ /// </summary>
+ public class PreferenceConfiguration : IEntityTypeConfiguration<Preference>
+ {
+ /// <inheritdoc/>
+ public void Configure(EntityTypeBuilder<Preference> builder)
+ {
+ 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 000000000..a369cf656
--- /dev/null
+++ b/Jellyfin.Server.Implementations/ModelConfiguration/UserConfiguration.cs
@@ -0,0 +1,56 @@
+using Jellyfin.Data.Entities;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Jellyfin.Server.Implementations.ModelConfiguration
+{
+ /// <summary>
+ /// FluentAPI configuration for the User entity.
+ /// </summary>
+ public class UserConfiguration : IEntityTypeConfiguration<User>
+ {
+ /// <inheritdoc/>
+ public void Configure(EntityTypeBuilder<User> builder)
+ {
+ builder
+ .Property(user => user.Username)
+ .UseCollation("NOCASE");
+
+ 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);
+
+ builder
+ .HasIndex(entity => entity.Username)
+ .IsUnique();
+ }
+ }
+}