| 
					
				 | 
			
			
				@@ -1,7 +1,7 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #pragma warning disable CA1307 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#pragma warning disable CA1309 // Use ordinal string comparison - EF can't translate this 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using System.Collections.Concurrent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Collections.Generic; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Globalization; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Linq; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -46,8 +46,6 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private readonly DefaultPasswordResetProvider _defaultPasswordResetProvider; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private readonly IServerConfigurationManager _serverConfigurationManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly IDictionary<Guid, User> _users; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// Initializes a new instance of the <see cref="UserManager"/> class. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -58,6 +56,8 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="imageProcessor">The image processor.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="logger">The logger.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="serverConfigurationManager">The system config manager.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="passwordResetProviders">The password reset providers.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="authenticationProviders">The authentication providers.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public UserManager( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IDbContextFactory<JellyfinDbContext> dbProvider, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IEventManager eventManager, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -65,7 +65,9 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IApplicationHost appHost, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IImageProcessor imageProcessor, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ILogger<UserManager> logger, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            IServerConfigurationManager serverConfigurationManager) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            IServerConfigurationManager serverConfigurationManager, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            IEnumerable<IPasswordResetProvider> passwordResetProviders, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            IEnumerable<IAuthenticationProvider> authenticationProviders) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _dbProvider = dbProvider; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _eventManager = eventManager; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -75,35 +77,36 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _logger = logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _serverConfigurationManager = serverConfigurationManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _passwordResetProviders = appHost.GetExports<IPasswordResetProvider>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _authenticationProviders = appHost.GetExports<IAuthenticationProvider>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _passwordResetProviders = passwordResetProviders.ToList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _authenticationProviders = authenticationProviders.ToList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _invalidAuthProvider = _authenticationProviders.OfType<InvalidAuthProvider>().First(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _defaultAuthenticationProvider = _authenticationProviders.OfType<DefaultAuthenticationProvider>().First(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _defaultPasswordResetProvider = _passwordResetProviders.OfType<DefaultPasswordResetProvider>().First(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _users = new ConcurrentDictionary<Guid, User>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            using var dbContext = _dbProvider.CreateDbContext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            foreach (var user in dbContext.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .AsSplitQuery() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .Include(user => user.Permissions) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .Include(user => user.Preferences) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .Include(user => user.AccessSchedules) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .Include(user => user.ProfileImage) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .AsEnumerable()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _users.Add(user.Id, user); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public event EventHandler<GenericEventArgs<User>>? OnUserUpdated; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public IEnumerable<User> Users => _users.Values; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public IEnumerable<User> Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            get 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                using var dbContext = _dbProvider.CreateDbContext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return GetUsersInternal(dbContext).ToList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public IEnumerable<Guid> UsersIds => _users.Keys; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public IEnumerable<Guid> UsersIds 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            get 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                using var dbContext = _dbProvider.CreateDbContext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return dbContext.Users.Select(u => u.Id).ToList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // This is some regex that matches only on unicode "word" characters, as well as -, _ and @ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // In theory this will cut out most if not all 'control' characters which should help minimize any weirdness 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -119,8 +122,8 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 throw new ArgumentException("Guid can't be empty", nameof(id)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _users.TryGetValue(id, out var user); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return user; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            using var dbContext = _dbProvider.CreateDbContext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return GetUsersInternal(dbContext).FirstOrDefault(u => u.Id.Equals(id)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -131,7 +134,9 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 throw new ArgumentException("Invalid username", nameof(name)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return _users.Values.FirstOrDefault(u => string.Equals(u.Username, name, StringComparison.OrdinalIgnoreCase)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            using var dbContext = _dbProvider.CreateDbContext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return GetUsersInternal(dbContext) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .FirstOrDefault(u => string.Equals(u.Username, name)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -196,8 +201,6 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             user.AddDefaultPermissions(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             user.AddDefaultPreferences(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _users.Add(user.Id, user); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return user; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -232,40 +235,46 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public async Task DeleteUserAsync(Guid userId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!_users.TryGetValue(userId, out var user)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw new ResourceNotFoundException(nameof(userId)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_users.Count == 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            await using (dbContext.ConfigureAwait(false)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw new InvalidOperationException(string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    "The user '{0}' cannot be deleted because there must be at least one user in the system.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    user.Username)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var user = await dbContext.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .AsSingleQuery() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .Include(u => u.Permissions) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .FirstOrDefaultAsync(u => u.Id.Equals(userId)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (user is null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    throw new ResourceNotFoundException(nameof(userId)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (user.HasPermission(PermissionKind.IsAdministrator) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                && Users.Count(i => i.HasPermission(PermissionKind.IsAdministrator)) == 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw new ArgumentException( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (await dbContext.Users.CountAsync().ConfigureAwait(false) == 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    throw new InvalidOperationException(string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        "The user '{0}' cannot be deleted because there must be at least one admin user in the system.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        user.Username), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    nameof(userId)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        "The user '{0}' cannot be deleted because there must be at least one user in the system.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        user.Username)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (user.HasPermission(PermissionKind.IsAdministrator) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    && await dbContext.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .CountAsync(u => u.Permissions.Any(p => p.Kind == PermissionKind.IsAdministrator && p.Value)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .ConfigureAwait(false) == 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    throw new ArgumentException( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            "The user '{0}' cannot be deleted because there must be at least one admin user in the system.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            user.Username), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        nameof(userId)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            await using (dbContext.ConfigureAwait(false)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 dbContext.Users.Remove(user); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 await dbContext.SaveChangesAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _users.Remove(userId); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            await _eventManager.PublishAsync(new UserDeletedEventArgs(user)).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                await _eventManager.PublishAsync(new UserDeletedEventArgs(user)).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -532,23 +541,23 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public async Task InitializeAsync() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // TODO: Refactor the startup wizard so that it doesn't require a user to already exist. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_users.Any()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            await using (dbContext.ConfigureAwait(false)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // TODO: Refactor the startup wizard so that it doesn't require a user to already exist. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (await dbContext.Users.AnyAsync().ConfigureAwait(false)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var defaultName = Environment.UserName; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (string.IsNullOrWhiteSpace(defaultName) || !ValidUsernameRegex().IsMatch(defaultName)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                defaultName = "MyJellyfinUser"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var defaultName = Environment.UserName; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (string.IsNullOrWhiteSpace(defaultName) || !ValidUsernameRegex().IsMatch(defaultName)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    defaultName = "MyJellyfinUser"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _logger.LogWarning("No users, creating one with username {UserName}", defaultName); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _logger.LogWarning("No users, creating one with username {UserName}", defaultName); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            await using (dbContext.ConfigureAwait(false)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var newUser = await CreateUserInternalAsync(defaultName, dbContext).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 newUser.SetPermission(PermissionKind.IsAdministrator, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 newUser.SetPermission(PermissionKind.EnableContentDeletion, true); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -595,12 +604,9 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             await using (dbContext.ConfigureAwait(false)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var user = dbContext.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               .Include(u => u.Permissions) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               .Include(u => u.Preferences) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               .Include(u => u.AccessSchedules) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               .Include(u => u.ProfileImage) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               .FirstOrDefault(u => u.Id.Equals(userId)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var user = await GetUsersInternal(dbContext) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .FirstOrDefaultAsync(u => u.Id.Equals(userId)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .ConfigureAwait(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                            ?? throw new ArgumentException("No user exists with given Id!"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 user.SubtitleMode = config.SubtitleMode; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -628,7 +634,6 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 user.SetPreference(PreferenceKind.LatestItemExcludes, config.LatestItemsExcludes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 dbContext.Update(user); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _users[user.Id] = user; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 await dbContext.SaveChangesAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -639,12 +644,9 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var dbContext = await _dbProvider.CreateDbContextAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             await using (dbContext.ConfigureAwait(false)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var user = dbContext.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               .Include(u => u.Permissions) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               .Include(u => u.Preferences) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               .Include(u => u.AccessSchedules) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               .Include(u => u.ProfileImage) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               .FirstOrDefault(u => u.Id.Equals(userId)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var user = await GetUsersInternal(dbContext) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .FirstOrDefaultAsync(u => u.Id.Equals(userId)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .ConfigureAwait(false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                            ?? throw new ArgumentException("No user exists with given Id!"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // The default number of login attempts is 3, but for some god forsaken reason it's sent to the server as "0" 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -704,7 +706,6 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 user.SetPreference(PreferenceKind.EnableContentDeletionFromFolders, policy.EnableContentDeletionFromFolders); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 dbContext.Update(user); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                _users[user.Id] = user; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 await dbContext.SaveChangesAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -725,7 +726,6 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             user.ProfileImage = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _users[user.Id] = user; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         internal static void ThrowIfInvalidUsername(string name) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -872,8 +872,15 @@ namespace Jellyfin.Server.Implementations.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private async Task UpdateUserInternalAsync(JellyfinDbContext dbContext, User user) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             dbContext.Users.Update(user); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _users[user.Id] = user; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             await dbContext.SaveChangesAsync().ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private IQueryable<User> GetUsersInternal(JellyfinDbContext dbContext) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            => dbContext.Users 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .AsSplitQuery() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .Include(user => user.Permissions) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .Include(user => user.Preferences) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .Include(user => user.AccessSchedules) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .Include(user => user.ProfileImage); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |