aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Server.Implementations')
-rw-r--r--Jellyfin.Server.Implementations/Activity/ActivityManager.cs40
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedNotifier.cs3
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs3
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedNotifier.cs3
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledNotifier.cs3
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs3
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledNotifier.cs3
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedNotifier.cs3
-rw-r--r--Jellyfin.Server.Implementations/Events/Consumers/Users/UserUpdatedNotifier.cs3
-rw-r--r--Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj5
-rw-r--r--Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs464
-rw-r--r--Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.cs28
-rw-r--r--Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs5
-rw-r--r--Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs1
-rw-r--r--Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs2
-rw-r--r--Jellyfin.Server.Implementations/Users/UserManager.cs15
16 files changed, 545 insertions, 39 deletions
diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs
index abdd290d4..5926abfe0 100644
--- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs
+++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs
@@ -3,8 +3,10 @@ using System.Linq;
using System.Threading.Tasks;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Events;
+using Jellyfin.Data.Queries;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.Querying;
+using Microsoft.EntityFrameworkCore;
namespace Jellyfin.Server.Implementations.Activity
{
@@ -39,41 +41,37 @@ namespace Jellyfin.Server.Implementations.Activity
}
/// <inheritdoc/>
- public QueryResult<ActivityLogEntry> GetPagedResult(
- Func<IQueryable<ActivityLog>, IQueryable<ActivityLog>> func,
- int? startIndex,
- int? limit)
+ public async Task<QueryResult<ActivityLogEntry>> GetPagedResultAsync(ActivityLogQuery query)
{
- using var dbContext = _provider.CreateContext();
+ await using var dbContext = _provider.CreateContext();
- var query = func(dbContext.ActivityLogs.OrderByDescending(entry => entry.DateCreated));
+ IQueryable<ActivityLog> entries = dbContext.ActivityLogs
+ .AsQueryable()
+ .OrderByDescending(entry => entry.DateCreated);
- if (startIndex.HasValue)
+ if (query.MinDate.HasValue)
{
- query = query.Skip(startIndex.Value);
+ entries = entries.Where(entry => entry.DateCreated >= query.MinDate);
}
- if (limit.HasValue)
+ if (query.HasUserId.HasValue)
{
- query = query.Take(limit.Value);
+ entries = entries.Where(entry => entry.UserId != Guid.Empty == query.HasUserId.Value );
}
- // This converts the objects from the new database model to the old for compatibility with the existing API.
- var list = query.Select(ConvertToOldModel).ToList();
-
return new QueryResult<ActivityLogEntry>
{
- Items = list,
- TotalRecordCount = func(dbContext.ActivityLogs).Count()
+ Items = await entries
+ .Skip(query.StartIndex ?? 0)
+ .Take(query.Limit ?? 100)
+ .AsAsyncEnumerable()
+ .Select(ConvertToOldModel)
+ .ToListAsync()
+ .ConfigureAwait(false),
+ TotalRecordCount = await entries.CountAsync().ConfigureAwait(false)
};
}
- /// <inheritdoc/>
- public QueryResult<ActivityLogEntry> GetPagedResult(int? startIndex, int? limit)
- {
- return GetPagedResult(logs => logs, startIndex, limit);
- }
-
private static ActivityLogEntry ConvertToOldModel(ActivityLog entry)
{
return new ActivityLogEntry
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedNotifier.cs
index 80ed56cd8..0993c6df7 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedNotifier.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedNotifier.cs
@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Session;
using MediaBrowser.Model.Tasks;
namespace Jellyfin.Server.Implementations.Events.Consumers.System
@@ -25,7 +26,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.System
/// <inheritdoc />
public async Task OnEvent(TaskCompletionEventArgs eventArgs)
{
- await _sessionManager.SendMessageToAdminSessions("ScheduledTaskEnded", eventArgs.Result, CancellationToken.None).ConfigureAwait(false);
+ await _sessionManager.SendMessageToAdminSessions(SessionMessageType.ScheduledTaskEnded, eventArgs.Result, CancellationToken.None).ConfigureAwait(false);
}
}
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs
index 1c600683a..1d790da6b 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Events.Updates;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Session;
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
{
@@ -25,7 +26,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
/// <inheritdoc />
public async Task OnEvent(PluginInstallationCancelledEventArgs eventArgs)
{
- await _sessionManager.SendMessageToAdminSessions("PackageInstallationCancelled", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
+ await _sessionManager.SendMessageToAdminSessions(SessionMessageType.PackageInstallationCancelled, eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
}
}
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedNotifier.cs
index ea0c878d4..a1faf18fc 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedNotifier.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedNotifier.cs
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Session;
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
{
@@ -25,7 +26,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
/// <inheritdoc />
public async Task OnEvent(InstallationFailedEventArgs eventArgs)
{
- await _sessionManager.SendMessageToAdminSessions("PackageInstallationFailed", eventArgs.InstallationInfo, CancellationToken.None).ConfigureAwait(false);
+ await _sessionManager.SendMessageToAdminSessions(SessionMessageType.PackageInstallationFailed, eventArgs.InstallationInfo, CancellationToken.None).ConfigureAwait(false);
}
}
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledNotifier.cs
index 3dda5a04c..bd1a71404 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledNotifier.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledNotifier.cs
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Events.Updates;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Session;
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
{
@@ -25,7 +26,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
/// <inheritdoc />
public async Task OnEvent(PluginInstalledEventArgs eventArgs)
{
- await _sessionManager.SendMessageToAdminSessions("PackageInstallationCompleted", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
+ await _sessionManager.SendMessageToAdminSessions(SessionMessageType.PackageInstallationCompleted, eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
}
}
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs
index f691d11a7..b513ac64a 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Events.Updates;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Session;
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
{
@@ -25,7 +26,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
/// <inheritdoc />
public async Task OnEvent(PluginInstallingEventArgs eventArgs)
{
- await _sessionManager.SendMessageToAdminSessions("PackageInstalling", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
+ await _sessionManager.SendMessageToAdminSessions(SessionMessageType.PackageInstalling, eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
}
}
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledNotifier.cs
index 709692f6b..1fd7b9adf 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledNotifier.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledNotifier.cs
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Events.Updates;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Session;
namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
{
@@ -25,7 +26,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Updates
/// <inheritdoc />
public async Task OnEvent(PluginUninstalledEventArgs eventArgs)
{
- await _sessionManager.SendMessageToAdminSessions("PluginUninstalled", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
+ await _sessionManager.SendMessageToAdminSessions(SessionMessageType.PackageUninstalled, eventArgs.Argument, CancellationToken.None).ConfigureAwait(false);
}
}
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedNotifier.cs
index 10367a939..303e88621 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedNotifier.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedNotifier.cs
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Jellyfin.Data.Events.Users;
using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Session;
namespace Jellyfin.Server.Implementations.Events.Consumers.Users
{
@@ -30,7 +31,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Users
{
await _sessionManager.SendMessageToUserSessions(
new List<Guid> { eventArgs.Argument.Id },
- "UserDeleted",
+ SessionMessageType.UserDeleted,
eventArgs.Argument.Id.ToString("N", CultureInfo.InvariantCulture),
CancellationToken.None).ConfigureAwait(false);
}
diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserUpdatedNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserUpdatedNotifier.cs
index 6081dd044..a14911b94 100644
--- a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserUpdatedNotifier.cs
+++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserUpdatedNotifier.cs
@@ -6,6 +6,7 @@ using Jellyfin.Data.Events.Users;
using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Session;
namespace Jellyfin.Server.Implementations.Events.Consumers.Users
{
@@ -33,7 +34,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Users
{
await _sessionManager.SendMessageToUserSessions(
new List<Guid> { e.Argument.Id },
- "UserUpdated",
+ SessionMessageType.UserUpdated,
_userManager.GetUserDto(e.Argument),
CancellationToken.None).ConfigureAwait(false);
}
diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
index 30ed3e6af..17ba09258 100644
--- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
+++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
@@ -24,11 +24,12 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.7">
+ <PackageReference Include="System.Linq.Async" Version="4.1.1" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
- <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.7">
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
diff --git a/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs
new file mode 100644
index 000000000..e5c326a32
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.Designer.cs
@@ -0,0 +1,464 @@
+#pragma warning disable CS1591
+
+// <auto-generated />
+using System;
+using Jellyfin.Server.Implementations;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace Jellyfin.Server.Implementations.Migrations
+{
+ [DbContext(typeof(JellyfinDb))]
+ [Migration("20201004171403_AddMaxActiveSessions")]
+ partial class AddMaxActiveSessions
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasDefaultSchema("jellyfin")
+ .HasAnnotation("ProductVersion", "3.1.8");
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("DayOfWeek")
+ .HasColumnType("INTEGER");
+
+ b.Property<double>("EndHour")
+ .HasColumnType("REAL");
+
+ b.Property<double>("StartHour")
+ .HasColumnType("REAL");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AccessSchedules");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("DateCreated")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("ItemId")
+ .HasColumnType("TEXT")
+ .HasMaxLength(256);
+
+ b.Property<int>("LogSeverity")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<string>("Overview")
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("ShortOverview")
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<string>("Type")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(256);
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("ActivityLogs");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("ChromecastVersion")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Client")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(32);
+
+ b.Property<string>("DashboardTheme")
+ .HasColumnType("TEXT")
+ .HasMaxLength(32);
+
+ b.Property<bool>("EnableNextVideoInfoOverlay")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("IndexBy")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("ScrollDirection")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("ShowBackdrop")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("ShowSidebar")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("SkipBackwardLength")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("SkipForwardLength")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("TvHome")
+ .HasColumnType("TEXT")
+ .HasMaxLength(32);
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("UserId", "Client")
+ .IsUnique();
+
+ b.ToTable("DisplayPreferences");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("DisplayPreferencesId")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Order")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Type")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DisplayPreferencesId");
+
+ b.ToTable("HomeSection");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime>("LastModified")
+ .HasColumnType("TEXT");
+
+ b.Property<string>("Path")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(512);
+
+ b.Property<Guid?>("UserId")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("ImageInfos");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Client")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(32);
+
+ b.Property<int?>("IndexBy")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid>("ItemId")
+ .HasColumnType("TEXT");
+
+ b.Property<bool>("RememberIndexing")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("RememberSorting")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SortBy")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(64);
+
+ b.Property<int>("SortOrder")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("TEXT");
+
+ b.Property<int>("ViewType")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ItemDisplayPreferences");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid?>("Permission_Permissions_Guid")
+ .HasColumnType("TEXT");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("Value")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Permission_Permissions_Guid");
+
+ b.ToTable("Permissions");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("Kind")
+ .HasColumnType("INTEGER");
+
+ b.Property<Guid?>("Preference_Preferences_Guid")
+ .HasColumnType("TEXT");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Value")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.HasKey("Id");
+
+ b.HasIndex("Preference_Preferences_Guid");
+
+ b.ToTable("Preferences");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.User", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT");
+
+ b.Property<string>("AudioLanguagePreference")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<string>("AuthenticationProviderId")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<bool>("DisplayCollectionsView")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("DisplayMissingEpisodes")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("EasyPassword")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<bool>("EnableAutoLogin")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("EnableLocalPassword")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("EnableNextEpisodeAutoPlay")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("EnableUserPreferenceAccess")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("HidePlayedInLatest")
+ .HasColumnType("INTEGER");
+
+ b.Property<long>("InternalId")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("InvalidLoginAttemptCount")
+ .HasColumnType("INTEGER");
+
+ b.Property<DateTime?>("LastActivityDate")
+ .HasColumnType("TEXT");
+
+ b.Property<DateTime?>("LastLoginDate")
+ .HasColumnType("TEXT");
+
+ b.Property<int?>("LoginAttemptsBeforeLockout")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MaxActiveSessions")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("MaxParentalAgeRating")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("MustUpdatePassword")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Password")
+ .HasColumnType("TEXT")
+ .HasMaxLength(65535);
+
+ b.Property<string>("PasswordResetProviderId")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<bool>("PlayDefaultAudioTrack")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("RememberAudioSelections")
+ .HasColumnType("INTEGER");
+
+ b.Property<bool>("RememberSubtitleSelections")
+ .HasColumnType("INTEGER");
+
+ b.Property<int?>("RemoteClientBitrateLimit")
+ .HasColumnType("INTEGER");
+
+ b.Property<uint>("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("SubtitleLanguagePreference")
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.Property<int>("SubtitleMode")
+ .HasColumnType("INTEGER");
+
+ b.Property<int>("SyncPlayAccess")
+ .HasColumnType("INTEGER");
+
+ b.Property<string>("Username")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(255);
+
+ b.HasKey("Id");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("AccessSchedules")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithOne("DisplayPreferences")
+ .HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.DisplayPreferences", null)
+ .WithMany("HomeSections")
+ .HasForeignKey("DisplayPreferencesId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithOne("ProfileImage")
+ .HasForeignKey("Jellyfin.Data.Entities.ImageInfo", "UserId");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("ItemDisplayPreferences")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Permissions")
+ .HasForeignKey("Permission_Permissions_Guid");
+ });
+
+ modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b =>
+ {
+ b.HasOne("Jellyfin.Data.Entities.User", null)
+ .WithMany("Preferences")
+ .HasForeignKey("Preference_Preferences_Guid");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.cs b/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.cs
new file mode 100644
index 000000000..10acb4def
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Migrations/20201004171403_AddMaxActiveSessions.cs
@@ -0,0 +1,28 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1601
+
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Jellyfin.Server.Implementations.Migrations
+{
+ public partial class AddMaxActiveSessions : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn<int>(
+ name: "MaxActiveSessions",
+ schema: "jellyfin",
+ table: "Users",
+ nullable: false,
+ defaultValue: 0);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "MaxActiveSessions",
+ schema: "jellyfin",
+ table: "Users");
+ }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
index ccfcf96b1..16d62f482 100644
--- a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
+++ b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs
@@ -15,7 +15,7 @@ namespace Jellyfin.Server.Implementations.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("jellyfin")
- .HasAnnotation("ProductVersion", "3.1.7");
+ .HasAnnotation("ProductVersion", "3.1.8");
modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b =>
{
@@ -344,6 +344,9 @@ namespace Jellyfin.Server.Implementations.Migrations
b.Property<int?>("LoginAttemptsBeforeLockout")
.HasColumnType("INTEGER");
+ b.Property<int>("MaxActiveSessions")
+ .HasColumnType("INTEGER");
+
b.Property<int?>("MaxParentalAgeRating")
.HasColumnType("INTEGER");
diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs
index 46f1c618f..76f943385 100644
--- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs
+++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs
@@ -61,6 +61,7 @@ namespace Jellyfin.Server.Implementations.Users
public IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client)
{
return _dbContext.ItemDisplayPreferences
+ .AsQueryable()
.Where(prefs => prefs.UserId == userId && prefs.ItemId != Guid.Empty && string.Equals(prefs.Client, client))
.ToList();
}
diff --git a/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs b/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs
index e38cd07f0..5f32479e1 100644
--- a/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs
+++ b/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs
@@ -15,7 +15,7 @@ namespace Jellyfin.Server.Implementations.Users
public string Name => "InvalidOrMissingAuthenticationProvider";
/// <inheritdoc />
- public bool IsEnabled => true;
+ public bool IsEnabled => false;
/// <inheritdoc />
public Task<ProviderAuthenticationResult> Authenticate(string username, string password)
diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs
index 8f04baa08..437833aa3 100644
--- a/Jellyfin.Server.Implementations/Users/UserManager.cs
+++ b/Jellyfin.Server.Implementations/Users/UserManager.cs
@@ -108,6 +108,7 @@ namespace Jellyfin.Server.Implementations.Users
{
using var dbContext = _dbProvider.CreateContext();
return dbContext.Users
+ .AsQueryable()
.Select(user => user.Id)
.ToList();
}
@@ -200,8 +201,8 @@ namespace Jellyfin.Server.Implementations.Users
internal async Task<User> CreateUserInternalAsync(string name, JellyfinDb dbContext)
{
// TODO: Remove after user item data is migrated.
- var max = await dbContext.Users.AnyAsync().ConfigureAwait(false)
- ? await dbContext.Users.Select(u => u.InternalId).MaxAsync().ConfigureAwait(false)
+ var max = await dbContext.Users.AsQueryable().AnyAsync().ConfigureAwait(false)
+ ? await dbContext.Users.AsQueryable().Select(u => u.InternalId).MaxAsync().ConfigureAwait(false)
: 0;
return new User(
@@ -221,7 +222,7 @@ namespace Jellyfin.Server.Implementations.Users
throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)");
}
- using var dbContext = _dbProvider.CreateContext();
+ await using var dbContext = _dbProvider.CreateContext();
var newUser = await CreateUserInternalAsync(name, dbContext).ConfigureAwait(false);
@@ -379,6 +380,7 @@ namespace Jellyfin.Server.Implementations.Users
PasswordResetProviderId = user.PasswordResetProviderId,
InvalidLoginAttemptCount = user.InvalidLoginAttemptCount,
LoginAttemptsBeforeLockout = user.LoginAttemptsBeforeLockout ?? -1,
+ MaxActiveSessions = user.MaxActiveSessions,
IsAdministrator = user.HasPermission(PermissionKind.IsAdministrator),
IsHidden = user.HasPermission(PermissionKind.IsHidden),
IsDisabled = user.HasPermission(PermissionKind.IsDisabled),
@@ -587,9 +589,9 @@ namespace Jellyfin.Server.Implementations.Users
public async Task InitializeAsync()
{
// TODO: Refactor the startup wizard so that it doesn't require a user to already exist.
- using var dbContext = _dbProvider.CreateContext();
+ await using var dbContext = _dbProvider.CreateContext();
- if (await dbContext.Users.AnyAsync().ConfigureAwait(false))
+ if (await dbContext.Users.AsQueryable().AnyAsync().ConfigureAwait(false))
{
return;
}
@@ -701,6 +703,7 @@ namespace Jellyfin.Server.Implementations.Users
user.PasswordResetProviderId = policy.PasswordResetProviderId;
user.InvalidLoginAttemptCount = policy.InvalidLoginAttemptCount;
user.LoginAttemptsBeforeLockout = maxLoginAttempts;
+ user.MaxActiveSessions = policy.MaxActiveSessions;
user.SyncPlayAccess = policy.SyncPlayAccess;
user.SetPermission(PermissionKind.IsAdministrator, policy.IsAdministrator);
user.SetPermission(PermissionKind.IsHidden, policy.IsHidden);
@@ -799,7 +802,7 @@ namespace Jellyfin.Server.Implementations.Users
private IList<IPasswordResetProvider> GetPasswordResetProviders(User user)
{
- var passwordResetProviderId = user?.PasswordResetProviderId;
+ var passwordResetProviderId = user.PasswordResetProviderId;
var providers = _passwordResetProviders.Where(i => i.IsEnabled).ToArray();
if (!string.IsNullOrEmpty(passwordResetProviderId))