From 68e1ecaaf9626c9596c833571bb591a326449dc8 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 7 Jun 2020 14:47:08 -0600 Subject: Remove EasyPassword from Authentication providers --- .../Users/DefaultAuthenticationProvider.cs | 24 ---------------------- .../Users/InvalidAuthProvider.cs | 12 ----------- 2 files changed, 36 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs index b0c02030e3..9c5056a6b7 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs @@ -111,29 +111,5 @@ namespace Jellyfin.Server.Implementations.Users return Task.CompletedTask; } - - /// - public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash) - { - if (newPassword != null) - { - newPasswordHash = _cryptographyProvider.CreatePasswordHash(newPassword).ToString(); - } - - if (string.IsNullOrWhiteSpace(newPasswordHash)) - { - throw new ArgumentNullException(nameof(newPasswordHash)); - } - - user.EasyPassword = newPasswordHash; - } - - /// - public string GetEasyPasswordHash(User user) - { - return string.IsNullOrEmpty(user.EasyPassword) - ? null - : Hex.Encode(PasswordHash.Parse(user.EasyPassword).Hash); - } } } diff --git a/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs b/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs index b6e65b5595..8ad2fecdb0 100644 --- a/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs +++ b/Jellyfin.Server.Implementations/Users/InvalidAuthProvider.cs @@ -32,17 +32,5 @@ namespace Jellyfin.Server.Implementations.Users { return Task.CompletedTask; } - - /// - public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash) - { - // Nothing here - } - - /// - public string GetEasyPasswordHash(User user) - { - return string.Empty; - } } } -- cgit v1.2.3 From 3d87c4c1b6bca920f444b4a16a99553d0ff6879e Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 7 Jun 2020 14:55:37 -0600 Subject: Fix EasyPassword setting --- Jellyfin.Server.Implementations/Users/UserManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 01151e65e4..35ec78f5c5 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -262,7 +262,7 @@ namespace Jellyfin.Server.Implementations.Users /// public void ChangeEasyPassword(User user, string newPassword, string newPasswordSha1) { - GetAuthenticationProvider(user).ChangeEasyPassword(user, newPassword, newPasswordSha1); + user.EasyPassword = _cryptoProvider.CreatePasswordHash(newPassword).ToString(); UpdateUser(user); OnUserPasswordChanged?.Invoke(this, new GenericEventArgs(user)); -- cgit v1.2.3 From 3169b0af8917ac0bfd189fdb2f261be774b8b869 Mon Sep 17 00:00:00 2001 From: crobibero Date: Mon, 22 Jun 2020 20:24:59 -0600 Subject: fix merge --- .../Users/DefaultAuthenticationProvider.cs | 28 ---------------------- 1 file changed, 28 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs index 9e1183c765..f79e433a67 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultAuthenticationProvider.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using MediaBrowser.Common; using MediaBrowser.Common.Cryptography; using MediaBrowser.Controller.Authentication; using MediaBrowser.Model.Cryptography; @@ -117,32 +116,5 @@ namespace Jellyfin.Server.Implementations.Users return Task.CompletedTask; } -<<<<<<< HEAD -======= - - /// - public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash) - { - if (newPassword != null) - { - newPasswordHash = _cryptographyProvider.CreatePasswordHash(newPassword).ToString(); - } - - if (string.IsNullOrWhiteSpace(newPasswordHash)) - { - throw new ArgumentNullException(nameof(newPasswordHash)); - } - - user.EasyPassword = newPasswordHash; - } - - /// - public string? GetEasyPasswordHash(User user) - { - return string.IsNullOrEmpty(user.EasyPassword) - ? null - : Hex.Encode(PasswordHash.Parse(user.EasyPassword).Hash); - } ->>>>>>> upstream/master } } -- cgit v1.2.3 From 44a8ea6bee3cf3fefc3d290dbaaa8c8e1554868f Mon Sep 17 00:00:00 2001 From: crobibero Date: Wed, 24 Jun 2020 09:45:11 -0600 Subject: implement ChangeEasyPassword from legacy provider --- Jellyfin.Server.Implementations/Users/UserManager.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 97ea03596d..55218c5de9 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -263,7 +263,17 @@ namespace Jellyfin.Server.Implementations.Users /// public void ChangeEasyPassword(User user, string newPassword, string? newPasswordSha1) { - user.EasyPassword = _cryptoProvider.CreatePasswordHash(newPassword).ToString(); + if (newPassword != null) + { + newPasswordSha1 = _cryptoProvider.CreatePasswordHash(newPassword).ToString(); + } + + if (string.IsNullOrWhiteSpace(newPasswordSha1)) + { + throw new ArgumentNullException(nameof(newPasswordSha1)); + } + + user.EasyPassword = newPasswordSha1; UpdateUser(user); OnUserPasswordChanged?.Invoke(this, new GenericEventArgs(user)); -- cgit v1.2.3 From 9a01cd8590ffcae8ce561e6f733bf59fe54932fa Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 24 Jun 2020 20:19:47 -0400 Subject: Fix user deletion. --- Jellyfin.Server.Implementations/Users/UserManager.cs | 19 ++++++++++++++----- MediaBrowser.Api/UserService.cs | 11 ++--------- MediaBrowser.Controller/Library/IUserManager.cs | 4 ++-- 3 files changed, 18 insertions(+), 16 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 9041147588..d86b25f81e 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -192,15 +192,15 @@ namespace Jellyfin.Server.Implementations.Users } /// - public void DeleteUser(User user) + public void DeleteUser(Guid userId) { + var dbContext = _dbProvider.CreateContext(); + var user = dbContext.Users.Find(userId); if (user == null) { - throw new ArgumentNullException(nameof(user)); + throw new ArgumentNullException(nameof(userId)); } - var dbContext = _dbProvider.CreateContext(); - if (dbContext.Users.Find(user.Id) == null) { throw new ArgumentException(string.Format( @@ -226,9 +226,18 @@ namespace Jellyfin.Server.Implementations.Users CultureInfo.InvariantCulture, "The user '{0}' cannot be deleted because there must be at least one admin user in the system.", user.Username), - nameof(user)); + nameof(userId)); + } + + // Clear all entities related to the user from the database. + if (user.ProfileImage != null) + { + dbContext.Remove(user.ProfileImage); } + dbContext.RemoveRange(user.Permissions); + dbContext.RemoveRange(user.Preferences); + dbContext.RemoveRange(user.AccessSchedules); dbContext.Users.Remove(user); dbContext.SaveChanges(); OnUserDeleted?.Invoke(this, new GenericEventArgs(user)); diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 131def5542..6e9d788dc1 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -365,15 +365,8 @@ namespace MediaBrowser.Api public Task DeleteAsync(DeleteUser request) { - var user = _userManager.GetUserById(request.Id); - - if (user == null) - { - throw new ResourceNotFoundException("User not found"); - } - - _sessionMananger.RevokeUserTokens(user.Id, null); - _userManager.DeleteUser(user); + _userManager.DeleteUser(request.Id); + _sessionMananger.RevokeUserTokens(request.Id, null); return Task.CompletedTask; } diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index fe3e4f9e68..4ff3cee0f0 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -111,8 +111,8 @@ namespace MediaBrowser.Controller.Library /// /// Deletes the specified user. /// - /// The user to be deleted. - void DeleteUser(User user); + /// The if of the user to be deleted. + void DeleteUser(Guid userId); /// /// Resets the password. -- cgit v1.2.3 From 2967dd6afd158fc278697fa593852de45e99b84a Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 24 Jun 2020 20:36:58 -0400 Subject: Change to ResourceNotFoundException --- Jellyfin.Server.Implementations/Users/UserManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index d86b25f81e..ae5c311bf2 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -12,6 +12,7 @@ using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using MediaBrowser.Common; using MediaBrowser.Common.Cryptography; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Drawing; @@ -198,7 +199,7 @@ namespace Jellyfin.Server.Implementations.Users var user = dbContext.Users.Find(userId); if (user == null) { - throw new ArgumentNullException(nameof(userId)); + throw new ResourceNotFoundException(nameof(userId)); } if (dbContext.Users.Find(user.Id) == null) -- cgit v1.2.3 From c0bd10879aeaeda9d1a62766c5cfd046cc3ff908 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 9 Jul 2020 21:55:07 -0400 Subject: Ignore casing when authenticating users --- Jellyfin.Server.Implementations/Users/UserManager.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index ace9c4af05..47d514b1a4 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -110,9 +110,8 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Invalid username", nameof(name)); } - // This can't use an overload with StringComparer because that would cause the query to - // have to be evaluated client-side. - return _dbProvider.CreateContext().Users.FirstOrDefault(u => string.Equals(u.Username, name)); + return _dbProvider.CreateContext().Users.ToList() + .FirstOrDefault(u => string.Equals(u.Username, name, StringComparison.OrdinalIgnoreCase)); } /// -- cgit v1.2.3 From 8959621da7d9e0696e530448fc028c0089c2609a Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sun, 12 Jul 2020 14:45:52 -0400 Subject: Fix EF Core memory leak --- .../Users/UserManager.cs | 54 ++++++++++++++++------ 1 file changed, 40 insertions(+), 14 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 47d514b1a4..c8d7fa769a 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -23,6 +23,7 @@ using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Events; using MediaBrowser.Model.Users; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace Jellyfin.Server.Implementations.Users @@ -86,7 +87,18 @@ namespace Jellyfin.Server.Implementations.Users public event EventHandler>? OnUserLockedOut; /// - public IEnumerable Users => _dbProvider.CreateContext().Users; + public IEnumerable Users + { + get + { + using var dbContext = _dbProvider.CreateContext(); + return dbContext.Users.Include(user => user.Permissions) + .Include(user => user.Preferences) + .Include(user => user.AccessSchedules) + .Include(user => user.ProfileImage) + .ToList(); + } + } /// public IEnumerable UsersIds => _dbProvider.CreateContext().Users.Select(u => u.Id); @@ -99,7 +111,12 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Guid can't be empty", nameof(id)); } - return _dbProvider.CreateContext().Users.Find(id); + using var dbContext = _dbProvider.CreateContext(); + return dbContext.Users.Include(user => user.Permissions) + .Include(user => user.Preferences) + .Include(user => user.AccessSchedules) + .Include(user => user.ProfileImage) + .FirstOrDefault(user => user.Id == id); } /// @@ -110,7 +127,13 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Invalid username", nameof(name)); } - return _dbProvider.CreateContext().Users.ToList() + using var dbContext = _dbProvider.CreateContext(); + + return dbContext.Users.Include(user => user.Permissions) + .Include(user => user.Preferences) + .Include(user => user.AccessSchedules) + .Include(user => user.ProfileImage) + .ToList() .FirstOrDefault(u => string.Equals(u.Username, name, StringComparison.OrdinalIgnoreCase)); } @@ -127,7 +150,7 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Invalid username", nameof(newName)); } - if (user.Username.Equals(newName, StringComparison.Ordinal)) + if (user.Username.Equals(newName, StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException("The new and old names must be different."); } @@ -149,7 +172,7 @@ namespace Jellyfin.Server.Implementations.Users /// public void UpdateUser(User user) { - var dbContext = _dbProvider.CreateContext(); + using var dbContext = _dbProvider.CreateContext(); dbContext.Users.Update(user); dbContext.SaveChanges(); } @@ -157,7 +180,7 @@ namespace Jellyfin.Server.Implementations.Users /// public async Task UpdateUserAsync(User user) { - var dbContext = _dbProvider.CreateContext(); + await using var dbContext = _dbProvider.CreateContext(); dbContext.Users.Update(user); await dbContext.SaveChangesAsync().ConfigureAwait(false); @@ -171,7 +194,7 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"); } - var dbContext = _dbProvider.CreateContext(); + using var dbContext = _dbProvider.CreateContext(); // TODO: Remove after user item data is migrated. var max = dbContext.Users.Any() ? dbContext.Users.Select(u => u.InternalId).Max() : 0; @@ -194,8 +217,12 @@ namespace Jellyfin.Server.Implementations.Users /// public void DeleteUser(Guid userId) { - var dbContext = _dbProvider.CreateContext(); - var user = dbContext.Users.Find(userId); + using var dbContext = _dbProvider.CreateContext(); + var user = dbContext.Users.Include(u => u.Permissions) + .Include(u => u.Preferences) + .Include(u => u.AccessSchedules) + .Include(u => u.ProfileImage) + .FirstOrDefault(u => u.Id == userId); if (user == null) { throw new ResourceNotFoundException(nameof(userId)); @@ -380,7 +407,7 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentNullException(nameof(username)); } - var user = Users.ToList().FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase)); + var user = Users.FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase)); bool success; IAuthenticationProvider? authenticationProvider; @@ -408,8 +435,7 @@ namespace Jellyfin.Server.Implementations.Users // Search the database for the user again // the authentication provider might have created it - user = Users - .ToList().FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase)); + user = Users.FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase)); if (authenticationProvider is IHasNewUserPolicy hasNewUserPolicy) { @@ -546,7 +572,7 @@ namespace Jellyfin.Server.Implementations.Users public void Initialize() { // TODO: Refactor the startup wizard so that it doesn't require a user to already exist. - var dbContext = _dbProvider.CreateContext(); + using var dbContext = _dbProvider.CreateContext(); if (dbContext.Users.Any()) { @@ -698,7 +724,7 @@ namespace Jellyfin.Server.Implementations.Users /// public void ClearProfileImage(User user) { - var dbContext = _dbProvider.CreateContext(); + using var dbContext = _dbProvider.CreateContext(); dbContext.Remove(user.ProfileImage); dbContext.SaveChanges(); } -- cgit v1.2.3 From 0ee55bc1f98283de0926e0e1608e48c71b833934 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sun, 12 Jul 2020 15:08:55 -0400 Subject: Use AsEnumerable instead of ToList --- Jellyfin.Server.Implementations/Users/UserManager.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 47d514b1a4..5a2d7774a4 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -110,7 +110,7 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Invalid username", nameof(name)); } - return _dbProvider.CreateContext().Users.ToList() + return _dbProvider.CreateContext().Users.AsEnumerable() .FirstOrDefault(u => string.Equals(u.Username, name, StringComparison.OrdinalIgnoreCase)); } @@ -380,7 +380,7 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentNullException(nameof(username)); } - var user = Users.ToList().FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase)); + var user = Users.AsEnumerable().FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase)); bool success; IAuthenticationProvider? authenticationProvider; @@ -408,8 +408,7 @@ namespace Jellyfin.Server.Implementations.Users // Search the database for the user again // the authentication provider might have created it - user = Users - .ToList().FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase)); + user = Users.AsEnumerable().FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase)); if (authenticationProvider is IHasNewUserPolicy hasNewUserPolicy) { -- cgit v1.2.3 From b468ae2aea3b42a3073a81c2566dd19a313dc3fa Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Mon, 13 Jul 2020 14:09:20 -0400 Subject: Use AsEnumerable for UserManager.Users --- Jellyfin.Server.Implementations/Users/UserManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 4ed0b7501a..6283a1bca5 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -96,7 +96,7 @@ namespace Jellyfin.Server.Implementations.Users .Include(user => user.Preferences) .Include(user => user.AccessSchedules) .Include(user => user.ProfileImage) - .ToList(); + .AsEnumerable(); } } -- cgit v1.2.3 From 3b085f6a03bfe945e12b104bb042be1d00981cd2 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 17 Jun 2020 10:24:25 -0400 Subject: Remove UserManager.AddParts --- Emby.Server.Implementations/ApplicationHost.cs | 4 ++- .../Users/UserManager.cs | 35 +++++++++++----------- MediaBrowser.Controller/Library/IUserManager.cs | 3 -- 3 files changed, 20 insertions(+), 22 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index f6077400d6..908fe4b302 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -547,6 +547,9 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(ServerConfigurationManager); + serviceCollection.AddSingleton>>(() => GetExports()); + serviceCollection.AddSingleton>>(() => GetExports()); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); @@ -795,7 +798,6 @@ namespace Emby.Server.Implementations Resolve().AddParts(GetExports()); Resolve().AddParts(GetExports(), GetExports()); - Resolve().AddParts(GetExports(), GetExports()); Resolve().AddParts(GetExports()); } diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 6283a1bca5..d4b91f3c53 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -39,12 +39,11 @@ namespace Jellyfin.Server.Implementations.Users private readonly IApplicationHost _appHost; private readonly IImageProcessor _imageProcessor; private readonly ILogger _logger; - - private IAuthenticationProvider[] _authenticationProviders = null!; - private DefaultAuthenticationProvider _defaultAuthenticationProvider = null!; - private InvalidAuthProvider _invalidAuthProvider = null!; - private IPasswordResetProvider[] _passwordResetProviders = null!; - private DefaultPasswordResetProvider _defaultPasswordResetProvider = null!; + private readonly IReadOnlyCollection _passwordResetProviders; + private readonly IReadOnlyCollection _authenticationProviders; + private readonly InvalidAuthProvider _invalidAuthProvider; + private readonly DefaultAuthenticationProvider _defaultAuthenticationProvider; + private readonly DefaultPasswordResetProvider _defaultPasswordResetProvider; /// /// Initializes a new instance of the class. @@ -55,13 +54,17 @@ namespace Jellyfin.Server.Implementations.Users /// The application host. /// The image processor. /// The logger. + /// A function that returns available password reset providers. + /// A function that returns available authentication providers. public UserManager( JellyfinDbProvider dbProvider, ICryptoProvider cryptoProvider, INetworkManager networkManager, IApplicationHost appHost, IImageProcessor imageProcessor, - ILogger logger) + ILogger logger, + Func> passwordResetProviders, + Func> authenticationProviders) { _dbProvider = dbProvider; _cryptoProvider = cryptoProvider; @@ -69,6 +72,13 @@ namespace Jellyfin.Server.Implementations.Users _appHost = appHost; _imageProcessor = imageProcessor; _logger = logger; + + _passwordResetProviders = passwordResetProviders.Invoke(); + _authenticationProviders = authenticationProviders.Invoke(); + + _invalidAuthProvider = _authenticationProviders.OfType().First(); + _defaultAuthenticationProvider = _authenticationProviders.OfType().First(); + _defaultPasswordResetProvider = _passwordResetProviders.OfType().First(); } /// @@ -557,17 +567,6 @@ namespace Jellyfin.Server.Implementations.Users }; } - /// - public void AddParts(IEnumerable authenticationProviders, IEnumerable passwordResetProviders) - { - _authenticationProviders = authenticationProviders.ToArray(); - _passwordResetProviders = passwordResetProviders.ToArray(); - - _invalidAuthProvider = _authenticationProviders.OfType().First(); - _defaultAuthenticationProvider = _authenticationProviders.OfType().First(); - _defaultPasswordResetProvider = _passwordResetProviders.OfType().First(); - } - /// public void Initialize() { diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index e73fe71205..88b96ddbf8 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using MediaBrowser.Controller.Authentication; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Events; @@ -166,8 +165,6 @@ namespace MediaBrowser.Controller.Library /// true if XXXX, false otherwise. Task RedeemPasswordResetPin(string pin); - void AddParts(IEnumerable authenticationProviders, IEnumerable passwordResetProviders); - NameIdPair[] GetAuthenticationProviders(); NameIdPair[] GetPasswordResetProviders(); -- cgit v1.2.3 From 303c175714db50bf865939fd12c66dcbda229431 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 20 Jun 2020 17:58:09 -0400 Subject: Fix circular dependency --- Emby.Server.Implementations/ApplicationHost.cs | 3 --- .../Users/DefaultPasswordResetProvider.cs | 16 +++++++++------- Jellyfin.Server.Implementations/Users/UserManager.cs | 17 +++++++++-------- 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 908fe4b302..1ff14bdb5c 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -547,9 +547,6 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(ServerConfigurationManager); - serviceCollection.AddSingleton>>(() => GetExports()); - serviceCollection.AddSingleton>>(() => GetExports()); - serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs index cf5a01f083..007c296436 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs @@ -6,6 +6,7 @@ using System.IO; using System.Security.Cryptography; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using MediaBrowser.Common; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Configuration; @@ -23,7 +24,7 @@ namespace Jellyfin.Server.Implementations.Users private const string BaseResetFileName = "passwordreset"; private readonly IJsonSerializer _jsonSerializer; - private readonly IUserManager _userManager; + private readonly IApplicationHost _appHost; private readonly string _passwordResetFileBase; private readonly string _passwordResetFileBaseDir; @@ -33,16 +34,17 @@ namespace Jellyfin.Server.Implementations.Users /// /// The configuration manager. /// The JSON serializer. - /// The user manager. + /// The application host. public DefaultPasswordResetProvider( IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, - IUserManager userManager) + IApplicationHost appHost) { _passwordResetFileBaseDir = configurationManager.ApplicationPaths.ProgramDataPath; _passwordResetFileBase = Path.Combine(_passwordResetFileBaseDir, BaseResetFileName); _jsonSerializer = jsonSerializer; - _userManager = userManager; + _appHost = appHost; + // TODO: Remove the circular dependency on UserManager } /// @@ -54,6 +56,7 @@ namespace Jellyfin.Server.Implementations.Users /// public async Task RedeemPasswordResetPin(string pin) { + var userManager = _appHost.Resolve(); var usersReset = new List(); foreach (var resetFile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{BaseResetFileName}*")) { @@ -72,10 +75,10 @@ namespace Jellyfin.Server.Implementations.Users pin.Replace("-", string.Empty, StringComparison.Ordinal), StringComparison.InvariantCultureIgnoreCase)) { - var resetUser = _userManager.GetUserByName(spr.UserName) + var resetUser = userManager.GetUserByName(spr.UserName) ?? throw new ResourceNotFoundException($"User with a username of {spr.UserName} not found"); - await _userManager.ChangePassword(resetUser, pin).ConfigureAwait(false); + await userManager.ChangePassword(resetUser, pin).ConfigureAwait(false); usersReset.Add(resetUser.Username); File.Delete(resetFile); } @@ -121,7 +124,6 @@ namespace Jellyfin.Server.Implementations.Users } user.EasyPassword = pin; - await _userManager.UpdateUserAsync(user).ConfigureAwait(false); return new ForgotPasswordResult { diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index d4b91f3c53..988b0c430b 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -54,17 +54,13 @@ namespace Jellyfin.Server.Implementations.Users /// The application host. /// The image processor. /// The logger. - /// A function that returns available password reset providers. - /// A function that returns available authentication providers. public UserManager( JellyfinDbProvider dbProvider, ICryptoProvider cryptoProvider, INetworkManager networkManager, IApplicationHost appHost, IImageProcessor imageProcessor, - ILogger logger, - Func> passwordResetProviders, - Func> authenticationProviders) + ILogger logger) { _dbProvider = dbProvider; _cryptoProvider = cryptoProvider; @@ -73,8 +69,8 @@ namespace Jellyfin.Server.Implementations.Users _imageProcessor = imageProcessor; _logger = logger; - _passwordResetProviders = passwordResetProviders.Invoke(); - _authenticationProviders = authenticationProviders.Invoke(); + _passwordResetProviders = appHost.GetExports(); + _authenticationProviders = appHost.GetExports(); _invalidAuthProvider = _authenticationProviders.OfType().First(); _defaultAuthenticationProvider = _authenticationProviders.OfType().First(); @@ -537,7 +533,12 @@ namespace Jellyfin.Server.Implementations.Users if (user != null && isInNetwork) { var passwordResetProvider = GetPasswordResetProvider(user); - return await passwordResetProvider.StartForgotPasswordProcess(user, isInNetwork).ConfigureAwait(false); + var result = await passwordResetProvider + .StartForgotPasswordProcess(user, isInNetwork) + .ConfigureAwait(false); + + await UpdateUserAsync(user).ConfigureAwait(false); + return result; } return new ForgotPasswordResult -- cgit v1.2.3 From 340b585234430efa9bc9ba1689aab09852b33358 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Tue, 14 Jul 2020 12:38:56 +0200 Subject: Use ToList instead of AsEnumerable due to delayed execution --- Jellyfin.Server.Implementations/Users/UserManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 6283a1bca5..4ed0b7501a 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -96,7 +96,7 @@ namespace Jellyfin.Server.Implementations.Users .Include(user => user.Preferences) .Include(user => user.AccessSchedules) .Include(user => user.ProfileImage) - .AsEnumerable(); + .ToList(); } } -- cgit v1.2.3 From e143387cbd339020e33d30b7e001172519d66923 Mon Sep 17 00:00:00 2001 From: crobibero Date: Tue, 14 Jul 2020 06:47:46 -0600 Subject: Fix update user --- .../Users/UserManager.cs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 4ed0b7501a..9aff808db0 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -92,7 +92,8 @@ namespace Jellyfin.Server.Implementations.Users get { using var dbContext = _dbProvider.CreateContext(); - return dbContext.Users.Include(user => user.Permissions) + return dbContext.Users + .Include(user => user.Permissions) .Include(user => user.Preferences) .Include(user => user.AccessSchedules) .Include(user => user.ProfileImage) @@ -112,7 +113,8 @@ namespace Jellyfin.Server.Implementations.Users } using var dbContext = _dbProvider.CreateContext(); - return dbContext.Users.Include(user => user.Permissions) + return dbContext.Users + .Include(user => user.Permissions) .Include(user => user.Preferences) .Include(user => user.AccessSchedules) .Include(user => user.ProfileImage) @@ -128,8 +130,8 @@ namespace Jellyfin.Server.Implementations.Users } using var dbContext = _dbProvider.CreateContext(); - - return dbContext.Users.Include(user => user.Permissions) + return dbContext.Users + .Include(user => user.Permissions) .Include(user => user.Preferences) .Include(user => user.AccessSchedules) .Include(user => user.ProfileImage) @@ -218,7 +220,8 @@ namespace Jellyfin.Server.Implementations.Users public void DeleteUser(Guid userId) { using var dbContext = _dbProvider.CreateContext(); - var user = dbContext.Users.Include(u => u.Permissions) + var user = dbContext.Users + .Include(u => u.Permissions) .Include(u => u.Preferences) .Include(u => u.AccessSchedules) .Include(u => u.ProfileImage) @@ -635,7 +638,14 @@ namespace Jellyfin.Server.Implementations.Users public void UpdateConfiguration(Guid userId, UserConfiguration config) { var dbContext = _dbProvider.CreateContext(); - var user = dbContext.Users.Find(userId) ?? throw new ArgumentException("No user exists with given Id!"); + var user = dbContext.Users + .Include(u => u.Permissions) + .Include(u => u.Preferences) + .Include(u => u.AccessSchedules) + .Include(u => u.ProfileImage) + .FirstOrDefault(u => u.Id == userId) + ?? throw new ArgumentException("No user exists with given Id!"); + user.SubtitleMode = config.SubtitleMode; user.HidePlayedInLatest = config.HidePlayedInLatest; user.EnableLocalPassword = config.EnableLocalPassword; -- cgit v1.2.3 From ab396225eaf486932fdb2f23eefa1cbfecbb27f4 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 30 Jun 2020 21:44:41 -0400 Subject: Migrate Display Preferences to EF Core --- Emby.Dlna/ContentDirectory/ControlHandler.cs | 1 + Emby.Server.Implementations/ApplicationHost.cs | 3 - .../Channels/ChannelManager.cs | 1 + .../Data/SqliteDisplayPreferencesRepository.cs | 225 ------------ .../Data/SqliteItemRepository.cs | 1 + .../Emby.Server.Implementations.csproj | 2 +- .../Images/CollectionFolderImageProvider.cs | 2 +- .../Images/FolderImageProvider.cs | 2 +- .../Images/GenreImageProvider.cs | 1 + .../Library/LibraryManager.cs | 1 - .../Library/MusicManager.cs | 2 +- .../Library/SearchEngine.cs | 2 +- .../LiveTv/EmbyTV/EmbyTV.cs | 1 + Jellyfin.Data/Entities/DisplayPreferences.cs | 72 ++++ Jellyfin.Data/Entities/HomeSection.cs | 21 ++ Jellyfin.Data/Entities/User.cs | 5 + Jellyfin.Data/Enums/HomeSectionType.cs | 53 +++ Jellyfin.Data/Enums/IndexingKind.cs | 20 + Jellyfin.Data/Enums/ScrollDirection.cs | 18 + Jellyfin.Data/Enums/SortOrder.cs | 18 + Jellyfin.Data/Enums/ViewType.cs | 38 ++ .../DisplayPreferencesManager.cs | 49 +++ Jellyfin.Server.Implementations/JellyfinDb.cs | 2 + ...0200630170339_AddDisplayPreferences.Designer.cs | 403 +++++++++++++++++++++ .../20200630170339_AddDisplayPreferences.cs | 92 +++++ .../Migrations/JellyfinDbModelSnapshot.cs | 93 ++++- Jellyfin.Server/CoreAppHost.cs | 2 + Jellyfin.Server/Migrations/MigrationRunner.cs | 3 +- .../Routines/MigrateDisplayPreferencesDb.cs | 118 ++++++ MediaBrowser.Api/ChannelService.cs | 2 +- MediaBrowser.Api/DisplayPreferencesService.cs | 92 ++++- MediaBrowser.Api/Movies/MoviesService.cs | 1 + MediaBrowser.Api/SuggestionsService.cs | 1 + MediaBrowser.Api/TvShowsService.cs | 1 + MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs | 5 +- .../Entities/UserViewBuilder.cs | 1 + .../IDisplayPreferencesManager.cs | 25 ++ MediaBrowser.Controller/Library/ILibraryManager.cs | 1 + .../Persistence/IDisplayPreferencesRepository.cs | 53 --- MediaBrowser.Controller/Playlists/Playlist.cs | 1 + MediaBrowser.Model/Dlna/SortCriteria.cs | 2 +- MediaBrowser.Model/Entities/DisplayPreferences.cs | 111 ------ .../Entities/DisplayPreferencesDto.cs | 107 ++++++ MediaBrowser.Model/Entities/ScrollDirection.cs | 18 - MediaBrowser.Model/Entities/SortOrder.cs | 18 - MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs | 2 +- MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs | 2 +- 47 files changed, 1232 insertions(+), 462 deletions(-) delete mode 100644 Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs create mode 100644 Jellyfin.Data/Entities/DisplayPreferences.cs create mode 100644 Jellyfin.Data/Entities/HomeSection.cs create mode 100644 Jellyfin.Data/Enums/HomeSectionType.cs create mode 100644 Jellyfin.Data/Enums/IndexingKind.cs create mode 100644 Jellyfin.Data/Enums/ScrollDirection.cs create mode 100644 Jellyfin.Data/Enums/SortOrder.cs create mode 100644 Jellyfin.Data/Enums/ViewType.cs create mode 100644 Jellyfin.Server.Implementations/DisplayPreferencesManager.cs create mode 100644 Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs create mode 100644 Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.cs create mode 100644 Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs create mode 100644 MediaBrowser.Controller/IDisplayPreferencesManager.cs delete mode 100644 MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs delete mode 100644 MediaBrowser.Model/Entities/DisplayPreferences.cs create mode 100644 MediaBrowser.Model/Entities/DisplayPreferencesDto.cs delete mode 100644 MediaBrowser.Model/Entities/ScrollDirection.cs delete mode 100644 MediaBrowser.Model/Entities/SortOrder.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 291de5245b..00821bf780 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -11,6 +11,7 @@ using System.Xml; using Emby.Dlna.Didl; using Emby.Dlna.Service; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index f6077400d6..f6f10beb09 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -554,8 +554,6 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); @@ -650,7 +648,6 @@ namespace Emby.Server.Implementations _httpServer = Resolve(); _httpClient = Resolve(); - ((SqliteDisplayPreferencesRepository)Resolve()).Initialize(); ((AuthenticationRepository)Resolve()).Initialize(); SetStaticProperties(); diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index c803d9d825..2a7cddd87b 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Channels; diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs deleted file mode 100644 index 5597155a8d..0000000000 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ /dev/null @@ -1,225 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text.Json; -using System.Threading; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Json; -using MediaBrowser.Controller.Persistence; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using Microsoft.Extensions.Logging; -using SQLitePCL.pretty; - -namespace Emby.Server.Implementations.Data -{ - /// - /// Class SQLiteDisplayPreferencesRepository. - /// - public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository - { - private readonly IFileSystem _fileSystem; - - private readonly JsonSerializerOptions _jsonOptions; - - public SqliteDisplayPreferencesRepository(ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem) - : base(logger) - { - _fileSystem = fileSystem; - - _jsonOptions = JsonDefaults.GetOptions(); - - DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db"); - } - - /// - /// Gets the name of the repository. - /// - /// The name. - public string Name => "SQLite"; - - public void Initialize() - { - try - { - InitializeInternal(); - } - catch (Exception ex) - { - Logger.LogError(ex, "Error loading database file. Will reset and retry."); - - _fileSystem.DeleteFile(DbFilePath); - - InitializeInternal(); - } - } - - /// - /// Opens the connection to the database. - /// - /// Task. - private void InitializeInternal() - { - string[] queries = - { - "create table if not exists userdisplaypreferences (id GUID NOT NULL, userId GUID NOT NULL, client text NOT NULL, data BLOB NOT NULL)", - "create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)" - }; - - using (var connection = GetConnection()) - { - connection.RunQueries(queries); - } - } - - /// - /// Save the display preferences associated with an item in the repo. - /// - /// The display preferences. - /// The user id. - /// The client. - /// The cancellation token. - /// item - public void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, CancellationToken cancellationToken) - { - if (displayPreferences == null) - { - throw new ArgumentNullException(nameof(displayPreferences)); - } - - if (string.IsNullOrEmpty(displayPreferences.Id)) - { - throw new ArgumentException("Display preferences has an invalid Id", nameof(displayPreferences)); - } - - cancellationToken.ThrowIfCancellationRequested(); - - using (var connection = GetConnection()) - { - connection.RunInTransaction( - db => SaveDisplayPreferences(displayPreferences, userId, client, db), - TransactionMode); - } - } - - private void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, IDatabaseConnection connection) - { - var serialized = JsonSerializer.SerializeToUtf8Bytes(displayPreferences, _jsonOptions); - - using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)")) - { - statement.TryBind("@id", new Guid(displayPreferences.Id).ToByteArray()); - statement.TryBind("@userId", userId.ToByteArray()); - statement.TryBind("@client", client); - statement.TryBind("@data", serialized); - - statement.MoveNext(); - } - } - - /// - /// Save all display preferences associated with a user in the repo. - /// - /// The display preferences. - /// The user id. - /// The cancellation token. - /// item - public void SaveAllDisplayPreferences(IEnumerable displayPreferences, Guid userId, CancellationToken cancellationToken) - { - if (displayPreferences == null) - { - throw new ArgumentNullException(nameof(displayPreferences)); - } - - cancellationToken.ThrowIfCancellationRequested(); - - using (var connection = GetConnection()) - { - connection.RunInTransaction( - db => - { - foreach (var displayPreference in displayPreferences) - { - SaveDisplayPreferences(displayPreference, userId, displayPreference.Client, db); - } - }, - TransactionMode); - } - } - - /// - /// Gets the display preferences. - /// - /// The display preferences id. - /// The user id. - /// The client. - /// Task{DisplayPreferences}. - /// item - public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, Guid userId, string client) - { - if (string.IsNullOrEmpty(displayPreferencesId)) - { - throw new ArgumentNullException(nameof(displayPreferencesId)); - } - - var guidId = displayPreferencesId.GetMD5(); - - using (var connection = GetConnection(true)) - { - using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client")) - { - statement.TryBind("@id", guidId.ToByteArray()); - statement.TryBind("@userId", userId.ToByteArray()); - statement.TryBind("@client", client); - - foreach (var row in statement.ExecuteQuery()) - { - return Get(row); - } - } - } - - return new DisplayPreferences - { - Id = guidId.ToString("N", CultureInfo.InvariantCulture) - }; - } - - /// - /// Gets all display preferences for the given user. - /// - /// The user id. - /// Task{DisplayPreferences}. - /// item - public IEnumerable GetAllDisplayPreferences(Guid userId) - { - var list = new List(); - - using (var connection = GetConnection(true)) - using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId")) - { - statement.TryBind("@userId", userId.ToByteArray()); - - foreach (var row in statement.ExecuteQuery()) - { - list.Add(Get(row)); - } - } - - return list; - } - - private DisplayPreferences Get(IReadOnlyList row) - => JsonSerializer.Deserialize(row[0].ToBlob(), _jsonOptions); - - public void SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken) - => SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken); - - public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, string userId, string client) - => GetDisplayPreferences(displayPreferencesId, new Guid(userId), client); - } -} diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index a6390b1ef2..04e5e570f7 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -9,6 +9,7 @@ using System.Text; using System.Text.Json; using System.Threading; using Emby.Server.Implementations.Playlists; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Json; using MediaBrowser.Controller; diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index f7ad59c10f..548dc7085c 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -54,7 +54,7 @@ netstandard2.1 false true - true + true diff --git a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs index da88b8d8ab..161b4c4528 100644 --- a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.IO; -using Emby.Server.Implementations.Images; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Images/FolderImageProvider.cs b/Emby.Server.Implementations/Images/FolderImageProvider.cs index e9523386ea..0224ab32a0 100644 --- a/Emby.Server.Implementations/Images/FolderImageProvider.cs +++ b/Emby.Server.Implementations/Images/FolderImageProvider.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 using System.Collections.Generic; -using Emby.Server.Implementations.Images; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Images/GenreImageProvider.cs b/Emby.Server.Implementations/Images/GenreImageProvider.cs index d2aeccdb21..1cd4cd66bd 100644 --- a/Emby.Server.Implementations/Images/GenreImageProvider.cs +++ b/Emby.Server.Implementations/Images/GenreImageProvider.cs @@ -1,6 +1,7 @@ #pragma warning disable CS1591 using System.Collections.Generic; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 77d44e1313..4690f20946 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -50,7 +50,6 @@ using Microsoft.Extensions.Logging; using Episode = MediaBrowser.Controller.Entities.TV.Episode; using Genre = MediaBrowser.Controller.Entities.Genre; using Person = MediaBrowser.Controller.Entities.Person; -using SortOrder = MediaBrowser.Model.Entities.SortOrder; using VideoResolver = Emby.Naming.Video.VideoResolver; namespace Emby.Server.Implementations.Library diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs index 0bdc599144..877fdec86e 100644 --- a/Emby.Server.Implementations/Library/MusicManager.cs +++ b/Emby.Server.Implementations/Library/MusicManager.cs @@ -4,12 +4,12 @@ using System; using System.Collections.Generic; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 3df9cc06f1..e3e554824a 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -4,12 +4,12 @@ using System; using System.Collections.Generic; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Extensions; using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Search; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 7b0fcbc9e5..80e09f0a34 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using System.Xml; using Emby.Server.Implementations.Library; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; diff --git a/Jellyfin.Data/Entities/DisplayPreferences.cs b/Jellyfin.Data/Entities/DisplayPreferences.cs new file mode 100644 index 0000000000..668030149b --- /dev/null +++ b/Jellyfin.Data/Entities/DisplayPreferences.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities +{ + public class DisplayPreferences + { + public DisplayPreferences(string client, Guid userId) + { + RememberIndexing = false; + ShowBackdrop = true; + Client = client; + UserId = userId; + + HomeSections = new HashSet(); + } + + protected DisplayPreferences() + { + } + + [Required] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; protected set; } + + [Required] + public Guid UserId { get; set; } + + /// + /// Gets or sets the id of the associated item. + /// + /// + /// This is currently unused. In the future, this will allow us to have users set + /// display preferences per item. + /// + public Guid? ItemId { get; set; } + + [Required] + [MaxLength(64)] + [StringLength(64)] + public string Client { get; set; } + + [Required] + public bool RememberIndexing { get; set; } + + [Required] + public bool RememberSorting { get; set; } + + [Required] + public SortOrder SortOrder { get; set; } + + [Required] + public bool ShowSidebar { get; set; } + + [Required] + public bool ShowBackdrop { get; set; } + + public string SortBy { get; set; } + + public ViewType? ViewType { get; set; } + + [Required] + public ScrollDirection ScrollDirection { get; set; } + + public IndexingKind? IndexBy { get; set; } + + public virtual ICollection HomeSections { get; protected set; } + } +} diff --git a/Jellyfin.Data/Entities/HomeSection.cs b/Jellyfin.Data/Entities/HomeSection.cs new file mode 100644 index 0000000000..f39956a54e --- /dev/null +++ b/Jellyfin.Data/Entities/HomeSection.cs @@ -0,0 +1,21 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities +{ + public class HomeSection + { + [Key] + [Required] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; protected set; } + + public int DisplayPreferencesId { get; set; } + + public int Order { get; set; } + + public HomeSectionType Type { get; set; } + } +} diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index b89b0a8f45..d93144e3a5 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -349,6 +349,11 @@ namespace Jellyfin.Data.Entities /// public virtual ICollection AccessSchedules { get; protected set; } + /// + /// Gets or sets the list of item display preferences. + /// + public virtual ICollection DisplayPreferences { get; protected set; } + /* /// /// Gets or sets the list of groups this user is a member of. diff --git a/Jellyfin.Data/Enums/HomeSectionType.cs b/Jellyfin.Data/Enums/HomeSectionType.cs new file mode 100644 index 0000000000..be764c5924 --- /dev/null +++ b/Jellyfin.Data/Enums/HomeSectionType.cs @@ -0,0 +1,53 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing the different options for the home screen sections. + /// + public enum HomeSectionType + { + /// + /// My Media. + /// + SmallLibraryTiles = 0, + + /// + /// My Media Small. + /// + LibraryButtons = 1, + + /// + /// Active Recordings. + /// + ActiveRecordings = 2, + + /// + /// Continue Watching. + /// + Resume = 3, + + /// + /// Continue Listening. + /// + ResumeAudio = 4, + + /// + /// Latest Media. + /// + LatestMedia = 5, + + /// + /// Next Up. + /// + NextUp = 6, + + /// + /// Live TV. + /// + LiveTv = 7, + + /// + /// None. + /// + None = 8 + } +} diff --git a/Jellyfin.Data/Enums/IndexingKind.cs b/Jellyfin.Data/Enums/IndexingKind.cs new file mode 100644 index 0000000000..c4d8e70ca6 --- /dev/null +++ b/Jellyfin.Data/Enums/IndexingKind.cs @@ -0,0 +1,20 @@ +namespace Jellyfin.Data.Enums +{ + public enum IndexingKind + { + /// + /// Index by the premiere date. + /// + PremiereDate, + + /// + /// Index by the production year. + /// + ProductionYear, + + /// + /// Index by the community rating. + /// + CommunityRating + } +} diff --git a/Jellyfin.Data/Enums/ScrollDirection.cs b/Jellyfin.Data/Enums/ScrollDirection.cs new file mode 100644 index 0000000000..382f585ba0 --- /dev/null +++ b/Jellyfin.Data/Enums/ScrollDirection.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing the axis that should be scrolled. + /// + public enum ScrollDirection + { + /// + /// Horizontal scrolling direction. + /// + Horizontal, + + /// + /// Vertical scrolling direction. + /// + Vertical + } +} diff --git a/Jellyfin.Data/Enums/SortOrder.cs b/Jellyfin.Data/Enums/SortOrder.cs new file mode 100644 index 0000000000..309fa78775 --- /dev/null +++ b/Jellyfin.Data/Enums/SortOrder.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing the sorting order. + /// + public enum SortOrder + { + /// + /// Sort in increasing order. + /// + Ascending, + + /// + /// Sort in decreasing order. + /// + Descending + } +} diff --git a/Jellyfin.Data/Enums/ViewType.cs b/Jellyfin.Data/Enums/ViewType.cs new file mode 100644 index 0000000000..595429ab1b --- /dev/null +++ b/Jellyfin.Data/Enums/ViewType.cs @@ -0,0 +1,38 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing the type of view for a library or collection. + /// + public enum ViewType + { + /// + /// Shows banners. + /// + Banner = 0, + + /// + /// Shows a list of content. + /// + List = 1, + + /// + /// Shows poster artwork. + /// + Poster = 2, + + /// + /// Shows poster artwork with a card containing the name and year. + /// + PosterCard = 3, + + /// + /// Shows a thumbnail. + /// + Thumb = 4, + + /// + /// Shows a thumbnail with a card containing the name and year. + /// + ThumbCard = 5 + } +} diff --git a/Jellyfin.Server.Implementations/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/DisplayPreferencesManager.cs new file mode 100644 index 0000000000..132e74c6aa --- /dev/null +++ b/Jellyfin.Server.Implementations/DisplayPreferencesManager.cs @@ -0,0 +1,49 @@ +using System; +using System.Linq; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller; + +namespace Jellyfin.Server.Implementations +{ + /// + /// Manages the storage and retrieval of display preferences through Entity Framework. + /// + public class DisplayPreferencesManager : IDisplayPreferencesManager + { + private readonly JellyfinDbProvider _dbProvider; + + /// + /// Initializes a new instance of the class. + /// + /// The Jellyfin db provider. + public DisplayPreferencesManager(JellyfinDbProvider dbProvider) + { + _dbProvider = dbProvider; + } + + /// + public DisplayPreferences GetDisplayPreferences(Guid userId, string client) + { + var dbContext = _dbProvider.CreateContext(); + var user = dbContext.Users.Find(userId); +#pragma warning disable CA1307 + var prefs = user.DisplayPreferences.FirstOrDefault(pref => string.Equals(pref.Client, client)); + + if (prefs == null) + { + prefs = new DisplayPreferences(client, userId); + user.DisplayPreferences.Add(prefs); + } + + return prefs; + } + + /// + public void SaveChanges(DisplayPreferences preferences) + { + var dbContext = _dbProvider.CreateContext(); + dbContext.Update(preferences); + dbContext.SaveChanges(); + } + } +} diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index 53120a763e..774970e942 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -27,6 +27,8 @@ namespace Jellyfin.Server.Implementations public virtual DbSet ActivityLogs { get; set; } + public virtual DbSet DisplayPreferences { get; set; } + public virtual DbSet ImageInfos { get; set; } public virtual DbSet Permissions { get; set; } diff --git a/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs new file mode 100644 index 0000000000..75f9bb7a3c --- /dev/null +++ b/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs @@ -0,0 +1,403 @@ +#pragma warning disable CS1591 + +// +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("20200630170339_AddDisplayPreferences")] + partial class AddDisplayPreferences + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "3.1.5"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Overview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Permission_Permissions_Guid"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("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) + .WithMany("DisplayPreferences") + .HasForeignKey("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.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/20200630170339_AddDisplayPreferences.cs b/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.cs new file mode 100644 index 0000000000..e9a493d9db --- /dev/null +++ b/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.cs @@ -0,0 +1,92 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1601 + +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddDisplayPreferences : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DisplayPreferences", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(nullable: false), + ItemId = table.Column(nullable: true), + Client = table.Column(maxLength: 64, nullable: false), + RememberIndexing = table.Column(nullable: false), + RememberSorting = table.Column(nullable: false), + SortOrder = table.Column(nullable: false), + ShowSidebar = table.Column(nullable: false), + ShowBackdrop = table.Column(nullable: false), + SortBy = table.Column(nullable: true), + ViewType = table.Column(nullable: true), + ScrollDirection = table.Column(nullable: false), + IndexBy = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DisplayPreferences", x => x.Id); + table.ForeignKey( + name: "FK_DisplayPreferences_Users_UserId", + column: x => x.UserId, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "HomeSection", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DisplayPreferencesId = table.Column(nullable: false), + Order = table.Column(nullable: false), + Type = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_HomeSection", x => x.Id); + table.ForeignKey( + name: "FK_HomeSection_DisplayPreferences_DisplayPreferencesId", + column: x => x.DisplayPreferencesId, + principalSchema: "jellyfin", + principalTable: "DisplayPreferences", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId", + schema: "jellyfin", + table: "DisplayPreferences", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_HomeSection_DisplayPreferencesId", + schema: "jellyfin", + table: "HomeSection", + column: "DisplayPreferencesId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "HomeSection", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "DisplayPreferences", + schema: "jellyfin"); + } + } +} diff --git a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs index 51fad82249..69b544e5ba 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.4"); + .HasAnnotation("ProductVersion", "3.1.5"); modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => { @@ -88,6 +88,79 @@ namespace Jellyfin.Server.Implementations.Migrations b.ToTable("ActivityLogs"); }); + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .HasColumnType("TEXT"); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => { b.Property("Id") @@ -282,6 +355,24 @@ namespace Jellyfin.Server.Implementations.Migrations .IsRequired(); }); + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.HasOne("Jellyfin.Data.Entities.User", null) + .WithMany("DisplayPreferences") + .HasForeignKey("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) diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 207eaa98d1..c5a7368aac 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -9,6 +9,7 @@ using Jellyfin.Server.Implementations; using Jellyfin.Server.Implementations.Activity; using Jellyfin.Server.Implementations.Users; using MediaBrowser.Common.Net; +using MediaBrowser.Controller; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Activity; @@ -73,6 +74,7 @@ namespace Jellyfin.Server serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); base.RegisterServices(serviceCollection); } diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs index d633c554de..7f208952ce 100644 --- a/Jellyfin.Server/Migrations/MigrationRunner.cs +++ b/Jellyfin.Server/Migrations/MigrationRunner.cs @@ -21,7 +21,8 @@ namespace Jellyfin.Server.Migrations typeof(Routines.MigrateActivityLogDb), typeof(Routines.RemoveDuplicateExtras), typeof(Routines.AddDefaultPluginRepository), - typeof(Routines.MigrateUserDb) + typeof(Routines.MigrateUserDb), + typeof(Routines.MigrateDisplayPreferencesDb) }; /// diff --git a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs new file mode 100644 index 0000000000..1ed23fe8e4 --- /dev/null +++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs @@ -0,0 +1,118 @@ +using System; +using System.IO; +using System.Text.Json; +using System.Text.Json.Serialization; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; +using Jellyfin.Server.Implementations; +using MediaBrowser.Controller; +using MediaBrowser.Model.Entities; +using Microsoft.Extensions.Logging; +using SQLitePCL.pretty; + +namespace Jellyfin.Server.Migrations.Routines +{ + /// + /// The migration routine for migrating the display preferences database to EF Core. + /// + public class MigrateDisplayPreferencesDb : IMigrationRoutine + { + private const string DbFilename = "displaypreferences.db"; + + private readonly ILogger _logger; + private readonly IServerApplicationPaths _paths; + private readonly JellyfinDbProvider _provider; + private readonly JsonSerializerOptions _jsonOptions; + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + /// The server application paths. + /// The database provider. + public MigrateDisplayPreferencesDb(ILogger logger, IServerApplicationPaths paths, JellyfinDbProvider provider) + { + _logger = logger; + _paths = paths; + _provider = provider; + _jsonOptions = new JsonSerializerOptions(); + _jsonOptions.Converters.Add(new JsonStringEnumConverter()); + } + + /// + public Guid Id => Guid.Parse("06387815-C3CC-421F-A888-FB5F9992BEA8"); + + /// + public string Name => "MigrateDisplayPreferencesDatabase"; + + /// + public void Perform() + { + HomeSectionType[] defaults = + { + HomeSectionType.SmallLibraryTiles, + HomeSectionType.Resume, + HomeSectionType.ResumeAudio, + HomeSectionType.LiveTv, + HomeSectionType.NextUp, + HomeSectionType.LatestMedia, + HomeSectionType.None, + }; + + var dbFilePath = Path.Combine(_paths.DataPath, DbFilename); + using (var connection = SQLite3.Open(dbFilePath, ConnectionFlags.ReadOnly, null)) + { + var dbContext = _provider.CreateContext(); + + var results = connection.Query("SELECT * FROM userdisplaypreferences"); + foreach (var result in results) + { + var dto = JsonSerializer.Deserialize(result[3].ToString(), _jsonOptions); + + var displayPreferences = new DisplayPreferences(result[2].ToString(), new Guid(result[1].ToBlob())) + { + ViewType = Enum.TryParse(dto.ViewType, true, out var viewType) ? viewType : (ViewType?)null, + IndexBy = Enum.TryParse(dto.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null, + ShowBackdrop = dto.ShowBackdrop, + ShowSidebar = dto.ShowSidebar, + SortBy = dto.SortBy, + SortOrder = dto.SortOrder, + RememberIndexing = dto.RememberIndexing, + RememberSorting = dto.RememberSorting, + ScrollDirection = dto.ScrollDirection + }; + + for (int i = 0; i < 7; i++) + { + dto.CustomPrefs.TryGetValue("homesection" + i, out var homeSection); + + displayPreferences.HomeSections.Add(new HomeSection + { + Order = i, + Type = Enum.TryParse(homeSection, true, out var type) ? type : defaults[i] + }); + } + + dbContext.Add(displayPreferences); + } + + dbContext.SaveChanges(); + } + + try + { + File.Move(dbFilePath, dbFilePath + ".old"); + + var journalPath = dbFilePath + "-journal"; + if (File.Exists(journalPath)) + { + File.Move(journalPath, dbFilePath + ".old-journal"); + } + } + catch (IOException e) + { + _logger.LogError(e, "Error renaming legacy display preferences database to 'displaypreferences.db.old'"); + } + } + } +} diff --git a/MediaBrowser.Api/ChannelService.cs b/MediaBrowser.Api/ChannelService.cs index 8c336b1c9d..8d3a9ee5a0 100644 --- a/MediaBrowser.Api/ChannelService.cs +++ b/MediaBrowser.Api/ChannelService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using MediaBrowser.Api.UserLibrary; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; @@ -11,7 +12,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Channels; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs index c3ed40ad3c..e5dd038076 100644 --- a/MediaBrowser.Api/DisplayPreferencesService.cs +++ b/MediaBrowser.Api/DisplayPreferencesService.cs @@ -1,9 +1,10 @@ -using System.Threading; +using System; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; +using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; @@ -13,7 +14,7 @@ namespace MediaBrowser.Api /// Class UpdateDisplayPreferences. /// [Route("/DisplayPreferences/{DisplayPreferencesId}", "POST", Summary = "Updates a user's display preferences for an item")] - public class UpdateDisplayPreferences : DisplayPreferences, IReturnVoid + public class UpdateDisplayPreferences : DisplayPreferencesDto, IReturnVoid { /// /// Gets or sets the id. @@ -27,7 +28,7 @@ namespace MediaBrowser.Api } [Route("/DisplayPreferences/{Id}", "GET", Summary = "Gets a user's display preferences for an item")] - public class GetDisplayPreferences : IReturn + public class GetDisplayPreferences : IReturn { /// /// Gets or sets the id. @@ -50,28 +51,21 @@ namespace MediaBrowser.Api public class DisplayPreferencesService : BaseApiService { /// - /// The _display preferences manager. + /// The user manager. /// - private readonly IDisplayPreferencesRepository _displayPreferencesManager; - /// - /// The _json serializer. - /// - private readonly IJsonSerializer _jsonSerializer; + private readonly IDisplayPreferencesManager _displayPreferencesManager; /// /// Initializes a new instance of the class. /// - /// The json serializer. /// The display preferences manager. public DisplayPreferencesService( ILogger logger, IServerConfigurationManager serverConfigurationManager, IHttpResultFactory httpResultFactory, - IJsonSerializer jsonSerializer, - IDisplayPreferencesRepository displayPreferencesManager) + IDisplayPreferencesManager displayPreferencesManager) : base(logger, serverConfigurationManager, httpResultFactory) { - _jsonSerializer = jsonSerializer; _displayPreferencesManager = displayPreferencesManager; } @@ -81,9 +75,34 @@ namespace MediaBrowser.Api /// The request. public object Get(GetDisplayPreferences request) { - var result = _displayPreferencesManager.GetDisplayPreferences(request.Id, request.UserId, request.Client); + var result = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); + + if (result == null) + { + return null; + } + + var dto = new DisplayPreferencesDto + { + Client = result.Client, + Id = result.UserId.ToString(), + ViewType = result.ViewType?.ToString(), + SortBy = result.SortBy, + SortOrder = result.SortOrder, + IndexBy = result.IndexBy?.ToString(), + RememberIndexing = result.RememberIndexing, + RememberSorting = result.RememberSorting, + ScrollDirection = result.ScrollDirection, + ShowBackdrop = result.ShowBackdrop, + ShowSidebar = result.ShowSidebar + }; - return ToOptimizedResult(result); + foreach (var homeSection in result.HomeSections) + { + dto.CustomPrefs["homesection" + homeSection.Order] = homeSection.Type.ToString().ToLowerInvariant(); + } + + return ToOptimizedResult(dto); } /// @@ -92,10 +111,43 @@ namespace MediaBrowser.Api /// The request. public void Post(UpdateDisplayPreferences request) { - // Serialize to json and then back so that the core doesn't see the request dto type - var displayPreferences = _jsonSerializer.DeserializeFromString(_jsonSerializer.SerializeToString(request)); + HomeSectionType[] defaults = + { + HomeSectionType.SmallLibraryTiles, + HomeSectionType.Resume, + HomeSectionType.ResumeAudio, + HomeSectionType.LiveTv, + HomeSectionType.NextUp, + HomeSectionType.LatestMedia, + HomeSectionType.None, + }; + + var prefs = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); + + prefs.ViewType = Enum.TryParse(request.ViewType, true, out var viewType) ? viewType : (ViewType?)null; + prefs.IndexBy = Enum.TryParse(request.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null; + prefs.ShowBackdrop = request.ShowBackdrop; + prefs.ShowSidebar = request.ShowSidebar; + prefs.SortBy = request.SortBy; + prefs.SortOrder = request.SortOrder; + prefs.RememberIndexing = request.RememberIndexing; + prefs.RememberSorting = request.RememberSorting; + prefs.ScrollDirection = request.ScrollDirection; + prefs.HomeSections.Clear(); + + for (int i = 0; i < 7; i++) + { + if (request.CustomPrefs.TryGetValue("homesection" + i, out var homeSection)) + { + prefs.HomeSections.Add(new HomeSection + { + Order = i, + Type = Enum.TryParse(homeSection, true, out var type) ? type : defaults[i] + }); + } + } - _displayPreferencesManager.SaveDisplayPreferences(displayPreferences, request.UserId, request.Client, CancellationToken.None); + _displayPreferencesManager.SaveChanges(prefs); } } } diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 34cccffa38..2ff322d293 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; diff --git a/MediaBrowser.Api/SuggestionsService.cs b/MediaBrowser.Api/SuggestionsService.cs index 17afa8e79c..b42e822e82 100644 --- a/MediaBrowser.Api/SuggestionsService.cs +++ b/MediaBrowser.Api/SuggestionsService.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 165abd613d..799cea6480 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index 344861a496..fc19575b30 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using Jellyfin.Data.Enums; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Services; @@ -466,8 +467,8 @@ namespace MediaBrowser.Api.UserLibrary var sortOrderValue = sortOrders.Length > sortOrderIndex ? sortOrders[sortOrderIndex] : null; var sortOrder = string.Equals(sortOrderValue, "Descending", StringComparison.OrdinalIgnoreCase) - ? MediaBrowser.Model.Entities.SortOrder.Descending - : MediaBrowser.Model.Entities.SortOrder.Ascending; + ? Jellyfin.Data.Enums.SortOrder.Descending + : Jellyfin.Data.Enums.SortOrder.Ascending; result[i] = new ValueTuple(vals[i], sortOrder); } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index cb35d6e321..22bb7fd550 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs new file mode 100644 index 0000000000..e27b0ec7c3 --- /dev/null +++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs @@ -0,0 +1,25 @@ +using System; +using Jellyfin.Data.Entities; + +namespace MediaBrowser.Controller +{ + /// + /// Manages the storage and retrieval of display preferences. + /// + public interface IDisplayPreferencesManager + { + /// + /// Gets the display preferences for the user and client. + /// + /// The user's id. + /// The client string. + /// The associated display preferences. + DisplayPreferences GetDisplayPreferences(Guid userId, string client); + + /// + /// Saves changes to the provided display preferences. + /// + /// The display preferences to save. + void SaveChanges(DisplayPreferences preferences); + } +} diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 9d6646857e..b5eec18463 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; diff --git a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs b/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs deleted file mode 100644 index c2dcb66d7c..0000000000 --- a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Controller.Persistence -{ - /// - /// Interface IDisplayPreferencesRepository. - /// - public interface IDisplayPreferencesRepository : IRepository - { - /// - /// Saves display preferences for an item. - /// - /// The display preferences. - /// The user id. - /// The client. - /// The cancellation token. - void SaveDisplayPreferences( - DisplayPreferences displayPreferences, - string userId, - string client, - CancellationToken cancellationToken); - - /// - /// Saves all display preferences for a user. - /// - /// The display preferences. - /// The user id. - /// The cancellation token. - void SaveAllDisplayPreferences( - IEnumerable displayPreferences, - Guid userId, - CancellationToken cancellationToken); - - /// - /// Gets the display preferences. - /// - /// The display preferences id. - /// The user id. - /// The client. - /// Task{DisplayPreferences}. - DisplayPreferences GetDisplayPreferences(string displayPreferencesId, string userId, string client); - - /// - /// Gets all display preferences for the given user. - /// - /// The user id. - /// Task{DisplayPreferences}. - IEnumerable GetAllDisplayPreferences(Guid userId); - } -} diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index b1a638883a..0fd63770f4 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -6,6 +6,7 @@ using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; diff --git a/MediaBrowser.Model/Dlna/SortCriteria.cs b/MediaBrowser.Model/Dlna/SortCriteria.cs index 1f7fa76ade..53e4540cbb 100644 --- a/MediaBrowser.Model/Dlna/SortCriteria.cs +++ b/MediaBrowser.Model/Dlna/SortCriteria.cs @@ -1,6 +1,6 @@ #pragma warning disable CS1591 -using MediaBrowser.Model.Entities; +using Jellyfin.Data.Enums; namespace MediaBrowser.Model.Dlna { diff --git a/MediaBrowser.Model/Entities/DisplayPreferences.cs b/MediaBrowser.Model/Entities/DisplayPreferences.cs deleted file mode 100644 index 7e5c5be3b6..0000000000 --- a/MediaBrowser.Model/Entities/DisplayPreferences.cs +++ /dev/null @@ -1,111 +0,0 @@ -#nullable disable -using System.Collections.Generic; - -namespace MediaBrowser.Model.Entities -{ - /// - /// Defines the display preferences for any item that supports them (usually Folders). - /// - public class DisplayPreferences - { - /// - /// The image scale. - /// - private const double ImageScale = .9; - - /// - /// Initializes a new instance of the class. - /// - public DisplayPreferences() - { - RememberIndexing = false; - PrimaryImageHeight = 250; - PrimaryImageWidth = 250; - ShowBackdrop = true; - CustomPrefs = new Dictionary(); - } - - /// - /// Gets or sets the user id. - /// - /// The user id. - public string Id { get; set; } - - /// - /// Gets or sets the type of the view. - /// - /// The type of the view. - public string ViewType { get; set; } - - /// - /// Gets or sets the sort by. - /// - /// The sort by. - public string SortBy { get; set; } - - /// - /// Gets or sets the index by. - /// - /// The index by. - public string IndexBy { get; set; } - - /// - /// Gets or sets a value indicating whether [remember indexing]. - /// - /// true if [remember indexing]; otherwise, false. - public bool RememberIndexing { get; set; } - - /// - /// Gets or sets the height of the primary image. - /// - /// The height of the primary image. - public int PrimaryImageHeight { get; set; } - - /// - /// Gets or sets the width of the primary image. - /// - /// The width of the primary image. - public int PrimaryImageWidth { get; set; } - - /// - /// Gets or sets the custom prefs. - /// - /// The custom prefs. - public Dictionary CustomPrefs { get; set; } - - /// - /// Gets or sets the scroll direction. - /// - /// The scroll direction. - public ScrollDirection ScrollDirection { get; set; } - - /// - /// Gets or sets a value indicating whether to show backdrops on this item. - /// - /// true if showing backdrops; otherwise, false. - public bool ShowBackdrop { get; set; } - - /// - /// Gets or sets a value indicating whether [remember sorting]. - /// - /// true if [remember sorting]; otherwise, false. - public bool RememberSorting { get; set; } - - /// - /// Gets or sets the sort order. - /// - /// The sort order. - public SortOrder SortOrder { get; set; } - - /// - /// Gets or sets a value indicating whether [show sidebar]. - /// - /// true if [show sidebar]; otherwise, false. - public bool ShowSidebar { get; set; } - - /// - /// Gets or sets the client. - /// - public string Client { get; set; } - } -} diff --git a/MediaBrowser.Model/Entities/DisplayPreferencesDto.cs b/MediaBrowser.Model/Entities/DisplayPreferencesDto.cs new file mode 100644 index 0000000000..1f7fe30300 --- /dev/null +++ b/MediaBrowser.Model/Entities/DisplayPreferencesDto.cs @@ -0,0 +1,107 @@ +#nullable disable +using System.Collections.Generic; +using Jellyfin.Data.Enums; + +namespace MediaBrowser.Model.Entities +{ + /// + /// Defines the display preferences for any item that supports them (usually Folders). + /// + public class DisplayPreferencesDto + { + /// + /// Initializes a new instance of the class. + /// + public DisplayPreferencesDto() + { + RememberIndexing = false; + PrimaryImageHeight = 250; + PrimaryImageWidth = 250; + ShowBackdrop = true; + CustomPrefs = new Dictionary(); + } + + /// + /// Gets or sets the user id. + /// + /// The user id. + public string Id { get; set; } + + /// + /// Gets or sets the type of the view. + /// + /// The type of the view. + public string ViewType { get; set; } + + /// + /// Gets or sets the sort by. + /// + /// The sort by. + public string SortBy { get; set; } + + /// + /// Gets or sets the index by. + /// + /// The index by. + public string IndexBy { get; set; } + + /// + /// Gets or sets a value indicating whether [remember indexing]. + /// + /// true if [remember indexing]; otherwise, false. + public bool RememberIndexing { get; set; } + + /// + /// Gets or sets the height of the primary image. + /// + /// The height of the primary image. + public int PrimaryImageHeight { get; set; } + + /// + /// Gets or sets the width of the primary image. + /// + /// The width of the primary image. + public int PrimaryImageWidth { get; set; } + + /// + /// Gets or sets the custom prefs. + /// + /// The custom prefs. + public Dictionary CustomPrefs { get; set; } + + /// + /// Gets or sets the scroll direction. + /// + /// The scroll direction. + public ScrollDirection ScrollDirection { get; set; } + + /// + /// Gets or sets a value indicating whether to show backdrops on this item. + /// + /// true if showing backdrops; otherwise, false. + public bool ShowBackdrop { get; set; } + + /// + /// Gets or sets a value indicating whether [remember sorting]. + /// + /// true if [remember sorting]; otherwise, false. + public bool RememberSorting { get; set; } + + /// + /// Gets or sets the sort order. + /// + /// The sort order. + public SortOrder SortOrder { get; set; } + + /// + /// Gets or sets a value indicating whether [show sidebar]. + /// + /// true if [show sidebar]; otherwise, false. + public bool ShowSidebar { get; set; } + + /// + /// Gets or sets the client. + /// + public string Client { get; set; } + } +} diff --git a/MediaBrowser.Model/Entities/ScrollDirection.cs b/MediaBrowser.Model/Entities/ScrollDirection.cs deleted file mode 100644 index a1de0edcbb..0000000000 --- a/MediaBrowser.Model/Entities/ScrollDirection.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace MediaBrowser.Model.Entities -{ - /// - /// Enum ScrollDirection. - /// - public enum ScrollDirection - { - /// - /// The horizontal. - /// - Horizontal, - - /// - /// The vertical. - /// - Vertical - } -} diff --git a/MediaBrowser.Model/Entities/SortOrder.cs b/MediaBrowser.Model/Entities/SortOrder.cs deleted file mode 100644 index f3abc06f33..0000000000 --- a/MediaBrowser.Model/Entities/SortOrder.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace MediaBrowser.Model.Entities -{ - /// - /// Enum SortOrder. - /// - public enum SortOrder - { - /// - /// The ascending. - /// - Ascending, - - /// - /// The descending. - /// - Descending - } -} diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs index 2b2377fdaf..ab74aff28b 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs @@ -2,7 +2,7 @@ #pragma warning disable CS1591 using System; -using MediaBrowser.Model.Entities; +using Jellyfin.Data.Enums; namespace MediaBrowser.Model.LiveTv { diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs index b899a464b4..dae885775c 100644 --- a/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs +++ b/MediaBrowser.Model/LiveTv/SeriesTimerQuery.cs @@ -1,6 +1,6 @@ #pragma warning disable CS1591 -using MediaBrowser.Model.Entities; +using Jellyfin.Data.Enums; namespace MediaBrowser.Model.LiveTv { -- cgit v1.2.3 From 27eefd49f1011a9be3be4f18069942cd484c1530 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 17 Jul 2020 19:36:55 -0400 Subject: Add missing fields --- Jellyfin.Data/Entities/DisplayPreferences.cs | 32 ++ Jellyfin.Data/Enums/ChromecastVersion.cs | 18 + ...0200630170339_AddDisplayPreferences.Designer.cs | 403 -------------------- .../20200630170339_AddDisplayPreferences.cs | 92 ----- ...0200717233541_AddDisplayPreferences.Designer.cs | 414 +++++++++++++++++++++ .../20200717233541_AddDisplayPreferences.cs | 93 +++++ .../Migrations/JellyfinDbModelSnapshot.cs | 15 +- MediaBrowser.Api/DisplayPreferencesService.cs | 8 + 8 files changed, 579 insertions(+), 496 deletions(-) create mode 100644 Jellyfin.Data/Enums/ChromecastVersion.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.cs create mode 100644 Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs create mode 100644 Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Data/Entities/DisplayPreferences.cs b/Jellyfin.Data/Entities/DisplayPreferences.cs index 6cefda7880..bcb872db37 100644 --- a/Jellyfin.Data/Entities/DisplayPreferences.cs +++ b/Jellyfin.Data/Entities/DisplayPreferences.cs @@ -135,6 +135,38 @@ namespace Jellyfin.Data.Entities /// public IndexingKind? IndexBy { get; set; } + /// + /// Gets or sets the length of time to skip forwards, in milliseconds. + /// + /// + /// Required. + /// + public int SkipForwardLength { get; set; } + + /// + /// Gets or sets the length of time to skip backwards, in milliseconds. + /// + /// + /// Required. + /// + public int SkipBackwardLength { get; set; } + + /// + /// Gets or sets the Chromecast Version. + /// + /// + /// Required. + /// + public ChromecastVersion ChromecastVersion { get; set; } + + /// + /// Gets or sets a value indicating whether the next video info overlay should be shown. + /// + /// + /// Required. + /// + public bool EnableNextVideoInfoOverlay { get; set; } + /// /// Gets or sets the home sections. /// diff --git a/Jellyfin.Data/Enums/ChromecastVersion.cs b/Jellyfin.Data/Enums/ChromecastVersion.cs new file mode 100644 index 0000000000..c549b6acc4 --- /dev/null +++ b/Jellyfin.Data/Enums/ChromecastVersion.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Data.Enums +{ + /// + /// An enum representing the version of Chromecast to be used by clients. + /// + public enum ChromecastVersion + { + /// + /// Stable Chromecast version. + /// + Stable, + + /// + /// Nightly Chromecast version. + /// + Nightly + } +} diff --git a/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs deleted file mode 100644 index 75f9bb7a3c..0000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.Designer.cs +++ /dev/null @@ -1,403 +0,0 @@ -#pragma warning disable CS1591 - -// -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("20200630170339_AddDisplayPreferences")] - partial class AddDisplayPreferences - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "3.1.5"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Overview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(64); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .HasColumnType("TEXT"); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("Permission_Permissions_Guid"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("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("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EasyPassword") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("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) - .WithMany("DisplayPreferences") - .HasForeignKey("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.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/20200630170339_AddDisplayPreferences.cs b/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.cs deleted file mode 100644 index e9a493d9db..0000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200630170339_AddDisplayPreferences.cs +++ /dev/null @@ -1,92 +0,0 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1601 - -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class AddDisplayPreferences : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "DisplayPreferences", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - UserId = table.Column(nullable: false), - ItemId = table.Column(nullable: true), - Client = table.Column(maxLength: 64, nullable: false), - RememberIndexing = table.Column(nullable: false), - RememberSorting = table.Column(nullable: false), - SortOrder = table.Column(nullable: false), - ShowSidebar = table.Column(nullable: false), - ShowBackdrop = table.Column(nullable: false), - SortBy = table.Column(nullable: true), - ViewType = table.Column(nullable: true), - ScrollDirection = table.Column(nullable: false), - IndexBy = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_DisplayPreferences", x => x.Id); - table.ForeignKey( - name: "FK_DisplayPreferences_Users_UserId", - column: x => x.UserId, - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "HomeSection", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - DisplayPreferencesId = table.Column(nullable: false), - Order = table.Column(nullable: false), - Type = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_HomeSection", x => x.Id); - table.ForeignKey( - name: "FK_HomeSection_DisplayPreferences_DisplayPreferencesId", - column: x => x.DisplayPreferencesId, - principalSchema: "jellyfin", - principalTable: "DisplayPreferences", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_DisplayPreferences_UserId", - schema: "jellyfin", - table: "DisplayPreferences", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_HomeSection_DisplayPreferencesId", - schema: "jellyfin", - table: "HomeSection", - column: "DisplayPreferencesId"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "HomeSection", - schema: "jellyfin"); - - migrationBuilder.DropTable( - name: "DisplayPreferences", - schema: "jellyfin"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs new file mode 100644 index 0000000000..cf6b166172 --- /dev/null +++ b/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs @@ -0,0 +1,414 @@ +// +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("20200717233541_AddDisplayPreferences")] + partial class AddDisplayPreferences + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "3.1.5"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Overview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Permission_Permissions_Guid"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("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) + .WithMany("DisplayPreferences") + .HasForeignKey("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.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/20200717233541_AddDisplayPreferences.cs b/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.cs new file mode 100644 index 0000000000..3cfd02e070 --- /dev/null +++ b/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.cs @@ -0,0 +1,93 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddDisplayPreferences : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DisplayPreferences", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(nullable: false), + ItemId = table.Column(nullable: true), + Client = table.Column(maxLength: 64, nullable: false), + RememberIndexing = table.Column(nullable: false), + RememberSorting = table.Column(nullable: false), + SortOrder = table.Column(nullable: false), + ShowSidebar = table.Column(nullable: false), + ShowBackdrop = table.Column(nullable: false), + SortBy = table.Column(maxLength: 64, nullable: true), + ViewType = table.Column(nullable: true), + ScrollDirection = table.Column(nullable: false), + IndexBy = table.Column(nullable: true), + SkipForwardLength = table.Column(nullable: false), + SkipBackwardLength = table.Column(nullable: false), + ChromecastVersion = table.Column(nullable: false), + EnableNextVideoInfoOverlay = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DisplayPreferences", x => x.Id); + table.ForeignKey( + name: "FK_DisplayPreferences_Users_UserId", + column: x => x.UserId, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "HomeSection", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DisplayPreferencesId = table.Column(nullable: false), + Order = table.Column(nullable: false), + Type = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_HomeSection", x => x.Id); + table.ForeignKey( + name: "FK_HomeSection_DisplayPreferences_DisplayPreferencesId", + column: x => x.DisplayPreferencesId, + principalSchema: "jellyfin", + principalTable: "DisplayPreferences", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId", + schema: "jellyfin", + table: "DisplayPreferences", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_HomeSection_DisplayPreferencesId", + schema: "jellyfin", + table: "HomeSection", + column: "DisplayPreferencesId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "HomeSection", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "DisplayPreferences", + schema: "jellyfin"); + } + } +} diff --git a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs index 69b544e5ba..76de592ac7 100644 --- a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs +++ b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs @@ -94,11 +94,17 @@ namespace Jellyfin.Server.Implementations.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + b.Property("Client") .IsRequired() .HasColumnType("TEXT") .HasMaxLength(64); + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + b.Property("IndexBy") .HasColumnType("INTEGER"); @@ -120,8 +126,15 @@ namespace Jellyfin.Server.Implementations.Migrations b.Property("ShowSidebar") .HasColumnType("INTEGER"); + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + b.Property("SortBy") - .HasColumnType("TEXT"); + .HasColumnType("TEXT") + .HasMaxLength(64); b.Property("SortOrder") .HasColumnType("INTEGER"); diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs index 5352bb36eb..877b124be5 100644 --- a/MediaBrowser.Api/DisplayPreferencesService.cs +++ b/MediaBrowser.Api/DisplayPreferencesService.cs @@ -134,6 +134,14 @@ namespace MediaBrowser.Api prefs.RememberIndexing = request.RememberIndexing; prefs.RememberSorting = request.RememberSorting; prefs.ScrollDirection = request.ScrollDirection; + prefs.ChromecastVersion = request.CustomPrefs.TryGetValue("chromecastVersion", out var chromecastVersion) + ? Enum.Parse(chromecastVersion, true) + : ChromecastVersion.Stable; + prefs.EnableNextVideoInfoOverlay = request.CustomPrefs.TryGetValue("enableNextVideoInfoOverlay", out var enableNextVideoInfoOverlay) + ? bool.Parse(enableNextVideoInfoOverlay) + : true; + prefs.SkipBackwardLength = request.CustomPrefs.TryGetValue("skipBackLength", out var skipBackLength) ? int.Parse(skipBackLength) : 10000; + prefs.SkipForwardLength = request.CustomPrefs.TryGetValue("skipForwardLength", out var skipForwardLength) ? int.Parse(skipForwardLength) : 30000; prefs.HomeSections.Clear(); foreach (var key in request.CustomPrefs.Keys.Where(key => key.StartsWith("homesection"))) -- cgit v1.2.3 From 4742ddbb711e9c7b0141b592b9b005f85e85c0df Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 17 Jul 2020 19:48:11 -0400 Subject: Update .NET Core to 3.1.6 --- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 8 ++++---- Jellyfin.Api/Jellyfin.Api.csproj | 2 +- Jellyfin.Data/Jellyfin.Data.csproj | 4 ++-- .../Jellyfin.Server.Implementations.csproj | 4 ++-- Jellyfin.Server/Jellyfin.Server.csproj | 4 ++-- MediaBrowser.Common/MediaBrowser.Common.csproj | 4 ++-- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 4 ++-- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 +- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 4 ++-- tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj | 2 +- tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index f7ad59c10f..4351b9aa59 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -34,10 +34,10 @@ - - - - + + + + diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 93c4612b66..3693d5122a 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -14,7 +14,7 @@ - + diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 58d1ba2f36..8ce0f3848c 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index dcac1b34b1..21748ca192 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -24,11 +24,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 6a2d252ab7..b1bd38cffb 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -41,8 +41,8 @@ - - + + diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index c9ca153c71..7380f39fda 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 73e966344f..67f17f7a52 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 83bd0c07e6..902e29b20b 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -23,7 +23,7 @@ - + diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 446e27df65..42c7cec535 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -16,8 +16,8 @@ - - + + diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 2190208886..132050e7b2 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj index a767c00397..8309faebd1 100644 --- a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj +++ b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj @@ -8,7 +8,7 @@ - + -- cgit v1.2.3 From 1ac11863126edd570cd3f0baeebd9efb5925dde7 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 17 Jul 2020 20:01:17 -0400 Subject: Add pragmas to DisplayPreferences migration files --- .../Migrations/20200717233541_AddDisplayPreferences.Designer.cs | 4 +++- .../Migrations/20200717233541_AddDisplayPreferences.cs | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs index cf6b166172..392e26daef 100644 --- a/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs +++ b/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs @@ -1,4 +1,6 @@ -// +#pragma warning disable CS1591 + +// using System; using Jellyfin.Server.Implementations; using Microsoft.EntityFrameworkCore; diff --git a/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.cs b/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.cs index 3cfd02e070..a5c344fac0 100644 --- a/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.cs +++ b/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.cs @@ -1,4 +1,7 @@ -using System; +#pragma warning disable CS1591 +#pragma warning disable SA1601 + +using System; using Microsoft.EntityFrameworkCore.Migrations; namespace Jellyfin.Server.Implementations.Migrations -- cgit v1.2.3 From 2f38d9700cd6f6e80976d2bfe320d1a829a8eed4 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sat, 18 Jul 2020 20:29:27 -0600 Subject: fix UserManager UpdatePolicy --- Jellyfin.Server.Implementations/Users/UserManager.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 9aff808db0..e3a7d54677 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -671,7 +671,13 @@ namespace Jellyfin.Server.Implementations.Users public void UpdatePolicy(Guid userId, UserPolicy policy) { var dbContext = _dbProvider.CreateContext(); - var user = dbContext.Users.Find(userId) ?? throw new ArgumentException("No user exists with given Id!"); + var user = dbContext.Users + .Include(u => u.Permissions) + .Include(u => u.Preferences) + .Include(u => u.AccessSchedules) + .Include(u => u.ProfileImage) + .FirstOrDefault(u => u.Id == userId) + ?? 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" int? maxLoginAttempts = policy.LoginAttemptsBeforeLockout switch -- cgit v1.2.3 From d1e351a00ac47c2caa7e7e1a22e20c65d27cec7f Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 19 Jul 2020 20:21:30 -0600 Subject: Fix username case change --- Jellyfin.Server.Implementations/Users/UserManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index e3a7d54677..343f452c7d 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -152,12 +152,12 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Invalid username", nameof(newName)); } - if (user.Username.Equals(newName, StringComparison.OrdinalIgnoreCase)) + if (user.Username.Equals(newName, StringComparison.Ordinal)) { throw new ArgumentException("The new and old names must be different."); } - if (Users.Any(u => u.Id != user.Id && u.Username.Equals(newName, StringComparison.OrdinalIgnoreCase))) + if (Users.Any(u => u.Id != user.Id && u.Username.Equals(newName, StringComparison.Ordinal))) { throw new ArgumentException(string.Format( CultureInfo.InvariantCulture, -- cgit v1.2.3 From 9787b2fe8a3004788e6d1b58217f74c41ecec826 Mon Sep 17 00:00:00 2001 From: crobibero Date: Tue, 21 Jul 2020 10:19:53 -0600 Subject: Detach tracked entries on dispose --- Jellyfin.Server.Implementations/JellyfinDb.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index 53120a763e..acc6eec1c5 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System; using System.Linq; using Jellyfin.Data; using Jellyfin.Data.Entities; @@ -133,6 +134,18 @@ namespace Jellyfin.Server.Implementations return base.SaveChanges(); } + /// + public override void Dispose() + { + foreach (var entry in ChangeTracker.Entries()) + { + entry.State = EntityState.Detached; + } + + GC.SuppressFinalize(this); + base.Dispose(); + } + /// protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { -- cgit v1.2.3 From 0c5ac10a68ff0d968579b67d48b0bc00580f6bf4 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 21 Jul 2020 14:25:52 -0400 Subject: Make IncrementInvalidLoginAttemptCount async. --- Jellyfin.Server.Implementations/Users/UserManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 343f452c7d..52e09a55a2 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -512,7 +512,7 @@ namespace Jellyfin.Server.Implementations.Users } else { - IncrementInvalidLoginAttemptCount(user); + await IncrementInvalidLoginAttemptCount(user).ConfigureAwait(false); _logger.LogInformation( "Authentication request for {UserName} has been denied (IP: {IP}).", user.Username, @@ -882,7 +882,7 @@ namespace Jellyfin.Server.Implementations.Users } } - private void IncrementInvalidLoginAttemptCount(User user) + private async Task IncrementInvalidLoginAttemptCount(User user) { user.InvalidLoginAttemptCount++; int? maxInvalidLogins = user.LoginAttemptsBeforeLockout; @@ -896,7 +896,7 @@ namespace Jellyfin.Server.Implementations.Users user.InvalidLoginAttemptCount); } - UpdateUser(user); + await UpdateUserAsync(user).ConfigureAwait(false); } } } -- cgit v1.2.3 From b4532ad3a2ea0066fa901bd46b6236aac46bceb7 Mon Sep 17 00:00:00 2001 From: crobibero Date: Wed, 22 Jul 2020 11:35:31 -0600 Subject: add missing using --- Jellyfin.Server.Implementations/Users/UserManager.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 343f452c7d..38468ce42e 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -102,7 +102,16 @@ namespace Jellyfin.Server.Implementations.Users } /// - public IEnumerable UsersIds => _dbProvider.CreateContext().Users.Select(u => u.Id); + public IEnumerable UsersIds + { + get + { + using var dbContext = _dbProvider.CreateContext(); + return dbContext.Users + .Select(user => user.Id) + .ToList(); + } + } /// public User? GetUserById(Guid id) @@ -637,7 +646,7 @@ namespace Jellyfin.Server.Implementations.Users /// public void UpdateConfiguration(Guid userId, UserConfiguration config) { - var dbContext = _dbProvider.CreateContext(); + using var dbContext = _dbProvider.CreateContext(); var user = dbContext.Users .Include(u => u.Permissions) .Include(u => u.Preferences) @@ -670,7 +679,7 @@ namespace Jellyfin.Server.Implementations.Users /// public void UpdatePolicy(Guid userId, UserPolicy policy) { - var dbContext = _dbProvider.CreateContext(); + using var dbContext = _dbProvider.CreateContext(); var user = dbContext.Users .Include(u => u.Permissions) .Include(u => u.Preferences) -- cgit v1.2.3 From 52ebf6ae8f050fcbdf675529a97cfbbfcca4953a Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 22 Jul 2020 14:53:32 -0400 Subject: Move DisplayPreferencesManager.cs to Users namespace --- .../DisplayPreferencesManager.cs | 49 ---------------------- .../Users/DisplayPreferencesManager.cs | 49 ++++++++++++++++++++++ MediaBrowser.Api/DisplayPreferencesService.cs | 2 +- 3 files changed, 50 insertions(+), 50 deletions(-) delete mode 100644 Jellyfin.Server.Implementations/DisplayPreferencesManager.cs create mode 100644 Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/DisplayPreferencesManager.cs deleted file mode 100644 index 132e74c6aa..0000000000 --- a/Jellyfin.Server.Implementations/DisplayPreferencesManager.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Linq; -using Jellyfin.Data.Entities; -using MediaBrowser.Controller; - -namespace Jellyfin.Server.Implementations -{ - /// - /// Manages the storage and retrieval of display preferences through Entity Framework. - /// - public class DisplayPreferencesManager : IDisplayPreferencesManager - { - private readonly JellyfinDbProvider _dbProvider; - - /// - /// Initializes a new instance of the class. - /// - /// The Jellyfin db provider. - public DisplayPreferencesManager(JellyfinDbProvider dbProvider) - { - _dbProvider = dbProvider; - } - - /// - public DisplayPreferences GetDisplayPreferences(Guid userId, string client) - { - var dbContext = _dbProvider.CreateContext(); - var user = dbContext.Users.Find(userId); -#pragma warning disable CA1307 - var prefs = user.DisplayPreferences.FirstOrDefault(pref => string.Equals(pref.Client, client)); - - if (prefs == null) - { - prefs = new DisplayPreferences(client, userId); - user.DisplayPreferences.Add(prefs); - } - - return prefs; - } - - /// - public void SaveChanges(DisplayPreferences preferences) - { - var dbContext = _dbProvider.CreateContext(); - dbContext.Update(preferences); - dbContext.SaveChanges(); - } - } -} diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs new file mode 100644 index 0000000000..29ec6e706e --- /dev/null +++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs @@ -0,0 +1,49 @@ +using System; +using System.Linq; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller; + +namespace Jellyfin.Server.Implementations.Users +{ + /// + /// Manages the storage and retrieval of display preferences through Entity Framework. + /// + public class DisplayPreferencesManager : IDisplayPreferencesManager + { + private readonly JellyfinDbProvider _dbProvider; + + /// + /// Initializes a new instance of the class. + /// + /// The Jellyfin db provider. + public DisplayPreferencesManager(JellyfinDbProvider dbProvider) + { + _dbProvider = dbProvider; + } + + /// + public DisplayPreferences GetDisplayPreferences(Guid userId, string client) + { + var dbContext = _dbProvider.CreateContext(); + var user = dbContext.Users.Find(userId); +#pragma warning disable CA1307 + var prefs = user.DisplayPreferences.FirstOrDefault(pref => string.Equals(pref.Client, client)); + + if (prefs == null) + { + prefs = new DisplayPreferences(client, userId); + user.DisplayPreferences.Add(prefs); + } + + return prefs; + } + + /// + public void SaveChanges(DisplayPreferences preferences) + { + var dbContext = _dbProvider.CreateContext(); + dbContext.Update(preferences); + dbContext.SaveChanges(); + } + } +} diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs index b95ab0dfde..cca2092e97 100644 --- a/MediaBrowser.Api/DisplayPreferencesService.cs +++ b/MediaBrowser.Api/DisplayPreferencesService.cs @@ -148,7 +148,7 @@ namespace MediaBrowser.Api foreach (var key in request.CustomPrefs.Keys.Where(key => key.StartsWith("homesection"))) { - var order = int.Parse(key.Substring("homesection".Length)); + var order = int.Parse(key.AsSpan().Slice("homesection".Length)); if (!Enum.TryParse(request.CustomPrefs[key], true, out var type)) { type = order < 7 ? defaults[order] : HomeSectionType.None; -- cgit v1.2.3 From 6cbfae209d5e4621624d9cc249c601f46c3721c5 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 22 Jul 2020 20:57:29 +0200 Subject: Make CreateUser async --- Jellyfin.Api/Controllers/StartupController.cs | 8 ++--- .../Users/UserManager.cs | 42 +++++++++++++--------- MediaBrowser.Api/UserService.cs | 2 +- MediaBrowser.Controller/Library/IUserManager.cs | 4 +-- 4 files changed, 31 insertions(+), 25 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs index 04f134b8bf..93fb22c4eb 100644 --- a/Jellyfin.Api/Controllers/StartupController.cs +++ b/Jellyfin.Api/Controllers/StartupController.cs @@ -46,14 +46,12 @@ namespace Jellyfin.Api.Controllers [HttpGet("Configuration")] public StartupConfigurationDto GetStartupConfiguration() { - var result = new StartupConfigurationDto + return new StartupConfigurationDto { UICulture = _config.Configuration.UICulture, MetadataCountryCode = _config.Configuration.MetadataCountryCode, PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage }; - - return result; } /// @@ -92,10 +90,10 @@ namespace Jellyfin.Api.Controllers /// /// The first user. [HttpGet("User")] - public StartupUserDto GetFirstUser() + public async Task GetFirstUser() { // TODO: Remove this method when startup wizard no longer requires an existing user. - _userManager.Initialize(); + await _userManager.InitializeAsync().ConfigureAwait(false); var user = _userManager.Users.First(); return new StartupUserDto { diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 343f452c7d..5d72ff9382 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -188,8 +188,24 @@ namespace Jellyfin.Server.Implementations.Users await dbContext.SaveChangesAsync().ConfigureAwait(false); } + internal async Task 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) + : 0; + + return new User( + name, + _defaultAuthenticationProvider.GetType().FullName, + _defaultPasswordResetProvider.GetType().FullName) + { + InternalId = max + 1 + }; + } + /// - public User CreateUser(string name) + public async Task CreateUserAsync(string name) { if (!IsValidUsername(name)) { @@ -198,18 +214,10 @@ namespace Jellyfin.Server.Implementations.Users using var dbContext = _dbProvider.CreateContext(); - // TODO: Remove after user item data is migrated. - var max = dbContext.Users.Any() ? dbContext.Users.Select(u => u.InternalId).Max() : 0; + var newUser = await CreateUserInternalAsync(name, dbContext).ConfigureAwait(false); - var newUser = new User( - name, - _defaultAuthenticationProvider.GetType().FullName, - _defaultPasswordResetProvider.GetType().FullName) - { - InternalId = max + 1 - }; - dbContext.Users.Add(newUser); - dbContext.SaveChanges(); + await dbContext.Users.AddAsync(newUser).ConfigureAwait(false); + await dbContext.SaveChangesAsync().ConfigureAwait(false); OnUserCreated?.Invoke(this, new GenericEventArgs(newUser)); @@ -572,12 +580,12 @@ namespace Jellyfin.Server.Implementations.Users } /// - public void Initialize() + 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(); - if (dbContext.Users.Any()) + if (await dbContext.Users.AnyAsync().ConfigureAwait(false)) { return; } @@ -595,13 +603,13 @@ namespace Jellyfin.Server.Implementations.Users throw new ArgumentException("Provided username is not valid!", defaultName); } - var newUser = CreateUser(defaultName); + var newUser = await CreateUserInternalAsync(defaultName, dbContext).ConfigureAwait(false); newUser.SetPermission(PermissionKind.IsAdministrator, true); newUser.SetPermission(PermissionKind.EnableContentDeletion, true); newUser.SetPermission(PermissionKind.EnableRemoteControlOfOtherUsers, true); - dbContext.Users.Update(newUser); - dbContext.SaveChanges(); + await dbContext.Users.AddAsync(newUser).ConfigureAwait(false); + await dbContext.SaveChangesAsync().ConfigureAwait(false); } /// diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 6e9d788dc1..440d1840d9 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -525,7 +525,7 @@ namespace MediaBrowser.Api /// System.Object. public async Task Post(CreateUserByName request) { - var newUser = _userManager.CreateUser(request.Name); + var newUser = await _userManager.CreateUserAsync(request.Name).ConfigureAwait(false); // no need to authenticate password for new user if (request.Password != null) diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index e73fe71205..a2ff0c1bc7 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -55,7 +55,7 @@ namespace MediaBrowser.Controller.Library /// /// Initializes the user manager and ensures that a user exists. /// - void Initialize(); + Task InitializeAsync(); /// /// Gets a user by Id. @@ -106,7 +106,7 @@ namespace MediaBrowser.Controller.Library /// The created user. /// name /// - User CreateUser(string name); + Task CreateUserAsync(string name); /// /// Deletes the specified user. -- cgit v1.2.3 From 941f326c0b786ba8bac02dd745ea998055e6e554 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 22 Jul 2020 21:07:13 +0200 Subject: Don't AddAsync --- Jellyfin.Server.Implementations/Users/UserManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 5d72ff9382..a0dd2a6b38 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -216,7 +216,7 @@ namespace Jellyfin.Server.Implementations.Users var newUser = await CreateUserInternalAsync(name, dbContext).ConfigureAwait(false); - await dbContext.Users.AddAsync(newUser).ConfigureAwait(false); + dbContext.Users.Add(newUser); await dbContext.SaveChangesAsync().ConfigureAwait(false); OnUserCreated?.Invoke(this, new GenericEventArgs(newUser)); @@ -608,7 +608,7 @@ namespace Jellyfin.Server.Implementations.Users newUser.SetPermission(PermissionKind.EnableContentDeletion, true); newUser.SetPermission(PermissionKind.EnableRemoteControlOfOtherUsers, true); - await dbContext.Users.AddAsync(newUser).ConfigureAwait(false); + dbContext.Users.Add(newUser); await dbContext.SaveChangesAsync().ConfigureAwait(false); } -- cgit v1.2.3 From 8a9ec7809fab05a30ff8e5f13b38b9d34ed15050 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 22 Jul 2020 15:19:18 -0400 Subject: Wrap context creation with using --- Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs index 29ec6e706e..4ad9a12d42 100644 --- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs +++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs @@ -2,6 +2,7 @@ using System.Linq; using Jellyfin.Data.Entities; using MediaBrowser.Controller; +using Microsoft.EntityFrameworkCore; namespace Jellyfin.Server.Implementations.Users { @@ -24,7 +25,7 @@ namespace Jellyfin.Server.Implementations.Users /// public DisplayPreferences GetDisplayPreferences(Guid userId, string client) { - var dbContext = _dbProvider.CreateContext(); + using var dbContext = _dbProvider.CreateContext(); var user = dbContext.Users.Find(userId); #pragma warning disable CA1307 var prefs = user.DisplayPreferences.FirstOrDefault(pref => string.Equals(pref.Client, client)); @@ -41,7 +42,7 @@ namespace Jellyfin.Server.Implementations.Users /// public void SaveChanges(DisplayPreferences preferences) { - var dbContext = _dbProvider.CreateContext(); + using var dbContext = _dbProvider.CreateContext(); dbContext.Update(preferences); dbContext.SaveChanges(); } -- cgit v1.2.3 From 5f67ba4d7087d7a0cad37fc9e2db212340076d12 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Wed, 22 Jul 2020 15:21:50 -0400 Subject: Restructure query to avoid extra database access. --- .../Users/DisplayPreferencesManager.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs index 4ad9a12d42..b7c65fc2cb 100644 --- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs +++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs @@ -1,4 +1,6 @@ -using System; +#pragma warning disable CA1307 + +using System; using System.Linq; using Jellyfin.Data.Entities; using MediaBrowser.Controller; @@ -26,14 +28,15 @@ namespace Jellyfin.Server.Implementations.Users public DisplayPreferences GetDisplayPreferences(Guid userId, string client) { using var dbContext = _dbProvider.CreateContext(); - var user = dbContext.Users.Find(userId); -#pragma warning disable CA1307 - var prefs = user.DisplayPreferences.FirstOrDefault(pref => string.Equals(pref.Client, client)); + var prefs = dbContext.DisplayPreferences + .Include(pref => pref.HomeSections) + .FirstOrDefault(pref => + pref.UserId == userId && pref.ItemId == null && string.Equals(pref.Client, client)); if (prefs == null) { prefs = new DisplayPreferences(client, userId); - user.DisplayPreferences.Add(prefs); + dbContext.DisplayPreferences.Add(prefs); } return prefs; -- cgit v1.2.3 From 1ee87901897290e971c2c65020f5576c08b0dc43 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 23 Jul 2020 21:50:41 -0400 Subject: Use System.Text.Json in DefaultPasswordResetProvider --- .../Users/DefaultPasswordResetProvider.cs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs index 007c296436..9b0201bfbf 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; +using System.Text.Json; using System.Threading.Tasks; using Jellyfin.Data.Entities; using MediaBrowser.Common; @@ -11,7 +12,6 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Users; namespace Jellyfin.Server.Implementations.Users @@ -23,7 +23,6 @@ namespace Jellyfin.Server.Implementations.Users { private const string BaseResetFileName = "passwordreset"; - private readonly IJsonSerializer _jsonSerializer; private readonly IApplicationHost _appHost; private readonly string _passwordResetFileBase; @@ -33,16 +32,11 @@ namespace Jellyfin.Server.Implementations.Users /// Initializes a new instance of the class. /// /// The configuration manager. - /// The JSON serializer. /// The application host. - public DefaultPasswordResetProvider( - IServerConfigurationManager configurationManager, - IJsonSerializer jsonSerializer, - IApplicationHost appHost) + public DefaultPasswordResetProvider(IServerConfigurationManager configurationManager, IApplicationHost appHost) { _passwordResetFileBaseDir = configurationManager.ApplicationPaths.ProgramDataPath; _passwordResetFileBase = Path.Combine(_passwordResetFileBaseDir, BaseResetFileName); - _jsonSerializer = jsonSerializer; _appHost = appHost; // TODO: Remove the circular dependency on UserManager } @@ -63,7 +57,7 @@ namespace Jellyfin.Server.Implementations.Users SerializablePasswordReset spr; await using (var str = File.OpenRead(resetFile)) { - spr = await _jsonSerializer.DeserializeFromStreamAsync(str).ConfigureAwait(false); + spr = await JsonSerializer.DeserializeAsync(str).ConfigureAwait(false); } if (spr.ExpirationDate < DateTime.UtcNow) @@ -119,7 +113,7 @@ namespace Jellyfin.Server.Implementations.Users await using (FileStream fileStream = File.OpenWrite(filePath)) { - _jsonSerializer.SerializeToStream(spr, fileStream); + fileStream.Write(JsonSerializer.SerializeToUtf8Bytes(spr)); await fileStream.FlushAsync().ConfigureAwait(false); } -- cgit v1.2.3 From 1aa853067a5b6daf54bfd01b38e4a4c8256d07c3 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 25 Jul 2020 13:07:12 -0400 Subject: Use async json serialization. --- Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs index 9b0201bfbf..6cb13cd23e 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs @@ -113,7 +113,7 @@ namespace Jellyfin.Server.Implementations.Users await using (FileStream fileStream = File.OpenWrite(filePath)) { - fileStream.Write(JsonSerializer.SerializeToUtf8Bytes(spr)); + await JsonSerializer.SerializeAsync(fileStream, spr).ConfigureAwait(false); await fileStream.FlushAsync().ConfigureAwait(false); } -- cgit v1.2.3 From 2da2f1b20b7f3ee49eeaab4db4ae19c666551190 Mon Sep 17 00:00:00 2001 From: Odd Stråbø Date: Sat, 25 Jul 2020 22:19:27 +0200 Subject: Allow space in username --- Jellyfin.Server.Implementations/Users/UserManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index e49a99fe53..c3cba4fbfe 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -767,7 +767,7 @@ namespace Jellyfin.Server.Implementations.Users // 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 // Usernames can contain letters (a-z + whatever else unicode is cool with), numbers (0-9), at-signs (@), dashes (-), underscores (_), apostrophes ('), and periods (.) - return Regex.IsMatch(name, @"^[\w\-'._@]*$"); + return Regex.IsMatch(name, @"^[\w\ \-'._@]*$"); } private IAuthenticationProvider GetAuthenticationProvider(User user) -- cgit v1.2.3 From 27e12798bc60ce1d27853afdb763681d4dce66cf Mon Sep 17 00:00:00 2001 From: Odd Stråbø Date: Sun, 26 Jul 2020 13:57:22 +0200 Subject: Update comment to include space --- Jellyfin.Server.Implementations/Users/UserManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index c3cba4fbfe..eaa6a0a814 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -766,7 +766,7 @@ namespace Jellyfin.Server.Implementations.Users { // 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 - // Usernames can contain letters (a-z + whatever else unicode is cool with), numbers (0-9), at-signs (@), dashes (-), underscores (_), apostrophes ('), and periods (.) + // Usernames can contain letters (a-z + whatever else unicode is cool with), numbers (0-9), at-signs (@), dashes (-), underscores (_), apostrophes ('), periods (.) and spaces ( ) return Regex.IsMatch(name, @"^[\w\ \-'._@]*$"); } -- cgit v1.2.3 From 68a185fd02844698ac5ecd5618d590ae254d95cf Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Mon, 27 Jul 2020 20:40:21 -0400 Subject: Serialize/deserialize new entities properly. --- Jellyfin.Data/Entities/ItemDisplayPreferences.cs | 120 +++++++++++++++++++++ .../Entities/LibraryDisplayPreferences.cs | 120 --------------------- Jellyfin.Data/Entities/User.cs | 4 +- Jellyfin.Server.Implementations/JellyfinDb.cs | 2 + .../Users/DisplayPreferencesManager.cs | 39 ++++++- .../Routines/MigrateDisplayPreferencesDb.cs | 33 ++++-- MediaBrowser.Api/DisplayPreferencesService.cs | 70 +++++++----- .../IDisplayPreferencesManager.cs | 24 +++++ 8 files changed, 254 insertions(+), 158 deletions(-) create mode 100644 Jellyfin.Data/Entities/ItemDisplayPreferences.cs delete mode 100644 Jellyfin.Data/Entities/LibraryDisplayPreferences.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Data/Entities/ItemDisplayPreferences.cs b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs new file mode 100644 index 0000000000..95c08e6c6c --- /dev/null +++ b/Jellyfin.Data/Entities/ItemDisplayPreferences.cs @@ -0,0 +1,120 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data.Entities +{ + public class ItemDisplayPreferences + { + /// + /// Initializes a new instance of the class. + /// + /// The user id. + /// The item id. + /// The client. + public ItemDisplayPreferences(Guid userId, Guid itemId, string client) + { + UserId = userId; + ItemId = itemId; + Client = client; + + SortBy = "SortName"; + ViewType = ViewType.Poster; + SortOrder = SortOrder.Ascending; + RememberSorting = false; + RememberIndexing = false; + } + + /// + /// Initializes a new instance of the class. + /// + protected ItemDisplayPreferences() + { + } + + /// + /// Gets or sets the Id. + /// + /// + /// Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; protected set; } + + /// + /// Gets or sets the user Id. + /// + /// + /// Required. + /// + public Guid UserId { get; set; } + + /// + /// Gets or sets the id of the associated item. + /// + /// + /// Required. + /// + public Guid ItemId { get; set; } + + /// + /// Gets or sets the client string. + /// + /// + /// Required. Max Length = 32. + /// + [Required] + [MaxLength(32)] + [StringLength(32)] + public string Client { get; set; } + + /// + /// Gets or sets the view type. + /// + /// + /// Required. + /// + public ViewType ViewType { get; set; } + + /// + /// Gets or sets a value indicating whether the indexing should be remembered. + /// + /// + /// Required. + /// + public bool RememberIndexing { get; set; } + + /// + /// Gets or sets what the view should be indexed by. + /// + public IndexingKind? IndexBy { get; set; } + + /// + /// Gets or sets a value indicating whether the sorting type should be remembered. + /// + /// + /// Required. + /// + public bool RememberSorting { get; set; } + + /// + /// Gets or sets what the view should be sorted by. + /// + /// + /// Required. + /// + [Required] + [MaxLength(64)] + [StringLength(64)] + public string SortBy { get; set; } + + /// + /// Gets or sets the sort order. + /// + /// + /// Required. + /// + public SortOrder SortOrder { get; set; } + } +} diff --git a/Jellyfin.Data/Entities/LibraryDisplayPreferences.cs b/Jellyfin.Data/Entities/LibraryDisplayPreferences.cs deleted file mode 100644 index 87be1c6f7e..0000000000 --- a/Jellyfin.Data/Entities/LibraryDisplayPreferences.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Jellyfin.Data.Enums; - -namespace Jellyfin.Data.Entities -{ - public class LibraryDisplayPreferences - { - /// - /// Initializes a new instance of the class. - /// - /// The user id. - /// The item id. - /// The client. - public LibraryDisplayPreferences(Guid userId, Guid itemId, string client) - { - UserId = userId; - ItemId = itemId; - Client = client; - - SortBy = "SortName"; - ViewType = ViewType.Poster; - SortOrder = SortOrder.Ascending; - RememberSorting = false; - RememberIndexing = false; - } - - /// - /// Initializes a new instance of the class. - /// - protected LibraryDisplayPreferences() - { - } - - /// - /// Gets or sets the Id. - /// - /// - /// Required. - /// - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; protected set; } - - /// - /// Gets or sets the user Id. - /// - /// - /// Required. - /// - public Guid UserId { get; set; } - - /// - /// Gets or sets the id of the associated item. - /// - /// - /// Required. - /// - public Guid ItemId { get; set; } - - /// - /// Gets or sets the client string. - /// - /// - /// Required. Max Length = 32. - /// - [Required] - [MaxLength(32)] - [StringLength(32)] - public string Client { get; set; } - - /// - /// Gets or sets the view type. - /// - /// - /// Required. - /// - public ViewType ViewType { get; set; } - - /// - /// Gets or sets a value indicating whether the indexing should be remembered. - /// - /// - /// Required. - /// - public bool RememberIndexing { get; set; } - - /// - /// Gets or sets what the view should be indexed by. - /// - public IndexingKind? IndexBy { get; set; } - - /// - /// Gets or sets a value indicating whether the sorting type should be remembered. - /// - /// - /// Required. - /// - public bool RememberSorting { get; set; } - - /// - /// Gets or sets what the view should be sorted by. - /// - /// - /// Required. - /// - [Required] - [MaxLength(64)] - [StringLength(64)] - public string SortBy { get; set; } - - /// - /// Gets or sets the sort order. - /// - /// - /// Required. - /// - public SortOrder SortOrder { get; set; } - } -} diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index dc4bd9979c..50810561f5 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -48,7 +48,7 @@ namespace Jellyfin.Data.Entities PasswordResetProviderId = passwordResetProviderId; AccessSchedules = new HashSet(); - LibraryDisplayPreferences = new HashSet(); + ItemDisplayPreferences = new HashSet(); // Groups = new HashSet(); Permissions = new HashSet(); Preferences = new HashSet(); @@ -362,7 +362,7 @@ namespace Jellyfin.Data.Entities /// /// Gets or sets the list of item display preferences. /// - public virtual ICollection LibraryDisplayPreferences { get; protected set; } + public virtual ICollection ItemDisplayPreferences { get; protected set; } /* /// diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index 4ad6840639..7d864ebc69 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -32,6 +32,8 @@ namespace Jellyfin.Server.Implementations public virtual DbSet ImageInfos { get; set; } + public virtual DbSet ItemDisplayPreferences { get; set; } + public virtual DbSet Permissions { get; set; } public virtual DbSet Preferences { get; set; } diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs index b7c65fc2cb..7c5c5a3ec5 100644 --- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs +++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs @@ -1,6 +1,7 @@ #pragma warning disable CA1307 using System; +using System.Collections.Generic; using System.Linq; using Jellyfin.Data.Entities; using MediaBrowser.Controller; @@ -31,17 +32,43 @@ namespace Jellyfin.Server.Implementations.Users var prefs = dbContext.DisplayPreferences .Include(pref => pref.HomeSections) .FirstOrDefault(pref => - pref.UserId == userId && pref.ItemId == null && string.Equals(pref.Client, client)); + pref.UserId == userId && string.Equals(pref.Client, client)); if (prefs == null) { - prefs = new DisplayPreferences(client, userId); + prefs = new DisplayPreferences(userId, client); dbContext.DisplayPreferences.Add(prefs); } return prefs; } + /// + public ItemDisplayPreferences GetItemDisplayPreferences(Guid userId, Guid itemId, string client) + { + using var dbContext = _dbProvider.CreateContext(); + var prefs = dbContext.ItemDisplayPreferences + .FirstOrDefault(pref => pref.UserId == userId && pref.ItemId == itemId && string.Equals(pref.Client, client)); + + if (prefs == null) + { + prefs = new ItemDisplayPreferences(userId, Guid.Empty, client); + dbContext.ItemDisplayPreferences.Add(prefs); + } + + return prefs; + } + + /// + public IList ListItemDisplayPreferences(Guid userId, string client) + { + using var dbContext = _dbProvider.CreateContext(); + + return dbContext.ItemDisplayPreferences + .Where(prefs => prefs.UserId == userId && prefs.ItemId != Guid.Empty && string.Equals(prefs.Client, client)) + .ToList(); + } + /// public void SaveChanges(DisplayPreferences preferences) { @@ -49,5 +76,13 @@ namespace Jellyfin.Server.Implementations.Users dbContext.Update(preferences); dbContext.SaveChanges(); } + + /// + public void SaveChanges(ItemDisplayPreferences preferences) + { + using var dbContext = _dbProvider.CreateContext(); + dbContext.Update(preferences); + dbContext.SaveChanges(); + } } } diff --git a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs index d8b081bb29..6a78bff4fa 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs @@ -1,6 +1,7 @@ using System; using System.Globalization; using System.IO; +using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using Jellyfin.Data.Entities; @@ -78,16 +79,11 @@ namespace Jellyfin.Server.Migrations.Routines : ChromecastVersion.Stable : ChromecastVersion.Stable; - var displayPreferences = new DisplayPreferences(result[2].ToString(), new Guid(result[1].ToBlob())) + var displayPreferences = new DisplayPreferences(new Guid(result[1].ToBlob()), result[2].ToString()) { - ViewType = Enum.TryParse(dto.ViewType, true, out var viewType) ? viewType : (ViewType?)null, IndexBy = Enum.TryParse(dto.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null, ShowBackdrop = dto.ShowBackdrop, ShowSidebar = dto.ShowSidebar, - SortBy = dto.SortBy, - SortOrder = dto.SortOrder, - RememberIndexing = dto.RememberIndexing, - RememberSorting = dto.RememberSorting, ScrollDirection = dto.ScrollDirection, ChromecastVersion = chromecastVersion, SkipForwardLength = dto.CustomPrefs.TryGetValue("skipForwardLength", out var length) @@ -95,7 +91,7 @@ namespace Jellyfin.Server.Migrations.Routines : 30000, SkipBackwardLength = dto.CustomPrefs.TryGetValue("skipBackLength", out length) ? int.Parse(length, CultureInfo.InvariantCulture) - : 30000, + : 10000, EnableNextVideoInfoOverlay = dto.CustomPrefs.TryGetValue("enableNextVideoInfoOverlay", out var enabled) ? bool.Parse(enabled) : true @@ -112,6 +108,29 @@ namespace Jellyfin.Server.Migrations.Routines }); } + foreach (var key in dto.CustomPrefs.Keys.Where(key => key.StartsWith("landing-", StringComparison.Ordinal))) + { + if (!Guid.TryParse(key.AsSpan().Slice("landing-".Length), out var itemId)) + { + continue; + } + + var libraryDisplayPreferences = new ItemDisplayPreferences(displayPreferences.UserId, itemId, displayPreferences.Client) + { + SortBy = dto.SortBy, + SortOrder = dto.SortOrder, + RememberIndexing = dto.RememberIndexing, + RememberSorting = dto.RememberSorting, + }; + + if (Enum.TryParse(dto.ViewType, true, out var viewType)) + { + libraryDisplayPreferences.ViewType = viewType; + } + + dbContext.ItemDisplayPreferences.Add(libraryDisplayPreferences); + } + dbContext.Add(displayPreferences); } diff --git a/MediaBrowser.Api/DisplayPreferencesService.cs b/MediaBrowser.Api/DisplayPreferencesService.cs index 0f3427e541..416d63100f 100644 --- a/MediaBrowser.Api/DisplayPreferencesService.cs +++ b/MediaBrowser.Api/DisplayPreferencesService.cs @@ -76,37 +76,38 @@ namespace MediaBrowser.Api /// The request. public object Get(GetDisplayPreferences request) { - var result = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); - - if (result == null) - { - return null; - } + var displayPreferences = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); + var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(displayPreferences.UserId, Guid.Empty, displayPreferences.Client); var dto = new DisplayPreferencesDto { - Client = result.Client, - Id = result.UserId.ToString(), - ViewType = result.ViewType?.ToString(), - SortBy = result.SortBy, - SortOrder = result.SortOrder, - IndexBy = result.IndexBy?.ToString(), - RememberIndexing = result.RememberIndexing, - RememberSorting = result.RememberSorting, - ScrollDirection = result.ScrollDirection, - ShowBackdrop = result.ShowBackdrop, - ShowSidebar = result.ShowSidebar + Client = displayPreferences.Client, + Id = displayPreferences.UserId.ToString(), + ViewType = itemPreferences.ViewType.ToString(), + SortBy = itemPreferences.SortBy, + SortOrder = itemPreferences.SortOrder, + IndexBy = displayPreferences.IndexBy?.ToString(), + RememberIndexing = itemPreferences.RememberIndexing, + RememberSorting = itemPreferences.RememberSorting, + ScrollDirection = displayPreferences.ScrollDirection, + ShowBackdrop = displayPreferences.ShowBackdrop, + ShowSidebar = displayPreferences.ShowSidebar }; - foreach (var homeSection in result.HomeSections) + foreach (var homeSection in displayPreferences.HomeSections) { dto.CustomPrefs["homesection" + homeSection.Order] = homeSection.Type.ToString().ToLowerInvariant(); } - dto.CustomPrefs["chromecastVersion"] = result.ChromecastVersion.ToString().ToLowerInvariant(); - dto.CustomPrefs["skipForwardLength"] = result.SkipForwardLength.ToString(); - dto.CustomPrefs["skipBackLength"] = result.SkipBackwardLength.ToString(); - dto.CustomPrefs["enableNextVideoInfoOverlay"] = result.EnableNextVideoInfoOverlay.ToString(); + foreach (var itemDisplayPreferences in _displayPreferencesManager.ListItemDisplayPreferences(displayPreferences.UserId, displayPreferences.Client)) + { + dto.CustomPrefs["landing-" + itemDisplayPreferences.ItemId] = itemDisplayPreferences.ViewType.ToString().ToLowerInvariant(); + } + + dto.CustomPrefs["chromecastVersion"] = displayPreferences.ChromecastVersion.ToString().ToLowerInvariant(); + dto.CustomPrefs["skipForwardLength"] = displayPreferences.SkipForwardLength.ToString(); + dto.CustomPrefs["skipBackLength"] = displayPreferences.SkipBackwardLength.ToString(); + dto.CustomPrefs["enableNextVideoInfoOverlay"] = displayPreferences.EnableNextVideoInfoOverlay.ToString(); return ToOptimizedResult(dto); } @@ -130,14 +131,10 @@ namespace MediaBrowser.Api var prefs = _displayPreferencesManager.GetDisplayPreferences(Guid.Parse(request.UserId), request.Client); - prefs.ViewType = Enum.TryParse(request.ViewType, true, out var viewType) ? viewType : (ViewType?)null; prefs.IndexBy = Enum.TryParse(request.IndexBy, true, out var indexBy) ? indexBy : (IndexingKind?)null; prefs.ShowBackdrop = request.ShowBackdrop; prefs.ShowSidebar = request.ShowSidebar; - prefs.SortBy = request.SortBy; - prefs.SortOrder = request.SortOrder; - prefs.RememberIndexing = request.RememberIndexing; - prefs.RememberSorting = request.RememberSorting; + prefs.ScrollDirection = request.ScrollDirection; prefs.ChromecastVersion = request.CustomPrefs.TryGetValue("chromecastVersion", out var chromecastVersion) ? Enum.Parse(chromecastVersion, true) @@ -164,7 +161,26 @@ namespace MediaBrowser.Api }); } + foreach (var key in request.CustomPrefs.Keys.Where(key => key.StartsWith("landing-"))) + { + var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(prefs.UserId, Guid.Parse(key.Substring("landing-".Length)), prefs.Client); + itemPreferences.ViewType = Enum.Parse(request.ViewType); + _displayPreferencesManager.SaveChanges(itemPreferences); + } + + var itemPrefs = _displayPreferencesManager.GetItemDisplayPreferences(prefs.UserId, Guid.Empty, prefs.Client); + itemPrefs.SortBy = request.SortBy; + itemPrefs.SortOrder = request.SortOrder; + itemPrefs.RememberIndexing = request.RememberIndexing; + itemPrefs.RememberSorting = request.RememberSorting; + + if (Enum.TryParse(request.ViewType, true, out var viewType)) + { + itemPrefs.ViewType = viewType; + } + _displayPreferencesManager.SaveChanges(prefs); + _displayPreferencesManager.SaveChanges(itemPrefs); } } } diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs index e27b0ec7c3..b6bfed3e59 100644 --- a/MediaBrowser.Controller/IDisplayPreferencesManager.cs +++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Jellyfin.Data.Entities; namespace MediaBrowser.Controller @@ -16,10 +17,33 @@ namespace MediaBrowser.Controller /// The associated display preferences. DisplayPreferences GetDisplayPreferences(Guid userId, string client); + /// + /// Gets the default item display preferences for the user and client. + /// + /// The user id. + /// The item id. + /// The client string. + /// The item display preferences. + ItemDisplayPreferences GetItemDisplayPreferences(Guid userId, Guid itemId, string client); + + /// + /// Gets all of the item display preferences for the user and client. + /// + /// The user id. + /// The client string. + /// A list of item display preferences. + IList ListItemDisplayPreferences(Guid userId, string client); + /// /// Saves changes to the provided display preferences. /// /// The display preferences to save. void SaveChanges(DisplayPreferences preferences); + + /// + /// Saves changes to the provided item display preferences. + /// + /// The item display preferences to save. + void SaveChanges(ItemDisplayPreferences preferences); } } -- cgit v1.2.3 From c3a36485b68c7eeaffd3b60af14a8ef051c25f96 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Mon, 27 Jul 2020 23:41:16 -0400 Subject: Recreate display preferences migration. --- ...0200717233541_AddDisplayPreferences.Designer.cs | 416 ------------------- .../20200717233541_AddDisplayPreferences.cs | 96 ----- ...0200728005145_AddDisplayPreferences.Designer.cs | 459 +++++++++++++++++++++ .../20200728005145_AddDisplayPreferences.cs | 132 ++++++ .../Migrations/JellyfinDbModelSnapshot.cs | 87 +++- 5 files changed, 656 insertions(+), 534 deletions(-) delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs delete mode 100644 Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.cs create mode 100644 Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.Designer.cs create mode 100644 Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs deleted file mode 100644 index 392e26daef..0000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.Designer.cs +++ /dev/null @@ -1,416 +0,0 @@ -#pragma warning disable CS1591 - -// -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("20200717233541_AddDisplayPreferences")] - partial class AddDisplayPreferences - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasDefaultSchema("jellyfin") - .HasAnnotation("ProductVersion", "3.1.5"); - - modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DayOfWeek") - .HasColumnType("INTEGER"); - - b.Property("EndHour") - .HasColumnType("REAL"); - - b.Property("StartHour") - .HasColumnType("REAL"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AccessSchedules"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DateCreated") - .HasColumnType("TEXT"); - - b.Property("ItemId") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("LogSeverity") - .HasColumnType("INTEGER"); - - b.Property("Name") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Overview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("ShortOverview") - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("Type") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.ToTable("ActivityLogs"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ChromecastVersion") - .HasColumnType("INTEGER"); - - b.Property("Client") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(64); - - b.Property("EnableNextVideoInfoOverlay") - .HasColumnType("INTEGER"); - - b.Property("IndexBy") - .HasColumnType("INTEGER"); - - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - - b.Property("ScrollDirection") - .HasColumnType("INTEGER"); - - b.Property("ShowBackdrop") - .HasColumnType("INTEGER"); - - b.Property("ShowSidebar") - .HasColumnType("INTEGER"); - - b.Property("SkipBackwardLength") - .HasColumnType("INTEGER"); - - b.Property("SkipForwardLength") - .HasColumnType("INTEGER"); - - b.Property("SortBy") - .HasColumnType("TEXT") - .HasMaxLength(64); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("ViewType") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("DisplayPreferences"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("DisplayPreferencesId") - .HasColumnType("INTEGER"); - - b.Property("Order") - .HasColumnType("INTEGER"); - - b.Property("Type") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("DisplayPreferencesId"); - - b.ToTable("HomeSection"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("LastModified") - .HasColumnType("TEXT"); - - b.Property("Path") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(512); - - b.Property("UserId") - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ImageInfos"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Permission_Permissions_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("Value") - .HasColumnType("INTEGER"); - - b.HasKey("Id"); - - b.HasIndex("Permission_Permissions_Guid"); - - b.ToTable("Permissions"); - }); - - modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("Kind") - .HasColumnType("INTEGER"); - - b.Property("Preference_Preferences_Guid") - .HasColumnType("TEXT"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("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("Id") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT"); - - b.Property("AudioLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("AuthenticationProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("DisplayCollectionsView") - .HasColumnType("INTEGER"); - - b.Property("DisplayMissingEpisodes") - .HasColumnType("INTEGER"); - - b.Property("EasyPassword") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("EnableAutoLogin") - .HasColumnType("INTEGER"); - - b.Property("EnableLocalPassword") - .HasColumnType("INTEGER"); - - b.Property("EnableNextEpisodeAutoPlay") - .HasColumnType("INTEGER"); - - b.Property("EnableUserPreferenceAccess") - .HasColumnType("INTEGER"); - - b.Property("HidePlayedInLatest") - .HasColumnType("INTEGER"); - - b.Property("InternalId") - .HasColumnType("INTEGER"); - - b.Property("InvalidLoginAttemptCount") - .HasColumnType("INTEGER"); - - b.Property("LastActivityDate") - .HasColumnType("TEXT"); - - b.Property("LastLoginDate") - .HasColumnType("TEXT"); - - b.Property("LoginAttemptsBeforeLockout") - .HasColumnType("INTEGER"); - - b.Property("MaxParentalAgeRating") - .HasColumnType("INTEGER"); - - b.Property("MustUpdatePassword") - .HasColumnType("INTEGER"); - - b.Property("Password") - .HasColumnType("TEXT") - .HasMaxLength(65535); - - b.Property("PasswordResetProviderId") - .IsRequired() - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("PlayDefaultAudioTrack") - .HasColumnType("INTEGER"); - - b.Property("RememberAudioSelections") - .HasColumnType("INTEGER"); - - b.Property("RememberSubtitleSelections") - .HasColumnType("INTEGER"); - - b.Property("RemoteClientBitrateLimit") - .HasColumnType("INTEGER"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .HasColumnType("INTEGER"); - - b.Property("SubtitleLanguagePreference") - .HasColumnType("TEXT") - .HasMaxLength(255); - - b.Property("SubtitleMode") - .HasColumnType("INTEGER"); - - b.Property("SyncPlayAccess") - .HasColumnType("INTEGER"); - - b.Property("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) - .WithMany("DisplayPreferences") - .HasForeignKey("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.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/20200717233541_AddDisplayPreferences.cs b/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.cs deleted file mode 100644 index a5c344fac0..0000000000 --- a/Jellyfin.Server.Implementations/Migrations/20200717233541_AddDisplayPreferences.cs +++ /dev/null @@ -1,96 +0,0 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1601 - -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Jellyfin.Server.Implementations.Migrations -{ - public partial class AddDisplayPreferences : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "DisplayPreferences", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - UserId = table.Column(nullable: false), - ItemId = table.Column(nullable: true), - Client = table.Column(maxLength: 64, nullable: false), - RememberIndexing = table.Column(nullable: false), - RememberSorting = table.Column(nullable: false), - SortOrder = table.Column(nullable: false), - ShowSidebar = table.Column(nullable: false), - ShowBackdrop = table.Column(nullable: false), - SortBy = table.Column(maxLength: 64, nullable: true), - ViewType = table.Column(nullable: true), - ScrollDirection = table.Column(nullable: false), - IndexBy = table.Column(nullable: true), - SkipForwardLength = table.Column(nullable: false), - SkipBackwardLength = table.Column(nullable: false), - ChromecastVersion = table.Column(nullable: false), - EnableNextVideoInfoOverlay = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_DisplayPreferences", x => x.Id); - table.ForeignKey( - name: "FK_DisplayPreferences_Users_UserId", - column: x => x.UserId, - principalSchema: "jellyfin", - principalTable: "Users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "HomeSection", - schema: "jellyfin", - columns: table => new - { - Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - DisplayPreferencesId = table.Column(nullable: false), - Order = table.Column(nullable: false), - Type = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_HomeSection", x => x.Id); - table.ForeignKey( - name: "FK_HomeSection_DisplayPreferences_DisplayPreferencesId", - column: x => x.DisplayPreferencesId, - principalSchema: "jellyfin", - principalTable: "DisplayPreferences", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_DisplayPreferences_UserId", - schema: "jellyfin", - table: "DisplayPreferences", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_HomeSection_DisplayPreferencesId", - schema: "jellyfin", - table: "HomeSection", - column: "DisplayPreferencesId"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "HomeSection", - schema: "jellyfin"); - - migrationBuilder.DropTable( - name: "DisplayPreferences", - schema: "jellyfin"); - } - } -} diff --git a/Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.Designer.cs b/Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.Designer.cs new file mode 100644 index 0000000000..d44707d069 --- /dev/null +++ b/Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.Designer.cs @@ -0,0 +1,459 @@ +#pragma warning disable CS1591 + +// +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("20200728005145_AddDisplayPreferences")] + partial class AddDisplayPreferences + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("jellyfin") + .HasAnnotation("ProductVersion", "3.1.6"); + + modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DayOfWeek") + .HasColumnType("INTEGER"); + + b.Property("EndHour") + .HasColumnType("REAL"); + + b.Property("StartHour") + .HasColumnType("REAL"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccessSchedules"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ActivityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateCreated") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("LogSeverity") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Overview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("ShortOverview") + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(256); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("ActivityLogs"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChromecastVersion") + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("DashboardTheme") + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("EnableNextVideoInfoOverlay") + .HasColumnType("INTEGER"); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ScrollDirection") + .HasColumnType("INTEGER"); + + b.Property("ShowBackdrop") + .HasColumnType("INTEGER"); + + b.Property("ShowSidebar") + .HasColumnType("INTEGER"); + + b.Property("SkipBackwardLength") + .HasColumnType("INTEGER"); + + b.Property("SkipForwardLength") + .HasColumnType("INTEGER"); + + b.Property("TvHome") + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("DisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.HomeSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DisplayPreferencesId") + .HasColumnType("INTEGER"); + + b.Property("Order") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("DisplayPreferencesId"); + + b.ToTable("HomeSection"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ImageInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("LastModified") + .HasColumnType("TEXT"); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(512); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ImageInfos"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Permission_Permissions_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("Value") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Permission_Permissions_Guid"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("Jellyfin.Data.Entities.Preference", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Kind") + .HasColumnType("INTEGER"); + + b.Property("Preference_Preferences_Guid") + .HasColumnType("TEXT"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("AudioLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("AuthenticationProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("DisplayCollectionsView") + .HasColumnType("INTEGER"); + + b.Property("DisplayMissingEpisodes") + .HasColumnType("INTEGER"); + + b.Property("EasyPassword") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("EnableAutoLogin") + .HasColumnType("INTEGER"); + + b.Property("EnableLocalPassword") + .HasColumnType("INTEGER"); + + b.Property("EnableNextEpisodeAutoPlay") + .HasColumnType("INTEGER"); + + b.Property("EnableUserPreferenceAccess") + .HasColumnType("INTEGER"); + + b.Property("HidePlayedInLatest") + .HasColumnType("INTEGER"); + + b.Property("InternalId") + .HasColumnType("INTEGER"); + + b.Property("InvalidLoginAttemptCount") + .HasColumnType("INTEGER"); + + b.Property("LastActivityDate") + .HasColumnType("TEXT"); + + b.Property("LastLoginDate") + .HasColumnType("TEXT"); + + b.Property("LoginAttemptsBeforeLockout") + .HasColumnType("INTEGER"); + + b.Property("MaxParentalAgeRating") + .HasColumnType("INTEGER"); + + b.Property("MustUpdatePassword") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasColumnType("TEXT") + .HasMaxLength(65535); + + b.Property("PasswordResetProviderId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("PlayDefaultAudioTrack") + .HasColumnType("INTEGER"); + + b.Property("RememberAudioSelections") + .HasColumnType("INTEGER"); + + b.Property("RememberSubtitleSelections") + .HasColumnType("INTEGER"); + + b.Property("RemoteClientBitrateLimit") + .HasColumnType("INTEGER"); + + b.Property("RowVersion") + .IsConcurrencyToken() + .HasColumnType("INTEGER"); + + b.Property("SubtitleLanguagePreference") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("SubtitleMode") + .HasColumnType("INTEGER"); + + b.Property("SyncPlayAccess") + .HasColumnType("INTEGER"); + + b.Property("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/20200728005145_AddDisplayPreferences.cs b/Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.cs new file mode 100644 index 0000000000..3009f0b61d --- /dev/null +++ b/Jellyfin.Server.Implementations/Migrations/20200728005145_AddDisplayPreferences.cs @@ -0,0 +1,132 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1601 + +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Jellyfin.Server.Implementations.Migrations +{ + public partial class AddDisplayPreferences : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DisplayPreferences", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(nullable: false), + Client = table.Column(maxLength: 32, nullable: false), + ShowSidebar = table.Column(nullable: false), + ShowBackdrop = table.Column(nullable: false), + ScrollDirection = table.Column(nullable: false), + IndexBy = table.Column(nullable: true), + SkipForwardLength = table.Column(nullable: false), + SkipBackwardLength = table.Column(nullable: false), + ChromecastVersion = table.Column(nullable: false), + EnableNextVideoInfoOverlay = table.Column(nullable: false), + DashboardTheme = table.Column(maxLength: 32, nullable: true), + TvHome = table.Column(maxLength: 32, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DisplayPreferences", x => x.Id); + table.ForeignKey( + name: "FK_DisplayPreferences_Users_UserId", + column: x => x.UserId, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "ItemDisplayPreferences", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(nullable: false), + ItemId = table.Column(nullable: false), + Client = table.Column(maxLength: 32, nullable: false), + ViewType = table.Column(nullable: false), + RememberIndexing = table.Column(nullable: false), + IndexBy = table.Column(nullable: true), + RememberSorting = table.Column(nullable: false), + SortBy = table.Column(maxLength: 64, nullable: false), + SortOrder = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ItemDisplayPreferences", x => x.Id); + table.ForeignKey( + name: "FK_ItemDisplayPreferences_Users_UserId", + column: x => x.UserId, + principalSchema: "jellyfin", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "HomeSection", + schema: "jellyfin", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DisplayPreferencesId = table.Column(nullable: false), + Order = table.Column(nullable: false), + Type = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_HomeSection", x => x.Id); + table.ForeignKey( + name: "FK_HomeSection_DisplayPreferences_DisplayPreferencesId", + column: x => x.DisplayPreferencesId, + principalSchema: "jellyfin", + principalTable: "DisplayPreferences", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_DisplayPreferences_UserId", + schema: "jellyfin", + table: "DisplayPreferences", + column: "UserId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_HomeSection_DisplayPreferencesId", + schema: "jellyfin", + table: "HomeSection", + column: "DisplayPreferencesId"); + + migrationBuilder.CreateIndex( + name: "IX_ItemDisplayPreferences_UserId", + schema: "jellyfin", + table: "ItemDisplayPreferences", + column: "UserId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "HomeSection", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "ItemDisplayPreferences", + schema: "jellyfin"); + + migrationBuilder.DropTable( + name: "DisplayPreferences", + schema: "jellyfin"); + } + } +} diff --git a/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs b/Jellyfin.Server.Implementations/Migrations/JellyfinDbModelSnapshot.cs index 76de592ac7..a6e6a23249 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.5"); + .HasAnnotation("ProductVersion", "3.1.6"); modelBuilder.Entity("Jellyfin.Data.Entities.AccessSchedule", b => { @@ -100,7 +100,11 @@ namespace Jellyfin.Server.Implementations.Migrations b.Property("Client") .IsRequired() .HasColumnType("TEXT") - .HasMaxLength(64); + .HasMaxLength(32); + + b.Property("DashboardTheme") + .HasColumnType("TEXT") + .HasMaxLength(32); b.Property("EnableNextVideoInfoOverlay") .HasColumnType("INTEGER"); @@ -108,15 +112,6 @@ namespace Jellyfin.Server.Implementations.Migrations b.Property("IndexBy") .HasColumnType("INTEGER"); - b.Property("ItemId") - .HasColumnType("TEXT"); - - b.Property("RememberIndexing") - .HasColumnType("INTEGER"); - - b.Property("RememberSorting") - .HasColumnType("INTEGER"); - b.Property("ScrollDirection") .HasColumnType("INTEGER"); @@ -132,22 +127,17 @@ namespace Jellyfin.Server.Implementations.Migrations b.Property("SkipForwardLength") .HasColumnType("INTEGER"); - b.Property("SortBy") + b.Property("TvHome") .HasColumnType("TEXT") - .HasMaxLength(64); - - b.Property("SortOrder") - .HasColumnType("INTEGER"); + .HasMaxLength(32); b.Property("UserId") .HasColumnType("TEXT"); - b.Property("ViewType") - .HasColumnType("INTEGER"); - b.HasKey("Id"); - b.HasIndex("UserId"); + b.HasIndex("UserId") + .IsUnique(); b.ToTable("DisplayPreferences"); }); @@ -199,6 +189,50 @@ namespace Jellyfin.Server.Implementations.Migrations b.ToTable("ImageInfos"); }); + modelBuilder.Entity("Jellyfin.Data.Entities.ItemDisplayPreferences", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Client") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(32); + + b.Property("IndexBy") + .HasColumnType("INTEGER"); + + b.Property("ItemId") + .HasColumnType("TEXT"); + + b.Property("RememberIndexing") + .HasColumnType("INTEGER"); + + b.Property("RememberSorting") + .HasColumnType("INTEGER"); + + b.Property("SortBy") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(64); + + b.Property("SortOrder") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("ViewType") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemDisplayPreferences"); + }); + modelBuilder.Entity("Jellyfin.Data.Entities.Permission", b => { b.Property("Id") @@ -371,8 +405,8 @@ namespace Jellyfin.Server.Implementations.Migrations modelBuilder.Entity("Jellyfin.Data.Entities.DisplayPreferences", b => { b.HasOne("Jellyfin.Data.Entities.User", null) - .WithMany("DisplayPreferences") - .HasForeignKey("UserId") + .WithOne("DisplayPreferences") + .HasForeignKey("Jellyfin.Data.Entities.DisplayPreferences", "UserId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); @@ -393,6 +427,15 @@ namespace Jellyfin.Server.Implementations.Migrations .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) -- cgit v1.2.3 From 3ed9463d25776c3a371872183742703d470f871d Mon Sep 17 00:00:00 2001 From: K900 Date: Tue, 28 Jul 2020 12:03:08 +0300 Subject: Fix #3624 It doesn't really make sense to throw an error when creating the default user, because the error is completely non-actionable. Instead, if the autodetected username is not valid, just fall back to a sane default. --- Jellyfin.Server.Implementations/Users/UserManager.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index eaa6a0a814..11402ee055 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -600,18 +600,13 @@ namespace Jellyfin.Server.Implementations.Users } var defaultName = Environment.UserName; - if (string.IsNullOrWhiteSpace(defaultName)) + if (string.IsNullOrWhiteSpace(defaultName) || !IsValidUsername(defaultName)) { defaultName = "MyJellyfinUser"; } _logger.LogWarning("No users, creating one with username {UserName}", defaultName); - if (!IsValidUsername(defaultName)) - { - throw new ArgumentException("Provided username is not valid!", defaultName); - } - var newUser = await CreateUserInternalAsync(defaultName, dbContext).ConfigureAwait(false); newUser.SetPermission(PermissionKind.IsAdministrator, true); newUser.SetPermission(PermissionKind.EnableContentDeletion, true); -- cgit v1.2.3 From 5f03fb0ef7d25ea36f75feea7577d47a164950c5 Mon Sep 17 00:00:00 2001 From: cvium Date: Fri, 31 Jul 2020 10:13:54 +0200 Subject: Use factory pattern to instantiate jellyfindb context to avoid disposed contexts piling up in DI container --- Jellyfin.Server.Implementations/JellyfinDbProvider.cs | 14 +++++++++++--- Jellyfin.Server/CoreAppHost.cs | 11 ++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/JellyfinDbProvider.cs b/Jellyfin.Server.Implementations/JellyfinDbProvider.cs index 8f5c199001..486be60537 100644 --- a/Jellyfin.Server.Implementations/JellyfinDbProvider.cs +++ b/Jellyfin.Server.Implementations/JellyfinDbProvider.cs @@ -1,4 +1,6 @@ using System; +using System.IO; +using MediaBrowser.Common.Configuration; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; @@ -10,15 +12,20 @@ namespace Jellyfin.Server.Implementations public class JellyfinDbProvider { private readonly IServiceProvider _serviceProvider; + private readonly IApplicationPaths _appPaths; /// /// Initializes a new instance of the class. /// /// The application's service provider. - public JellyfinDbProvider(IServiceProvider serviceProvider) + /// The application paths. + public JellyfinDbProvider(IServiceProvider serviceProvider, IApplicationPaths appPaths) { _serviceProvider = serviceProvider; - serviceProvider.GetRequiredService().Database.Migrate(); + _appPaths = appPaths; + + using var jellyfinDb = CreateContext(); + jellyfinDb.Database.Migrate(); } /// @@ -27,7 +34,8 @@ namespace Jellyfin.Server.Implementations /// The newly created context. public JellyfinDb CreateContext() { - return _serviceProvider.GetRequiredService(); + var contextOptions = new DbContextOptionsBuilder().UseSqlite($"Filename={Path.Combine(_appPaths.DataPath, "jellyfin.db")}"); + return ActivatorUtilities.CreateInstance(_serviceProvider, contextOptions.Options); } } } diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 71b0fd8f35..7db3db36bd 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -64,11 +64,12 @@ namespace Jellyfin.Server Logger.LogWarning($"Skia not available. Will fallback to {nameof(NullImageEncoder)}."); } - // TODO: Set up scoping and use AddDbContextPool - serviceCollection.AddDbContext( - options => options - .UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}"), - ServiceLifetime.Transient); + // TODO: Set up scoping and use AddDbContextPool, + // can't register as Transient since tracking transient in GC is funky + // serviceCollection.AddDbContext( + // options => options + // .UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}"), + // ServiceLifetime.Transient); serviceCollection.AddSingleton(); -- cgit v1.2.3 From 6f306f0a17571eba7466a5f8bd591498d252e1be Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 1 Aug 2020 16:20:08 -0400 Subject: Minor fixes to ActivityManager --- Jellyfin.Server.Implementations/Activity/ActivityManager.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs index 65ceee32bf..2deefbe819 100644 --- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs +++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs @@ -40,8 +40,9 @@ namespace Jellyfin.Server.Implementations.Activity /// public async Task CreateAsync(ActivityLog entry) { - using var dbContext = _provider.CreateContext(); - await dbContext.ActivityLogs.AddAsync(entry); + await using var dbContext = _provider.CreateContext(); + + dbContext.ActivityLogs.Add(entry); await dbContext.SaveChangesAsync().ConfigureAwait(false); EntryCreated?.Invoke(this, new GenericEventArgs(ConvertToOldModel(entry))); -- cgit v1.2.3 From 229a5d9e0bf99f9c6f741f654f1dbe0a7f975872 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 8 Aug 2020 13:39:49 -0400 Subject: Make DisplayPreferencesManager scoped --- .../Controllers/DisplayPreferencesController.cs | 4 +-- .../Users/DisplayPreferencesManager.cs | 36 +++++++--------------- Jellyfin.Server/CoreAppHost.cs | 2 +- .../IDisplayPreferencesManager.cs | 11 ++----- 4 files changed, 15 insertions(+), 38 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs index c547d0cde3..c3b67eec3f 100644 --- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs +++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs @@ -153,7 +153,6 @@ namespace Jellyfin.Api.Controllers { var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(existingDisplayPreferences.UserId, Guid.Parse(key.Substring("landing-".Length)), existingDisplayPreferences.Client); itemPreferences.ViewType = Enum.Parse(displayPreferences.ViewType); - _displayPreferencesManager.SaveChanges(itemPreferences); } var itemPrefs = _displayPreferencesManager.GetItemDisplayPreferences(existingDisplayPreferences.UserId, Guid.Empty, existingDisplayPreferences.Client); @@ -167,8 +166,7 @@ namespace Jellyfin.Api.Controllers itemPrefs.ViewType = viewType; } - _displayPreferencesManager.SaveChanges(existingDisplayPreferences); - _displayPreferencesManager.SaveChanges(itemPrefs); + _displayPreferencesManager.SaveChanges(); return NoContent(); } diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs index 7c5c5a3ec5..46f1c618f2 100644 --- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs +++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs @@ -14,22 +14,21 @@ namespace Jellyfin.Server.Implementations.Users /// public class DisplayPreferencesManager : IDisplayPreferencesManager { - private readonly JellyfinDbProvider _dbProvider; + private readonly JellyfinDb _dbContext; /// /// Initializes a new instance of the class. /// - /// The Jellyfin db provider. - public DisplayPreferencesManager(JellyfinDbProvider dbProvider) + /// The database context. + public DisplayPreferencesManager(JellyfinDb dbContext) { - _dbProvider = dbProvider; + _dbContext = dbContext; } /// public DisplayPreferences GetDisplayPreferences(Guid userId, string client) { - using var dbContext = _dbProvider.CreateContext(); - var prefs = dbContext.DisplayPreferences + var prefs = _dbContext.DisplayPreferences .Include(pref => pref.HomeSections) .FirstOrDefault(pref => pref.UserId == userId && string.Equals(pref.Client, client)); @@ -37,7 +36,7 @@ namespace Jellyfin.Server.Implementations.Users if (prefs == null) { prefs = new DisplayPreferences(userId, client); - dbContext.DisplayPreferences.Add(prefs); + _dbContext.DisplayPreferences.Add(prefs); } return prefs; @@ -46,14 +45,13 @@ namespace Jellyfin.Server.Implementations.Users /// public ItemDisplayPreferences GetItemDisplayPreferences(Guid userId, Guid itemId, string client) { - using var dbContext = _dbProvider.CreateContext(); - var prefs = dbContext.ItemDisplayPreferences + var prefs = _dbContext.ItemDisplayPreferences .FirstOrDefault(pref => pref.UserId == userId && pref.ItemId == itemId && string.Equals(pref.Client, client)); if (prefs == null) { prefs = new ItemDisplayPreferences(userId, Guid.Empty, client); - dbContext.ItemDisplayPreferences.Add(prefs); + _dbContext.ItemDisplayPreferences.Add(prefs); } return prefs; @@ -62,27 +60,15 @@ namespace Jellyfin.Server.Implementations.Users /// public IList ListItemDisplayPreferences(Guid userId, string client) { - using var dbContext = _dbProvider.CreateContext(); - - return dbContext.ItemDisplayPreferences + return _dbContext.ItemDisplayPreferences .Where(prefs => prefs.UserId == userId && prefs.ItemId != Guid.Empty && string.Equals(prefs.Client, client)) .ToList(); } /// - public void SaveChanges(DisplayPreferences preferences) - { - using var dbContext = _dbProvider.CreateContext(); - dbContext.Update(preferences); - dbContext.SaveChanges(); - } - - /// - public void SaveChanges(ItemDisplayPreferences preferences) + public void SaveChanges() { - using var dbContext = _dbProvider.CreateContext(); - dbContext.Update(preferences); - dbContext.SaveChanges(); + _dbContext.SaveChanges(); } } } diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 7b20bfb5af..6f2434422c 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -71,7 +71,7 @@ namespace Jellyfin.Server serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddScoped(); base.RegisterServices(serviceCollection); } diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs index b6bfed3e59..4288a2a549 100644 --- a/MediaBrowser.Controller/IDisplayPreferencesManager.cs +++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs @@ -35,15 +35,8 @@ namespace MediaBrowser.Controller IList ListItemDisplayPreferences(Guid userId, string client); /// - /// Saves changes to the provided display preferences. + /// Saves changes made to the database. /// - /// The display preferences to save. - void SaveChanges(DisplayPreferences preferences); - - /// - /// Saves changes to the provided item display preferences. - /// - /// The item display preferences to save. - void SaveChanges(ItemDisplayPreferences preferences); + void SaveChanges(); } } -- cgit v1.2.3 From 6709645ec910051ca6427c38836548b4ce164d87 Mon Sep 17 00:00:00 2001 From: crobibero Date: Wed, 12 Aug 2020 15:52:29 -0600 Subject: bump deps --- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 8 ++++---- Jellyfin.Api/Jellyfin.Api.csproj | 4 ++-- Jellyfin.Data/Jellyfin.Data.csproj | 4 ++-- .../Jellyfin.Server.Implementations.csproj | 4 ++-- Jellyfin.Server/Jellyfin.Server.csproj | 4 ++-- MediaBrowser.Common/MediaBrowser.Common.csproj | 4 ++-- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 4 ++-- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 +- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 4 ++-- tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj | 8 ++++---- tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj | 2 +- tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj | 2 +- .../Jellyfin.MediaEncoding.Tests.csproj | 2 +- tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj | 2 +- .../Jellyfin.Server.Implementations.Tests.csproj | 4 ++-- tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj | 4 ++-- 16 files changed, 31 insertions(+), 31 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 1adef68aa7..3245c0c8b0 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -32,10 +32,10 @@ - - - - + + + + diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 24bc07b666..ca0542b036 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -14,9 +14,9 @@ - + - + diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 8ce0f3848c..367d147697 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -19,8 +19,8 @@ - - + + diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index 21748ca192..30ed3e6af3 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -24,11 +24,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 7541707d9f..5e85ff4f15 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -41,8 +41,8 @@ - - + + diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 7380f39fda..e0e271e3e3 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 67f17f7a52..da474fcab8 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 902e29b20b..4de9329821 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -23,7 +23,7 @@ - + diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 7c0b542509..e2a9172d8f 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -16,8 +16,8 @@ - - + + diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index f77eba376b..4118594ca3 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -14,12 +14,12 @@ - - - + + + - + diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index 7464740445..cc802ccdeb 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj index 1559f70ab3..25459287c8 100644 --- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj +++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj index e1a0895476..c43323abc2 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj @@ -21,7 +21,7 @@ - + diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj index 0e9e915632..d305a10a87 100644 --- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj +++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index 03187f4b9c..2f47d5ffe2 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -15,10 +15,10 @@ - + - + diff --git a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj index a4ef10648b..0fea965d2b 100644 --- a/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj +++ b/tests/MediaBrowser.Api.Tests/MediaBrowser.Api.Tests.csproj @@ -8,10 +8,10 @@ - + - + -- cgit v1.2.3 From 3e5fe04427d60261bb87df2e124ce7b2e066b88e Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 13 Aug 2020 20:31:26 -0400 Subject: Migrate ActivityLogEntryPoint.OnPlaybackStart to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 53 ----------- .../Consumers/Session/PlaybackStartLogger.cs | 105 +++++++++++++++++++++ .../Library/PlaybackStartEventArgs.cs | 6 ++ 3 files changed, 111 insertions(+), 53 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs create mode 100644 MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 84bec92014..53b3a6293b 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Text; using System.Threading.Tasks; using Jellyfin.Data.Entities; @@ -83,7 +82,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationFailed += OnAuthenticationFailed; _sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded; _sessionManager.SessionEnded += OnSessionEnded; - _sessionManager.PlaybackStart += OnPlaybackStart; _sessionManager.PlaybackStopped += OnPlaybackStopped; _subManager.SubtitleDownloadFailure += OnSubtitleDownloadFailure; @@ -161,41 +159,6 @@ namespace Emby.Server.Implementations.Activity .ConfigureAwait(false); } - private async void OnPlaybackStart(object sender, PlaybackProgressEventArgs e) - { - var item = e.MediaInfo; - - if (item == null) - { - _logger.LogWarning("PlaybackStart reported with null media info."); - return; - } - - if (e.Item != null && e.Item.IsThemeMedia) - { - // Don't report theme song or local trailer playback - return; - } - - if (e.Users.Count == 0) - { - return; - } - - var user = e.Users.First(); - - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserStartedPlayingItemWithValues"), - user.Username, - GetItemName(item), - e.DeviceName), - GetPlaybackNotificationType(item.MediaType), - user.Id)) - .ConfigureAwait(false); - } - private static string GetItemName(BaseItemDto item) { var name = item.Name; @@ -213,21 +176,6 @@ namespace Emby.Server.Implementations.Activity return name; } - private static string GetPlaybackNotificationType(string mediaType) - { - if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase)) - { - return NotificationType.AudioPlayback.ToString(); - } - - if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase)) - { - return NotificationType.VideoPlayback.ToString(); - } - - return null; - } - private static string GetPlaybackStoppedNotificationType(string mediaType) { if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase)) @@ -494,7 +442,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationSucceeded -= OnAuthenticationSucceeded; _sessionManager.SessionEnded -= OnSessionEnded; - _sessionManager.PlaybackStart -= OnPlaybackStart; _sessionManager.PlaybackStopped -= OnPlaybackStopped; _subManager.SubtitleDownloadFailure -= OnSubtitleDownloadFailure; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs new file mode 100644 index 0000000000..c48683ea38 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs @@ -0,0 +1,105 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Session +{ + /// + /// Creates an entry in the activity log whenever a user starts playback. + /// + public class PlaybackStartLogger : IEventConsumer + { + private readonly ILogger _logger; + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + /// The localization manager. + /// The activity manager. + public PlaybackStartLogger(ILogger logger, ILocalizationManager localizationManager, IActivityManager activityManager) + { + _logger = logger; + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(PlaybackStartEventArgs eventArgs) + { + if (eventArgs.MediaInfo == null) + { + _logger.LogWarning("PlaybackStart reported with null media info."); + return; + } + + if (eventArgs.Item != null && eventArgs.Item.IsThemeMedia) + { + // Don't report theme song or local trailer playback + return; + } + + if (eventArgs.Users.Count == 0) + { + return; + } + + var user = eventArgs.Users.First(); + + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserStartedPlayingItemWithValues"), + user.Username, + GetItemName(eventArgs.MediaInfo), + eventArgs.DeviceName), + GetPlaybackNotificationType(eventArgs.MediaInfo.MediaType), + user.Id)) + .ConfigureAwait(false); + } + + private static string GetItemName(BaseItemDto item) + { + var name = item.Name; + + if (!string.IsNullOrEmpty(item.SeriesName)) + { + name = item.SeriesName + " - " + name; + } + + if (item.Artists != null && item.Artists.Count > 0) + { + name = item.Artists[0] + " - " + name; + } + + return name; + } + + private static string GetPlaybackNotificationType(string mediaType) + { + if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase)) + { + return NotificationType.AudioPlayback.ToString(); + } + + if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase)) + { + return NotificationType.VideoPlayback.ToString(); + } + + return null; + } + } +} diff --git a/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs new file mode 100644 index 0000000000..3aa9c28954 --- /dev/null +++ b/MediaBrowser.Controller/Library/PlaybackStartEventArgs.cs @@ -0,0 +1,6 @@ +namespace MediaBrowser.Controller.Library +{ + public class PlaybackStartEventArgs : PlaybackProgressEventArgs + { + } +} -- cgit v1.2.3 From 5c29b8982d3277ad7456e96331ac6fddbe7e390c Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 13 Aug 2020 20:33:16 -0400 Subject: Migrate ActivityLogEntryPoint.OnPlaybackStopped to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 76 --------------- .../Events/Consumers/Session/PlaybackStopLogger.cs | 106 +++++++++++++++++++++ 2 files changed, 106 insertions(+), 76 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 53b3a6293b..00910c8a23 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -12,8 +12,6 @@ using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Subtitles; using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Notifications; @@ -28,7 +26,6 @@ namespace Emby.Server.Implementations.Activity /// public sealed class ActivityLogEntryPoint : IServerEntryPoint { - private readonly ILogger _logger; private readonly IInstallationManager _installationManager; private readonly ISessionManager _sessionManager; private readonly ITaskManager _taskManager; @@ -40,7 +37,6 @@ namespace Emby.Server.Implementations.Activity /// /// Initializes a new instance of the class. /// - /// The logger. /// The session manager. /// The task manager. /// The activity manager. @@ -49,7 +45,6 @@ namespace Emby.Server.Implementations.Activity /// The subtitle manager. /// The user manager. public ActivityLogEntryPoint( - ILogger logger, ISessionManager sessionManager, ITaskManager taskManager, IActivityManager activityManager, @@ -58,7 +53,6 @@ namespace Emby.Server.Implementations.Activity ISubtitleManager subManager, IUserManager userManager) { - _logger = logger; _sessionManager = sessionManager; _taskManager = taskManager; _activityManager = activityManager; @@ -82,7 +76,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationFailed += OnAuthenticationFailed; _sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded; _sessionManager.SessionEnded += OnSessionEnded; - _sessionManager.PlaybackStopped += OnPlaybackStopped; _subManager.SubtitleDownloadFailure += OnSubtitleDownloadFailure; @@ -124,73 +117,6 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnPlaybackStopped(object sender, PlaybackStopEventArgs e) - { - var item = e.MediaInfo; - - if (item == null) - { - _logger.LogWarning("PlaybackStopped reported with null media info."); - return; - } - - if (e.Item != null && e.Item.IsThemeMedia) - { - // Don't report theme song or local trailer playback - return; - } - - if (e.Users.Count == 0) - { - return; - } - - var user = e.Users[0]; - - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserStoppedPlayingItemWithValues"), - user.Username, - GetItemName(item), - e.DeviceName), - GetPlaybackStoppedNotificationType(item.MediaType), - user.Id)) - .ConfigureAwait(false); - } - - private static string GetItemName(BaseItemDto item) - { - var name = item.Name; - - if (!string.IsNullOrEmpty(item.SeriesName)) - { - name = item.SeriesName + " - " + name; - } - - if (item.Artists != null && item.Artists.Count > 0) - { - name = item.Artists[0] + " - " + name; - } - - return name; - } - - private static string GetPlaybackStoppedNotificationType(string mediaType) - { - if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase)) - { - return NotificationType.AudioPlaybackStopped.ToString(); - } - - if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase)) - { - return NotificationType.VideoPlaybackStopped.ToString(); - } - - return null; - } - private async void OnSessionEnded(object sender, SessionEventArgs e) { var session = e.SessionInfo; @@ -442,8 +368,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationSucceeded -= OnAuthenticationSucceeded; _sessionManager.SessionEnded -= OnSessionEnded; - _sessionManager.PlaybackStopped -= OnPlaybackStopped; - _subManager.SubtitleDownloadFailure -= OnSubtitleDownloadFailure; _userManager.OnUserCreated -= OnUserCreated; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs new file mode 100644 index 0000000000..51a882c143 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStopLogger.cs @@ -0,0 +1,106 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Session +{ + /// + /// Creates an activity log entry whenever a user stops playback. + /// + public class PlaybackStopLogger : IEventConsumer + { + private readonly ILogger _logger; + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + /// The localization manager. + /// The activity manager. + public PlaybackStopLogger(ILogger logger, ILocalizationManager localizationManager, IActivityManager activityManager) + { + _logger = logger; + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(PlaybackStopEventArgs eventArgs) + { + var item = eventArgs.MediaInfo; + + if (item == null) + { + _logger.LogWarning("PlaybackStopped reported with null media info."); + return; + } + + if (eventArgs.Item != null && eventArgs.Item.IsThemeMedia) + { + // Don't report theme song or local trailer playback + return; + } + + if (eventArgs.Users.Count == 0) + { + return; + } + + var user = eventArgs.Users[0]; + + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserStoppedPlayingItemWithValues"), + user.Username, + GetItemName(item), + eventArgs.DeviceName), + GetPlaybackStoppedNotificationType(item.MediaType), + user.Id)) + .ConfigureAwait(false); + } + + private static string GetItemName(BaseItemDto item) + { + var name = item.Name; + + if (!string.IsNullOrEmpty(item.SeriesName)) + { + name = item.SeriesName + " - " + name; + } + + if (item.Artists != null && item.Artists.Count > 0) + { + name = item.Artists[0] + " - " + name; + } + + return name; + } + + private static string GetPlaybackStoppedNotificationType(string mediaType) + { + if (string.Equals(mediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase)) + { + return NotificationType.AudioPlaybackStopped.ToString(); + } + + if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase)) + { + return NotificationType.VideoPlaybackStopped.ToString(); + } + + return null; + } + } +} -- cgit v1.2.3 From fdd73f1186ab8f938e1139e814aa2afbd4702a78 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 13 Aug 2020 20:34:28 -0400 Subject: Migrate ActivityLogEntryPoint.OnTaskCompleted to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 136 ------------------ .../Events/Consumers/TaskCompletedLogger.cs | 152 +++++++++++++++++++++ 2 files changed, 152 insertions(+), 136 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 00910c8a23..79d7e17115 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Globalization; -using System.Text; using System.Threading.Tasks; using Jellyfin.Data.Entities; using MediaBrowser.Common.Plugins; @@ -15,7 +13,6 @@ using MediaBrowser.Model.Activity; using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Notifications; -using MediaBrowser.Model.Tasks; using MediaBrowser.Model.Updates; using Microsoft.Extensions.Logging; @@ -28,7 +25,6 @@ namespace Emby.Server.Implementations.Activity { private readonly IInstallationManager _installationManager; private readonly ISessionManager _sessionManager; - private readonly ITaskManager _taskManager; private readonly IActivityManager _activityManager; private readonly ILocalizationManager _localization; private readonly ISubtitleManager _subManager; @@ -38,7 +34,6 @@ namespace Emby.Server.Implementations.Activity /// Initializes a new instance of the class. /// /// The session manager. - /// The task manager. /// The activity manager. /// The localization manager. /// The installation manager. @@ -46,7 +41,6 @@ namespace Emby.Server.Implementations.Activity /// The user manager. public ActivityLogEntryPoint( ISessionManager sessionManager, - ITaskManager taskManager, IActivityManager activityManager, ILocalizationManager localization, IInstallationManager installationManager, @@ -54,7 +48,6 @@ namespace Emby.Server.Implementations.Activity IUserManager userManager) { _sessionManager = sessionManager; - _taskManager = taskManager; _activityManager = activityManager; _localization = localization; _installationManager = installationManager; @@ -65,8 +58,6 @@ namespace Emby.Server.Implementations.Activity /// public Task RunAsync() { - _taskManager.TaskCompleted += OnTaskCompleted; - _installationManager.PluginInstalled += OnPluginInstalled; _installationManager.PluginUninstalled += OnPluginUninstalled; _installationManager.PluginUpdated += OnPluginUpdated; @@ -307,57 +298,12 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnTaskCompleted(object sender, TaskCompletionEventArgs e) - { - var result = e.Result; - var task = e.Task; - - if (task.ScheduledTask is IConfigurableScheduledTask activityTask - && !activityTask.IsLogged) - { - return; - } - - var time = result.EndTimeUtc - result.StartTimeUtc; - var runningTime = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("LabelRunningTimeValue"), - ToUserFriendlyString(time)); - - if (result.Status == TaskCompletionStatus.Failed) - { - var vals = new List(); - - if (!string.IsNullOrEmpty(e.Result.ErrorMessage)) - { - vals.Add(e.Result.ErrorMessage); - } - - if (!string.IsNullOrEmpty(e.Result.LongErrorMessage)) - { - vals.Add(e.Result.LongErrorMessage); - } - - await CreateLogEntry(new ActivityLog( - string.Format(CultureInfo.InvariantCulture, _localization.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name), - NotificationType.TaskFailed.ToString(), - Guid.Empty) - { - LogSeverity = LogLevel.Error, - Overview = string.Join(Environment.NewLine, vals), - ShortOverview = runningTime - }).ConfigureAwait(false); - } - } - private async Task CreateLogEntry(ActivityLog entry) => await _activityManager.CreateAsync(entry).ConfigureAwait(false); /// public void Dispose() { - _taskManager.TaskCompleted -= OnTaskCompleted; - _installationManager.PluginInstalled -= OnPluginInstalled; _installationManager.PluginUninstalled -= OnPluginUninstalled; _installationManager.PluginUpdated -= OnPluginUpdated; @@ -375,87 +321,5 @@ namespace Emby.Server.Implementations.Activity _userManager.OnUserDeleted -= OnUserDeleted; _userManager.OnUserLockedOut -= OnUserLockedOut; } - - /// - /// Constructs a user-friendly string for this TimeSpan instance. - /// - private static string ToUserFriendlyString(TimeSpan span) - { - const int DaysInYear = 365; - const int DaysInMonth = 30; - - // Get each non-zero value from TimeSpan component - var values = new List(); - - // Number of years - int days = span.Days; - if (days >= DaysInYear) - { - int years = days / DaysInYear; - values.Add(CreateValueString(years, "year")); - days %= DaysInYear; - } - - // Number of months - if (days >= DaysInMonth) - { - int months = days / DaysInMonth; - values.Add(CreateValueString(months, "month")); - days = days % DaysInMonth; - } - - // Number of days - if (days >= 1) - { - values.Add(CreateValueString(days, "day")); - } - - // Number of hours - if (span.Hours >= 1) - { - values.Add(CreateValueString(span.Hours, "hour")); - } - - // Number of minutes - if (span.Minutes >= 1) - { - values.Add(CreateValueString(span.Minutes, "minute")); - } - - // Number of seconds (include when 0 if no other components included) - if (span.Seconds >= 1 || values.Count == 0) - { - values.Add(CreateValueString(span.Seconds, "second")); - } - - // Combine values into string - var builder = new StringBuilder(); - for (int i = 0; i < values.Count; i++) - { - if (builder.Length > 0) - { - builder.Append(i == values.Count - 1 ? " and " : ", "); - } - - builder.Append(values[i]); - } - - // Return result - return builder.ToString(); - } - - /// - /// Constructs a string description of a time-span value. - /// - /// The value of this item. - /// The name of this item (singular form). - private static string CreateValueString(int value, string description) - { - return string.Format( - CultureInfo.InvariantCulture, - "{0:#,##0} {1}", - value, - value == 1 ? description : string.Format(CultureInfo.InvariantCulture, "{0}s", description)); - } } } diff --git a/Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs new file mode 100644 index 0000000000..faca66ffd2 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; +using MediaBrowser.Model.Tasks; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Implementations.Events.Consumers +{ + /// + /// Creates an activity log entry whenever a task is completed. + /// + public class TaskCompletedLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + public TaskCompletedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + public async Task OnEvent(TaskCompletionEventArgs e) + { + var result = e.Result; + var task = e.Task; + + if (task.ScheduledTask is IConfigurableScheduledTask activityTask + && !activityTask.IsLogged) + { + return; + } + + var time = result.EndTimeUtc - result.StartTimeUtc; + var runningTime = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("LabelRunningTimeValue"), + ToUserFriendlyString(time)); + + if (result.Status == TaskCompletionStatus.Failed) + { + var vals = new List(); + + if (!string.IsNullOrEmpty(e.Result.ErrorMessage)) + { + vals.Add(e.Result.ErrorMessage); + } + + if (!string.IsNullOrEmpty(e.Result.LongErrorMessage)) + { + vals.Add(e.Result.LongErrorMessage); + } + + await _activityManager.CreateAsync(new ActivityLog( + string.Format(CultureInfo.InvariantCulture, _localizationManager.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name), + NotificationType.TaskFailed.ToString(), + Guid.Empty) + { + LogSeverity = LogLevel.Error, + Overview = string.Join(Environment.NewLine, vals), + ShortOverview = runningTime + }).ConfigureAwait(false); + } + } + + private static string ToUserFriendlyString(TimeSpan span) + { + const int DaysInYear = 365; + const int DaysInMonth = 30; + + // Get each non-zero value from TimeSpan component + var values = new List(); + + // Number of years + int days = span.Days; + if (days >= DaysInYear) + { + int years = days / DaysInYear; + values.Add(CreateValueString(years, "year")); + days %= DaysInYear; + } + + // Number of months + if (days >= DaysInMonth) + { + int months = days / DaysInMonth; + values.Add(CreateValueString(months, "month")); + days = days % DaysInMonth; + } + + // Number of days + if (days >= 1) + { + values.Add(CreateValueString(days, "day")); + } + + // Number of hours + if (span.Hours >= 1) + { + values.Add(CreateValueString(span.Hours, "hour")); + } + + // Number of minutes + if (span.Minutes >= 1) + { + values.Add(CreateValueString(span.Minutes, "minute")); + } + + // Number of seconds (include when 0 if no other components included) + if (span.Seconds >= 1 || values.Count == 0) + { + values.Add(CreateValueString(span.Seconds, "second")); + } + + // Combine values into string + var builder = new StringBuilder(); + for (int i = 0; i < values.Count; i++) + { + if (builder.Length > 0) + { + builder.Append(i == values.Count - 1 ? " and " : ", "); + } + + builder.Append(values[i]); + } + + // Return result + return builder.ToString(); + } + + /// + /// Constructs a string description of a time-span value. + /// + /// The value of this item. + /// The name of this item (singular form). + private static string CreateValueString(int value, string description) + { + return string.Format( + CultureInfo.InvariantCulture, + "{0:#,##0} {1}", + value, + value == 1 ? description : string.Format(CultureInfo.InvariantCulture, "{0}s", description)); + } + } +} -- cgit v1.2.3 From ade40a4c428ecfab53507fdb6df5ac541f10f3ad Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 13 Aug 2020 20:40:18 -0400 Subject: Migrate ActivityLogEntryPoint.OnSubtitleDownloadFailure to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 25 ----- .../Library/SubtitleDownloadFailureLogger.cs | 102 +++++++++++++++++++++ 2 files changed, 102 insertions(+), 25 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 79d7e17115..39b6361b7c 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -8,7 +8,6 @@ using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; -using MediaBrowser.Controller.Subtitles; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; @@ -27,7 +26,6 @@ namespace Emby.Server.Implementations.Activity private readonly ISessionManager _sessionManager; private readonly IActivityManager _activityManager; private readonly ILocalizationManager _localization; - private readonly ISubtitleManager _subManager; private readonly IUserManager _userManager; /// @@ -37,21 +35,18 @@ namespace Emby.Server.Implementations.Activity /// The activity manager. /// The localization manager. /// The installation manager. - /// The subtitle manager. /// The user manager. public ActivityLogEntryPoint( ISessionManager sessionManager, IActivityManager activityManager, ILocalizationManager localization, IInstallationManager installationManager, - ISubtitleManager subManager, IUserManager userManager) { _sessionManager = sessionManager; _activityManager = activityManager; _localization = localization; _installationManager = installationManager; - _subManager = subManager; _userManager = userManager; } @@ -68,8 +63,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded; _sessionManager.SessionEnded += OnSessionEnded; - _subManager.SubtitleDownloadFailure += OnSubtitleDownloadFailure; - _userManager.OnUserCreated += OnUserCreated; _userManager.OnUserPasswordChanged += OnUserPasswordChanged; _userManager.OnUserDeleted += OnUserDeleted; @@ -92,22 +85,6 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnSubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("SubtitleDownloadFailureFromForItem"), - e.Provider, - Notifications.NotificationEntryPoint.GetItemName(e.Item)), - "SubtitleDownloadFailure", - Guid.Empty) - { - ItemId = e.Item.Id.ToString("N", CultureInfo.InvariantCulture), - ShortOverview = e.Exception.Message - }).ConfigureAwait(false); - } - private async void OnSessionEnded(object sender, SessionEventArgs e) { var session = e.SessionInfo; @@ -314,8 +291,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationSucceeded -= OnAuthenticationSucceeded; _sessionManager.SessionEnded -= OnSessionEnded; - _subManager.SubtitleDownloadFailure -= OnSubtitleDownloadFailure; - _userManager.OnUserCreated -= OnUserCreated; _userManager.OnUserPasswordChanged -= OnUserPasswordChanged; _userManager.OnUserDeleted -= OnUserDeleted; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs new file mode 100644 index 0000000000..449f27be2c --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Library/SubtitleDownloadFailureLogger.cs @@ -0,0 +1,102 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Subtitles; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Library +{ + /// + /// Creates an entry in the activity log whenever a subtitle download fails. + /// + public class SubtitleDownloadFailureLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public SubtitleDownloadFailureLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(SubtitleDownloadFailureEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("SubtitleDownloadFailureFromForItem"), + eventArgs.Provider, + GetItemName(eventArgs.Item)), + "SubtitleDownloadFailure", + Guid.Empty) + { + ItemId = eventArgs.Item.Id.ToString("N", CultureInfo.InvariantCulture), + ShortOverview = eventArgs.Exception.Message + }).ConfigureAwait(false); + } + + private static string GetItemName(BaseItem item) + { + var name = item.Name; + if (item is Episode episode) + { + if (episode.IndexNumber.HasValue) + { + name = string.Format( + CultureInfo.InvariantCulture, + "Ep{0} - {1}", + episode.IndexNumber.Value, + name); + } + + if (episode.ParentIndexNumber.HasValue) + { + name = string.Format( + CultureInfo.InvariantCulture, + "S{0}, {1}", + episode.ParentIndexNumber.Value, + name); + } + } + + if (item is IHasSeries hasSeries) + { + name = hasSeries.SeriesName + " - " + name; + } + + if (item is IHasAlbumArtist hasAlbumArtist) + { + var artists = hasAlbumArtist.AlbumArtists; + + if (artists.Count > 0) + { + name = artists[0] + " - " + name; + } + } + else if (item is IHasArtist hasArtist) + { + var artists = hasArtist.Artists; + + if (artists.Count > 0) + { + name = artists[0] + " - " + name; + } + } + + return name; + } + } +} -- cgit v1.2.3 From ca1f15af19e26f8f610a7b56cd6b15a6a308a58f Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 13 Aug 2020 20:48:28 -0400 Subject: Move GenericEventArgs to Jellyfin.Data.Events --- Emby.Dlna/PlayTo/PlayToController.cs | 2 +- Emby.Dlna/PlayTo/PlayToManager.cs | 2 +- Emby.Dlna/Ssdp/DeviceDiscovery.cs | 2 +- Emby.Notifications/NotificationEntryPoint.cs | 2 +- .../Activity/ActivityLogEntryPoint.cs | 2 +- .../Configuration/ServerConfigurationManager.cs | 2 +- .../Devices/DeviceManager.cs | 2 +- .../EntryPoints/ExternalPortForwarding.cs | 2 +- .../EntryPoints/LibraryChangedNotifier.cs | 2 +- .../EntryPoints/RecordingNotifier.cs | 9 ++++---- .../EntryPoints/ServerEventNotifier.cs | 2 +- .../HttpServer/HttpListenerHost.cs | 2 +- .../LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../LiveTv/EmbyTV/TimerManager.cs | 2 +- .../LiveTv/LiveTvManager.cs | 2 +- .../ScheduledTasks/ScheduledTaskWorker.cs | 3 +-- .../ScheduledTasks/TaskManager.cs | 2 +- .../Session/SessionManager.cs | 2 +- .../Session/SessionWebSocketListener.cs | 2 +- .../ActivityLogWebSocketListener.cs | 2 +- .../ScheduledTasksWebSocketListener.cs | 2 +- Jellyfin.Data/Events/GenericEventArgs.cs | 26 ++++++++++++++++++++++ .../Activity/ActivityManager.cs | 2 +- .../Users/DeviceAccessEntryPoint.cs | 2 +- .../Users/UserManager.cs | 2 +- MediaBrowser.Controller/Devices/IDeviceManager.cs | 2 +- MediaBrowser.Controller/Library/IUserManager.cs | 2 +- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 2 +- MediaBrowser.Controller/Net/IHttpServer.cs | 2 +- .../Providers/IProviderManager.cs | 2 +- MediaBrowser.Controller/Session/ISessionManager.cs | 2 +- MediaBrowser.Model/Activity/IActivityManager.cs | 2 +- MediaBrowser.Model/Dlna/IDeviceDiscovery.cs | 2 +- MediaBrowser.Model/Events/GenericEventArgs.cs | 26 ---------------------- MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs | 2 +- MediaBrowser.Model/Tasks/ITaskManager.cs | 2 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 2 +- 37 files changed, 65 insertions(+), 65 deletions(-) create mode 100644 Jellyfin.Data/Events/GenericEventArgs.cs delete mode 100644 MediaBrowser.Model/Events/GenericEventArgs.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 92a93d4349..1f0da8d753 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Emby.Dlna.Didl; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; @@ -18,7 +19,6 @@ using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Session; using Microsoft.AspNetCore.WebUtilities; diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs index 512589e4d7..00edff1a65 100644 --- a/Emby.Dlna/PlayTo/PlayToManager.cs +++ b/Emby.Dlna/PlayTo/PlayToManager.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; @@ -16,7 +17,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Session; using Microsoft.Extensions.Logging; diff --git a/Emby.Dlna/Ssdp/DeviceDiscovery.cs b/Emby.Dlna/Ssdp/DeviceDiscovery.cs index 7daac96d1d..18ee188fd0 100644 --- a/Emby.Dlna/Ssdp/DeviceDiscovery.cs +++ b/Emby.Dlna/Ssdp/DeviceDiscovery.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Events; using Rssdp; using Rssdp.Infrastructure; diff --git a/Emby.Notifications/NotificationEntryPoint.cs b/Emby.Notifications/NotificationEntryPoint.cs index b923fd26ce..ded22d26cc 100644 --- a/Emby.Notifications/NotificationEntryPoint.cs +++ b/Emby.Notifications/NotificationEntryPoint.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; @@ -13,7 +14,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Notifications; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Notifications; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 39b6361b7c..75a7916869 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -2,6 +2,7 @@ using System; using System.Globalization; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Authentication; @@ -9,7 +10,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Notifications; using MediaBrowser.Model.Updates; diff --git a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs index a15295fca4..f05a30a897 100644 --- a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs +++ b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs @@ -2,11 +2,11 @@ using System; using System.Globalization; using System.IO; using Emby.Server.Implementations.AppBase; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs index cc4b407f5c..f98c694c46 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/Emby.Server.Implementations/Devices/DeviceManager.cs @@ -7,13 +7,13 @@ using System.IO; using System.Linq; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Security; using MediaBrowser.Model.Devices; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Session; diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 9fce49425e..2e8cc76d23 100644 --- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -7,11 +7,11 @@ using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Events; using Microsoft.Extensions.Logging; using Mono.Nat; diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 1deef7f720..c9d21d9638 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -15,7 +16,6 @@ using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.EntryPoints diff --git a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs index 6327359106..44d2580d68 100644 --- a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Plugins; @@ -43,22 +44,22 @@ namespace Emby.Server.Implementations.EntryPoints return Task.CompletedTask; } - private async void OnLiveTvManagerSeriesTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs e) + private async void OnLiveTvManagerSeriesTimerCreated(object sender, GenericEventArgs e) { await SendMessage("SeriesTimerCreated", e.Argument).ConfigureAwait(false); } - private async void OnLiveTvManagerTimerCreated(object sender, MediaBrowser.Model.Events.GenericEventArgs e) + private async void OnLiveTvManagerTimerCreated(object sender, GenericEventArgs e) { await SendMessage("TimerCreated", e.Argument).ConfigureAwait(false); } - private async void OnLiveTvManagerSeriesTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs e) + private async void OnLiveTvManagerSeriesTimerCancelled(object sender, GenericEventArgs e) { await SendMessage("SeriesTimerCancelled", e.Argument).ConfigureAwait(false); } - private async void OnLiveTvManagerTimerCancelled(object sender, MediaBrowser.Model.Events.GenericEventArgs e) + private async void OnLiveTvManagerTimerCancelled(object sender, GenericEventArgs e) { await SendMessage("TimerCancelled", e.Argument).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 826d4d8dc3..d023591e19 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -4,13 +4,13 @@ using System.Globalization; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Tasks; using MediaBrowser.Model.Updates; diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index dafdd5b7bf..fe39bb4b29 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -12,13 +12,13 @@ using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.Services; using Emby.Server.Implementations.SocketSharp; +using Jellyfin.Data.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 80e09f0a34..09c52d95bb 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -13,6 +13,7 @@ using System.Threading.Tasks; using System.Xml; using Emby.Server.Implementations.Library; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; @@ -29,7 +30,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.MediaInfo; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs index 285a59a249..dd479b7d1b 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs @@ -5,8 +5,8 @@ using System.Collections.Concurrent; using System.Globalization; using System.Linq; using System.Threading; +using Jellyfin.Data.Events; using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Model.Events; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 1b075d86a8..ef505c78e6 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Emby.Server.Implementations.Library; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; @@ -24,7 +25,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.LiveTv; diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 8a900f42cd..36faae65d2 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -6,11 +6,10 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Progress; -using MediaBrowser.Model.Events; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index 81096026bd..fff52ff88a 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -5,8 +5,8 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 862a7296ca..6e41244639 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; @@ -24,7 +25,6 @@ using MediaBrowser.Controller.Session; using MediaBrowser.Model.Devices; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Library; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 8bebd37dc8..1da7a64730 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -4,9 +4,9 @@ using System.Linq; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Net; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; diff --git a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs index 6395b8d62f..849b3b7095 100644 --- a/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ActivityLogWebSocketListener.cs @@ -1,8 +1,8 @@ using System; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Events; using Microsoft.Extensions.Logging; namespace Jellyfin.Api.WebSocketListeners diff --git a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs index 12f815ff75..8a966c1376 100644 --- a/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs +++ b/Jellyfin.Api/WebSocketListeners/ScheduledTasksWebSocketListener.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; diff --git a/Jellyfin.Data/Events/GenericEventArgs.cs b/Jellyfin.Data/Events/GenericEventArgs.cs new file mode 100644 index 0000000000..7b9a5111ee --- /dev/null +++ b/Jellyfin.Data/Events/GenericEventArgs.cs @@ -0,0 +1,26 @@ +using System; + +namespace Jellyfin.Data.Events +{ + /// + /// Provides a generic EventArgs subclass that can hold any kind of object. + /// + /// The type of this event. + public class GenericEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The argument. + public GenericEventArgs(T arg) + { + Argument = arg; + } + + /// + /// Gets the argument. + /// + /// The argument. + public T Argument { get; } + } +} diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs index 2deefbe819..09f2611e4e 100644 --- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs +++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs @@ -2,8 +2,8 @@ using System; using System.Linq; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Querying; namespace Jellyfin.Server.Implementations.Activity diff --git a/Jellyfin.Server.Implementations/Users/DeviceAccessEntryPoint.cs b/Jellyfin.Server.Implementations/Users/DeviceAccessEntryPoint.cs index 140853e529..1fb89c4a63 100644 --- a/Jellyfin.Server.Implementations/Users/DeviceAccessEntryPoint.cs +++ b/Jellyfin.Server.Implementations/Users/DeviceAccessEntryPoint.cs @@ -4,12 +4,12 @@ using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Events; namespace Jellyfin.Server.Implementations.Users { diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 11402ee055..267c1c1033 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -10,6 +10,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; +using Jellyfin.Data.Events; using MediaBrowser.Common; using MediaBrowser.Common.Cryptography; using MediaBrowser.Common.Extensions; @@ -21,7 +22,6 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Users; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index 7d279230b5..a038d84d81 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -1,7 +1,7 @@ using System; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Model.Devices; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 6685861a9a..c8d8375b38 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -2,9 +2,9 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Library diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index f619b011bf..d6f629a1b9 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Events; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Querying; diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index e6609fae38..b04ebda8ca 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using MediaBrowser.Model.Events; +using Jellyfin.Data.Events; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 955db0278c..ef744ee3c1 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -4,12 +4,12 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Providers; namespace MediaBrowser.Controller.Providers diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index e54f210506..d461a9281a 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -2,11 +2,11 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Security; using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Session; using MediaBrowser.Model.SyncPlay; diff --git a/MediaBrowser.Model/Activity/IActivityManager.cs b/MediaBrowser.Model/Activity/IActivityManager.cs index 9dab5e77b7..2362f7e927 100644 --- a/MediaBrowser.Model/Activity/IActivityManager.cs +++ b/MediaBrowser.Model/Activity/IActivityManager.cs @@ -4,7 +4,7 @@ using System; using System.Linq; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using MediaBrowser.Model.Events; +using Jellyfin.Data.Events; using MediaBrowser.Model.Querying; namespace MediaBrowser.Model.Activity diff --git a/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs b/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs index 76c9a4b044..05209e53d0 100644 --- a/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs +++ b/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs @@ -1,7 +1,7 @@ #pragma warning disable CS1591 using System; -using MediaBrowser.Model.Events; +using Jellyfin.Data.Events; namespace MediaBrowser.Model.Dlna { diff --git a/MediaBrowser.Model/Events/GenericEventArgs.cs b/MediaBrowser.Model/Events/GenericEventArgs.cs deleted file mode 100644 index 347ea2281e..0000000000 --- a/MediaBrowser.Model/Events/GenericEventArgs.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace MediaBrowser.Model.Events -{ - /// - /// Provides a generic EventArgs subclass that can hold any kind of object. - /// - /// The type of this event. - public class GenericEventArgs : EventArgs - { - /// - /// Initializes a new instance of the class. - /// - /// The argument. - public GenericEventArgs(T arg) - { - Argument = arg; - } - - /// - /// Gets the argument. - /// - /// The argument. - public T Argument { get; } - } -} diff --git a/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs b/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs index b08acba2c6..2f05e08c51 100644 --- a/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs +++ b/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs @@ -1,6 +1,6 @@ #nullable disable using System; -using MediaBrowser.Model.Events; +using Jellyfin.Data.Events; namespace MediaBrowser.Model.Tasks { diff --git a/MediaBrowser.Model/Tasks/ITaskManager.cs b/MediaBrowser.Model/Tasks/ITaskManager.cs index 363773ff74..02b29074e3 100644 --- a/MediaBrowser.Model/Tasks/ITaskManager.cs +++ b/MediaBrowser.Model/Tasks/ITaskManager.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using MediaBrowser.Model.Events; +using Jellyfin.Data.Events; namespace MediaBrowser.Model.Tasks { diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index bbd7166e68..9f63c60465 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -9,6 +9,7 @@ using System.Net.Mime; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; using MediaBrowser.Common.Net; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; @@ -22,7 +23,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Subtitles; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using MediaBrowser.Model.Providers; -- cgit v1.2.3 From 18d34f953b4639240b92b373b3f660e87a1e55b5 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 13 Aug 2020 20:57:13 -0400 Subject: Migrate ActivityLogEntryPoint.OnUserCreated to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 14 ------- Jellyfin.Data/Events/Users/UserCreatedEventArgs.cs | 18 +++++++++ .../Events/Consumers/Users/UserCreatedLogger.cs | 43 ++++++++++++++++++++++ 3 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 Jellyfin.Data/Events/Users/UserCreatedEventArgs.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 75a7916869..b11feff7c7 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -63,7 +63,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded; _sessionManager.SessionEnded += OnSessionEnded; - _userManager.OnUserCreated += OnUserCreated; _userManager.OnUserPasswordChanged += OnUserPasswordChanged; _userManager.OnUserDeleted += OnUserDeleted; _userManager.OnUserLockedOut += OnUserLockedOut; @@ -171,18 +170,6 @@ namespace Emby.Server.Implementations.Activity .ConfigureAwait(false); } - private async void OnUserCreated(object sender, GenericEventArgs e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserCreatedWithName"), - e.Argument.Username), - "UserCreated", - e.Argument.Id)) - .ConfigureAwait(false); - } - private async void OnSessionStarted(object sender, SessionEventArgs e) { var session = e.SessionInfo; @@ -291,7 +278,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationSucceeded -= OnAuthenticationSucceeded; _sessionManager.SessionEnded -= OnSessionEnded; - _userManager.OnUserCreated -= OnUserCreated; _userManager.OnUserPasswordChanged -= OnUserPasswordChanged; _userManager.OnUserDeleted -= OnUserDeleted; _userManager.OnUserLockedOut -= OnUserLockedOut; diff --git a/Jellyfin.Data/Events/Users/UserCreatedEventArgs.cs b/Jellyfin.Data/Events/Users/UserCreatedEventArgs.cs new file mode 100644 index 0000000000..66f7c8d4fc --- /dev/null +++ b/Jellyfin.Data/Events/Users/UserCreatedEventArgs.cs @@ -0,0 +1,18 @@ +using Jellyfin.Data.Entities; + +namespace Jellyfin.Data.Events.Users +{ + /// + /// An event that occurs when a user is created. + /// + public class UserCreatedEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The user. + public UserCreatedEventArgs(User arg) : base(arg) + { + } + } +} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs new file mode 100644 index 0000000000..dc855cc368 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserCreatedLogger.cs @@ -0,0 +1,43 @@ +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Events.Users; +using MediaBrowser.Controller.Events; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Users +{ + /// + /// Creates an entry in the activity log when a user is created. + /// + public class UserCreatedLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public UserCreatedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(UserCreatedEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserCreatedWithName"), + eventArgs.Argument.Username), + "UserCreated", + eventArgs.Argument.Id)) + .ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From 737a86d0cbd4dfce86bbe25fb7669f74cbde6d0a Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 13 Aug 2020 21:01:35 -0400 Subject: Migrate ActivityLogEntryPoint.OnUserDeleted to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 14 --------- Jellyfin.Data/Events/Users/UserDeletedEventArgs.cs | 18 +++++++++++ .../Events/Consumers/Users/UserDeletedLogger.cs | 35 ++++++++++++++++++++++ 3 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 Jellyfin.Data/Events/Users/UserDeletedEventArgs.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index b11feff7c7..e5ef944311 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -64,7 +64,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.SessionEnded += OnSessionEnded; _userManager.OnUserPasswordChanged += OnUserPasswordChanged; - _userManager.OnUserDeleted += OnUserDeleted; _userManager.OnUserLockedOut += OnUserLockedOut; return Task.CompletedTask; @@ -146,18 +145,6 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnUserDeleted(object sender, GenericEventArgs e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserDeletedWithName"), - e.Argument.Username), - "UserDeleted", - Guid.Empty)) - .ConfigureAwait(false); - } - private async void OnUserPasswordChanged(object sender, GenericEventArgs e) { await CreateLogEntry(new ActivityLog( @@ -279,7 +266,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.SessionEnded -= OnSessionEnded; _userManager.OnUserPasswordChanged -= OnUserPasswordChanged; - _userManager.OnUserDeleted -= OnUserDeleted; _userManager.OnUserLockedOut -= OnUserLockedOut; } } diff --git a/Jellyfin.Data/Events/Users/UserDeletedEventArgs.cs b/Jellyfin.Data/Events/Users/UserDeletedEventArgs.cs new file mode 100644 index 0000000000..0b94933754 --- /dev/null +++ b/Jellyfin.Data/Events/Users/UserDeletedEventArgs.cs @@ -0,0 +1,18 @@ +using Jellyfin.Data.Entities; + +namespace Jellyfin.Data.Events.Users +{ + /// + /// An event that occurs when a user is deleted. + /// + public class UserDeletedEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The user. + public UserDeletedEventArgs(User arg) : base(arg) + { + } + } +} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs new file mode 100644 index 0000000000..1a3975067c --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs @@ -0,0 +1,35 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Events.Users; +using MediaBrowser.Controller.Events; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Users +{ + public class UserDeletedLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + public UserDeletedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + public async Task OnEvent(UserDeletedEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserDeletedWithName"), + eventArgs.Argument.Username), + "UserDeleted", + Guid.Empty)) + .ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From a1ecafb40d8cacb9ea63833ddc311c59d738044c Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 13 Aug 2020 21:07:08 -0400 Subject: Migrate ActivityLogEntryPoint.OnUserPasswordChanged to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 14 ------- .../Events/Users/UserPasswordChangedEventArgs.cs | 18 +++++++++ .../Consumers/Users/UserPasswordChangedLogger.cs | 43 ++++++++++++++++++++++ 3 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 Jellyfin.Data/Events/Users/UserPasswordChangedEventArgs.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index e5ef944311..8fc0b527f0 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -63,7 +63,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded; _sessionManager.SessionEnded += OnSessionEnded; - _userManager.OnUserPasswordChanged += OnUserPasswordChanged; _userManager.OnUserLockedOut += OnUserLockedOut; return Task.CompletedTask; @@ -145,18 +144,6 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnUserPasswordChanged(object sender, GenericEventArgs e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserPasswordChangedWithName"), - e.Argument.Username), - "UserPasswordChanged", - e.Argument.Id)) - .ConfigureAwait(false); - } - private async void OnSessionStarted(object sender, SessionEventArgs e) { var session = e.SessionInfo; @@ -265,7 +252,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationSucceeded -= OnAuthenticationSucceeded; _sessionManager.SessionEnded -= OnSessionEnded; - _userManager.OnUserPasswordChanged -= OnUserPasswordChanged; _userManager.OnUserLockedOut -= OnUserLockedOut; } } diff --git a/Jellyfin.Data/Events/Users/UserPasswordChangedEventArgs.cs b/Jellyfin.Data/Events/Users/UserPasswordChangedEventArgs.cs new file mode 100644 index 0000000000..087ec9ab68 --- /dev/null +++ b/Jellyfin.Data/Events/Users/UserPasswordChangedEventArgs.cs @@ -0,0 +1,18 @@ +using Jellyfin.Data.Entities; + +namespace Jellyfin.Data.Events.Users +{ + /// + /// An event that occurs when a user's password has changed. + /// + public class UserPasswordChangedEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The user. + public UserPasswordChangedEventArgs(User arg) : base(arg) + { + } + } +} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs new file mode 100644 index 0000000000..dc8ecbf48f --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserPasswordChangedLogger.cs @@ -0,0 +1,43 @@ +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Events.Users; +using MediaBrowser.Controller.Events; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Users +{ + /// + /// Creates an entry in the activity log when a user's password is changed. + /// + public class UserPasswordChangedLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public UserPasswordChangedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(UserPasswordChangedEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserPasswordChangedWithName"), + eventArgs.Argument.Username), + "UserPasswordChanged", + eventArgs.Argument.Id)) + .ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From 8a4bdaed6bce53d8ea10dba8a71fb450edd5feca Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 13 Aug 2020 21:11:38 -0400 Subject: Migrate ActivityLogEntryPoint.OnUserLockedOut to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 25 +----------- .../Events/Users/UserLockedOutEventArgs.cs | 18 +++++++++ .../Events/Consumers/Users/UserLockedOutLogger.cs | 47 ++++++++++++++++++++++ 3 files changed, 66 insertions(+), 24 deletions(-) create mode 100644 Jellyfin.Data/Events/Users/UserLockedOutEventArgs.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 8fc0b527f0..0000195d86 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -6,7 +6,6 @@ using Jellyfin.Data.Events; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Authentication; -using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Activity; @@ -26,7 +25,6 @@ namespace Emby.Server.Implementations.Activity private readonly ISessionManager _sessionManager; private readonly IActivityManager _activityManager; private readonly ILocalizationManager _localization; - private readonly IUserManager _userManager; /// /// Initializes a new instance of the class. @@ -35,19 +33,16 @@ namespace Emby.Server.Implementations.Activity /// The activity manager. /// The localization manager. /// The installation manager. - /// The user manager. public ActivityLogEntryPoint( ISessionManager sessionManager, IActivityManager activityManager, ILocalizationManager localization, - IInstallationManager installationManager, - IUserManager userManager) + IInstallationManager installationManager) { _sessionManager = sessionManager; _activityManager = activityManager; _localization = localization; _installationManager = installationManager; - _userManager = userManager; } /// @@ -63,25 +58,9 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded; _sessionManager.SessionEnded += OnSessionEnded; - _userManager.OnUserLockedOut += OnUserLockedOut; - return Task.CompletedTask; } - private async void OnUserLockedOut(object sender, GenericEventArgs e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserLockedOutWithName"), - e.Argument.Username), - NotificationType.UserLockedOut.ToString(), - e.Argument.Id) - { - LogSeverity = LogLevel.Error - }).ConfigureAwait(false); - } - private async void OnSessionEnded(object sender, SessionEventArgs e) { var session = e.SessionInfo; @@ -251,8 +230,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.AuthenticationFailed -= OnAuthenticationFailed; _sessionManager.AuthenticationSucceeded -= OnAuthenticationSucceeded; _sessionManager.SessionEnded -= OnSessionEnded; - - _userManager.OnUserLockedOut -= OnUserLockedOut; } } } diff --git a/Jellyfin.Data/Events/Users/UserLockedOutEventArgs.cs b/Jellyfin.Data/Events/Users/UserLockedOutEventArgs.cs new file mode 100644 index 0000000000..cca3726dc5 --- /dev/null +++ b/Jellyfin.Data/Events/Users/UserLockedOutEventArgs.cs @@ -0,0 +1,18 @@ +using Jellyfin.Data.Entities; + +namespace Jellyfin.Data.Events.Users +{ + /// + /// An event that occurs when a user is locked out. + /// + public class UserLockedOutEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The user. + public UserLockedOutEventArgs(User arg) : base(arg) + { + } + } +} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs new file mode 100644 index 0000000000..a31f222ee7 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserLockedOutLogger.cs @@ -0,0 +1,47 @@ +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Events.Users; +using MediaBrowser.Controller.Events; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Users +{ + /// + /// Creates an entry in the activity log when a user is locked out. + /// + public class UserLockedOutLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public UserLockedOutLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(UserLockedOutEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserLockedOutWithName"), + eventArgs.Argument.Username), + NotificationType.UserLockedOut.ToString(), + eventArgs.Argument.Id) + { + LogSeverity = LogLevel.Error + }).ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From bff05d71861bd1b82777df3140a6f9dd5599ba98 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 13 Aug 2020 21:33:28 -0400 Subject: Migrate ActivityLogEntryPoint.OnAuthenticationFailed to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 21 --------- .../Security/AuthenticationFailedLogger.cs | 52 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 0000195d86..8279503ec8 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -12,7 +12,6 @@ using MediaBrowser.Model.Activity; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Notifications; using MediaBrowser.Model.Updates; -using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Activity { @@ -54,7 +53,6 @@ namespace Emby.Server.Implementations.Activity _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; _sessionManager.SessionStarted += OnSessionStarted; - _sessionManager.AuthenticationFailed += OnAuthenticationFailed; _sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded; _sessionManager.SessionEnded += OnSessionEnded; @@ -105,24 +103,6 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnAuthenticationFailed(object sender, GenericEventArgs e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("FailedLoginAttemptWithUserName"), - e.Argument.Username), - "AuthenticationFailed", - Guid.Empty) - { - LogSeverity = LogLevel.Error, - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("LabelIpAddressValue"), - e.Argument.RemoteEndPoint), - }).ConfigureAwait(false); - } - private async void OnSessionStarted(object sender, SessionEventArgs e) { var session = e.SessionInfo; @@ -227,7 +207,6 @@ namespace Emby.Server.Implementations.Activity _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; _sessionManager.SessionStarted -= OnSessionStarted; - _sessionManager.AuthenticationFailed -= OnAuthenticationFailed; _sessionManager.AuthenticationSucceeded -= OnAuthenticationSucceeded; _sessionManager.SessionEnded -= OnSessionEnded; } diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs new file mode 100644 index 0000000000..f899b4497a --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationFailedLogger.cs @@ -0,0 +1,52 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Security +{ + /// + /// Creates an entry in the activity log when there is a failed login attempt. + /// + public class AuthenticationFailedLogger : IEventConsumer> + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public AuthenticationFailedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(GenericEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("FailedLoginAttemptWithUserName"), + eventArgs.Argument.Username), + "AuthenticationFailed", + Guid.Empty) + { + LogSeverity = LogLevel.Error, + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("LabelIpAddressValue"), + eventArgs.Argument.RemoteEndPoint), + }).ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From f4275adfcb4c7c5e2daedbad09c64c04fc1ebc53 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Thu, 13 Aug 2020 21:38:24 -0400 Subject: Migrate ActivityLogEntryPoint.OnAuthenticationSucceeded to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 23 ---------- .../Security/AuthenticationSucceededLogger.cs | 49 ++++++++++++++++++++++ 2 files changed, 49 insertions(+), 23 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 8279503ec8..40fc7d8907 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -2,10 +2,8 @@ using System; using System.Globalization; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using Jellyfin.Data.Events; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; -using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Activity; @@ -53,7 +51,6 @@ namespace Emby.Server.Implementations.Activity _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; _sessionManager.SessionStarted += OnSessionStarted; - _sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded; _sessionManager.SessionEnded += OnSessionEnded; return Task.CompletedTask; @@ -84,25 +81,6 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnAuthenticationSucceeded(object sender, GenericEventArgs e) - { - var user = e.Argument.User; - - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("AuthenticationSucceededWithUserName"), - user.Name), - "AuthenticationSucceeded", - user.Id) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("LabelIpAddressValue"), - e.Argument.SessionInfo.RemoteEndPoint), - }).ConfigureAwait(false); - } - private async void OnSessionStarted(object sender, SessionEventArgs e) { var session = e.SessionInfo; @@ -207,7 +185,6 @@ namespace Emby.Server.Implementations.Activity _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; _sessionManager.SessionStarted -= OnSessionStarted; - _sessionManager.AuthenticationSucceeded -= OnAuthenticationSucceeded; _sessionManager.SessionEnded -= OnSessionEnded; } } diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs new file mode 100644 index 0000000000..2f9f44ed67 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Security/AuthenticationSucceededLogger.cs @@ -0,0 +1,49 @@ +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Events; +using MediaBrowser.Controller.Authentication; +using MediaBrowser.Controller.Events; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Security +{ + /// + /// Creates an entry in the activity log when there is a successful login attempt. + /// + public class AuthenticationSucceededLogger : IEventConsumer> + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public AuthenticationSucceededLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(GenericEventArgs e) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("AuthenticationSucceededWithUserName"), + e.Argument.User.Name), + "AuthenticationSucceeded", + e.Argument.User.Id) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("LabelIpAddressValue"), + e.Argument.SessionInfo.RemoteEndPoint), + }).ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From b7f21971f43d6d9f956ff0aade31625d3995858a Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 14 Aug 2020 15:21:17 -0400 Subject: Migrate ActivityLogEntryPoint.OnPluginInstalled to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 19 -------- .../Consumers/Updates/PluginInstalledLogger.cs | 50 ++++++++++++++++++++++ .../Events/Updates/PluginInstalledEventArgs.cs | 19 ++++++++ 3 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs create mode 100644 MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 40fc7d8907..600c1d3ea2 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -45,7 +45,6 @@ namespace Emby.Server.Implementations.Activity /// public Task RunAsync() { - _installationManager.PluginInstalled += OnPluginInstalled; _installationManager.PluginUninstalled += OnPluginUninstalled; _installationManager.PluginUpdated += OnPluginUpdated; _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; @@ -136,23 +135,6 @@ namespace Emby.Server.Implementations.Activity .ConfigureAwait(false); } - private async void OnPluginInstalled(object sender, InstallationInfo e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("PluginInstalledWithName"), - e.Name), - NotificationType.PluginInstalled.ToString(), - Guid.Empty) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("VersionNumber"), - e.Version) - }).ConfigureAwait(false); - } - private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e) { var installationInfo = e.InstallationInfo; @@ -179,7 +161,6 @@ namespace Emby.Server.Implementations.Activity /// public void Dispose() { - _installationManager.PluginInstalled -= OnPluginInstalled; _installationManager.PluginUninstalled -= OnPluginUninstalled; _installationManager.PluginUpdated -= OnPluginUpdated; _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs new file mode 100644 index 0000000000..8837172dbe --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledLogger.cs @@ -0,0 +1,50 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// + /// Creates an entry in the activity log when a plugin is installed. + /// + public class PluginInstalledLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public PluginInstalledLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(PluginInstalledEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("PluginInstalledWithName"), + eventArgs.Argument.Name), + NotificationType.PluginInstalled.ToString(), + Guid.Empty) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("VersionNumber"), + eventArgs.Argument.Version) + }).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs new file mode 100644 index 0000000000..dfadc9f61f --- /dev/null +++ b/MediaBrowser.Controller/Events/Updates/PluginInstalledEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Model.Updates; + +namespace MediaBrowser.Controller.Events.Updates +{ + /// + /// An event that occurs when a plugin is installed. + /// + public class PluginInstalledEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The installation info. + public PluginInstalledEventArgs(InstallationInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From 0da7c0568d61e834b8b11693ed79eee2855d4ae6 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 14 Aug 2020 15:22:12 -0400 Subject: Migrate ActivityLogEntryPoint.OnPluginUninstalled to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 15 -------- .../Consumers/Updates/PluginUninstalledLogger.cs | 45 ++++++++++++++++++++++ .../Events/Updates/PluginUninstalledEventArgs.cs | 19 +++++++++ 3 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs create mode 100644 MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 600c1d3ea2..ba0bf9ea2e 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -2,7 +2,6 @@ using System; using System.Globalization; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; @@ -45,7 +44,6 @@ namespace Emby.Server.Implementations.Activity /// public Task RunAsync() { - _installationManager.PluginUninstalled += OnPluginUninstalled; _installationManager.PluginUpdated += OnPluginUpdated; _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; @@ -123,18 +121,6 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnPluginUninstalled(object sender, IPlugin e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("PluginUninstalledWithName"), - e.Name), - NotificationType.PluginUninstalled.ToString(), - Guid.Empty)) - .ConfigureAwait(false); - } - private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e) { var installationInfo = e.InstallationInfo; @@ -161,7 +147,6 @@ namespace Emby.Server.Implementations.Activity /// public void Dispose() { - _installationManager.PluginUninstalled -= OnPluginUninstalled; _installationManager.PluginUpdated -= OnPluginUpdated; _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs new file mode 100644 index 0000000000..91a30069e8 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledLogger.cs @@ -0,0 +1,45 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// + /// Creates an entry in the activity log when a plugin is uninstalled. + /// + public class PluginUninstalledLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public PluginUninstalledLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(PluginUninstalledEventArgs e) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("PluginUninstalledWithName"), + e.Argument.Name), + NotificationType.PluginUninstalled.ToString(), + Guid.Empty)) + .ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs new file mode 100644 index 0000000000..7510b62b88 --- /dev/null +++ b/MediaBrowser.Controller/Events/Updates/PluginUninstalledEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Common.Plugins; + +namespace MediaBrowser.Controller.Events.Updates +{ + /// + /// An event that occurs when a plugin is uninstalled. + /// + public class PluginUninstalledEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The plugin. + public PluginUninstalledEventArgs(IPlugin arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From e9244448809cb4251b341832c8fdfecde5f169ab Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 14 Aug 2020 15:50:17 -0400 Subject: Migrate ActivityLogEntryPoint.OnPluginUpdated to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 21 --------- .../Consumers/Updates/PluginUpdatedLogger.cs | 51 ++++++++++++++++++++++ .../Events/Updates/PluginUpdatedEventArgs.cs | 19 ++++++++ 3 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs create mode 100644 MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index ba0bf9ea2e..ee058fd468 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -8,7 +8,6 @@ using MediaBrowser.Controller.Session; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Notifications; -using MediaBrowser.Model.Updates; namespace Emby.Server.Implementations.Activity { @@ -44,7 +43,6 @@ namespace Emby.Server.Implementations.Activity /// public Task RunAsync() { - _installationManager.PluginUpdated += OnPluginUpdated; _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; _sessionManager.SessionStarted += OnSessionStarted; @@ -103,24 +101,6 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnPluginUpdated(object sender, InstallationInfo e) - { - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("PluginUpdatedWithName"), - e.Name), - NotificationType.PluginUpdateInstalled.ToString(), - Guid.Empty) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("VersionNumber"), - e.Version), - Overview = e.Changelog - }).ConfigureAwait(false); - } - private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e) { var installationInfo = e.InstallationInfo; @@ -147,7 +127,6 @@ namespace Emby.Server.Implementations.Activity /// public void Dispose() { - _installationManager.PluginUpdated -= OnPluginUpdated; _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; _sessionManager.SessionStarted -= OnSessionStarted; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs new file mode 100644 index 0000000000..9ce16f774f --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUpdatedLogger.cs @@ -0,0 +1,51 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// + /// Creates an entry in the activity log when a plugin is updated. + /// + public class PluginUpdatedLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public PluginUpdatedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(PluginUpdatedEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("PluginUpdatedWithName"), + eventArgs.Argument.Name), + NotificationType.PluginUpdateInstalled.ToString(), + Guid.Empty) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("VersionNumber"), + eventArgs.Argument.Version), + Overview = eventArgs.Argument.Changelog + }).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs new file mode 100644 index 0000000000..661ca066a8 --- /dev/null +++ b/MediaBrowser.Controller/Events/Updates/PluginUpdatedEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Model.Updates; + +namespace MediaBrowser.Controller.Events.Updates +{ + /// + /// An event that occurs when a plugin is updated. + /// + public class PluginUpdatedEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The installation info. + public PluginUpdatedEventArgs(InstallationInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From 98cbf1c2de5151e88977143e415fe4a0b3cad7cf Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Fri, 14 Aug 2020 15:56:54 -0400 Subject: Migrate ActivityLogEntryPoint.OnPackageInstallationFailed to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 33 +------------- .../Updates/PackageInstallationFailedLogger.cs | 51 ++++++++++++++++++++++ .../Updates/InstallationEventArgs.cs | 3 +- 3 files changed, 54 insertions(+), 33 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PackageInstallationFailedLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index ee058fd468..00a14fb0bd 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -1,13 +1,10 @@ -using System; using System.Globalization; using System.Threading.Tasks; using Jellyfin.Data.Entities; -using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.Notifications; namespace Emby.Server.Implementations.Activity { @@ -16,7 +13,6 @@ namespace Emby.Server.Implementations.Activity /// public sealed class ActivityLogEntryPoint : IServerEntryPoint { - private readonly IInstallationManager _installationManager; private readonly ISessionManager _sessionManager; private readonly IActivityManager _activityManager; private readonly ILocalizationManager _localization; @@ -27,24 +23,19 @@ namespace Emby.Server.Implementations.Activity /// The session manager. /// The activity manager. /// The localization manager. - /// The installation manager. public ActivityLogEntryPoint( ISessionManager sessionManager, IActivityManager activityManager, - ILocalizationManager localization, - IInstallationManager installationManager) + ILocalizationManager localization) { _sessionManager = sessionManager; _activityManager = activityManager; _localization = localization; - _installationManager = installationManager; } /// public Task RunAsync() { - _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; - _sessionManager.SessionStarted += OnSessionStarted; _sessionManager.SessionEnded += OnSessionEnded; @@ -101,34 +92,12 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e) - { - var installationInfo = e.InstallationInfo; - - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("NameInstallFailed"), - installationInfo.Name), - NotificationType.InstallationFailed.ToString(), - Guid.Empty) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("VersionNumber"), - installationInfo.Version), - Overview = e.Exception.Message - }).ConfigureAwait(false); - } - private async Task CreateLogEntry(ActivityLog entry) => await _activityManager.CreateAsync(entry).ConfigureAwait(false); /// public void Dispose() { - _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; - _sessionManager.SessionStarted -= OnSessionStarted; _sessionManager.SessionEnded -= OnSessionEnded; } diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PackageInstallationFailedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PackageInstallationFailedLogger.cs new file mode 100644 index 0000000000..5d7296b3b7 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PackageInstallationFailedLogger.cs @@ -0,0 +1,51 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Common.Updates; +using MediaBrowser.Controller.Events; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// + /// Creates an entry in the activity log when a package installation fails. + /// + public class PackageInstallationFailedLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public PackageInstallationFailedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(InstallationFailedEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("NameInstallFailed"), + eventArgs.InstallationInfo.Name), + NotificationType.InstallationFailed.ToString(), + Guid.Empty) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("VersionNumber"), + eventArgs.InstallationInfo.Version), + Overview = eventArgs.Exception.Message + }).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Common/Updates/InstallationEventArgs.cs b/MediaBrowser.Common/Updates/InstallationEventArgs.cs index 11eb2ad34a..61178f631c 100644 --- a/MediaBrowser.Common/Updates/InstallationEventArgs.cs +++ b/MediaBrowser.Common/Updates/InstallationEventArgs.cs @@ -1,10 +1,11 @@ #pragma warning disable CS1591 +using System; using MediaBrowser.Model.Updates; namespace MediaBrowser.Common.Updates { - public class InstallationEventArgs + public class InstallationEventArgs : EventArgs { public InstallationInfo InstallationInfo { get; set; } -- cgit v1.2.3 From ca3a8bdb98aeb5d112a4d2a456ebcc445dc5fd12 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 02:02:58 -0400 Subject: Migrate ActivityLogEntryPoint.OnSessionStarted to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 27 ----------- .../Consumers/Session/SessionStartedLogger.cs | 54 ++++++++++++++++++++++ .../Events/Session/SessionStartedEventArgs.cs | 19 ++++++++ 3 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs create mode 100644 MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 00a14fb0bd..d863acd0b4 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -36,7 +36,6 @@ namespace Emby.Server.Implementations.Activity /// public Task RunAsync() { - _sessionManager.SessionStarted += OnSessionStarted; _sessionManager.SessionEnded += OnSessionEnded; return Task.CompletedTask; @@ -67,38 +66,12 @@ namespace Emby.Server.Implementations.Activity }).ConfigureAwait(false); } - private async void OnSessionStarted(object sender, SessionEventArgs e) - { - var session = e.SessionInfo; - - if (string.IsNullOrEmpty(session.UserName)) - { - return; - } - - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserOnlineFromDevice"), - session.UserName, - session.DeviceName), - "SessionStarted", - session.UserId) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("LabelIpAddressValue"), - session.RemoteEndPoint) - }).ConfigureAwait(false); - } - private async Task CreateLogEntry(ActivityLog entry) => await _activityManager.CreateAsync(entry).ConfigureAwait(false); /// public void Dispose() { - _sessionManager.SessionStarted -= OnSessionStarted; _sessionManager.SessionEnded -= OnSessionEnded; } } diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs new file mode 100644 index 0000000000..6a0f29b09f --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionStartedLogger.cs @@ -0,0 +1,54 @@ +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Session; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Session +{ + /// + /// Creates an entry in the activity log when a session is started. + /// + public class SessionStartedLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public SessionStartedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(SessionStartedEventArgs eventArgs) + { + if (string.IsNullOrEmpty(eventArgs.Argument.UserName)) + { + return; + } + + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserOnlineFromDevice"), + eventArgs.Argument.UserName, + eventArgs.Argument.DeviceName), + "SessionStarted", + eventArgs.Argument.UserId) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("LabelIpAddressValue"), + eventArgs.Argument.RemoteEndPoint) + }).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs b/MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs new file mode 100644 index 0000000000..aab19cc46a --- /dev/null +++ b/MediaBrowser.Controller/Events/Session/SessionStartedEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Controller.Session; + +namespace MediaBrowser.Controller.Events.Session +{ + /// + /// An event that fires when a session is started. + /// + public class SessionStartedEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The session info. + public SessionStartedEventArgs(SessionInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From 8570cfdba652eb61e2746ea9de6cb9c8bb23eaf5 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 02:07:28 -0400 Subject: Migrate ActivityLogEntryPoint.OnSessionEnded to IEventConsumer --- .../Activity/ActivityLogEntryPoint.cs | 78 ---------------------- .../Consumers/Session/SessionManagerEndedLogger.cs | 54 +++++++++++++++ .../Events/Session/SessionEndedEventArgs.cs | 19 ++++++ 3 files changed, 73 insertions(+), 78 deletions(-) delete mode 100644 Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs create mode 100644 MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs deleted file mode 100644 index d863acd0b4..0000000000 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Globalization; -using System.Threading.Tasks; -using Jellyfin.Data.Entities; -using MediaBrowser.Controller.Plugins; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Globalization; - -namespace Emby.Server.Implementations.Activity -{ - /// - /// Entry point for the activity logger. - /// - public sealed class ActivityLogEntryPoint : IServerEntryPoint - { - private readonly ISessionManager _sessionManager; - private readonly IActivityManager _activityManager; - private readonly ILocalizationManager _localization; - - /// - /// Initializes a new instance of the class. - /// - /// The session manager. - /// The activity manager. - /// The localization manager. - public ActivityLogEntryPoint( - ISessionManager sessionManager, - IActivityManager activityManager, - ILocalizationManager localization) - { - _sessionManager = sessionManager; - _activityManager = activityManager; - _localization = localization; - } - - /// - public Task RunAsync() - { - _sessionManager.SessionEnded += OnSessionEnded; - - return Task.CompletedTask; - } - - private async void OnSessionEnded(object sender, SessionEventArgs e) - { - var session = e.SessionInfo; - - if (string.IsNullOrEmpty(session.UserName)) - { - return; - } - - await CreateLogEntry(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("UserOfflineFromDevice"), - session.UserName, - session.DeviceName), - "SessionEnded", - session.UserId) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localization.GetLocalizedString("LabelIpAddressValue"), - session.RemoteEndPoint), - }).ConfigureAwait(false); - } - - private async Task CreateLogEntry(ActivityLog entry) - => await _activityManager.CreateAsync(entry).ConfigureAwait(false); - - /// - public void Dispose() - { - _sessionManager.SessionEnded -= OnSessionEnded; - } - } -} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs new file mode 100644 index 0000000000..1162fe89b7 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs @@ -0,0 +1,54 @@ +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Session; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Session +{ + /// + /// Creates an entry in the activity log whenever a session ends. + /// + public class SessionManagerEndedLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public SessionManagerEndedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(SessionEndedEventArgs eventArgs) + { + if (string.IsNullOrEmpty(eventArgs.Argument.UserName)) + { + return; + } + + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserOfflineFromDevice"), + eventArgs.Argument.UserName, + eventArgs.Argument.DeviceName), + "SessionEnded", + eventArgs.Argument.UserId) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("LabelIpAddressValue"), + eventArgs.Argument.RemoteEndPoint), + }).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs b/MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs new file mode 100644 index 0000000000..46d7e5a17a --- /dev/null +++ b/MediaBrowser.Controller/Events/Session/SessionEndedEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Controller.Session; + +namespace MediaBrowser.Controller.Events.Session +{ + /// + /// An event that fires when a session is ended. + /// + public class SessionEndedEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The session info. + public SessionEndedEventArgs(SessionInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From 665f58dfbd28d455754cf7bdfc2cafcd84464d64 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 03:34:52 -0400 Subject: Document TaskCompletedLogger --- .../Events/Consumers/TaskCompletedLogger.cs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs index faca66ffd2..7f737ee7e6 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs @@ -21,12 +21,18 @@ namespace Jellyfin.Server.Implementations.Events.Consumers private readonly ILocalizationManager _localizationManager; private readonly IActivityManager _activityManager; + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. public TaskCompletedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) { _localizationManager = localizationManager; _activityManager = activityManager; } + /// public async Task OnEvent(TaskCompletionEventArgs e) { var result = e.Result; -- cgit v1.2.3 From 4d18dbf9de7346c6620a6f9fad7e8f09c13dc68c Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 03:35:42 -0400 Subject: Document UserDeletedLogger --- .../Events/Consumers/Users/UserDeletedLogger.cs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs index 1a3975067c..c68a62c812 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedLogger.cs @@ -9,17 +9,26 @@ using MediaBrowser.Model.Globalization; namespace Jellyfin.Server.Implementations.Events.Consumers.Users { + /// + /// Adds an entry to the activity log when a user is deleted. + /// public class UserDeletedLogger : IEventConsumer { private readonly ILocalizationManager _localizationManager; private readonly IActivityManager _activityManager; + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. public UserDeletedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) { _localizationManager = localizationManager; _activityManager = activityManager; } + /// public async Task OnEvent(UserDeletedEventArgs eventArgs) { await _activityManager.CreateAsync(new ActivityLog( -- cgit v1.2.3 From 93c00c144046ef9dfd2c9ba47f71e3a45ceade8f Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 13:48:12 -0400 Subject: Rename to SessionEndedLogger --- .../Events/Consumers/Session/SessionEndedLogger.cs | 54 ++++++++++++++++++++++ .../Consumers/Session/SessionManagerEndedLogger.cs | 54 ---------------------- 2 files changed, 54 insertions(+), 54 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs delete mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs new file mode 100644 index 0000000000..cf20946ec9 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionEndedLogger.cs @@ -0,0 +1,54 @@ +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Session; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Session +{ + /// + /// Creates an entry in the activity log whenever a session ends. + /// + public class SessionEndedLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public SessionEndedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(SessionEndedEventArgs eventArgs) + { + if (string.IsNullOrEmpty(eventArgs.Argument.UserName)) + { + return; + } + + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("UserOfflineFromDevice"), + eventArgs.Argument.UserName, + eventArgs.Argument.DeviceName), + "SessionEnded", + eventArgs.Argument.UserId) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("LabelIpAddressValue"), + eventArgs.Argument.RemoteEndPoint), + }).ConfigureAwait(false); + } + } +} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs deleted file mode 100644 index 1162fe89b7..0000000000 --- a/Jellyfin.Server.Implementations/Events/Consumers/Session/SessionManagerEndedLogger.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Globalization; -using System.Threading.Tasks; -using Jellyfin.Data.Entities; -using MediaBrowser.Controller.Events; -using MediaBrowser.Controller.Events.Session; -using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Globalization; - -namespace Jellyfin.Server.Implementations.Events.Consumers.Session -{ - /// - /// Creates an entry in the activity log whenever a session ends. - /// - public class SessionManagerEndedLogger : IEventConsumer - { - private readonly ILocalizationManager _localizationManager; - private readonly IActivityManager _activityManager; - - /// - /// Initializes a new instance of the class. - /// - /// The localization manager. - /// The activity manager. - public SessionManagerEndedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) - { - _localizationManager = localizationManager; - _activityManager = activityManager; - } - - /// - public async Task OnEvent(SessionEndedEventArgs eventArgs) - { - if (string.IsNullOrEmpty(eventArgs.Argument.UserName)) - { - return; - } - - await _activityManager.CreateAsync(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localizationManager.GetLocalizedString("UserOfflineFromDevice"), - eventArgs.Argument.UserName, - eventArgs.Argument.DeviceName), - "SessionEnded", - eventArgs.Argument.UserId) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localizationManager.GetLocalizedString("LabelIpAddressValue"), - eventArgs.Argument.RemoteEndPoint), - }).ConfigureAwait(false); - } - } -} -- cgit v1.2.3 From d39e236dfe146de65c2451dfe59abbcc9e8a3b4e Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 15:49:11 -0400 Subject: Migrates ServerEventNotifier.OnUserDeleted to IEventConsumer --- .../EntryPoints/ServerEventNotifier.cs | 13 -------- .../Events/Consumers/Users/UserDeletedNotifier.cs | 38 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedNotifier.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index d023591e19..1ec1f08683 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; @@ -68,7 +67,6 @@ namespace Emby.Server.Implementations.EntryPoints /// public Task RunAsync() { - _userManager.OnUserDeleted += OnUserDeleted; _userManager.OnUserUpdated += OnUserUpdated; _appHost.HasPendingRestartChanged += OnHasPendingRestartChanged; @@ -141,16 +139,6 @@ namespace Emby.Server.Implementations.EntryPoints await SendMessageToUserSession(e.Argument, "UserUpdated", dto).ConfigureAwait(false); } - /// - /// Users the manager_ user deleted. - /// - /// The sender. - /// The e. - private async void OnUserDeleted(object sender, GenericEventArgs e) - { - await SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N", CultureInfo.InvariantCulture)).ConfigureAwait(false); - } - private async Task SendMessageToAdminSessions(string name, T data) { try @@ -192,7 +180,6 @@ namespace Emby.Server.Implementations.EntryPoints { if (dispose) { - _userManager.OnUserDeleted -= OnUserDeleted; _userManager.OnUserUpdated -= OnUserUpdated; _installationManager.PluginUninstalled -= OnPluginUninstalled; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedNotifier.cs new file mode 100644 index 0000000000..10367a939b --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserDeletedNotifier.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Data.Events.Users; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Session; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Users +{ + /// + /// Notifies the user's sessions when a user is deleted. + /// + public class UserDeletedNotifier : IEventConsumer + { + private readonly ISessionManager _sessionManager; + + /// + /// Initializes a new instance of the class. + /// + /// The session manager. + public UserDeletedNotifier(ISessionManager sessionManager) + { + _sessionManager = sessionManager; + } + + /// + public async Task OnEvent(UserDeletedEventArgs eventArgs) + { + await _sessionManager.SendMessageToUserSessions( + new List { eventArgs.Argument.Id }, + "UserDeleted", + eventArgs.Argument.Id.ToString("N", CultureInfo.InvariantCulture), + CancellationToken.None).ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From 816c80525a64fcac441f44f1d508028070fdc21d Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 15:55:15 -0400 Subject: Use IEventManager in UserManager --- .../Users/UserManager.cs | 29 +++++++++------------- MediaBrowser.Controller/Events/IEventManager.cs | 10 +++++++- MediaBrowser.Controller/Library/IUserManager.cs | 20 --------------- 3 files changed, 21 insertions(+), 38 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 267c1c1033..3e8edeb442 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -11,12 +11,14 @@ using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; +using Jellyfin.Data.Events.Users; using MediaBrowser.Common; using MediaBrowser.Common.Cryptography; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Configuration; @@ -34,6 +36,7 @@ namespace Jellyfin.Server.Implementations.Users public class UserManager : IUserManager { private readonly JellyfinDbProvider _dbProvider; + private readonly IEventManager _eventManager; private readonly ICryptoProvider _cryptoProvider; private readonly INetworkManager _networkManager; private readonly IApplicationHost _appHost; @@ -49,6 +52,7 @@ namespace Jellyfin.Server.Implementations.Users /// Initializes a new instance of the class. /// /// The database provider. + /// The event manager. /// The cryptography provider. /// The network manager. /// The application host. @@ -56,6 +60,7 @@ namespace Jellyfin.Server.Implementations.Users /// The logger. public UserManager( JellyfinDbProvider dbProvider, + IEventManager eventManager, ICryptoProvider cryptoProvider, INetworkManager networkManager, IApplicationHost appHost, @@ -63,6 +68,7 @@ namespace Jellyfin.Server.Implementations.Users ILogger logger) { _dbProvider = dbProvider; + _eventManager = eventManager; _cryptoProvider = cryptoProvider; _networkManager = networkManager; _appHost = appHost; @@ -77,21 +83,9 @@ namespace Jellyfin.Server.Implementations.Users _defaultPasswordResetProvider = _passwordResetProviders.OfType().First(); } - /// - public event EventHandler>? OnUserPasswordChanged; - /// public event EventHandler>? OnUserUpdated; - /// - public event EventHandler>? OnUserCreated; - - /// - public event EventHandler>? OnUserDeleted; - - /// - public event EventHandler>? OnUserLockedOut; - /// public IEnumerable Users { @@ -234,7 +228,7 @@ namespace Jellyfin.Server.Implementations.Users dbContext.Users.Add(newUser); await dbContext.SaveChangesAsync().ConfigureAwait(false); - OnUserCreated?.Invoke(this, new GenericEventArgs(newUser)); + await _eventManager.PublishAsync(new UserCreatedEventArgs(newUser)).ConfigureAwait(false); return newUser; } @@ -293,7 +287,8 @@ namespace Jellyfin.Server.Implementations.Users dbContext.RemoveRange(user.AccessSchedules); dbContext.Users.Remove(user); dbContext.SaveChanges(); - OnUserDeleted?.Invoke(this, new GenericEventArgs(user)); + + _eventManager.Publish(new UserDeletedEventArgs(user)); } /// @@ -319,7 +314,7 @@ namespace Jellyfin.Server.Implementations.Users await GetAuthenticationProvider(user).ChangePassword(user, newPassword).ConfigureAwait(false); await UpdateUserAsync(user).ConfigureAwait(false); - OnUserPasswordChanged?.Invoke(this, new GenericEventArgs(user)); + await _eventManager.PublishAsync(new UserPasswordChangedEventArgs(user)).ConfigureAwait(false); } /// @@ -338,7 +333,7 @@ namespace Jellyfin.Server.Implementations.Users user.EasyPassword = newPasswordSha1; UpdateUser(user); - OnUserPasswordChanged?.Invoke(this, new GenericEventArgs(user)); + _eventManager.Publish(new UserPasswordChangedEventArgs(user)); } /// @@ -901,7 +896,7 @@ namespace Jellyfin.Server.Implementations.Users if (maxInvalidLogins.HasValue && user.InvalidLoginAttemptCount >= maxInvalidLogins) { user.SetPermission(PermissionKind.IsDisabled, true); - OnUserLockedOut?.Invoke(this, new GenericEventArgs(user)); + await _eventManager.PublishAsync(new UserLockedOutEventArgs(user)).ConfigureAwait(false); _logger.LogWarning( "Disabling user {Username} due to {Attempts} unsuccessful login attempts.", user.Username, diff --git a/MediaBrowser.Controller/Events/IEventManager.cs b/MediaBrowser.Controller/Events/IEventManager.cs index 794a8709e5..a1f40b3a6d 100644 --- a/MediaBrowser.Controller/Events/IEventManager.cs +++ b/MediaBrowser.Controller/Events/IEventManager.cs @@ -11,10 +11,18 @@ namespace MediaBrowser.Controller.Events /// /// Publishes an event. /// + /// the event arguments. + /// The type of event. + void Publish(T eventArgs) + where T : EventArgs; + + /// + /// Publishes an event asynchronously. + /// /// The event arguments. /// The type of event. /// A task representing the publishing of the event. - Task Publish(T eventArgs) + Task PublishAsync(T eventArgs) where T : EventArgs; } } diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index c8d8375b38..96a41920ab 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -19,26 +19,6 @@ namespace MediaBrowser.Controller.Library /// event EventHandler> OnUserUpdated; - /// - /// Occurs when a user is created. - /// - event EventHandler> OnUserCreated; - - /// - /// Occurs when a user is deleted. - /// - event EventHandler> OnUserDeleted; - - /// - /// Occurs when a user's password is changed. - /// - event EventHandler> OnUserPasswordChanged; - - /// - /// Occurs when a user is locked out. - /// - event EventHandler> OnUserLockedOut; - /// /// Gets the users. /// -- cgit v1.2.3 From 6f7d289feb6940afe1a266e8cec89c67b3b196ab Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 15:55:58 -0400 Subject: Create EventManager --- .../Events/EventManager.cs | 49 ++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Jellyfin.Server.Implementations/Events/EventManager.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Events/EventManager.cs b/Jellyfin.Server.Implementations/Events/EventManager.cs new file mode 100644 index 0000000000..d79b731063 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/EventManager.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading.Tasks; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Events; +using Microsoft.Extensions.DependencyInjection; + +namespace Jellyfin.Server.Implementations.Events +{ + /// + /// Handles the firing of events. + /// + public class EventManager : IEventManager + { + private readonly IServerApplicationHost _appHost; + + /// + /// Initializes a new instance of the class. + /// + /// The application host. + public EventManager(IServerApplicationHost appHost) + { + _appHost = appHost; + } + + /// + public void Publish(T eventArgs) + where T : EventArgs + { + Task.WaitAll(PublishInternal(eventArgs)); + } + + /// + public async Task PublishAsync(T eventArgs) + where T : EventArgs + { + await PublishInternal(eventArgs).ConfigureAwait(false); + } + + private async Task PublishInternal(T eventArgs) + where T : EventArgs + { + using var scope = _appHost.ServiceProvider.CreateScope(); + foreach (var service in scope.ServiceProvider.GetServices>()) + { + await service.OnEvent(eventArgs).ConfigureAwait(false); + } + } + } +} -- cgit v1.2.3 From 8b90e0205c5bbb1c2cddd1802ce74b153b24ba77 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 15:56:47 -0400 Subject: Add EventingServiceCollectionExtensions --- .../Events/EventingServiceCollectionExtensions.cs | 56 ++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs new file mode 100644 index 0000000000..1a43697b8a --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs @@ -0,0 +1,56 @@ +using Jellyfin.Data.Events; +using Jellyfin.Data.Events.Users; +using Jellyfin.Server.Implementations.Events.Consumers; +using Jellyfin.Server.Implementations.Events.Consumers.Library; +using Jellyfin.Server.Implementations.Events.Consumers.Security; +using Jellyfin.Server.Implementations.Events.Consumers.Session; +using Jellyfin.Server.Implementations.Events.Consumers.Updates; +using Jellyfin.Server.Implementations.Events.Consumers.Users; +using MediaBrowser.Common.Updates; +using MediaBrowser.Controller.Authentication; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Session; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Session; +using MediaBrowser.Controller.Subtitles; +using MediaBrowser.Model.Tasks; +using Microsoft.Extensions.DependencyInjection; + +namespace Jellyfin.Server.Implementations.Events +{ + /// + /// A class containing extensions to for eventing. + /// + public static class EventingServiceCollectionExtensions + { + /// + /// Adds the event services to the service collection. + /// + /// The service collection. + public static void AddEventServices(this IServiceCollection collection) + { + collection.AddScoped, SubtitleDownloadFailureLogger>(); + + collection.AddScoped>, AuthenticationSucceededLogger>(); + collection.AddScoped>, AuthenticationFailedLogger>(); + + collection.AddScoped, PlaybackStartLogger>(); + collection.AddScoped, PlaybackStopLogger>(); + collection.AddScoped, SessionStartedLogger>(); + collection.AddScoped, SessionEndedLogger>(); + + collection.AddScoped, PluginInstalledLogger>(); + collection.AddScoped, PluginUninstalledLogger>(); + collection.AddScoped, PluginUpdatedLogger>(); + collection.AddScoped, PackageInstallationFailedLogger>(); + + collection.AddScoped, UserCreatedLogger>(); + collection.AddScoped, UserDeletedLogger>(); + collection.AddScoped, UserLockedOutLogger>(); + collection.AddScoped, UserPasswordChangedLogger>(); + + collection.AddScoped, TaskCompletedLogger>(); + } + } +} -- cgit v1.2.3 From a0453a0fe65d19d0484cc83ce2f31b08dadcfd09 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 18:16:20 -0400 Subject: Migrate ServerEventNotifier.OnUserUpdated to IEventConsumer --- .../EntryPoints/ServerEventNotifier.cs | 44 ------ Jellyfin.Data/Events/Users/UserUpdatedEventArgs.cs | 18 +++ .../Events/Consumers/System/TaskCompletedLogger.cs | 158 +++++++++++++++++++++ .../Events/Consumers/TaskCompletedLogger.cs | 158 --------------------- .../Events/Consumers/Users/UserUpdatedNotifier.cs | 41 ++++++ .../Events/EventingServiceCollectionExtensions.cs | 4 +- 6 files changed, 220 insertions(+), 203 deletions(-) create mode 100644 Jellyfin.Data/Events/Users/UserUpdatedEventArgs.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs delete mode 100644 Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Users/UserUpdatedNotifier.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 1ec1f08683..0e50866851 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -1,16 +1,11 @@ using System; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; -using Jellyfin.Data.Events; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller; -using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Tasks; using MediaBrowser.Model.Updates; namespace Emby.Server.Implementations.EntryPoints @@ -20,11 +15,6 @@ namespace Emby.Server.Implementations.EntryPoints /// public class ServerEventNotifier : IServerEntryPoint { - /// - /// The user manager. - /// - private readonly IUserManager _userManager; - /// /// The installation manager. /// @@ -46,18 +36,15 @@ namespace Emby.Server.Implementations.EntryPoints /// Initializes a new instance of the class. /// /// The application host. - /// The user manager. /// The installation manager. /// The task manager. /// The session manager. public ServerEventNotifier( IServerApplicationHost appHost, - IUserManager userManager, IInstallationManager installationManager, ITaskManager taskManager, ISessionManager sessionManager) { - _userManager = userManager; _installationManager = installationManager; _appHost = appHost; _taskManager = taskManager; @@ -67,8 +54,6 @@ namespace Emby.Server.Implementations.EntryPoints /// public Task RunAsync() { - _userManager.OnUserUpdated += OnUserUpdated; - _appHost.HasPendingRestartChanged += OnHasPendingRestartChanged; _installationManager.PluginUninstalled += OnPluginUninstalled; @@ -127,18 +112,6 @@ namespace Emby.Server.Implementations.EntryPoints await _sessionManager.SendRestartRequiredNotification(CancellationToken.None).ConfigureAwait(false); } - /// - /// Users the manager_ user updated. - /// - /// The sender. - /// The e. - private async void OnUserUpdated(object sender, GenericEventArgs e) - { - var dto = _userManager.GetUserDto(e.Argument); - - await SendMessageToUserSession(e.Argument, "UserUpdated", dto).ConfigureAwait(false); - } - private async Task SendMessageToAdminSessions(string name, T data) { try @@ -150,21 +123,6 @@ namespace Emby.Server.Implementations.EntryPoints } } - private async Task SendMessageToUserSession(User user, string name, T data) - { - try - { - await _sessionManager.SendMessageToUserSessions( - new List { user.Id }, - name, - data, - CancellationToken.None).ConfigureAwait(false); - } - catch (Exception) - { - } - } - /// public void Dispose() { @@ -180,8 +138,6 @@ namespace Emby.Server.Implementations.EntryPoints { if (dispose) { - _userManager.OnUserUpdated -= OnUserUpdated; - _installationManager.PluginUninstalled -= OnPluginUninstalled; _installationManager.PackageInstalling -= OnPackageInstalling; _installationManager.PackageInstallationCancelled -= OnPackageInstallationCancelled; diff --git a/Jellyfin.Data/Events/Users/UserUpdatedEventArgs.cs b/Jellyfin.Data/Events/Users/UserUpdatedEventArgs.cs new file mode 100644 index 0000000000..2b4e49cdf6 --- /dev/null +++ b/Jellyfin.Data/Events/Users/UserUpdatedEventArgs.cs @@ -0,0 +1,18 @@ +using Jellyfin.Data.Entities; + +namespace Jellyfin.Data.Events.Users +{ + /// + /// An event that occurs when a user is updated. + /// + public class UserUpdatedEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The user. + public UserUpdatedEventArgs(User arg) : base(arg) + { + } + } +} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs new file mode 100644 index 0000000000..05201a3469 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedLogger.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Controller.Events; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; +using MediaBrowser.Model.Tasks; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Implementations.Events.Consumers.System +{ + /// + /// Creates an activity log entry whenever a task is completed. + /// + public class TaskCompletedLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public TaskCompletedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(TaskCompletionEventArgs e) + { + var result = e.Result; + var task = e.Task; + + if (task.ScheduledTask is IConfigurableScheduledTask activityTask + && !activityTask.IsLogged) + { + return; + } + + var time = result.EndTimeUtc - result.StartTimeUtc; + var runningTime = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("LabelRunningTimeValue"), + ToUserFriendlyString(time)); + + if (result.Status == TaskCompletionStatus.Failed) + { + var vals = new List(); + + if (!string.IsNullOrEmpty(e.Result.ErrorMessage)) + { + vals.Add(e.Result.ErrorMessage); + } + + if (!string.IsNullOrEmpty(e.Result.LongErrorMessage)) + { + vals.Add(e.Result.LongErrorMessage); + } + + await _activityManager.CreateAsync(new ActivityLog( + string.Format(CultureInfo.InvariantCulture, _localizationManager.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name), + NotificationType.TaskFailed.ToString(), + Guid.Empty) + { + LogSeverity = LogLevel.Error, + Overview = string.Join(Environment.NewLine, vals), + ShortOverview = runningTime + }).ConfigureAwait(false); + } + } + + private static string ToUserFriendlyString(TimeSpan span) + { + const int DaysInYear = 365; + const int DaysInMonth = 30; + + // Get each non-zero value from TimeSpan component + var values = new List(); + + // Number of years + int days = span.Days; + if (days >= DaysInYear) + { + int years = days / DaysInYear; + values.Add(CreateValueString(years, "year")); + days %= DaysInYear; + } + + // Number of months + if (days >= DaysInMonth) + { + int months = days / DaysInMonth; + values.Add(CreateValueString(months, "month")); + days = days % DaysInMonth; + } + + // Number of days + if (days >= 1) + { + values.Add(CreateValueString(days, "day")); + } + + // Number of hours + if (span.Hours >= 1) + { + values.Add(CreateValueString(span.Hours, "hour")); + } + + // Number of minutes + if (span.Minutes >= 1) + { + values.Add(CreateValueString(span.Minutes, "minute")); + } + + // Number of seconds (include when 0 if no other components included) + if (span.Seconds >= 1 || values.Count == 0) + { + values.Add(CreateValueString(span.Seconds, "second")); + } + + // Combine values into string + var builder = new StringBuilder(); + for (int i = 0; i < values.Count; i++) + { + if (builder.Length > 0) + { + builder.Append(i == values.Count - 1 ? " and " : ", "); + } + + builder.Append(values[i]); + } + + // Return result + return builder.ToString(); + } + + /// + /// Constructs a string description of a time-span value. + /// + /// The value of this item. + /// The name of this item (singular form). + private static string CreateValueString(int value, string description) + { + return string.Format( + CultureInfo.InvariantCulture, + "{0:#,##0} {1}", + value, + value == 1 ? description : string.Format(CultureInfo.InvariantCulture, "{0}s", description)); + } + } +} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs deleted file mode 100644 index 7f737ee7e6..0000000000 --- a/Jellyfin.Server.Implementations/Events/Consumers/TaskCompletedLogger.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text; -using System.Threading.Tasks; -using Jellyfin.Data.Entities; -using MediaBrowser.Controller.Events; -using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.Notifications; -using MediaBrowser.Model.Tasks; -using Microsoft.Extensions.Logging; - -namespace Jellyfin.Server.Implementations.Events.Consumers -{ - /// - /// Creates an activity log entry whenever a task is completed. - /// - public class TaskCompletedLogger : IEventConsumer - { - private readonly ILocalizationManager _localizationManager; - private readonly IActivityManager _activityManager; - - /// - /// Initializes a new instance of the class. - /// - /// The localization manager. - /// The activity manager. - public TaskCompletedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) - { - _localizationManager = localizationManager; - _activityManager = activityManager; - } - - /// - public async Task OnEvent(TaskCompletionEventArgs e) - { - var result = e.Result; - var task = e.Task; - - if (task.ScheduledTask is IConfigurableScheduledTask activityTask - && !activityTask.IsLogged) - { - return; - } - - var time = result.EndTimeUtc - result.StartTimeUtc; - var runningTime = string.Format( - CultureInfo.InvariantCulture, - _localizationManager.GetLocalizedString("LabelRunningTimeValue"), - ToUserFriendlyString(time)); - - if (result.Status == TaskCompletionStatus.Failed) - { - var vals = new List(); - - if (!string.IsNullOrEmpty(e.Result.ErrorMessage)) - { - vals.Add(e.Result.ErrorMessage); - } - - if (!string.IsNullOrEmpty(e.Result.LongErrorMessage)) - { - vals.Add(e.Result.LongErrorMessage); - } - - await _activityManager.CreateAsync(new ActivityLog( - string.Format(CultureInfo.InvariantCulture, _localizationManager.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name), - NotificationType.TaskFailed.ToString(), - Guid.Empty) - { - LogSeverity = LogLevel.Error, - Overview = string.Join(Environment.NewLine, vals), - ShortOverview = runningTime - }).ConfigureAwait(false); - } - } - - private static string ToUserFriendlyString(TimeSpan span) - { - const int DaysInYear = 365; - const int DaysInMonth = 30; - - // Get each non-zero value from TimeSpan component - var values = new List(); - - // Number of years - int days = span.Days; - if (days >= DaysInYear) - { - int years = days / DaysInYear; - values.Add(CreateValueString(years, "year")); - days %= DaysInYear; - } - - // Number of months - if (days >= DaysInMonth) - { - int months = days / DaysInMonth; - values.Add(CreateValueString(months, "month")); - days = days % DaysInMonth; - } - - // Number of days - if (days >= 1) - { - values.Add(CreateValueString(days, "day")); - } - - // Number of hours - if (span.Hours >= 1) - { - values.Add(CreateValueString(span.Hours, "hour")); - } - - // Number of minutes - if (span.Minutes >= 1) - { - values.Add(CreateValueString(span.Minutes, "minute")); - } - - // Number of seconds (include when 0 if no other components included) - if (span.Seconds >= 1 || values.Count == 0) - { - values.Add(CreateValueString(span.Seconds, "second")); - } - - // Combine values into string - var builder = new StringBuilder(); - for (int i = 0; i < values.Count; i++) - { - if (builder.Length > 0) - { - builder.Append(i == values.Count - 1 ? " and " : ", "); - } - - builder.Append(values[i]); - } - - // Return result - return builder.ToString(); - } - - /// - /// Constructs a string description of a time-span value. - /// - /// The value of this item. - /// The name of this item (singular form). - private static string CreateValueString(int value, string description) - { - return string.Format( - CultureInfo.InvariantCulture, - "{0:#,##0} {1}", - value, - value == 1 ? description : string.Format(CultureInfo.InvariantCulture, "{0}s", description)); - } - } -} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Users/UserUpdatedNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserUpdatedNotifier.cs new file mode 100644 index 0000000000..6081dd044f --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Users/UserUpdatedNotifier.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Data.Events.Users; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Session; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Users +{ + /// + /// Notifies a user when their account has been updated. + /// + public class UserUpdatedNotifier : IEventConsumer + { + private readonly IUserManager _userManager; + private readonly ISessionManager _sessionManager; + + /// + /// Initializes a new instance of the class. + /// + /// The user manager. + /// The session manager. + public UserUpdatedNotifier(IUserManager userManager, ISessionManager sessionManager) + { + _userManager = userManager; + _sessionManager = sessionManager; + } + + /// + public async Task OnEvent(UserUpdatedEventArgs e) + { + await _sessionManager.SendMessageToUserSessions( + new List { e.Argument.Id }, + "UserUpdated", + _userManager.GetUserDto(e.Argument), + CancellationToken.None).ConfigureAwait(false); + } + } +} diff --git a/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs index 1a43697b8a..84181f4fee 100644 --- a/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs +++ b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs @@ -1,9 +1,9 @@ using Jellyfin.Data.Events; using Jellyfin.Data.Events.Users; -using Jellyfin.Server.Implementations.Events.Consumers; using Jellyfin.Server.Implementations.Events.Consumers.Library; using Jellyfin.Server.Implementations.Events.Consumers.Security; using Jellyfin.Server.Implementations.Events.Consumers.Session; +using Jellyfin.Server.Implementations.Events.Consumers.System; using Jellyfin.Server.Implementations.Events.Consumers.Updates; using Jellyfin.Server.Implementations.Events.Consumers.Users; using MediaBrowser.Common.Updates; @@ -47,6 +47,8 @@ namespace Jellyfin.Server.Implementations.Events collection.AddScoped, UserCreatedLogger>(); collection.AddScoped, UserDeletedLogger>(); + collection.AddScoped, UserDeletedNotifier>(); + collection.AddScoped, UserUpdatedNotifier>(); collection.AddScoped, UserLockedOutLogger>(); collection.AddScoped, UserPasswordChangedLogger>(); -- cgit v1.2.3 From 5282a5c8c2224ec36121cdf99ef2a14f7d703973 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 18:16:41 -0400 Subject: Migrate ServerEventNotifier.OnTaskCompleted to IEventConsumer --- .../EntryPoints/ServerEventNotifier.cs | 17 ------------ .../Consumers/System/TaskCompletedNotifier.cs | 31 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 17 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedNotifier.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 0e50866851..833c061066 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -25,11 +25,6 @@ namespace Emby.Server.Implementations.EntryPoints /// private readonly IServerApplicationHost _appHost; - /// - /// The task manager. - /// - private readonly ITaskManager _taskManager; - private readonly ISessionManager _sessionManager; /// @@ -37,17 +32,14 @@ namespace Emby.Server.Implementations.EntryPoints /// /// The application host. /// The installation manager. - /// The task manager. /// The session manager. public ServerEventNotifier( IServerApplicationHost appHost, IInstallationManager installationManager, - ITaskManager taskManager, ISessionManager sessionManager) { _installationManager = installationManager; _appHost = appHost; - _taskManager = taskManager; _sessionManager = sessionManager; } @@ -62,8 +54,6 @@ namespace Emby.Server.Implementations.EntryPoints _installationManager.PackageInstallationCompleted += OnPackageInstallationCompleted; _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; - _taskManager.TaskCompleted += OnTaskCompleted; - return Task.CompletedTask; } @@ -87,11 +77,6 @@ namespace Emby.Server.Implementations.EntryPoints await SendMessageToAdminSessions("PackageInstallationFailed", e.InstallationInfo).ConfigureAwait(false); } - private async void OnTaskCompleted(object sender, TaskCompletionEventArgs e) - { - await SendMessageToAdminSessions("ScheduledTaskEnded", e.Result).ConfigureAwait(false); - } - /// /// Installations the manager_ plugin uninstalled. /// @@ -145,8 +130,6 @@ namespace Emby.Server.Implementations.EntryPoints _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; _appHost.HasPendingRestartChanged -= OnHasPendingRestartChanged; - - _taskManager.TaskCompleted -= OnTaskCompleted; } } } diff --git a/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedNotifier.cs new file mode 100644 index 0000000000..80ed56cd8f --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/System/TaskCompletedNotifier.cs @@ -0,0 +1,31 @@ +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Tasks; + +namespace Jellyfin.Server.Implementations.Events.Consumers.System +{ + /// + /// Notifies admin users when a task is completed. + /// + public class TaskCompletedNotifier : IEventConsumer + { + private readonly ISessionManager _sessionManager; + + /// + /// Initializes a new instance of the class. + /// + /// The session manager. + public TaskCompletedNotifier(ISessionManager sessionManager) + { + _sessionManager = sessionManager; + } + + /// + public async Task OnEvent(TaskCompletionEventArgs eventArgs) + { + await _sessionManager.SendMessageToAdminSessions("ScheduledTaskEnded", eventArgs.Result, CancellationToken.None).ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From dc88e93504a98a377881f7425ffba5d2221fada0 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 18:33:30 -0400 Subject: Migrate ServerEventNotifier.OnHasPendingRestartChanged to IEventConsumer --- .../EntryPoints/ServerEventNotifier.cs | 23 ---------------- .../Events/System/PendingRestartEventArgs.cs | 11 ++++++++ .../Consumers/System/PendingRestartNotifier.cs | 31 ++++++++++++++++++++++ 3 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 Jellyfin.Data/Events/System/PendingRestartEventArgs.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/System/PendingRestartNotifier.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 833c061066..3d58b91e1d 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -3,7 +3,6 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; -using MediaBrowser.Controller; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Updates; @@ -20,34 +19,24 @@ namespace Emby.Server.Implementations.EntryPoints /// private readonly IInstallationManager _installationManager; - /// - /// The kernel. - /// - private readonly IServerApplicationHost _appHost; - private readonly ISessionManager _sessionManager; /// /// Initializes a new instance of the class. /// - /// The application host. /// The installation manager. /// The session manager. public ServerEventNotifier( - IServerApplicationHost appHost, IInstallationManager installationManager, ISessionManager sessionManager) { _installationManager = installationManager; - _appHost = appHost; _sessionManager = sessionManager; } /// public Task RunAsync() { - _appHost.HasPendingRestartChanged += OnHasPendingRestartChanged; - _installationManager.PluginUninstalled += OnPluginUninstalled; _installationManager.PackageInstalling += OnPackageInstalling; _installationManager.PackageInstallationCancelled += OnPackageInstallationCancelled; @@ -87,16 +76,6 @@ namespace Emby.Server.Implementations.EntryPoints await SendMessageToAdminSessions("PluginUninstalled", e).ConfigureAwait(false); } - /// - /// Handles the HasPendingRestartChanged event of the kernel control. - /// - /// The source of the event. - /// The instance containing the event data. - private async void OnHasPendingRestartChanged(object sender, EventArgs e) - { - await _sessionManager.SendRestartRequiredNotification(CancellationToken.None).ConfigureAwait(false); - } - private async Task SendMessageToAdminSessions(string name, T data) { try @@ -128,8 +107,6 @@ namespace Emby.Server.Implementations.EntryPoints _installationManager.PackageInstallationCancelled -= OnPackageInstallationCancelled; _installationManager.PackageInstallationCompleted -= OnPackageInstallationCompleted; _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; - - _appHost.HasPendingRestartChanged -= OnHasPendingRestartChanged; } } } diff --git a/Jellyfin.Data/Events/System/PendingRestartEventArgs.cs b/Jellyfin.Data/Events/System/PendingRestartEventArgs.cs new file mode 100644 index 0000000000..17a4549699 --- /dev/null +++ b/Jellyfin.Data/Events/System/PendingRestartEventArgs.cs @@ -0,0 +1,11 @@ +using System; + +namespace Jellyfin.Data.Events.System +{ + /// + /// An event that fires when there is a pending restart. + /// + public class PendingRestartEventArgs : EventArgs + { + } +} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/System/PendingRestartNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/System/PendingRestartNotifier.cs new file mode 100644 index 0000000000..2fa38dd71a --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/System/PendingRestartNotifier.cs @@ -0,0 +1,31 @@ +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Data.Events.System; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Session; + +namespace Jellyfin.Server.Implementations.Events.Consumers.System +{ + /// + /// Notifies users when there is a pending restart. + /// + public class PendingRestartNotifier : IEventConsumer + { + private readonly ISessionManager _sessionManager; + + /// + /// Initializes a new instance of the class. + /// + /// The session manager. + public PendingRestartNotifier(ISessionManager sessionManager) + { + _sessionManager = sessionManager; + } + + /// + public async Task OnEvent(PendingRestartEventArgs eventArgs) + { + await _sessionManager.SendRestartRequiredNotification(CancellationToken.None).ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From b2f734efd127c04815d0a4799dd20449b96c501b Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 18:36:37 -0400 Subject: Gracefully handle exceptions in IEventConsumers --- Jellyfin.Server.Implementations/Events/EventManager.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Events/EventManager.cs b/Jellyfin.Server.Implementations/Events/EventManager.cs index d79b731063..7070024422 100644 --- a/Jellyfin.Server.Implementations/Events/EventManager.cs +++ b/Jellyfin.Server.Implementations/Events/EventManager.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace Jellyfin.Server.Implementations.Events { @@ -11,14 +12,17 @@ namespace Jellyfin.Server.Implementations.Events /// public class EventManager : IEventManager { + private readonly ILogger _logger; private readonly IServerApplicationHost _appHost; /// /// Initializes a new instance of the class. /// + /// The logger. /// The application host. - public EventManager(IServerApplicationHost appHost) + public EventManager(ILogger logger, IServerApplicationHost appHost) { + _logger = logger; _appHost = appHost; } @@ -42,7 +46,14 @@ namespace Jellyfin.Server.Implementations.Events using var scope = _appHost.ServiceProvider.CreateScope(); foreach (var service in scope.ServiceProvider.GetServices>()) { - await service.OnEvent(eventArgs).ConfigureAwait(false); + try + { + await service.OnEvent(eventArgs).ConfigureAwait(false); + } + catch (Exception e) + { + _logger.LogError(e, "Uncaught exception in EventConsumer {type}: ", service.GetType()); + } } } } -- cgit v1.2.3 From b7ceb40d6efe083653734e6417b2f5e48b522872 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 18:57:46 -0400 Subject: Migrate ServerEventNotifier.OnPackageInstalling to IEventConsumer --- .../EntryPoints/ServerEventNotifier.cs | 7 ----- .../Consumers/Updates/PluginInstallingNotifier.cs | 31 ++++++++++++++++++++++ .../Events/Updates/PluginInstallingEventArgs.cs | 19 +++++++++++++ 3 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs create mode 100644 MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 3d58b91e1d..068872420b 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -38,7 +38,6 @@ namespace Emby.Server.Implementations.EntryPoints public Task RunAsync() { _installationManager.PluginUninstalled += OnPluginUninstalled; - _installationManager.PackageInstalling += OnPackageInstalling; _installationManager.PackageInstallationCancelled += OnPackageInstallationCancelled; _installationManager.PackageInstallationCompleted += OnPackageInstallationCompleted; _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; @@ -46,11 +45,6 @@ namespace Emby.Server.Implementations.EntryPoints return Task.CompletedTask; } - private async void OnPackageInstalling(object sender, InstallationInfo e) - { - await SendMessageToAdminSessions("PackageInstalling", e).ConfigureAwait(false); - } - private async void OnPackageInstallationCancelled(object sender, InstallationInfo e) { await SendMessageToAdminSessions("PackageInstallationCancelled", e).ConfigureAwait(false); @@ -103,7 +97,6 @@ namespace Emby.Server.Implementations.EntryPoints if (dispose) { _installationManager.PluginUninstalled -= OnPluginUninstalled; - _installationManager.PackageInstalling -= OnPackageInstalling; _installationManager.PackageInstallationCancelled -= OnPackageInstallationCancelled; _installationManager.PackageInstallationCompleted -= OnPackageInstallationCompleted; _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs new file mode 100644 index 0000000000..f691d11a7d --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallingNotifier.cs @@ -0,0 +1,31 @@ +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Controller.Session; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// + /// Notifies admin users when a plugin is being installed. + /// + public class PluginInstallingNotifier : IEventConsumer + { + private readonly ISessionManager _sessionManager; + + /// + /// Initializes a new instance of the class. + /// + /// The session manager. + public PluginInstallingNotifier(ISessionManager sessionManager) + { + _sessionManager = sessionManager; + } + + /// + public async Task OnEvent(PluginInstallingEventArgs eventArgs) + { + await _sessionManager.SendMessageToAdminSessions("PackageInstalling", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs new file mode 100644 index 0000000000..045a600272 --- /dev/null +++ b/MediaBrowser.Controller/Events/Updates/PluginInstallingEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Model.Updates; + +namespace MediaBrowser.Controller.Events.Updates +{ + /// + /// An event that occurs when a plugin is installing. + /// + public class PluginInstallingEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The installation info. + public PluginInstallingEventArgs(InstallationInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From 4478945e20e0861c720a1035778f3f13be90226d Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 23:12:01 -0400 Subject: Migrate ServerEventNotifier.OnPluginUninstalled to IEventConsumer --- .../EntryPoints/ServerEventNotifier.cs | 13 --------- .../Consumers/Updates/PluginUninstalledNotifier.cs | 31 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledNotifier.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 068872420b..247bb87c75 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -1,7 +1,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; @@ -37,7 +36,6 @@ namespace Emby.Server.Implementations.EntryPoints /// public Task RunAsync() { - _installationManager.PluginUninstalled += OnPluginUninstalled; _installationManager.PackageInstallationCancelled += OnPackageInstallationCancelled; _installationManager.PackageInstallationCompleted += OnPackageInstallationCompleted; _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; @@ -60,16 +58,6 @@ namespace Emby.Server.Implementations.EntryPoints await SendMessageToAdminSessions("PackageInstallationFailed", e.InstallationInfo).ConfigureAwait(false); } - /// - /// Installations the manager_ plugin uninstalled. - /// - /// The sender. - /// The e. - private async void OnPluginUninstalled(object sender, IPlugin e) - { - await SendMessageToAdminSessions("PluginUninstalled", e).ConfigureAwait(false); - } - private async Task SendMessageToAdminSessions(string name, T data) { try @@ -96,7 +84,6 @@ namespace Emby.Server.Implementations.EntryPoints { if (dispose) { - _installationManager.PluginUninstalled -= OnPluginUninstalled; _installationManager.PackageInstallationCancelled -= OnPackageInstallationCancelled; _installationManager.PackageInstallationCompleted -= OnPackageInstallationCompleted; _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledNotifier.cs new file mode 100644 index 0000000000..709692f6bb --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginUninstalledNotifier.cs @@ -0,0 +1,31 @@ +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Controller.Session; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// + /// Notifies admin users when a plugin is uninstalled. + /// + public class PluginUninstalledNotifier : IEventConsumer + { + private readonly ISessionManager _sessionManager; + + /// + /// Initializes a new instance of the class. + /// + /// The session manager. + public PluginUninstalledNotifier(ISessionManager sessionManager) + { + _sessionManager = sessionManager; + } + + /// + public async Task OnEvent(PluginUninstalledEventArgs eventArgs) + { + await _sessionManager.SendMessageToAdminSessions("PluginUninstalled", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From 25437af594bbac517ab3a9bfef26e2b4af7ee899 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 23:12:34 -0400 Subject: Migrate ServerEventNotifier.OnPackageInstallationFailed to IEventConsumer --- .../EntryPoints/ServerEventNotifier.cs | 7 ----- .../Updates/PluginInstallationFailedNotifier.cs | 31 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedNotifier.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 247bb87c75..549e1d5690 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -38,7 +38,6 @@ namespace Emby.Server.Implementations.EntryPoints { _installationManager.PackageInstallationCancelled += OnPackageInstallationCancelled; _installationManager.PackageInstallationCompleted += OnPackageInstallationCompleted; - _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; return Task.CompletedTask; } @@ -53,11 +52,6 @@ namespace Emby.Server.Implementations.EntryPoints await SendMessageToAdminSessions("PackageInstallationCompleted", e).ConfigureAwait(false); } - private async void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e) - { - await SendMessageToAdminSessions("PackageInstallationFailed", e.InstallationInfo).ConfigureAwait(false); - } - private async Task SendMessageToAdminSessions(string name, T data) { try @@ -86,7 +80,6 @@ namespace Emby.Server.Implementations.EntryPoints { _installationManager.PackageInstallationCancelled -= OnPackageInstallationCancelled; _installationManager.PackageInstallationCompleted -= OnPackageInstallationCompleted; - _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; } } } diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedNotifier.cs new file mode 100644 index 0000000000..ea0c878d42 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedNotifier.cs @@ -0,0 +1,31 @@ +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.Updates; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Session; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// + /// Notifies admin users when a plugin installation fails. + /// + public class PluginInstallationFailedNotifier : IEventConsumer + { + private readonly ISessionManager _sessionManager; + + /// + /// Initializes a new instance of the class. + /// + /// The session manager. + public PluginInstallationFailedNotifier(ISessionManager sessionManager) + { + _sessionManager = sessionManager; + } + + /// + public async Task OnEvent(InstallationFailedEventArgs eventArgs) + { + await _sessionManager.SendMessageToAdminSessions("PackageInstallationFailed", eventArgs.InstallationInfo, CancellationToken.None).ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From e82dd8b70ee5fe1d09c7230a7de21f47456b8c55 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 23:16:15 -0400 Subject: Migrate ServerEventNotifier.OnPackageInstallationCompleted to IEventConsumer --- .../EntryPoints/ServerEventNotifier.cs | 7 ----- .../Consumers/Updates/PluginInstalledNotifier.cs | 31 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledNotifier.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs index 549e1d5690..1fbb9f3037 100644 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs @@ -37,7 +37,6 @@ namespace Emby.Server.Implementations.EntryPoints public Task RunAsync() { _installationManager.PackageInstallationCancelled += OnPackageInstallationCancelled; - _installationManager.PackageInstallationCompleted += OnPackageInstallationCompleted; return Task.CompletedTask; } @@ -47,11 +46,6 @@ namespace Emby.Server.Implementations.EntryPoints await SendMessageToAdminSessions("PackageInstallationCancelled", e).ConfigureAwait(false); } - private async void OnPackageInstallationCompleted(object sender, InstallationInfo e) - { - await SendMessageToAdminSessions("PackageInstallationCompleted", e).ConfigureAwait(false); - } - private async Task SendMessageToAdminSessions(string name, T data) { try @@ -79,7 +73,6 @@ namespace Emby.Server.Implementations.EntryPoints if (dispose) { _installationManager.PackageInstallationCancelled -= OnPackageInstallationCancelled; - _installationManager.PackageInstallationCompleted -= OnPackageInstallationCompleted; } } } diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledNotifier.cs new file mode 100644 index 0000000000..3dda5a04c4 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstalledNotifier.cs @@ -0,0 +1,31 @@ +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Controller.Session; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// + /// Notifies admin users when a plugin is installed. + /// + public class PluginInstalledNotifier : IEventConsumer + { + private readonly ISessionManager _sessionManager; + + /// + /// Initializes a new instance of the class. + /// + /// The session manager. + public PluginInstalledNotifier(ISessionManager sessionManager) + { + _sessionManager = sessionManager; + } + + /// + public async Task OnEvent(PluginInstalledEventArgs eventArgs) + { + await _sessionManager.SendMessageToAdminSessions("PackageInstallationCompleted", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false); + } + } +} -- cgit v1.2.3 From a40064a146da17a49582f7ef1ad754a497725ccc Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 23:20:41 -0400 Subject: Migrate ServerEventNotifier.OnPackageInstallationCancelled to IEventConsumer --- .../EntryPoints/ServerEventNotifier.cs | 79 ---------------------- .../Updates/PluginInstallationCancelledNotifier.cs | 31 +++++++++ .../PluginInstallationCancelledEventArgs.cs | 19 ++++++ 3 files changed, 50 insertions(+), 79 deletions(-) delete mode 100644 Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs create mode 100644 MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs deleted file mode 100644 index 1fbb9f3037..0000000000 --- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Updates; -using MediaBrowser.Controller.Plugins; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Updates; - -namespace Emby.Server.Implementations.EntryPoints -{ - /// - /// Class WebSocketEvents. - /// - public class ServerEventNotifier : IServerEntryPoint - { - /// - /// The installation manager. - /// - private readonly IInstallationManager _installationManager; - - private readonly ISessionManager _sessionManager; - - /// - /// Initializes a new instance of the class. - /// - /// The installation manager. - /// The session manager. - public ServerEventNotifier( - IInstallationManager installationManager, - ISessionManager sessionManager) - { - _installationManager = installationManager; - _sessionManager = sessionManager; - } - - /// - public Task RunAsync() - { - _installationManager.PackageInstallationCancelled += OnPackageInstallationCancelled; - - return Task.CompletedTask; - } - - private async void OnPackageInstallationCancelled(object sender, InstallationInfo e) - { - await SendMessageToAdminSessions("PackageInstallationCancelled", e).ConfigureAwait(false); - } - - private async Task SendMessageToAdminSessions(string name, T data) - { - try - { - await _sessionManager.SendMessageToAdminSessions(name, data, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception) - { - } - } - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - _installationManager.PackageInstallationCancelled -= OnPackageInstallationCancelled; - } - } - } -} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs new file mode 100644 index 0000000000..1c600683a9 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationCancelledNotifier.cs @@ -0,0 +1,31 @@ +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; +using MediaBrowser.Controller.Session; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// + /// Notifies admin users when a plugin installation is cancelled. + /// + public class PluginInstallationCancelledNotifier : IEventConsumer + { + private readonly ISessionManager _sessionManager; + + /// + /// Initializes a new instance of the class. + /// + /// The session manager. + public PluginInstallationCancelledNotifier(ISessionManager sessionManager) + { + _sessionManager = sessionManager; + } + + /// + public async Task OnEvent(PluginInstallationCancelledEventArgs eventArgs) + { + await _sessionManager.SendMessageToAdminSessions("PackageInstallationCancelled", eventArgs.Argument, CancellationToken.None).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs b/MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs new file mode 100644 index 0000000000..b06046c05a --- /dev/null +++ b/MediaBrowser.Controller/Events/Updates/PluginInstallationCancelledEventArgs.cs @@ -0,0 +1,19 @@ +using Jellyfin.Data.Events; +using MediaBrowser.Model.Updates; + +namespace MediaBrowser.Controller.Events.Updates +{ + /// + /// An event that occurs when a plugin installation is cancelled. + /// + public class PluginInstallationCancelledEventArgs : GenericEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The installation info. + public PluginInstallationCancelledEventArgs(InstallationInfo arg) : base(arg) + { + } + } +} -- cgit v1.2.3 From dcf97efaf8f24c8ee28c616c8f45263ccaa77b5c Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 23:22:26 -0400 Subject: Rename PackageInstallationFailedLogger to have more consistent naming. --- .../Updates/PackageInstallationFailedLogger.cs | 51 ---------------------- .../Updates/PluginInstallationFailedLogger.cs | 51 ++++++++++++++++++++++ .../Events/EventingServiceCollectionExtensions.cs | 2 +- 3 files changed, 52 insertions(+), 52 deletions(-) delete mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PackageInstallationFailedLogger.cs create mode 100644 Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PackageInstallationFailedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PackageInstallationFailedLogger.cs deleted file mode 100644 index 5d7296b3b7..0000000000 --- a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PackageInstallationFailedLogger.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Globalization; -using System.Threading.Tasks; -using Jellyfin.Data.Entities; -using MediaBrowser.Common.Updates; -using MediaBrowser.Controller.Events; -using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.Notifications; - -namespace Jellyfin.Server.Implementations.Events.Consumers.Updates -{ - /// - /// Creates an entry in the activity log when a package installation fails. - /// - public class PackageInstallationFailedLogger : IEventConsumer - { - private readonly ILocalizationManager _localizationManager; - private readonly IActivityManager _activityManager; - - /// - /// Initializes a new instance of the class. - /// - /// The localization manager. - /// The activity manager. - public PackageInstallationFailedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) - { - _localizationManager = localizationManager; - _activityManager = activityManager; - } - - /// - public async Task OnEvent(InstallationFailedEventArgs eventArgs) - { - await _activityManager.CreateAsync(new ActivityLog( - string.Format( - CultureInfo.InvariantCulture, - _localizationManager.GetLocalizedString("NameInstallFailed"), - eventArgs.InstallationInfo.Name), - NotificationType.InstallationFailed.ToString(), - Guid.Empty) - { - ShortOverview = string.Format( - CultureInfo.InvariantCulture, - _localizationManager.GetLocalizedString("VersionNumber"), - eventArgs.InstallationInfo.Version), - Overview = eventArgs.Exception.Message - }).ConfigureAwait(false); - } - } -} diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs new file mode 100644 index 0000000000..d71c298c54 --- /dev/null +++ b/Jellyfin.Server.Implementations/Events/Consumers/Updates/PluginInstallationFailedLogger.cs @@ -0,0 +1,51 @@ +using System; +using System.Globalization; +using System.Threading.Tasks; +using Jellyfin.Data.Entities; +using MediaBrowser.Common.Updates; +using MediaBrowser.Controller.Events; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; + +namespace Jellyfin.Server.Implementations.Events.Consumers.Updates +{ + /// + /// Creates an entry in the activity log when a package installation fails. + /// + public class PluginInstallationFailedLogger : IEventConsumer + { + private readonly ILocalizationManager _localizationManager; + private readonly IActivityManager _activityManager; + + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. + /// The activity manager. + public PluginInstallationFailedLogger(ILocalizationManager localizationManager, IActivityManager activityManager) + { + _localizationManager = localizationManager; + _activityManager = activityManager; + } + + /// + public async Task OnEvent(InstallationFailedEventArgs eventArgs) + { + await _activityManager.CreateAsync(new ActivityLog( + string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("NameInstallFailed"), + eventArgs.InstallationInfo.Name), + NotificationType.InstallationFailed.ToString(), + Guid.Empty) + { + ShortOverview = string.Format( + CultureInfo.InvariantCulture, + _localizationManager.GetLocalizedString("VersionNumber"), + eventArgs.InstallationInfo.Version), + Overview = eventArgs.Exception.Message + }).ConfigureAwait(false); + } + } +} diff --git a/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs index 84181f4fee..de9dc08afa 100644 --- a/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs +++ b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs @@ -43,7 +43,7 @@ namespace Jellyfin.Server.Implementations.Events collection.AddScoped, PluginInstalledLogger>(); collection.AddScoped, PluginUninstalledLogger>(); collection.AddScoped, PluginUpdatedLogger>(); - collection.AddScoped, PackageInstallationFailedLogger>(); + collection.AddScoped, PluginInstallationFailedLogger>(); collection.AddScoped, UserCreatedLogger>(); collection.AddScoped, UserDeletedLogger>(); -- cgit v1.2.3 From 075ae53d831abdb4eb72aa7da575058a51d36753 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 15 Aug 2020 23:27:51 -0400 Subject: Register new IEventConsumer services. --- .../Events/EventingServiceCollectionExtensions.cs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs index de9dc08afa..517d4c27bd 100644 --- a/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs +++ b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs @@ -40,10 +40,15 @@ namespace Jellyfin.Server.Implementations.Events collection.AddScoped, SessionStartedLogger>(); collection.AddScoped, SessionEndedLogger>(); + collection.AddScoped, PluginInstallingNotifier>(); collection.AddScoped, PluginInstalledLogger>(); + collection.AddScoped, PluginInstalledNotifier>(); collection.AddScoped, PluginUninstalledLogger>(); + collection.AddScoped, PluginUninstalledNotifier>(); collection.AddScoped, PluginUpdatedLogger>(); collection.AddScoped, PluginInstallationFailedLogger>(); + collection.AddScoped, PluginInstallationFailedNotifier>(); + collection.AddScoped, PluginInstallationCancelledNotifier>(); collection.AddScoped, UserCreatedLogger>(); collection.AddScoped, UserDeletedLogger>(); -- cgit v1.2.3 From 6f88087fa9ef27b6f052ee632c4dbf5f18b78b0b Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Mon, 17 Aug 2020 21:42:59 -0400 Subject: Use index access instead of LINQ. --- .../Events/Consumers/Session/PlaybackStartLogger.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs index c48683ea38..ec4a76e7ff 100644 --- a/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs +++ b/Jellyfin.Server.Implementations/Events/Consumers/Session/PlaybackStartLogger.cs @@ -1,6 +1,5 @@ using System; using System.Globalization; -using System.Linq; using System.Threading.Tasks; using Jellyfin.Data.Entities; using MediaBrowser.Controller.Events; @@ -56,7 +55,7 @@ namespace Jellyfin.Server.Implementations.Events.Consumers.Session return; } - var user = eventArgs.Users.First(); + var user = eventArgs.Users[0]; await _activityManager.CreateAsync(new ActivityLog( string.Format( -- cgit v1.2.3 From ee7beed804a23e1f4ef180ab17a0c99b47401caa Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Mon, 17 Aug 2020 21:47:49 -0400 Subject: Comment and reorder service registration. --- .../Events/EventingServiceCollectionExtensions.cs | 27 ++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs index 517d4c27bd..5d558189b1 100644 --- a/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs +++ b/Jellyfin.Server.Implementations/Events/EventingServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ using Jellyfin.Data.Events; +using Jellyfin.Data.Events.System; using Jellyfin.Data.Events.Users; using Jellyfin.Server.Implementations.Events.Consumers.Library; using Jellyfin.Server.Implementations.Events.Consumers.Security; @@ -30,34 +31,42 @@ namespace Jellyfin.Server.Implementations.Events /// The service collection. public static void AddEventServices(this IServiceCollection collection) { + // Library consumers collection.AddScoped, SubtitleDownloadFailureLogger>(); - collection.AddScoped>, AuthenticationSucceededLogger>(); + // Security consumers collection.AddScoped>, AuthenticationFailedLogger>(); + collection.AddScoped>, AuthenticationSucceededLogger>(); + // Session consumers collection.AddScoped, PlaybackStartLogger>(); collection.AddScoped, PlaybackStopLogger>(); - collection.AddScoped, SessionStartedLogger>(); collection.AddScoped, SessionEndedLogger>(); + collection.AddScoped, SessionStartedLogger>(); - collection.AddScoped, PluginInstallingNotifier>(); + // System consumers + collection.AddScoped, PendingRestartNotifier>(); + collection.AddScoped, TaskCompletedLogger>(); + collection.AddScoped, TaskCompletedNotifier>(); + + // Update consumers + collection.AddScoped, PluginInstallationCancelledNotifier>(); + collection.AddScoped, PluginInstallationFailedLogger>(); + collection.AddScoped, PluginInstallationFailedNotifier>(); collection.AddScoped, PluginInstalledLogger>(); collection.AddScoped, PluginInstalledNotifier>(); + collection.AddScoped, PluginInstallingNotifier>(); collection.AddScoped, PluginUninstalledLogger>(); collection.AddScoped, PluginUninstalledNotifier>(); collection.AddScoped, PluginUpdatedLogger>(); - collection.AddScoped, PluginInstallationFailedLogger>(); - collection.AddScoped, PluginInstallationFailedNotifier>(); - collection.AddScoped, PluginInstallationCancelledNotifier>(); + // User consumers collection.AddScoped, UserCreatedLogger>(); collection.AddScoped, UserDeletedLogger>(); collection.AddScoped, UserDeletedNotifier>(); - collection.AddScoped, UserUpdatedNotifier>(); collection.AddScoped, UserLockedOutLogger>(); collection.AddScoped, UserPasswordChangedLogger>(); - - collection.AddScoped, TaskCompletedLogger>(); + collection.AddScoped, UserUpdatedNotifier>(); } } } -- cgit v1.2.3 From fa8892fde4282906f4522f033aa88e15b4397a03 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Mon, 24 Aug 2020 20:27:10 -0400 Subject: Make LibraryController.GetDownload async --- Jellyfin.Api/Controllers/LibraryController.cs | 10 +++++----- Jellyfin.Server.Implementations/Activity/ActivityManager.cs | 10 ---------- MediaBrowser.Model/Activity/IActivityManager.cs | 2 -- 3 files changed, 5 insertions(+), 17 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 4548e202a0..796d2d8aa0 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -619,7 +619,7 @@ namespace Jellyfin.Api.Controllers [Authorize(Policy = Policies.Download)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult GetDownload([FromRoute] Guid itemId) + public async Task GetDownload([FromRoute] Guid itemId) { var item = _libraryManager.GetItemById(itemId); if (item == null) @@ -648,7 +648,7 @@ namespace Jellyfin.Api.Controllers if (user != null) { - LogDownload(item, user, auth); + await LogDownloadAsync(item, user, auth).ConfigureAwait(false); } var path = item.Path; @@ -861,17 +861,17 @@ namespace Jellyfin.Api.Controllers : item; } - private void LogDownload(BaseItem item, User user, AuthorizationInfo auth) + private async Task LogDownloadAsync(BaseItem item, User user, AuthorizationInfo auth) { try { - _activityManager.Create(new ActivityLog( + await _activityManager.CreateAsync(new ActivityLog( string.Format(CultureInfo.InvariantCulture, _localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Username, item.Name), "UserDownloadingContent", auth.UserId) { ShortOverview = string.Format(CultureInfo.InvariantCulture, _localization.GetLocalizedString("AppDeviceValues"), auth.Client, auth.Device), - }); + }).ConfigureAwait(false); } catch { diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs index 2deefbe819..bd285f6f15 100644 --- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs +++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs @@ -27,16 +27,6 @@ namespace Jellyfin.Server.Implementations.Activity /// public event EventHandler> EntryCreated; - /// - public void Create(ActivityLog entry) - { - using var dbContext = _provider.CreateContext(); - dbContext.ActivityLogs.Add(entry); - dbContext.SaveChanges(); - - EntryCreated?.Invoke(this, new GenericEventArgs(ConvertToOldModel(entry))); - } - /// public async Task CreateAsync(ActivityLog entry) { diff --git a/MediaBrowser.Model/Activity/IActivityManager.cs b/MediaBrowser.Model/Activity/IActivityManager.cs index 9dab5e77b7..e5e7b0763c 100644 --- a/MediaBrowser.Model/Activity/IActivityManager.cs +++ b/MediaBrowser.Model/Activity/IActivityManager.cs @@ -13,8 +13,6 @@ namespace MediaBrowser.Model.Activity { event EventHandler> EntryCreated; - void Create(ActivityLog entry); - Task CreateAsync(ActivityLog entry); QueryResult GetPagedResult(int? startIndex, int? limit); -- cgit v1.2.3 From ec8967b8e6f201db84139c6ea96cc1769c2416ff Mon Sep 17 00:00:00 2001 From: crobibero Date: Thu, 27 Aug 2020 10:00:06 -0600 Subject: Fix partial library and channel access --- Jellyfin.Server.Implementations/Users/UserManager.cs | 12 ++++++------ Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs | 6 ++++-- MediaBrowser.Model/Users/UserPolicy.cs | 12 ++++++------ 3 files changed, 16 insertions(+), 14 deletions(-) (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs index 3e8edeb442..8f04baa089 100644 --- a/Jellyfin.Server.Implementations/Users/UserManager.cs +++ b/Jellyfin.Server.Implementations/Users/UserManager.cs @@ -402,13 +402,13 @@ namespace Jellyfin.Server.Implementations.Users EnablePublicSharing = user.HasPermission(PermissionKind.EnablePublicSharing), AccessSchedules = user.AccessSchedules.ToArray(), BlockedTags = user.GetPreference(PreferenceKind.BlockedTags), - EnabledChannels = user.GetPreference(PreferenceKind.EnabledChannels), + EnabledChannels = user.GetPreference(PreferenceKind.EnabledChannels)?.Select(Guid.Parse).ToArray(), EnabledDevices = user.GetPreference(PreferenceKind.EnabledDevices), - EnabledFolders = user.GetPreference(PreferenceKind.EnabledFolders), + EnabledFolders = user.GetPreference(PreferenceKind.EnabledFolders)?.Select(Guid.Parse).ToArray(), EnableContentDeletionFromFolders = user.GetPreference(PreferenceKind.EnableContentDeletionFromFolders), SyncPlayAccess = user.SyncPlayAccess, - BlockedChannels = user.GetPreference(PreferenceKind.BlockedChannels), - BlockedMediaFolders = user.GetPreference(PreferenceKind.BlockedMediaFolders), + BlockedChannels = user.GetPreference(PreferenceKind.BlockedChannels)?.Select(Guid.Parse).ToArray(), + BlockedMediaFolders = user.GetPreference(PreferenceKind.BlockedMediaFolders)?.Select(Guid.Parse).ToArray(), BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems).Select(Enum.Parse).ToArray() } }; @@ -735,9 +735,9 @@ namespace Jellyfin.Server.Implementations.Users PreferenceKind.BlockUnratedItems, policy.BlockUnratedItems?.Select(i => i.ToString()).ToArray() ?? Array.Empty()); user.SetPreference(PreferenceKind.BlockedTags, policy.BlockedTags); - user.SetPreference(PreferenceKind.EnabledChannels, policy.EnabledChannels); + user.SetPreference(PreferenceKind.EnabledChannels, policy.EnabledChannels?.Select(i => i.ToString("N", CultureInfo.InvariantCulture)).ToArray()); user.SetPreference(PreferenceKind.EnabledDevices, policy.EnabledDevices); - user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders); + user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders?.Select(i => i.ToString("N", CultureInfo.InvariantCulture)).ToArray()); user.SetPreference(PreferenceKind.EnableContentDeletionFromFolders, policy.EnableContentDeletionFromFolders); dbContext.Update(user); diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs index ac6890f386..74c5503314 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs @@ -1,5 +1,7 @@ using System; +using System.Globalization; using System.IO; +using System.Linq; using Emby.Server.Implementations.Data; using Emby.Server.Implementations.Serialization; using Jellyfin.Data.Entities; @@ -166,9 +168,9 @@ namespace Jellyfin.Server.Migrations.Routines } user.SetPreference(PreferenceKind.BlockedTags, policy.BlockedTags); - user.SetPreference(PreferenceKind.EnabledChannels, policy.EnabledChannels); + user.SetPreference(PreferenceKind.EnabledChannels, policy.EnabledChannels?.Select(i => i.ToString("N", CultureInfo.InvariantCulture)).ToArray()); user.SetPreference(PreferenceKind.EnabledDevices, policy.EnabledDevices); - user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders); + user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders?.Select(i => i.ToString("N", CultureInfo.InvariantCulture)).ToArray()); user.SetPreference(PreferenceKind.EnableContentDeletionFromFolders, policy.EnableContentDeletionFromFolders); user.SetPreference(PreferenceKind.OrderedViews, config.OrderedViews); user.SetPreference(PreferenceKind.GroupedFolders, config.GroupedFolders); diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index caf2e0f549..a1f01f7e8e 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -80,11 +80,11 @@ namespace MediaBrowser.Model.Users public bool EnableAllDevices { get; set; } - public string[] EnabledChannels { get; set; } + public Guid[] EnabledChannels { get; set; } public bool EnableAllChannels { get; set; } - public string[] EnabledFolders { get; set; } + public Guid[] EnabledFolders { get; set; } public bool EnableAllFolders { get; set; } @@ -94,9 +94,9 @@ namespace MediaBrowser.Model.Users public bool EnablePublicSharing { get; set; } - public string[] BlockedMediaFolders { get; set; } + public Guid[] BlockedMediaFolders { get; set; } - public string[] BlockedChannels { get; set; } + public Guid[] BlockedChannels { get; set; } public int RemoteClientBitrateLimit { get; set; } @@ -145,10 +145,10 @@ namespace MediaBrowser.Model.Users LoginAttemptsBeforeLockout = -1; EnableAllChannels = true; - EnabledChannels = Array.Empty(); + EnabledChannels = Array.Empty(); EnableAllFolders = true; - EnabledFolders = Array.Empty(); + EnabledFolders = Array.Empty(); EnabledDevices = Array.Empty(); EnableAllDevices = true; -- cgit v1.2.3 From acb213e4b8edf1c55f615fa8d0079f0fb7fdea68 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sun, 30 Aug 2020 18:50:54 -0400 Subject: First pass at cleaning entity classes. - Documents all library entities - Fixes styling warnings for library entities - Updates library entities to inherit from interfaces - Makes library entites no longer partial. --- Jellyfin.Data/Entities/ActivityLog.cs | 3 +- Jellyfin.Data/Entities/Group.cs | 3 +- Jellyfin.Data/Entities/Libraries/Artwork.cs | 203 ++--------- Jellyfin.Data/Entities/Libraries/Book.cs | 62 +--- Jellyfin.Data/Entities/Libraries/BookMetadata.cs | 120 ++----- Jellyfin.Data/Entities/Libraries/Chapter.cs | 257 +++----------- Jellyfin.Data/Entities/Libraries/Collection.cs | 112 ++---- Jellyfin.Data/Entities/Libraries/CollectionItem.cs | 152 +++----- Jellyfin.Data/Entities/Libraries/Company.cs | 156 ++------ .../Entities/Libraries/CompanyMetadata.cs | 226 ++---------- Jellyfin.Data/Entities/Libraries/CustomItem.cs | 61 +--- .../Entities/Libraries/CustomItemMetadata.cs | 77 +--- Jellyfin.Data/Entities/Libraries/Episode.cs | 114 ++---- .../Entities/Libraries/EpisodeMetadata.cs | 191 ++-------- Jellyfin.Data/Entities/Libraries/Genre.cs | 147 ++------ Jellyfin.Data/Entities/Libraries/Library.cs | 143 ++------ Jellyfin.Data/Entities/Libraries/LibraryItem.cs | 164 ++------- Jellyfin.Data/Entities/Libraries/LibraryRoot.cs | 199 ----------- Jellyfin.Data/Entities/Libraries/MediaFile.cs | 200 +++-------- .../Entities/Libraries/MediaFileStream.cs | 144 ++------ Jellyfin.Data/Entities/Libraries/Metadata.cs | 392 +++++---------------- .../Entities/Libraries/MetadataProvider.cs | 134 ++----- .../Entities/Libraries/MetadataProviderId.cs | 194 ++-------- Jellyfin.Data/Entities/Libraries/Movie.cs | 64 +--- Jellyfin.Data/Entities/Libraries/MovieMetadata.cs | 249 +++---------- Jellyfin.Data/Entities/Libraries/MusicAlbum.cs | 60 +--- .../Entities/Libraries/MusicAlbumMetadata.cs | 204 ++--------- Jellyfin.Data/Entities/Libraries/Person.cs | 308 +++------------- Jellyfin.Data/Entities/Libraries/PersonRole.cs | 215 +++-------- Jellyfin.Data/Entities/Libraries/Photo.cs | 61 +--- Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs | 79 +---- Jellyfin.Data/Entities/Libraries/Rating.cs | 186 ++-------- Jellyfin.Data/Entities/Libraries/RatingSource.cs | 227 +++--------- Jellyfin.Data/Entities/Libraries/Release.cs | 211 ++--------- Jellyfin.Data/Entities/Libraries/Season.cs | 114 ++---- Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs | 115 ++---- Jellyfin.Data/Entities/Libraries/Series.cs | 153 +------- Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs | 241 +++---------- Jellyfin.Data/Entities/Libraries/Track.cs | 116 ++---- Jellyfin.Data/Entities/Libraries/TrackMetadata.cs | 77 +--- Jellyfin.Data/Entities/Permission.cs | 3 +- Jellyfin.Data/Entities/Preference.cs | 3 +- Jellyfin.Data/Entities/User.cs | 3 +- Jellyfin.Data/IHasPermissions.cs | 31 -- Jellyfin.Data/ISavingChanges.cs | 9 - Jellyfin.Data/Interfaces/IHasArtwork.cs | 16 + Jellyfin.Data/Interfaces/IHasCompanies.cs | 16 + Jellyfin.Data/Interfaces/IHasConcurrencyToken.cs | 18 + Jellyfin.Data/Interfaces/IHasPermissions.cs | 31 ++ Jellyfin.Data/Interfaces/IHasReleases.cs | 16 + Jellyfin.Server.Implementations/JellyfinDb.cs | 4 +- 51 files changed, 1203 insertions(+), 5081 deletions(-) delete mode 100644 Jellyfin.Data/Entities/Libraries/LibraryRoot.cs delete mode 100644 Jellyfin.Data/IHasPermissions.cs delete mode 100644 Jellyfin.Data/ISavingChanges.cs create mode 100644 Jellyfin.Data/Interfaces/IHasArtwork.cs create mode 100644 Jellyfin.Data/Interfaces/IHasCompanies.cs create mode 100644 Jellyfin.Data/Interfaces/IHasConcurrencyToken.cs create mode 100644 Jellyfin.Data/Interfaces/IHasPermissions.cs create mode 100644 Jellyfin.Data/Interfaces/IHasReleases.cs (limited to 'Jellyfin.Server.Implementations') diff --git a/Jellyfin.Data/Entities/ActivityLog.cs b/Jellyfin.Data/Entities/ActivityLog.cs index ac61b9e3ba..3858916d15 100644 --- a/Jellyfin.Data/Entities/ActivityLog.cs +++ b/Jellyfin.Data/Entities/ActivityLog.cs @@ -3,6 +3,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; using Microsoft.Extensions.Logging; namespace Jellyfin.Data.Entities @@ -10,7 +11,7 @@ namespace Jellyfin.Data.Entities /// /// An entity referencing an activity log entry. /// - public partial class ActivityLog : ISavingChanges + public partial class ActivityLog : IHasConcurrencyToken { /// /// Initializes a new instance of the class. diff --git a/Jellyfin.Data/Entities/Group.cs b/Jellyfin.Data/Entities/Group.cs index a1ec6b1fa4..ca12ba4213 100644 --- a/Jellyfin.Data/Entities/Group.cs +++ b/Jellyfin.Data/Entities/Group.cs @@ -6,13 +6,14 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities { /// /// An entity representing a group. /// - public partial class Group : IHasPermissions, ISavingChanges + public partial class Group : IHasPermissions, IHasConcurrencyToken { /// /// Initializes a new instance of the class. diff --git a/Jellyfin.Data/Entities/Libraries/Artwork.cs b/Jellyfin.Data/Entities/Libraries/Artwork.cs index 2a34a8dff1..7be22af254 100644 --- a/Jellyfin.Data/Entities/Libraries/Artwork.cs +++ b/Jellyfin.Data/Entities/Libraries/Artwork.cs @@ -1,210 +1,81 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Artwork + /// + /// An entity representing artwork. + /// + public class Artwork : IHasConcurrencyToken { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected Artwork() - { - Init(); - } - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. + /// Initializes a new instance of the class. /// - public static Artwork CreateArtworkUnsafe() - { - return new Artwork(); - } - - /// - /// Public constructor with required data. - /// - /// - /// - /// - /// - public Artwork(string path, Enums.ArtKind kind, Metadata _metadata0, PersonRole _personrole1) + /// The path. + /// The kind of art. + /// The owner. + public Artwork(string path, ArtKind kind, IHasArtwork owner) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } - this.Path = path; - - this.Kind = kind; - - if (_metadata0 == null) - { - throw new ArgumentNullException(nameof(_metadata0)); - } - - _metadata0.Artwork.Add(this); + Path = path; + Kind = kind; - if (_personrole1 == null) - { - throw new ArgumentNullException(nameof(_personrole1)); - } - - _personrole1.Artwork = this; - - Init(); + owner?.Artwork.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - /// - /// - /// - public static Artwork Create(string path, Enums.ArtKind kind, Metadata _metadata0, PersonRole _personrole1) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected Artwork() { - return new Artwork(path, kind, _metadata0, _personrole1); } - /************************************************************************* - * Properties - *************************************************************************/ - /// - /// Backing field for Id. + /// Gets or sets the id. /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } - - /// - /// Backing field for Path. - /// - protected string _Path; - /// - /// When provided in a partial class, allows value of Path to be changed before setting. - /// - partial void SetPath(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Path to be changed before returning. - /// - partial void GetPath(ref string result); + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; protected set; } /// - /// Required, Max length = 65535 + /// Gets or sets the path. /// + /// + /// Required, Max length = 65535. + /// [Required] [MaxLength(65535)] [StringLength(65535)] - public string Path - { - get - { - string value = _Path; - GetPath(ref value); - return _Path = value; - } + public string Path { get; set; } - set - { - string oldValue = _Path; - SetPath(oldValue, ref value); - if (oldValue != value) - { - _Path = value; - } - } - } - - /// - /// Backing field for Kind. - /// - internal Enums.ArtKind _Kind; /// - /// When provided in a partial class, allows value of Kind to be changed before setting. + /// Gets or sets the kind of artwork. /// - partial void SetKind(Enums.ArtKind oldValue, ref Enums.ArtKind newValue); - /// - /// When provided in a partial class, allows value of Kind to be changed before returning. - /// - partial void GetKind(ref Enums.ArtKind result); - - /// - /// Indexed, Required. - /// - [Required] - public Enums.ArtKind Kind - { - get - { - Enums.ArtKind value = _Kind; - GetKind(ref value); - return _Kind = value; - } + /// + /// Required. + /// + public ArtKind Kind { get; set; } - set - { - Enums.ArtKind oldValue = _Kind; - SetKind(oldValue, ref value); - if (oldValue != value) - { - _Kind = value; - } - } - } - - /// - /// Required, ConcurrenyToken. - /// + /// [ConcurrencyCheck] - [Required] public uint RowVersion { get; set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ } } - diff --git a/Jellyfin.Data/Entities/Libraries/Book.cs b/Jellyfin.Data/Entities/Libraries/Book.cs index 1ddc5ce8b1..8337788ddd 100644 --- a/Jellyfin.Data/Entities/Libraries/Book.cs +++ b/Jellyfin.Data/Entities/Libraries/Book.cs @@ -1,72 +1,28 @@ -#pragma warning disable CS1591 - -using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Book : LibraryItem + /// + /// An entity representing a book. + /// + public class Book : LibraryItem, IHasReleases { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected Book() + public Book() { BookMetadata = new HashSet(); Releases = new HashSet(); - - Init(); } /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. + /// Gets or sets a collection containing the metadata for this book. /// - public static Book CreateBookUnsafe() - { - return new Book(); - } - - /// - /// Public constructor with required data. - /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public Book(Guid urlid, DateTime dateadded) - { - this.UrlId = urlid; - - this.BookMetadata = new HashSet(); - this.Releases = new HashSet(); - - Init(); - } - - /// - /// Static create function (for use in LINQ queries, etc.) - /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public static Book Create(Guid urlid, DateTime dateadded) - { - return new Book(urlid, dateadded); - } - - /************************************************************************* - * Properties - *************************************************************************/ - - /************************************************************************* - * Navigation properties - *************************************************************************/ - - [ForeignKey("BookMetadata_BookMetadata_Id")] public virtual ICollection BookMetadata { get; protected set; } - [ForeignKey("Release_Releases_Id")] + /// public virtual ICollection Releases { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs b/Jellyfin.Data/Entities/Libraries/BookMetadata.cs index 91eecbbf99..bd716712b1 100644 --- a/Jellyfin.Data/Entities/Libraries/BookMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/BookMetadata.cs @@ -1,125 +1,55 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class BookMetadata : Metadata + /// + /// An entity containing metadata for a book. + /// + public class BookMetadata : Metadata, IHasCompanies { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected BookMetadata() - { - Publishers = new HashSet(); - - Init(); - } - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static BookMetadata CreateBookMetadataUnsafe() - { - return new BookMetadata(); - } - - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// /// The title or name of the object. /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public BookMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Book _book0) + /// The book. + public BookMetadata(string title, string language, Book book) : base(title, language) { - if (string.IsNullOrEmpty(title)) - { - throw new ArgumentNullException(nameof(title)); - } - - this.Title = title; - - if (string.IsNullOrEmpty(language)) - { - throw new ArgumentNullException(nameof(language)); - } - - this.Language = language; - - if (_book0 == null) + if (book == null) { - throw new ArgumentNullException(nameof(_book0)); + throw new ArgumentNullException(nameof(book)); } - _book0.BookMetadata.Add(this); - - this.Publishers = new HashSet(); + book.BookMetadata.Add(this); - Init(); + Publishers = new HashSet(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public static BookMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Book _book0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected BookMetadata() { - return new BookMetadata(title, language, dateadded, datemodified, _book0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for ISBN. - /// - protected long? _ISBN; /// - /// When provided in a partial class, allows value of ISBN to be changed before setting. + /// Gets or sets the ISBN. /// - partial void SetISBN(long? oldValue, ref long? newValue); + public long? Isbn { get; set; } + /// - /// When provided in a partial class, allows value of ISBN to be changed before returning. + /// Gets or sets a collection of the publishers for this book. /// - partial void GetISBN(ref long? result); - - public long? ISBN - { - get - { - long? value = _ISBN; - GetISBN(ref value); - return _ISBN = value; - } - - set - { - long? oldValue = _ISBN; - SetISBN(oldValue, ref value); - if (oldValue != value) - { - _ISBN = value; - } - } - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - - [ForeignKey("Company_Publishers_Id")] public virtual ICollection Publishers { get; protected set; } + + /// + [NotMapped] + public ICollection Companies => Publishers; } } - diff --git a/Jellyfin.Data/Entities/Libraries/Chapter.cs b/Jellyfin.Data/Entities/Libraries/Chapter.cs index 2f36443183..d9293c3cc4 100644 --- a/Jellyfin.Data/Entities/Libraries/Chapter.cs +++ b/Jellyfin.Data/Entities/Libraries/Chapter.cs @@ -1,277 +1,102 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Chapter + /// + /// An entity representing a chapter. + /// + public class Chapter : IHasConcurrencyToken { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected Chapter() - { - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static Chapter CreateChapterUnsafe() - { - return new Chapter(); - } - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// /// ISO-639-3 3-character language codes. - /// - /// - public Chapter(string language, long timestart, Release _release0) + /// The start time for this chapter. + /// The release. + public Chapter(string language, long startTime, Release release) { if (string.IsNullOrEmpty(language)) { throw new ArgumentNullException(nameof(language)); } - this.Language = language; - - this.TimeStart = timestart; + Language = language; + StartTime = startTime; - if (_release0 == null) + if (release == null) { - throw new ArgumentNullException(nameof(_release0)); + throw new ArgumentNullException(nameof(release)); } - _release0.Chapters.Add(this); - - - Init(); + release.Chapters.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// ISO-639-3 3-character language codes. - /// - /// - public static Chapter Create(string language, long timestart, Release _release0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected Chapter() { - return new Chapter(language, timestart, _release0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); /// - /// When provided in a partial class, allows value of Id to be changed before returning. + /// Gets or sets the id. /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } + public int Id { get; protected set; } /// - /// Backing field for Name. - /// - protected string _Name; - /// - /// When provided in a partial class, allows value of Name to be changed before setting. - /// - partial void SetName(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Name to be changed before returning. - /// - partial void GetName(ref string result); - - /// - /// Max length = 1024 + /// Gets or sets the name. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Name - { - get - { - string value = _Name; - GetName(ref value); - return _Name = value; - } - - set - { - string oldValue = _Name; - SetName(oldValue, ref value); - if (oldValue != value) - { - _Name = value; - } - } - } + public string Name { get; set; } /// - /// Backing field for Language. - /// - protected string _Language; - /// - /// When provided in a partial class, allows value of Language to be changed before setting. - /// - partial void SetLanguage(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Language to be changed before returning. + /// Gets or sets the language. /// - partial void GetLanguage(ref string result); - - /// + /// /// Required, Min length = 3, Max length = 3 /// ISO-639-3 3-character language codes. - /// + /// [Required] [MinLength(3)] [MaxLength(3)] [StringLength(3)] - public string Language - { - get - { - string value = _Language; - GetLanguage(ref value); - return _Language = value; - } + public string Language { get; set; } - set - { - string oldValue = _Language; - SetLanguage(oldValue, ref value); - if (oldValue != value) - { - _Language = value; - } - } - } - - /// - /// Backing field for TimeStart. - /// - protected long _TimeStart; /// - /// When provided in a partial class, allows value of TimeStart to be changed before setting. + /// Gets or sets the start time. /// - partial void SetTimeStart(long oldValue, ref long newValue); - /// - /// When provided in a partial class, allows value of TimeStart to be changed before returning. - /// - partial void GetTimeStart(ref long result); - - /// + /// /// Required. - /// - [Required] - public long TimeStart - { - get - { - long value = _TimeStart; - GetTimeStart(ref value); - return _TimeStart = value; - } - - set - { - long oldValue = _TimeStart; - SetTimeStart(oldValue, ref value); - if (oldValue != value) - { - _TimeStart = value; - } - } - } + /// + public long StartTime { get; set; } /// - /// Backing field for TimeEnd. - /// - protected long? _TimeEnd; - /// - /// When provided in a partial class, allows value of TimeEnd to be changed before setting. + /// Gets or sets the end time. /// - partial void SetTimeEnd(long? oldValue, ref long? newValue); - /// - /// When provided in a partial class, allows value of TimeEnd to be changed before returning. - /// - partial void GetTimeEnd(ref long? result); - - public long? TimeEnd - { - get - { - long? value = _TimeEnd; - GetTimeEnd(ref value); - return _TimeEnd = value; - } - - set - { - long? oldValue = _TimeEnd; - SetTimeEnd(oldValue, ref value); - if (oldValue != value) - { - _TimeEnd = value; - } - } - } + public long? EndTime { get; set; } - /// - /// Required, ConcurrenyToken. - /// + /// [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + public uint RowVersion { get; protected set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ } } - diff --git a/Jellyfin.Data/Entities/Libraries/Collection.cs b/Jellyfin.Data/Entities/Libraries/Collection.cs index d054d8ff99..2e1bbcfb60 100644 --- a/Jellyfin.Data/Entities/Libraries/Collection.cs +++ b/Jellyfin.Data/Entities/Libraries/Collection.cs @@ -1,123 +1,55 @@ -#pragma warning disable CS1591 - using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Collection + /// + /// An entity representing a collection. + /// + public class Collection : IHasConcurrencyToken { - partial void Init(); - /// - /// Default constructor. + /// Initializes a new instance of the class. /// public Collection() { - CollectionItem = new LinkedList(); - - Init(); + Items = new HashSet(); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); /// - /// When provided in a partial class, allows value of Id to be changed before returning. + /// Gets or sets the id. /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } + public int Id { get; protected set; } /// - /// Backing field for Name. - /// - protected string _Name; - /// - /// When provided in a partial class, allows value of Name to be changed before setting. - /// - partial void SetName(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Name to be changed before returning. - /// - partial void GetName(ref string result); - - /// - /// Max length = 1024 + /// Gets or sets the name. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Name - { - get - { - string value = _Name; - GetName(ref value); - return _Name = value; - } + public string Name { get; set; } - set - { - string oldValue = _Name; - SetName(oldValue, ref value); - if (oldValue != value) - { - _Name = value; - } - } - } + /// + [ConcurrencyCheck] + public uint RowVersion { get; set; } /// - /// Required, ConcurrenyToken. + /// Gets or sets a collection containing this collection's items. /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + public virtual ICollection Items { get; protected set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("CollectionItem_CollectionItem_Id")] - public virtual ICollection CollectionItem { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs b/Jellyfin.Data/Entities/Libraries/CollectionItem.cs index 4b01d814fb..c9306f630a 100644 --- a/Jellyfin.Data/Entities/Libraries/CollectionItem.cs +++ b/Jellyfin.Data/Entities/Libraries/CollectionItem.cs @@ -1,156 +1,94 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class CollectionItem + /// + /// An entity representing a collection item. + /// + public class CollectionItem : IHasConcurrencyToken { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected CollectionItem() - { - // NOTE: This class has one-to-one associations with CollectionItem. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static CollectionItem CreateCollectionItemUnsafe() - { - return new CollectionItem(); - } - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// - /// - /// - /// - public CollectionItem(Collection _collection0, CollectionItem _collectionitem1, CollectionItem _collectionitem2) + /// The collection. + /// The previous item. + /// The next item. + public CollectionItem(Collection collection, CollectionItem previous, CollectionItem next) { - // NOTE: This class has one-to-one associations with CollectionItem. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - - if (_collection0 == null) + if (collection == null) { - throw new ArgumentNullException(nameof(_collection0)); + throw new ArgumentNullException(nameof(collection)); } - _collection0.CollectionItem.Add(this); + collection.Items.Add(this); - if (_collectionitem1 == null) + if (next != null) { - throw new ArgumentNullException(nameof(_collectionitem1)); + Next = next; + next.Previous = this; } - _collectionitem1.Next = this; - - if (_collectionitem2 == null) + if (previous != null) { - throw new ArgumentNullException(nameof(_collectionitem2)); + Previous = previous; + previous.Next = this; } - - _collectionitem2.Previous = this; - - Init(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - /// - /// - public static CollectionItem Create(Collection _collection0, CollectionItem _collectionitem1, CollectionItem _collectionitem2) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected CollectionItem() { - return new CollectionItem(_collection0, _collectionitem1, _collectionitem2); } - /************************************************************************* - * Properties - *************************************************************************/ - /// - /// Backing field for Id. + /// Gets or sets the id. /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } + public int Id { get; set; } - /// - /// Required, ConcurrenyToken. - /// + /// [ConcurrencyCheck] - [Required] public uint RowVersion { get; set; } - public void OnSavingChanges() - { - RowVersion++; - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - /// - /// Required. + /// Gets or sets the library item. /// - [ForeignKey("LibraryItem_Id")] + /// + /// Required. + /// public virtual LibraryItem LibraryItem { get; set; } + /// + /// Gets or sets the next item in the collection. + /// /// /// TODO check if this properly updated dependant and has the proper principal relationship /// - [ForeignKey("CollectionItem_Next_Id")] public virtual CollectionItem Next { get; set; } + /// + /// Gets or sets the previous item in the collection. + /// /// /// TODO check if this properly updated dependant and has the proper principal relationship /// - [ForeignKey("CollectionItem_Previous_Id")] public virtual CollectionItem Previous { get; set; } + + /// + public void OnSavingChanges() + { + RowVersion++; + } } } - diff --git a/Jellyfin.Data/Entities/Libraries/Company.cs b/Jellyfin.Data/Entities/Libraries/Company.cs index 10df429cd7..02da26bc22 100644 --- a/Jellyfin.Data/Entities/Libraries/Company.cs +++ b/Jellyfin.Data/Entities/Libraries/Company.cs @@ -1,159 +1,67 @@ -#pragma warning disable CS1591 - -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Company + /// + /// An entity representing a company. + /// + public class Company : IHasCompanies, IHasConcurrencyToken { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected Company() + /// The owner of this company. + public Company(IHasCompanies owner) { - CompanyMetadata = new HashSet(); - - Init(); - } + owner?.Companies.Add(this); - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static Company CreateCompanyUnsafe() - { - return new Company(); + CompanyMetadata = new HashSet(); } /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// - /// - /// - /// - /// - /// - public Company(MovieMetadata _moviemetadata0, SeriesMetadata _seriesmetadata1, MusicAlbumMetadata _musicalbummetadata2, BookMetadata _bookmetadata3, Company _company4) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected Company() { - if (_moviemetadata0 == null) - { - throw new ArgumentNullException(nameof(_moviemetadata0)); - } - - _moviemetadata0.Studios.Add(this); - - if (_seriesmetadata1 == null) - { - throw new ArgumentNullException(nameof(_seriesmetadata1)); - } - - _seriesmetadata1.Networks.Add(this); - - if (_musicalbummetadata2 == null) - { - throw new ArgumentNullException(nameof(_musicalbummetadata2)); - } - - _musicalbummetadata2.Labels.Add(this); - - if (_bookmetadata3 == null) - { - throw new ArgumentNullException(nameof(_bookmetadata3)); - } - - _bookmetadata3.Publishers.Add(this); - - if (_company4 == null) - { - throw new ArgumentNullException(nameof(_company4)); - } - - _company4.Parent = this; - - this.CompanyMetadata = new HashSet(); - - Init(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Gets or sets the id. /// - /// - /// - /// - /// - /// - public static Company Create(MovieMetadata _moviemetadata0, SeriesMetadata _seriesmetadata1, MusicAlbumMetadata _musicalbummetadata2, BookMetadata _bookmetadata3, Company _company4) - { - return new Company(_moviemetadata0, _seriesmetadata1, _musicalbummetadata2, _bookmetadata3, _company4); - } + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; protected set; } - /************************************************************************* - * Properties - *************************************************************************/ + /// + [ConcurrencyCheck] + public uint RowVersion { get; set; } /// - /// Backing field for Id. + /// Gets or sets a collection containing the metadata. /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); + public virtual ICollection CompanyMetadata { get; protected set; } /// - /// Identity, Indexed, Required. + /// Gets or sets a collection containing this company's child companies. /// - [Key] - [Required] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } + public virtual ICollection ChildCompanies { get; protected set; } - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } - - /// - /// Required, ConcurrenyToken. - /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + /// + [NotMapped] + public ICollection Companies => ChildCompanies; + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("CompanyMetadata_CompanyMetadata_Id")] - public virtual ICollection CompanyMetadata { get; protected set; } - [ForeignKey("Company_Parent_Id")] - public virtual Company Parent { get; set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs b/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs index f81beb0d58..60cc96a340 100644 --- a/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/CompanyMetadata.cs @@ -1,236 +1,74 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; namespace Jellyfin.Data.Entities.Libraries { - public partial class CompanyMetadata : Metadata + /// + /// An entity holding metadata for a . + /// + public class CompanyMetadata : Metadata { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected CompanyMetadata() - { - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static CompanyMetadata CreateCompanyMetadataUnsafe() - { - return new CompanyMetadata(); - } - - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// /// The title or name of the object. /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public CompanyMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Company _company0) + /// The company. + public CompanyMetadata(string title, string language, Company company) : base(title, language) { - if (string.IsNullOrEmpty(title)) - { - throw new ArgumentNullException(nameof(title)); - } - - this.Title = title; - - if (string.IsNullOrEmpty(language)) - { - throw new ArgumentNullException(nameof(language)); - } - - this.Language = language; - - if (_company0 == null) + if (company == null) { - throw new ArgumentNullException(nameof(_company0)); + throw new ArgumentNullException(nameof(company)); } - _company0.CompanyMetadata.Add(this); - - Init(); + company.CompanyMetadata.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public static CompanyMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Company _company0) + protected CompanyMetadata() { - return new CompanyMetadata(title, language, dateadded, datemodified, _company0); } - /************************************************************************* - * Properties - *************************************************************************/ - /// - /// Backing field for Description. - /// - protected string _Description; - /// - /// When provided in a partial class, allows value of Description to be changed before setting. - /// - partial void SetDescription(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Description to be changed before returning. - /// - partial void GetDescription(ref string result); - - /// - /// Max length = 65535 + /// Gets or sets the description. /// + /// + /// Max length = 65535. + /// [MaxLength(65535)] [StringLength(65535)] - public string Description - { - get - { - string value = _Description; - GetDescription(ref value); - return _Description = value; - } - - set - { - string oldValue = _Description; - SetDescription(oldValue, ref value); - if (oldValue != value) - { - _Description = value; - } - } - } - - /// - /// Backing field for Headquarters. - /// - protected string _Headquarters; - /// - /// When provided in a partial class, allows value of Headquarters to be changed before setting. - /// - partial void SetHeadquarters(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Headquarters to be changed before returning. - /// - partial void GetHeadquarters(ref string result); + public string Description { get; set; } /// - /// Max length = 255 + /// Gets or sets the headquarters. /// + /// + /// Max length = 255. + /// [MaxLength(255)] [StringLength(255)] - public string Headquarters - { - get - { - string value = _Headquarters; - GetHeadquarters(ref value); - return _Headquarters = value; - } + public string Headquarters { get; set; } - set - { - string oldValue = _Headquarters; - SetHeadquarters(oldValue, ref value); - if (oldValue != value) - { - _Headquarters = value; - } - } - } - - /// - /// Backing field for Country. - /// - protected string _Country; - /// - /// When provided in a partial class, allows value of Country to be changed before setting. - /// - partial void SetCountry(string oldValue, ref string newValue); /// - /// When provided in a partial class, allows value of Country to be changed before returning. - /// - partial void GetCountry(ref string result); - - /// - /// Max length = 2 + /// Gets or sets the country code. /// + /// + /// Max length = 2. + /// [MaxLength(2)] [StringLength(2)] - public string Country - { - get - { - string value = _Country; - GetCountry(ref value); - return _Country = value; - } - - set - { - string oldValue = _Country; - SetCountry(oldValue, ref value); - if (oldValue != value) - { - _Country = value; - } - } - } + public string Country { get; set; } /// - /// Backing field for Homepage. - /// - protected string _Homepage; - /// - /// When provided in a partial class, allows value of Homepage to be changed before setting. - /// - partial void SetHomepage(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Homepage to be changed before returning. - /// - partial void GetHomepage(ref string result); - - /// - /// Max length = 1024 + /// Gets or sets the homepage. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Homepage - { - get - { - string value = _Homepage; - GetHomepage(ref value); - return _Homepage = value; - } - - set - { - string oldValue = _Homepage; - SetHomepage(oldValue, ref value); - if (oldValue != value) - { - _Homepage = value; - } - } - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ + public string Homepage { get; set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/CustomItem.cs b/Jellyfin.Data/Entities/Libraries/CustomItem.cs index ffe06db249..6a4f0a5378 100644 --- a/Jellyfin.Data/Entities/Libraries/CustomItem.cs +++ b/Jellyfin.Data/Entities/Libraries/CustomItem.cs @@ -1,71 +1,28 @@ -#pragma warning disable CS1591 - -using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class CustomItem : LibraryItem + /// + /// An entity representing a custom item. + /// + public class CustomItem : LibraryItem, IHasReleases { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected CustomItem() + public CustomItem() { CustomItemMetadata = new HashSet(); Releases = new HashSet(); - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static CustomItem CreateCustomItemUnsafe() - { - return new CustomItem(); - } - - /// - /// Public constructor with required data. - /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public CustomItem(Guid urlid, DateTime dateadded) - { - this.UrlId = urlid; - - this.CustomItemMetadata = new HashSet(); - this.Releases = new HashSet(); - - Init(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Gets or sets a collection containing the metadata for this item. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public static CustomItem Create(Guid urlid, DateTime dateadded) - { - return new CustomItem(urlid, dateadded); - } - - /************************************************************************* - * Properties - *************************************************************************/ - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("CustomItemMetadata_CustomItemMetadata_Id")] public virtual ICollection CustomItemMetadata { get; protected set; } - [ForeignKey("Release_Releases_Id")] + /// public virtual ICollection Releases { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs b/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs index 8606302d7d..bc18355281 100644 --- a/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/CustomItemMetadata.cs @@ -1,83 +1,36 @@ -#pragma warning disable CS1591 - using System; namespace Jellyfin.Data.Entities.Libraries { - public partial class CustomItemMetadata : Metadata + /// + /// An entity containing metadata for a custom item. + /// + public class CustomItemMetadata : Metadata { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected CustomItemMetadata() - { - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static CustomItemMetadata CreateCustomItemMetadataUnsafe() - { - return new CustomItemMetadata(); - } - - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// /// The title or name of the object. /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public CustomItemMetadata(string title, string language, DateTime dateadded, DateTime datemodified, CustomItem _customitem0) + /// The item. + public CustomItemMetadata(string title, string language, CustomItem item) : base(title, language) { - if (string.IsNullOrEmpty(title)) - { - throw new ArgumentNullException(nameof(title)); - } - - this.Title = title; - - if (string.IsNullOrEmpty(language)) - { - throw new ArgumentNullException(nameof(language)); - } - - this.Language = language; - - if (_customitem0 == null) + if (item == null) { - throw new ArgumentNullException(nameof(_customitem0)); + throw new ArgumentNullException(nameof(item)); } - _customitem0.CustomItemMetadata.Add(this); - - Init(); + item.CustomItemMetadata.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public static CustomItemMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, CustomItem _customitem0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected CustomItemMetadata() { - return new CustomItemMetadata(title, language, dateadded, datemodified, _customitem0); } - - /************************************************************************* - * Properties - *************************************************************************/ - - /************************************************************************* - * Navigation properties - *************************************************************************/ } } - diff --git a/Jellyfin.Data/Entities/Libraries/Episode.cs b/Jellyfin.Data/Entities/Libraries/Episode.cs index 3315b3e30b..430a11e3c8 100644 --- a/Jellyfin.Data/Entities/Libraries/Episode.cs +++ b/Jellyfin.Data/Entities/Libraries/Episode.cs @@ -1,118 +1,52 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Episode : LibraryItem + /// + /// An entity representing an episode. + /// + public class Episode : LibraryItem, IHasReleases { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected Episode() + /// The season. + public Episode(Season season) { - // NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. + if (season == null) + { + throw new ArgumentNullException(nameof(season)); + } + + season.Episodes.Add(this); Releases = new HashSet(); EpisodeMetadata = new HashSet(); - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static Episode CreateEpisodeUnsafe() - { - return new Episode(); } /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - /// - public Episode(Guid urlid, DateTime dateadded, Season _season0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected Episode() { - // NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - - this.UrlId = urlid; - - if (_season0 == null) - { - throw new ArgumentNullException(nameof(_season0)); - } - - _season0.Episodes.Add(this); - - this.Releases = new HashSet(); - this.EpisodeMetadata = new HashSet(); - - Init(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Gets or sets the episode number. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - /// - public static Episode Create(Guid urlid, DateTime dateadded, Season _season0) - { - return new Episode(urlid, dateadded, _season0); - } + public int? EpisodeNumber { get; set; } - /************************************************************************* - * Properties - *************************************************************************/ + /// + public virtual ICollection Releases { get; protected set; } /// - /// Backing field for EpisodeNumber. + /// Gets or sets a collection containing the metadata for this episode. /// - protected int? _EpisodeNumber; - /// - /// When provided in a partial class, allows value of EpisodeNumber to be changed before setting. - /// - partial void SetEpisodeNumber(int? oldValue, ref int? newValue); - /// - /// When provided in a partial class, allows value of EpisodeNumber to be changed before returning. - /// - partial void GetEpisodeNumber(ref int? result); - - public int? EpisodeNumber - { - get - { - int? value = _EpisodeNumber; - GetEpisodeNumber(ref value); - return _EpisodeNumber = value; - } - - set - { - int? oldValue = _EpisodeNumber; - SetEpisodeNumber(oldValue, ref value); - if (oldValue != value) - { - _EpisodeNumber = value; - } - } - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("Release_Releases_Id")] - public virtual ICollection Releases { get; protected set; } - [ForeignKey("EpisodeMetadata_EpisodeMetadata_Id")] public virtual ICollection EpisodeMetadata { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs b/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs index f20ed3573f..348100cb4c 100644 --- a/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/EpisodeMetadata.cs @@ -1,198 +1,67 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; namespace Jellyfin.Data.Entities.Libraries { - public partial class EpisodeMetadata : Metadata + /// + /// An entity containing metadata for an . + /// + public class EpisodeMetadata : Metadata { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected EpisodeMetadata() - { - Init(); - } - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static EpisodeMetadata CreateEpisodeMetadataUnsafe() - { - return new EpisodeMetadata(); - } - - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// /// The title or name of the object. /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public EpisodeMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Episode _episode0) + /// The episode. + public EpisodeMetadata(string title, string language, Episode episode) : base(title, language) { - if (string.IsNullOrEmpty(title)) - { - throw new ArgumentNullException(nameof(title)); - } - - this.Title = title; - - if (string.IsNullOrEmpty(language)) + if (episode == null) { - throw new ArgumentNullException(nameof(language)); + throw new ArgumentNullException(nameof(episode)); } - this.Language = language; - - if (_episode0 == null) - { - throw new ArgumentNullException(nameof(_episode0)); - } - - _episode0.EpisodeMetadata.Add(this); - - Init(); + episode.EpisodeMetadata.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public static EpisodeMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Episode _episode0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected EpisodeMetadata() { - return new EpisodeMetadata(title, language, dateadded, datemodified, _episode0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Outline. - /// - protected string _Outline; - /// - /// When provided in a partial class, allows value of Outline to be changed before setting. - /// - partial void SetOutline(string oldValue, ref string newValue); /// - /// When provided in a partial class, allows value of Outline to be changed before returning. - /// - partial void GetOutline(ref string result); - - /// - /// Max length = 1024 + /// Gets or sets the outline. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Outline - { - get - { - string value = _Outline; - GetOutline(ref value); - return _Outline = value; - } - - set - { - string oldValue = _Outline; - SetOutline(oldValue, ref value); - if (oldValue != value) - { - _Outline = value; - } - } - } - - /// - /// Backing field for Plot. - /// - protected string _Plot; - /// - /// When provided in a partial class, allows value of Plot to be changed before setting. - /// - partial void SetPlot(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Plot to be changed before returning. - /// - partial void GetPlot(ref string result); + public string Outline { get; set; } /// - /// Max length = 65535 + /// Gets or sets the plot. /// + /// + /// Max length = 65535. + /// [MaxLength(65535)] [StringLength(65535)] - public string Plot - { - get - { - string value = _Plot; - GetPlot(ref value); - return _Plot = value; - } - - set - { - string oldValue = _Plot; - SetPlot(oldValue, ref value); - if (oldValue != value) - { - _Plot = value; - } - } - } - - /// - /// Backing field for Tagline. - /// - protected string _Tagline; - /// - /// When provided in a partial class, allows value of Tagline to be changed before setting. - /// - partial void SetTagline(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Tagline to be changed before returning. - /// - partial void GetTagline(ref string result); + public string Plot { get; set; } /// - /// Max length = 1024 + /// Gets or sets the tagline. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Tagline - { - get - { - string value = _Tagline; - GetTagline(ref value); - return _Tagline = value; - } - - set - { - string oldValue = _Tagline; - SetTagline(oldValue, ref value); - if (oldValue != value) - { - _Tagline = value; - } - } - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ + public string Tagline { get; set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/Genre.cs b/Jellyfin.Data/Entities/Libraries/Genre.cs index c0b391ac8c..aeedd7bfde 100644 --- a/Jellyfin.Data/Entities/Libraries/Genre.cs +++ b/Jellyfin.Data/Entities/Libraries/Genre.cs @@ -1,162 +1,75 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Genre + /// + /// An entity representing a genre. + /// + public class Genre : IHasConcurrencyToken { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected Genre() - { - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static Genre CreateGenreUnsafe() - { - return new Genre(); - } - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// - /// - /// - public Genre(string name, Metadata _metadata0) + /// The name. + /// The metadata. + public Genre(string name, Metadata metadata) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } - this.Name = name; + Name = name; - if (_metadata0 == null) + if (metadata == null) { - throw new ArgumentNullException(nameof(_metadata0)); + throw new ArgumentNullException(nameof(metadata)); } - _metadata0.Genres.Add(this); - - Init(); + metadata.Genres.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - /// - public static Genre Create(string name, Metadata _metadata0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected Genre() { - return new Genre(name, _metadata0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; /// - /// When provided in a partial class, allows value of Id to be changed before setting. + /// Gets or sets the id. /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } - - /// - /// Backing field for Name. - /// - internal string _Name; - /// - /// When provided in a partial class, allows value of Name to be changed before setting. - /// - partial void SetName(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Name to be changed before returning. - /// - partial void GetName(ref string result); + public int Id { get; protected set; } /// - /// Indexed, Required, Max length = 255 + /// Gets or sets the name. /// + /// + /// Indexed, Required, Max length = 255. + /// [Required] [MaxLength(255)] [StringLength(255)] - public string Name - { - get - { - string value = _Name; - GetName(ref value); - return _Name = value; - } + public string Name { get; set; } - set - { - string oldValue = _Name; - SetName(oldValue, ref value); - if (oldValue != value) - { - _Name = value; - } - } - } - - /// - /// Required, ConcurrenyToken. - /// + /// [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + public uint RowVersion { get; protected set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ } } - diff --git a/Jellyfin.Data/Entities/Libraries/Library.cs b/Jellyfin.Data/Entities/Libraries/Library.cs index 9a97a3b00c..4f82a2e2a7 100644 --- a/Jellyfin.Data/Entities/Libraries/Library.cs +++ b/Jellyfin.Data/Entities/Libraries/Library.cs @@ -1,153 +1,76 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Library + /// + /// An entity representing a library. + /// + public class Library : IHasConcurrencyToken { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected Library() - { - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static Library CreateLibraryUnsafe() - { - return new Library(); - } - - /// - /// Public constructor with required data. - /// - /// + /// The name of the library. public Library(string name) { - if (string.IsNullOrEmpty(name)) + if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentNullException(nameof(name)); } - this.Name = name; - - Init(); + Name = name; } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - public static Library Create(string name) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected Library() { - return new Library(name); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); /// - /// When provided in a partial class, allows value of Id to be changed before returning. + /// Gets or sets the id. /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } + public int Id { get; protected set; } - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } - - /// - /// Backing field for Name. - /// - protected string _Name; /// - /// When provided in a partial class, allows value of Name to be changed before setting. + /// Gets or sets the name. /// - partial void SetName(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Name to be changed before returning. - /// - partial void GetName(ref string result); + /// + /// Required, Max length = 128. + /// + [Required] + [MaxLength(128)] + [StringLength(128)] + public string Name { get; set; } /// - /// Required, Max length = 1024 + /// Gets or sets the root path of the library. /// + /// + /// Required. + /// [Required] - [MaxLength(1024)] - [StringLength(1024)] - public string Name - { - get - { - string value = _Name; - GetName(ref value); - return _Name = value; - } - - set - { - string oldValue = _Name; - SetName(oldValue, ref value); - if (oldValue != value) - { - _Name = value; - } - } - } + public string Path { get; set; } - /// - /// Required, ConcurrenyToken. - /// + /// [ConcurrencyCheck] - [Required] public uint RowVersion { get; set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ } } - diff --git a/Jellyfin.Data/Entities/Libraries/LibraryItem.cs b/Jellyfin.Data/Entities/Libraries/LibraryItem.cs index b5f0323653..a9167aa7fd 100644 --- a/Jellyfin.Data/Entities/Libraries/LibraryItem.cs +++ b/Jellyfin.Data/Entities/Libraries/LibraryItem.cs @@ -1,175 +1,63 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public abstract partial class LibraryItem + /// + /// An entity representing a library item. + /// + public abstract class LibraryItem : IHasConcurrencyToken { - partial void Init(); - /// - /// Default constructor. Protected due to being abstract. + /// Initializes a new instance of the class. /// - protected LibraryItem() + /// The library of this item. + protected LibraryItem(Library library) { - Init(); + DateAdded = DateTime.UtcNow; + Library = library; } /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - protected LibraryItem(Guid urlid, DateTime dateadded) + protected LibraryItem() { - this.UrlId = urlid; - - - Init(); } - /************************************************************************* - * Properties - *************************************************************************/ - /// - /// Backing field for Id. + /// Gets or sets the id. /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } - - /// - /// Backing field for UrlId. - /// - internal Guid _UrlId; - /// - /// When provided in a partial class, allows value of UrlId to be changed before setting. - /// - partial void SetUrlId(Guid oldValue, ref Guid newValue); - /// - /// When provided in a partial class, allows value of UrlId to be changed before returning. - /// - partial void GetUrlId(ref Guid result); + public int Id { get; protected set; } /// - /// Indexed, Required - /// This is whats gets displayed in the Urls and API requests. This could also be a string. + /// Gets or sets the date this library item was added. /// - [Required] - public Guid UrlId - { - get - { - Guid value = _UrlId; - GetUrlId(ref value); - return _UrlId = value; - } + public DateTime DateAdded { get; protected set; } - set - { - Guid oldValue = _UrlId; - SetUrlId(oldValue, ref value); - if (oldValue != value) - { - _UrlId = value; - } - } - } + /// + [ConcurrencyCheck] + public uint RowVersion { get; protected set; } /// - /// Backing field for DateAdded. + /// Gets or sets the library of this item. /// - protected DateTime _DateAdded; - /// - /// When provided in a partial class, allows value of DateAdded to be changed before setting. - /// - partial void SetDateAdded(DateTime oldValue, ref DateTime newValue); - /// - /// When provided in a partial class, allows value of DateAdded to be changed before returning. - /// - partial void GetDateAdded(ref DateTime result); - - /// + /// /// Required. - /// + /// [Required] - public DateTime DateAdded - { - get - { - DateTime value = _DateAdded; - GetDateAdded(ref value); - return _DateAdded = value; - } - - internal set - { - DateTime oldValue = _DateAdded; - SetDateAdded(oldValue, ref value); - if (oldValue != value) - { - _DateAdded = value; - } - } - } - - /// - /// Required, ConcurrenyToken. - /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + public virtual Library Library { get; set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - - /// - /// Required. - /// - [ForeignKey("LibraryRoot_Id")] - public virtual LibraryRoot LibraryRoot { get; set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/LibraryRoot.cs b/Jellyfin.Data/Entities/Libraries/LibraryRoot.cs deleted file mode 100644 index bbd9044477..0000000000 --- a/Jellyfin.Data/Entities/Libraries/LibraryRoot.cs +++ /dev/null @@ -1,199 +0,0 @@ -#pragma warning disable CS1591 - -using System; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Jellyfin.Data.Entities.Libraries -{ - public partial class LibraryRoot - { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected LibraryRoot() - { - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static LibraryRoot CreateLibraryRootUnsafe() - { - return new LibraryRoot(); - } - - /// - /// Public constructor with required data. - /// - /// Absolute Path. - public LibraryRoot(string path) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException(nameof(path)); - } - - this.Path = path; - - Init(); - } - - /// - /// Static create function (for use in LINQ queries, etc.) - /// - /// Absolute Path. - public static LibraryRoot Create(string path) - { - return new LibraryRoot(path); - } - - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// - /// Identity, Indexed, Required. - /// - [Key] - [Required] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } - - /// - /// Backing field for Path. - /// - protected string _Path; - /// - /// When provided in a partial class, allows value of Path to be changed before setting. - /// - partial void SetPath(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Path to be changed before returning. - /// - partial void GetPath(ref string result); - - /// - /// Required, Max length = 65535 - /// Absolute Path. - /// - [Required] - [MaxLength(65535)] - [StringLength(65535)] - public string Path - { - get - { - string value = _Path; - GetPath(ref value); - return _Path = value; - } - - set - { - string oldValue = _Path; - SetPath(oldValue, ref value); - if (oldValue != value) - { - _Path = value; - } - } - } - - /// - /// Backing field for NetworkPath. - /// - protected string _NetworkPath; - /// - /// When provided in a partial class, allows value of NetworkPath to be changed before setting. - /// - partial void SetNetworkPath(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of NetworkPath to be changed before returning. - /// - partial void GetNetworkPath(ref string result); - - /// - /// Max length = 65535 - /// Absolute network path, for example for transcoding sattelites. - /// - [MaxLength(65535)] - [StringLength(65535)] - public string NetworkPath - { - get - { - string value = _NetworkPath; - GetNetworkPath(ref value); - return _NetworkPath = value; - } - - set - { - string oldValue = _NetworkPath; - SetNetworkPath(oldValue, ref value); - if (oldValue != value) - { - _NetworkPath = value; - } - } - } - - /// - /// Required, ConcurrenyToken. - /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } - - public void OnSavingChanges() - { - RowVersion++; - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - - /// - /// Required. - /// - [ForeignKey("Library_Id")] - public virtual Library Library { get; set; } - } -} - diff --git a/Jellyfin.Data/Entities/Libraries/MediaFile.cs b/Jellyfin.Data/Entities/Libraries/MediaFile.cs index c9efdb143b..8bc649c98f 100644 --- a/Jellyfin.Data/Entities/Libraries/MediaFile.cs +++ b/Jellyfin.Data/Entities/Libraries/MediaFile.cs @@ -1,212 +1,94 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class MediaFile + /// + /// An entity representing a file on disk. + /// + public class MediaFile : IHasConcurrencyToken { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected MediaFile() - { - MediaFileStreams = new HashSet(); - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static MediaFile CreateMediaFileUnsafe() - { - return new MediaFile(); - } - - /// - /// Public constructor with required data. - /// - /// Relative to the LibraryRoot. - /// - /// - public MediaFile(string path, Enums.MediaFileKind kind, Release _release0) + /// The path relative to the LibraryRoot. + /// The file kind. + /// The release. + public MediaFile(string path, MediaFileKind kind, Release release) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } - this.Path = path; - - this.Kind = kind; + Path = path; + Kind = kind; - if (_release0 == null) + if (release == null) { - throw new ArgumentNullException(nameof(_release0)); + throw new ArgumentNullException(nameof(release)); } - _release0.MediaFiles.Add(this); + release.MediaFiles.Add(this); - this.MediaFileStreams = new HashSet(); - - Init(); + MediaFileStreams = new HashSet(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// Relative to the LibraryRoot. - /// - /// - public static MediaFile Create(string path, Enums.MediaFileKind kind, Release _release0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected MediaFile() { - return new MediaFile(path, kind, _release0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; /// - /// When provided in a partial class, allows value of Id to be changed before setting. + /// Gets or sets the id. /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } + public int Id { get; protected set; } /// - /// Backing field for Path. - /// - protected string _Path; - /// - /// When provided in a partial class, allows value of Path to be changed before setting. - /// - partial void SetPath(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Path to be changed before returning. - /// - partial void GetPath(ref string result); - - /// - /// Required, Max length = 65535 - /// Relative to the LibraryRoot. + /// Gets or sets the path relative to the library root. /// + /// + /// Required, Max length = 65535. + /// [Required] [MaxLength(65535)] [StringLength(65535)] - public string Path - { - get - { - string value = _Path; - GetPath(ref value); - return _Path = value; - } + public string Path { get; set; } - set - { - string oldValue = _Path; - SetPath(oldValue, ref value); - if (oldValue != value) - { - _Path = value; - } - } - } - - /// - /// Backing field for Kind. - /// - protected Enums.MediaFileKind _Kind; /// - /// When provided in a partial class, allows value of Kind to be changed before setting. + /// Gets or sets the kind of media file. /// - partial void SetKind(Enums.MediaFileKind oldValue, ref Enums.MediaFileKind newValue); - /// - /// When provided in a partial class, allows value of Kind to be changed before returning. - /// - partial void GetKind(ref Enums.MediaFileKind result); - - /// + /// /// Required. - /// - [Required] - public Enums.MediaFileKind Kind - { - get - { - Enums.MediaFileKind value = _Kind; - GetKind(ref value); - return _Kind = value; - } + /// + public MediaFileKind Kind { get; set; } - set - { - Enums.MediaFileKind oldValue = _Kind; - SetKind(oldValue, ref value); - if (oldValue != value) - { - _Kind = value; - } - } - } + /// + [ConcurrencyCheck] + public uint RowVersion { get; set; } /// - /// Required, ConcurrenyToken. + /// Gets or sets a collection containing the streams in this file. /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + public virtual ICollection MediaFileStreams { get; protected set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - - [ForeignKey("MediaFileStream_MediaFileStreams_Id")] - public virtual ICollection MediaFileStreams { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/MediaFileStream.cs b/Jellyfin.Data/Entities/Libraries/MediaFileStream.cs index f1f26ecbb9..5b03e260e2 100644 --- a/Jellyfin.Data/Entities/Libraries/MediaFileStream.cs +++ b/Jellyfin.Data/Entities/Libraries/MediaFileStream.cs @@ -1,155 +1,67 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class MediaFileStream + /// + /// An entity representing a stream in a media file. + /// + public class MediaFileStream : IHasConcurrencyToken { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected MediaFileStream() + /// The number of this stream. + /// The media file. + public MediaFileStream(int streamNumber, MediaFile mediaFile) { - Init(); - } + StreamNumber = streamNumber; - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static MediaFileStream CreateMediaFileStreamUnsafe() - { - return new MediaFileStream(); - } - - /// - /// Public constructor with required data. - /// - /// - /// - public MediaFileStream(int streamnumber, MediaFile _mediafile0) - { - this.StreamNumber = streamnumber; - - if (_mediafile0 == null) + if (mediaFile == null) { - throw new ArgumentNullException(nameof(_mediafile0)); + throw new ArgumentNullException(nameof(mediaFile)); } - _mediafile0.MediaFileStreams.Add(this); - - Init(); + mediaFile.MediaFileStreams.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - /// - public static MediaFileStream Create(int streamnumber, MediaFile _mediafile0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected MediaFileStream() { - return new MediaFileStream(streamnumber, _mediafile0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); /// - /// When provided in a partial class, allows value of Id to be changed before returning. + /// Gets or sets the id. /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } + public int Id { get; protected set; } /// - /// Backing field for StreamNumber. + /// Gets or sets the stream number. /// - protected int _StreamNumber; - /// - /// When provided in a partial class, allows value of StreamNumber to be changed before setting. - /// - partial void SetStreamNumber(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of StreamNumber to be changed before returning. - /// - partial void GetStreamNumber(ref int result); - - /// + /// /// Required. - /// - [Required] - public int StreamNumber - { - get - { - int value = _StreamNumber; - GetStreamNumber(ref value); - return _StreamNumber = value; - } - - set - { - int oldValue = _StreamNumber; - SetStreamNumber(oldValue, ref value); - if (oldValue != value) - { - _StreamNumber = value; - } - } - } + /// + public int StreamNumber { get; set; } - /// - /// Required, ConcurrenyToken. - /// + /// [ConcurrencyCheck] - [Required] public uint RowVersion { get; set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ } } - diff --git a/Jellyfin.Data/Entities/Libraries/Metadata.cs b/Jellyfin.Data/Entities/Libraries/Metadata.cs index 449e807dec..877bb5fbdc 100644 --- a/Jellyfin.Data/Entities/Libraries/Metadata.cs +++ b/Jellyfin.Data/Entities/Libraries/Metadata.cs @@ -1,399 +1,165 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public abstract partial class Metadata + /// + /// An abstract class that holds metadata. + /// + public abstract class Metadata : IHasArtwork, IHasConcurrencyToken { - partial void Init(); - - /// - /// Default constructor. Protected due to being abstract. - /// - protected Metadata() - { - PersonRoles = new HashSet(); - Genres = new HashSet(); - Artwork = new HashSet(); - Ratings = new HashSet(); - Sources = new HashSet(); - - Init(); - } - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// /// The title or name of the object. /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - protected Metadata(string title, string language, DateTime dateadded, DateTime datemodified) + protected Metadata(string title, string language) { if (string.IsNullOrEmpty(title)) { throw new ArgumentNullException(nameof(title)); } - this.Title = title; - if (string.IsNullOrEmpty(language)) { throw new ArgumentNullException(nameof(language)); } - this.Language = language; - - this.PersonRoles = new HashSet(); - this.Genres = new HashSet(); - this.Artwork = new HashSet(); - this.Ratings = new HashSet(); - this.Sources = new HashSet(); + Title = title; + Language = language; + DateAdded = DateTime.UtcNow; + DateModified = DateAdded; - Init(); + PersonRoles = new HashSet(); + Genres = new HashSet(); + Artwork = new HashSet(); + Ratings = new HashSet(); + Sources = new HashSet(); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; /// - /// When provided in a partial class, allows value of Id to be changed before setting. + /// Initializes a new instance of the class. /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// - /// Identity, Indexed, Required. - /// - [Key] - [Required] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id + /// + /// Default constructor. Protected due to being abstract. + /// + protected Metadata() { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } } /// - /// Backing field for Title. - /// - protected string _Title; - /// - /// When provided in a partial class, allows value of Title to be changed before setting. - /// - partial void SetTitle(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Title to be changed before returning. + /// Gets or sets the id. /// - partial void GetTitle(ref string result); + /// + /// Identity, Indexed, Required. + /// + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; protected set; } /// - /// Required, Max length = 1024 - /// The title or name of the object. + /// Gets or sets the title. /// + /// + /// Required, Max length = 1024. + /// [Required] [MaxLength(1024)] [StringLength(1024)] - public string Title - { - get - { - string value = _Title; - GetTitle(ref value); - return _Title = value; - } + public string Title { get; set; } - set - { - string oldValue = _Title; - SetTitle(oldValue, ref value); - if (oldValue != value) - { - _Title = value; - } - } - } - - /// - /// Backing field for OriginalTitle. - /// - protected string _OriginalTitle; - /// - /// When provided in a partial class, allows value of OriginalTitle to be changed before setting. - /// - partial void SetOriginalTitle(string oldValue, ref string newValue); /// - /// When provided in a partial class, allows value of OriginalTitle to be changed before returning. - /// - partial void GetOriginalTitle(ref string result); - - /// - /// Max length = 1024 + /// Gets or sets the original title. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string OriginalTitle - { - get - { - string value = _OriginalTitle; - GetOriginalTitle(ref value); - return _OriginalTitle = value; - } - - set - { - string oldValue = _OriginalTitle; - SetOriginalTitle(oldValue, ref value); - if (oldValue != value) - { - _OriginalTitle = value; - } - } - } + public string OriginalTitle { get; set; } /// - /// Backing field for SortTitle. - /// - protected string _SortTitle; - /// - /// When provided in a partial class, allows value of SortTitle to be changed before setting. - /// - partial void SetSortTitle(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of SortTitle to be changed before returning. - /// - partial void GetSortTitle(ref string result); - - /// - /// Max length = 1024 + /// Gets or sets the sort title. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string SortTitle - { - get - { - string value = _SortTitle; - GetSortTitle(ref value); - return _SortTitle = value; - } - - set - { - string oldValue = _SortTitle; - SetSortTitle(oldValue, ref value); - if (oldValue != value) - { - _SortTitle = value; - } - } - } + public string SortTitle { get; set; } /// - /// Backing field for Language. - /// - protected string _Language; - /// - /// When provided in a partial class, allows value of Language to be changed before setting. + /// Gets or sets the language. /// - partial void SetLanguage(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Language to be changed before returning. - /// - partial void GetLanguage(ref string result); - - /// - /// Required, Min length = 3, Max length = 3 + /// + /// Required, Min length = 3, Max length = 3. /// ISO-639-3 3-character language codes. - /// + /// [Required] [MinLength(3)] [MaxLength(3)] [StringLength(3)] - public string Language - { - get - { - string value = _Language; - GetLanguage(ref value); - return _Language = value; - } - - set - { - string oldValue = _Language; - SetLanguage(oldValue, ref value); - if (oldValue != value) - { - _Language = value; - } - } - } + public string Language { get; set; } /// - /// Backing field for ReleaseDate. + /// Gets or sets the release date. /// - protected DateTimeOffset? _ReleaseDate; - /// - /// When provided in a partial class, allows value of ReleaseDate to be changed before setting. - /// - partial void SetReleaseDate(DateTimeOffset? oldValue, ref DateTimeOffset? newValue); - /// - /// When provided in a partial class, allows value of ReleaseDate to be changed before returning. - /// - partial void GetReleaseDate(ref DateTimeOffset? result); - - public DateTimeOffset? ReleaseDate - { - get - { - DateTimeOffset? value = _ReleaseDate; - GetReleaseDate(ref value); - return _ReleaseDate = value; - } - - set - { - DateTimeOffset? oldValue = _ReleaseDate; - SetReleaseDate(oldValue, ref value); - if (oldValue != value) - { - _ReleaseDate = value; - } - } - } + public DateTimeOffset? ReleaseDate { get; set; } /// - /// Backing field for DateAdded. + /// Gets or sets the date added. /// - protected DateTime _DateAdded; - /// - /// When provided in a partial class, allows value of DateAdded to be changed before setting. - /// - partial void SetDateAdded(DateTime oldValue, ref DateTime newValue); - /// - /// When provided in a partial class, allows value of DateAdded to be changed before returning. - /// - partial void GetDateAdded(ref DateTime result); + /// + /// Required. + /// + public DateTime DateAdded { get; protected set; } /// - /// Required. + /// Gets or sets the date modified. /// - [Required] - public DateTime DateAdded - { - get - { - DateTime value = _DateAdded; - GetDateAdded(ref value); - return _DateAdded = value; - } - - internal set - { - DateTime oldValue = _DateAdded; - SetDateAdded(oldValue, ref value); - if (oldValue != value) - { - _DateAdded = value; - } - } - } + /// + /// Required. + /// + public DateTime DateModified { get; set; } /// - /// Backing field for DateModified. + /// Gets or sets the row version. /// - protected DateTime _DateModified; + /// + /// Required, ConcurrencyToken. + /// + [ConcurrencyCheck] + public uint RowVersion { get; set; } + /// - /// When provided in a partial class, allows value of DateModified to be changed before setting. + /// Gets or sets a collection containing the person roles for this item. /// - partial void SetDateModified(DateTime oldValue, ref DateTime newValue); + public virtual ICollection PersonRoles { get; protected set; } + /// - /// When provided in a partial class, allows value of DateModified to be changed before returning. + /// Gets or sets a collection containing the generes for this item. /// - partial void GetDateModified(ref DateTime result); + public virtual ICollection Genres { get; protected set; } + + /// + public virtual ICollection Artwork { get; protected set; } /// - /// Required. + /// Gets or sets a collection containing the ratings for this item. /// - [Required] - public DateTime DateModified - { - get - { - DateTime value = _DateModified; - GetDateModified(ref value); - return _DateModified = value; - } - - internal set - { - DateTime oldValue = _DateModified; - SetDateModified(oldValue, ref value); - if (oldValue != value) - { - _DateModified = value; - } - } - } + public virtual ICollection Ratings { get; protected set; } /// - /// Required, ConcurrenyToken. + /// Gets or sets a collection containing the metadata sources for this item. /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + public virtual ICollection Sources { get; protected set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - - [ForeignKey("PersonRole_PersonRoles_Id")] - public virtual ICollection PersonRoles { get; protected set; } - - [ForeignKey("PersonRole_PersonRoles_Id")] - public virtual ICollection Genres { get; protected set; } - - [ForeignKey("PersonRole_PersonRoles_Id")] - public virtual ICollection Artwork { get; protected set; } - - [ForeignKey("PersonRole_PersonRoles_Id")] - public virtual ICollection Ratings { get; protected set; } - - [ForeignKey("PersonRole_PersonRoles_Id")] - public virtual ICollection Sources { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs b/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs index d5462113b0..a18a612bcd 100644 --- a/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs +++ b/Jellyfin.Data/Entities/Libraries/MetadataProvider.cs @@ -1,35 +1,19 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class MetadataProvider + /// + /// An entity representing a metadata provider. + /// + public class MetadataProvider : IHasConcurrencyToken { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected MetadataProvider() - { - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static MetadataProvider CreateMetadataProviderUnsafe() - { - return new MetadataProvider(); - } - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// - /// + /// The name of the metadata provider. public MetadataProvider(string name) { if (string.IsNullOrEmpty(name)) @@ -37,117 +21,47 @@ namespace Jellyfin.Data.Entities.Libraries throw new ArgumentNullException(nameof(name)); } - this.Name = name; - - Init(); + Name = name; } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - public static MetadataProvider Create(string name) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected MetadataProvider() { - return new MetadataProvider(name); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; /// - /// When provided in a partial class, allows value of Id to be changed before setting. + /// Gets or sets the id. /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } - - /// - /// Backing field for Name. - /// - protected string _Name; - /// - /// When provided in a partial class, allows value of Name to be changed before setting. - /// - partial void SetName(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Name to be changed before returning. - /// - partial void GetName(ref string result); + public int Id { get; protected set; } /// - /// Required, Max length = 1024 + /// Gets or sets the name. /// + /// + /// Required, Max length = 1024. + /// [Required] [MaxLength(1024)] [StringLength(1024)] - public string Name - { - get - { - string value = _Name; - GetName(ref value); - return _Name = value; - } + public string Name { get; set; } - set - { - string oldValue = _Name; - SetName(oldValue, ref value); - if (oldValue != value) - { - _Name = value; - } - } - } - - /// - /// Required, ConcurrenyToken. - /// + /// [ConcurrencyCheck] - [Required] public uint RowVersion { get; set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ } } - diff --git a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs b/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs index fed9d4f0bf..6e6de598e8 100644 --- a/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs +++ b/Jellyfin.Data/Entities/Libraries/MetadataProviderId.cs @@ -1,201 +1,83 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class MetadataProviderId + /// + /// An entity representing a unique identifier for a metadata provider. + /// + public class MetadataProviderId : IHasConcurrencyToken { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected MetadataProviderId() - { - // NOTE: This class has one-to-one associations with MetadataProviderId. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - - Init(); - } - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. + /// Initializes a new instance of the class. /// - public static MetadataProviderId CreateMetadataProviderIdUnsafe() + /// The provider id. + /// The metadata entity. + public MetadataProviderId(string providerId, Metadata metadata) { - return new MetadataProviderId(); - } - - /// - /// Public constructor with required data. - /// - /// - /// - /// - /// - /// - public MetadataProviderId(string providerid, Metadata _metadata0, Person _person1, PersonRole _personrole2, RatingSource _ratingsource3) - { - // NOTE: This class has one-to-one associations with MetadataProviderId. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - - if (string.IsNullOrEmpty(providerid)) + if (string.IsNullOrEmpty(providerId)) { - throw new ArgumentNullException(nameof(providerid)); + throw new ArgumentNullException(nameof(providerId)); } - this.ProviderId = providerid; + ProviderId = providerId; - if (_metadata0 == null) + if (metadata == null) { - throw new ArgumentNullException(nameof(_metadata0)); + throw new ArgumentNullException(nameof(metadata)); } - _metadata0.Sources.Add(this); - - if (_person1 == null) - { - throw new ArgumentNullException(nameof(_person1)); - } - - _person1.Sources.Add(this); - - if (_personrole2 == null) - { - throw new ArgumentNullException(nameof(_personrole2)); - } - - _personrole2.Sources.Add(this); - - if (_ratingsource3 == null) - { - throw new ArgumentNullException(nameof(_ratingsource3)); - } - - _ratingsource3.Source = this; - - Init(); + metadata.Sources.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - /// - /// - /// - /// - public static MetadataProviderId Create(string providerid, Metadata _metadata0, Person _person1, PersonRole _personrole2, RatingSource _ratingsource3) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected MetadataProviderId() { - return new MetadataProviderId(providerid, _metadata0, _person1, _personrole2, _ratingsource3); } - /************************************************************************* - * Properties - *************************************************************************/ - /// - /// Backing field for Id. + /// Gets or sets the id. /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } + public int Id { get; protected set; } /// - /// Backing field for ProviderId. - /// - protected string _ProviderId; - /// - /// When provided in a partial class, allows value of ProviderId to be changed before setting. - /// - partial void SetProviderId(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of ProviderId to be changed before returning. - /// - partial void GetProviderId(ref string result); - - /// - /// Required, Max length = 255 + /// Gets or sets the provider id. /// + /// + /// Required, Max length = 255. + /// [Required] [MaxLength(255)] [StringLength(255)] - public string ProviderId - { - get - { - string value = _ProviderId; - GetProviderId(ref value); - return _ProviderId = value; - } + public string ProviderId { get; set; } - set - { - string oldValue = _ProviderId; - SetProviderId(oldValue, ref value); - if (oldValue != value) - { - _ProviderId = value; - } - } - } + /// + [ConcurrencyCheck] + public uint RowVersion { get; set; } /// - /// Required, ConcurrenyToken. + /// Gets or sets the metadata provider. /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + /// + /// Required. + /// + public virtual MetadataProvider MetadataProvider { get; set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - - /// - /// Required. - /// - [ForeignKey("MetadataProvider_Id")] - public virtual MetadataProvider MetadataProvider { get; set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/Movie.cs b/Jellyfin.Data/Entities/Libraries/Movie.cs index e7d27b5519..0a8cc83dda 100644 --- a/Jellyfin.Data/Entities/Libraries/Movie.cs +++ b/Jellyfin.Data/Entities/Libraries/Movie.cs @@ -1,72 +1,28 @@ -#pragma warning disable CS1591 - -using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Movie : LibraryItem + /// + /// An entity representing a movie. + /// + public class Movie : LibraryItem, IHasReleases { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected Movie() + public Movie() { Releases = new HashSet(); MovieMetadata = new HashSet(); - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static Movie CreateMovieUnsafe() - { - return new Movie(); } - /// - /// Public constructor with required data. - /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public Movie(Guid urlid, DateTime dateadded) - { - this.UrlId = urlid; - - this.Releases = new HashSet(); - this.MovieMetadata = new HashSet(); - - Init(); - } + /// + public virtual ICollection Releases { get; protected set; } /// - /// Static create function (for use in LINQ queries, etc.) + /// Gets or sets a collection containing the metadata for this movie. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public static Movie Create(Guid urlid, DateTime dateadded) - { - return new Movie(urlid, dateadded); - } - - /************************************************************************* - * Properties - *************************************************************************/ - - /************************************************************************* - * Navigation properties - *************************************************************************/ - - [ForeignKey("Release_Releases_Id")] - public virtual ICollection Releases { get; protected set; } - - [ForeignKey("MovieMetadata_MovieMetadata_Id")] public virtual ICollection MovieMetadata { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs b/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs index f65da11d20..31102bf130 100644 --- a/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/MovieMetadata.cs @@ -1,244 +1,85 @@ -#pragma warning disable CS1591 - -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class MovieMetadata : Metadata + /// + /// An entity holding the metadata for a movie. + /// + public class MovieMetadata : Metadata, IHasCompanies { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected MovieMetadata() - { - Studios = new HashSet(); - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static MovieMetadata CreateMovieMetadataUnsafe() - { - return new MovieMetadata(); - } - - /// - /// Public constructor with required data. - /// - /// The title or name of the object. + /// The title or name of the movie. /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public MovieMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Movie _movie0) + /// The movie. + public MovieMetadata(string title, string language, Movie movie) : base(title, language) { - if (string.IsNullOrEmpty(title)) - { - throw new ArgumentNullException(nameof(title)); - } - - this.Title = title; - - if (string.IsNullOrEmpty(language)) - { - throw new ArgumentNullException(nameof(language)); - } - - this.Language = language; - - if (_movie0 == null) - { - throw new ArgumentNullException(nameof(_movie0)); - } - - _movie0.MovieMetadata.Add(this); - - this.Studios = new HashSet(); + Studios = new HashSet(); - Init(); + movie.MovieMetadata.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public static MovieMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Movie _movie0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected MovieMetadata() { - return new MovieMetadata(title, language, dateadded, datemodified, _movie0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Outline. - /// - protected string _Outline; /// - /// When provided in a partial class, allows value of Outline to be changed before setting. - /// - partial void SetOutline(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Outline to be changed before returning. - /// - partial void GetOutline(ref string result); - - /// - /// Max length = 1024 + /// Gets or sets the outline. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Outline - { - get - { - string value = _Outline; - GetOutline(ref value); - return _Outline = value; - } - - set - { - string oldValue = _Outline; - SetOutline(oldValue, ref value); - if (oldValue != value) - { - _Outline = value; - } - } - } + public string Outline { get; set; } /// - /// Backing field for Plot. - /// - protected string _Plot; - /// - /// When provided in a partial class, allows value of Plot to be changed before setting. - /// - partial void SetPlot(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Plot to be changed before returning. - /// - partial void GetPlot(ref string result); - - /// - /// Max length = 65535 - /// - [MaxLength(65535)] - [StringLength(65535)] - public string Plot - { - get - { - string value = _Plot; - GetPlot(ref value); - return _Plot = value; - } - - set - { - string oldValue = _Plot; - SetPlot(oldValue, ref value); - if (oldValue != value) - { - _Plot = value; - } - } - } - - /// - /// Backing field for Tagline. - /// - protected string _Tagline; - /// - /// When provided in a partial class, allows value of Tagline to be changed before setting. - /// - partial void SetTagline(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Tagline to be changed before returning. - /// - partial void GetTagline(ref string result); - - /// - /// Max length = 1024 + /// Gets or sets the tagline. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Tagline - { - get - { - string value = _Tagline; - GetTagline(ref value); - return _Tagline = value; - } - - set - { - string oldValue = _Tagline; - SetTagline(oldValue, ref value); - if (oldValue != value) - { - _Tagline = value; - } - } - } + public string Tagline { get; set; } /// - /// Backing field for Country. - /// - protected string _Country; - /// - /// When provided in a partial class, allows value of Country to be changed before setting. - /// - partial void SetCountry(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Country to be changed before returning. + /// Gets or sets the plot. /// - partial void GetCountry(ref string result); + /// + /// Max length = 65535. + /// + [MaxLength(65535)] + [StringLength(65535)] + public string Plot { get; set; } /// - /// Max length = 2 + /// Gets or sets the country code. /// + /// + /// Max length = 2. + /// [MaxLength(2)] [StringLength(2)] - public string Country - { - get - { - string value = _Country; - GetCountry(ref value); - return _Country = value; - } - - set - { - string oldValue = _Country; - SetCountry(oldValue, ref value); - if (oldValue != value) - { - _Country = value; - } - } - } + public string Country { get; set; } - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("Company_Studios_Id")] + /// + /// Gets or sets the studios that produced this movie. + /// public virtual ICollection Studios { get; protected set; } + + /// + [NotMapped] + public ICollection Companies => Studios; } } - diff --git a/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs b/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs index 52776b12e6..2ed1f78c56 100644 --- a/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs +++ b/Jellyfin.Data/Entities/Libraries/MusicAlbum.cs @@ -1,71 +1,29 @@ -#pragma warning disable CS1591 - -using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities.Libraries { - public partial class MusicAlbum : LibraryItem + /// + /// An entity representing a music album. + /// + public class MusicAlbum : LibraryItem { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected MusicAlbum() + public MusicAlbum() { MusicAlbumMetadata = new HashSet(); Tracks = new HashSet(); - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static MusicAlbum CreateMusicAlbumUnsafe() - { - return new MusicAlbum(); } /// - /// Public constructor with required data. + /// Gets or sets a collection containing the album metadata. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public MusicAlbum(Guid urlid, DateTime dateadded) - { - this.UrlId = urlid; - - this.MusicAlbumMetadata = new HashSet(); - this.Tracks = new HashSet(); - - Init(); - } + public virtual ICollection MusicAlbumMetadata { get; protected set; } /// - /// Static create function (for use in LINQ queries, etc.) + /// Gets or sets a collection containing the tracks. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public static MusicAlbum Create(Guid urlid, DateTime dateadded) - { - return new MusicAlbum(urlid, dateadded); - } - - /************************************************************************* - * Properties - *************************************************************************/ - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("MusicAlbumMetadata_MusicAlbumMetadata_Id")] - public virtual ICollection MusicAlbumMetadata { get; protected set; } - - [ForeignKey("Track_Tracks_Id")] public virtual ICollection Tracks { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs b/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs index f2480a5c54..cc5919bfe3 100644 --- a/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/MusicAlbumMetadata.cs @@ -1,207 +1,69 @@ -#pragma warning disable CS1591 - -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities.Libraries { - public partial class MusicAlbumMetadata : Metadata + /// + /// An entity holding the metadata for a music album. + /// + public class MusicAlbumMetadata : Metadata { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected MusicAlbumMetadata() - { - Labels = new HashSet(); - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static MusicAlbumMetadata CreateMusicAlbumMetadataUnsafe() - { - return new MusicAlbumMetadata(); - } - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// - /// The title or name of the object. + /// The title or name of the album. /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public MusicAlbumMetadata(string title, string language, DateTime dateadded, DateTime datemodified, MusicAlbum _musicalbum0) + /// The music album. + public MusicAlbumMetadata(string title, string language, MusicAlbum album) : base(title, language) { - if (string.IsNullOrEmpty(title)) - { - throw new ArgumentNullException(nameof(title)); - } - - this.Title = title; - - if (string.IsNullOrEmpty(language)) - { - throw new ArgumentNullException(nameof(language)); - } - - this.Language = language; - - if (_musicalbum0 == null) - { - throw new ArgumentNullException(nameof(_musicalbum0)); - } - - _musicalbum0.MusicAlbumMetadata.Add(this); - - this.Labels = new HashSet(); + Labels = new HashSet(); - Init(); + album.MusicAlbumMetadata.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public static MusicAlbumMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, MusicAlbum _musicalbum0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected MusicAlbumMetadata() { - return new MusicAlbumMetadata(title, language, dateadded, datemodified, _musicalbum0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Barcode. - /// - protected string _Barcode; - /// - /// When provided in a partial class, allows value of Barcode to be changed before setting. - /// - partial void SetBarcode(string oldValue, ref string newValue); /// - /// When provided in a partial class, allows value of Barcode to be changed before returning. - /// - partial void GetBarcode(ref string result); - - /// - /// Max length = 255 + /// Gets or sets the barcode. /// + /// + /// Max length = 255. + /// [MaxLength(255)] [StringLength(255)] - public string Barcode - { - get - { - string value = _Barcode; - GetBarcode(ref value); - return _Barcode = value; - } + public string Barcode { get; set; } - set - { - string oldValue = _Barcode; - SetBarcode(oldValue, ref value); - if (oldValue != value) - { - _Barcode = value; - } - } - } - - /// - /// Backing field for LabelNumber. - /// - protected string _LabelNumber; /// - /// When provided in a partial class, allows value of LabelNumber to be changed before setting. - /// - partial void SetLabelNumber(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of LabelNumber to be changed before returning. - /// - partial void GetLabelNumber(ref string result); - - /// - /// Max length = 255 + /// Gets or sets the label number. /// + /// + /// Max length = 255. + /// [MaxLength(255)] [StringLength(255)] - public string LabelNumber - { - get - { - string value = _LabelNumber; - GetLabelNumber(ref value); - return _LabelNumber = value; - } - - set - { - string oldValue = _LabelNumber; - SetLabelNumber(oldValue, ref value); - if (oldValue != value) - { - _LabelNumber = value; - } - } - } - - /// - /// Backing field for Country. - /// - protected string _Country; - /// - /// When provided in a partial class, allows value of Country to be changed before setting. - /// - partial void SetCountry(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Country to be changed before returning. - /// - partial void GetCountry(ref string result); + public string LabelNumber { get; set; } /// - /// Max length = 2 + /// Gets or sets the country code. /// + /// + /// Max length = 2. + /// [MaxLength(2)] [StringLength(2)] - public string Country - { - get - { - string value = _Country; - GetCountry(ref value); - return _Country = value; - } - - set - { - string oldValue = _Country; - SetCountry(oldValue, ref value); - if (oldValue != value) - { - _Country = value; - } - } - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ + public string Country { get; set; } - [ForeignKey("Company_Labels_Id")] + /// + /// Gets or sets a collection containing the labels. + /// public virtual ICollection Labels { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/Person.cs b/Jellyfin.Data/Entities/Libraries/Person.cs index f325a07ff8..8beb3dd084 100644 --- a/Jellyfin.Data/Entities/Libraries/Person.cs +++ b/Jellyfin.Data/Entities/Libraries/Person.cs @@ -1,317 +1,103 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Person + /// + /// An entity representing a person. + /// + public class Person : IHasConcurrencyToken { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected Person() - { - Sources = new HashSet(); - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static Person CreatePersonUnsafe() - { - return new Person(); - } - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// - /// - /// - /// The date the object was added. - /// The date the object was last modified. - public Person(Guid urlid, string name, DateTime dateadded, DateTime datemodified) + /// The name of the person. + public Person(string name) { - this.UrlId = urlid; - if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } - this.Name = name; - - this.Sources = new HashSet(); + Name = name; + DateAdded = DateTime.UtcNow; + DateModified = DateAdded; - Init(); + Sources = new HashSet(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - /// - /// The date the object was added. - /// The date the object was last modified. - public static Person Create(Guid urlid, string name, DateTime dateadded, DateTime datemodified) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected Person() { - return new Person(urlid, name, dateadded, datemodified); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; /// - /// When provided in a partial class, allows value of Id to be changed before setting. + /// Gets or sets the id. /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } - - /// - /// Backing field for UrlId. - /// - protected Guid _UrlId; - /// - /// When provided in a partial class, allows value of UrlId to be changed before setting. - /// - partial void SetUrlId(Guid oldValue, ref Guid newValue); - /// - /// When provided in a partial class, allows value of UrlId to be changed before returning. - /// - partial void GetUrlId(ref Guid result); - - /// - /// Required. - /// - [Required] - public Guid UrlId - { - get - { - Guid value = _UrlId; - GetUrlId(ref value); - return _UrlId = value; - } - - set - { - Guid oldValue = _UrlId; - SetUrlId(oldValue, ref value); - if (oldValue != value) - { - _UrlId = value; - } - } - } - - /// - /// Backing field for Name. - /// - protected string _Name; - /// - /// When provided in a partial class, allows value of Name to be changed before setting. - /// - partial void SetName(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Name to be changed before returning. - /// - partial void GetName(ref string result); + public int Id { get; protected set; } /// - /// Required, Max length = 1024 + /// Gets or sets the name. /// + /// + /// Required, Max length = 1024. + /// [Required] [MaxLength(1024)] [StringLength(1024)] - public string Name - { - get - { - string value = _Name; - GetName(ref value); - return _Name = value; - } - - set - { - string oldValue = _Name; - SetName(oldValue, ref value); - if (oldValue != value) - { - _Name = value; - } - } - } + public string Name { get; set; } /// - /// Backing field for SourceId. - /// - protected string _SourceId; - /// - /// When provided in a partial class, allows value of SourceId to be changed before setting. - /// - partial void SetSourceId(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of SourceId to be changed before returning. + /// Gets or sets the source id. /// - partial void GetSourceId(ref string result); + /// + /// Max length = 255. + /// + [MaxLength(256)] + [StringLength(256)] + public string SourceId { get; set; } /// - /// Max length = 255 + /// Gets or sets the date added. /// - [MaxLength(255)] - [StringLength(255)] - public string SourceId - { - get - { - string value = _SourceId; - GetSourceId(ref value); - return _SourceId = value; - } - - set - { - string oldValue = _SourceId; - SetSourceId(oldValue, ref value); - if (oldValue != value) - { - _SourceId = value; - } - } - } - - /// - /// Backing field for DateAdded. - /// - protected DateTime _DateAdded; - /// - /// When provided in a partial class, allows value of DateAdded to be changed before setting. - /// - partial void SetDateAdded(DateTime oldValue, ref DateTime newValue); - /// - /// When provided in a partial class, allows value of DateAdded to be changed before returning. - /// - partial void GetDateAdded(ref DateTime result); - - /// + /// /// Required. - /// - [Required] - public DateTime DateAdded - { - get - { - DateTime value = _DateAdded; - GetDateAdded(ref value); - return _DateAdded = value; - } - - internal set - { - DateTime oldValue = _DateAdded; - SetDateAdded(oldValue, ref value); - if (oldValue != value) - { - _DateAdded = value; - } - } - } + /// + public DateTime DateAdded { get; protected set; } /// - /// Backing field for DateModified. + /// Gets or sets the date modified. /// - protected DateTime _DateModified; - /// - /// When provided in a partial class, allows value of DateModified to be changed before setting. - /// - partial void SetDateModified(DateTime oldValue, ref DateTime newValue); - /// - /// When provided in a partial class, allows value of DateModified to be changed before returning. - /// - partial void GetDateModified(ref DateTime result); - - /// + /// /// Required. - /// - [Required] - public DateTime DateModified - { - get - { - DateTime value = _DateModified; - GetDateModified(ref value); - return _DateModified = value; - } + /// + public DateTime DateModified { get; set; } - internal set - { - DateTime oldValue = _DateModified; - SetDateModified(oldValue, ref value); - if (oldValue != value) - { - _DateModified = value; - } - } - } + /// + [ConcurrencyCheck] + public uint RowVersion { get; set; } /// - /// Required, ConcurrenyToken. + /// Gets or sets a list of metadata sources for this person. /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + public virtual ICollection Sources { get; protected set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("MetadataProviderId_Sources_Id")] - public virtual ICollection Sources { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/PersonRole.cs b/Jellyfin.Data/Entities/Libraries/PersonRole.cs index 04d50deaf7..5290228d6e 100644 --- a/Jellyfin.Data/Entities/Libraries/PersonRole.cs +++ b/Jellyfin.Data/Entities/Libraries/PersonRole.cs @@ -1,217 +1,98 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class PersonRole + /// + /// An entity representing a person's role in media. + /// + public class PersonRole : IHasArtwork, IHasConcurrencyToken { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected PersonRole() + /// The role type. + /// The metadata. + public PersonRole(PersonRoleType type, Metadata metadata) { - // NOTE: This class has one-to-one associations with PersonRole. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - - Sources = new HashSet(); + Type = type; - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static PersonRole CreatePersonRoleUnsafe() - { - return new PersonRole(); - } - - /// - /// Public constructor with required data. - /// - /// - /// - public PersonRole(Enums.PersonRoleType type, Metadata _metadata0) - { - // NOTE: This class has one-to-one associations with PersonRole. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - - this.Type = type; - - if (_metadata0 == null) + if (metadata == null) { - throw new ArgumentNullException(nameof(_metadata0)); + throw new ArgumentNullException(nameof(metadata)); } - _metadata0.PersonRoles.Add(this); - - this.Sources = new HashSet(); + metadata.PersonRoles.Add(this); - Init(); + Sources = new HashSet(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - /// - public static PersonRole Create(Enums.PersonRoleType type, Metadata _metadata0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected PersonRole() { - return new PersonRole(type, _metadata0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); /// - /// When provided in a partial class, allows value of Id to be changed before returning. + /// Gets or sets the id. /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } - - /// - /// Backing field for Role. - /// - protected string _Role; - /// - /// When provided in a partial class, allows value of Role to be changed before setting. - /// - partial void SetRole(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Role to be changed before returning. - /// - partial void GetRole(ref string result); + public int Id { get; protected set; } /// - /// Max length = 1024 + /// Gets or sets the name of the person's role. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Role - { - get - { - string value = _Role; - GetRole(ref value); - return _Role = value; - } - - set - { - string oldValue = _Role; - SetRole(oldValue, ref value); - if (oldValue != value) - { - _Role = value; - } - } - } + public string Role { get; set; } /// - /// Backing field for Type. + /// Gets or sets the person's role type. /// - protected Enums.PersonRoleType _Type; - /// - /// When provided in a partial class, allows value of Type to be changed before setting. - /// - partial void SetType(Enums.PersonRoleType oldValue, ref Enums.PersonRoleType newValue); - /// - /// When provided in a partial class, allows value of Type to be changed before returning. - /// - partial void GetType(ref Enums.PersonRoleType result); + /// + /// Required. + /// + public PersonRoleType Type { get; set; } + + /// + [ConcurrencyCheck] + public uint RowVersion { get; protected set; } /// - /// Required. + /// Gets or sets the person. /// + /// + /// Required. + /// [Required] - public Enums.PersonRoleType Type - { - get - { - Enums.PersonRoleType value = _Type; - GetType(ref value); - return _Type = value; - } + public virtual Person Person { get; set; } - set - { - Enums.PersonRoleType oldValue = _Type; - SetType(oldValue, ref value); - if (oldValue != value) - { - _Type = value; - } - } - } + /// + public virtual ICollection Artwork { get; protected set; } /// - /// Required, ConcurrenyToken. + /// Gets or sets a collection containing the metadata sources for this person role. /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + public virtual ICollection Sources { get; protected set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - - /// - /// Required. - /// - [ForeignKey("Person_Id")] - - public virtual Person Person { get; set; } - - [ForeignKey("Artwork_Artwork_Id")] - public virtual Artwork Artwork { get; set; } - - [ForeignKey("MetadataProviderId_Sources_Id")] - public virtual ICollection Sources { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/Photo.cs b/Jellyfin.Data/Entities/Libraries/Photo.cs index 01c39b3ead..44338a4cea 100644 --- a/Jellyfin.Data/Entities/Libraries/Photo.cs +++ b/Jellyfin.Data/Entities/Libraries/Photo.cs @@ -1,71 +1,28 @@ -#pragma warning disable CS1591 - -using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Photo : LibraryItem + /// + /// An entity representing a photo. + /// + public class Photo : LibraryItem, IHasReleases { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected Photo() + public Photo() { PhotoMetadata = new HashSet(); Releases = new HashSet(); - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static Photo CreatePhotoUnsafe() - { - return new Photo(); - } - - /// - /// Public constructor with required data. - /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public Photo(Guid urlid, DateTime dateadded) - { - this.UrlId = urlid; - - this.PhotoMetadata = new HashSet(); - this.Releases = new HashSet(); - - Init(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Gets or sets a collection containing the photo metadata. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public static Photo Create(Guid urlid, DateTime dateadded) - { - return new Photo(urlid, dateadded); - } - - /************************************************************************* - * Properties - *************************************************************************/ - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("PhotoMetadata_PhotoMetadata_Id")] public virtual ICollection PhotoMetadata { get; protected set; } - [ForeignKey("Release_Releases_Id")] + /// public virtual ICollection Releases { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs b/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs index 701623fd14..1ef9dd5f9c 100644 --- a/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/PhotoMetadata.cs @@ -1,83 +1,36 @@ -#pragma warning disable CS1591 - using System; namespace Jellyfin.Data.Entities.Libraries { - public partial class PhotoMetadata : Metadata + /// + /// An entity that holds metadata for a photo. + /// + public class PhotoMetadata : Metadata { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected PhotoMetadata() - { - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static PhotoMetadata CreatePhotoMetadataUnsafe() - { - return new PhotoMetadata(); - } - - /// - /// Public constructor with required data. - /// - /// The title or name of the object. + /// The title or name of the photo. /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public PhotoMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Photo _photo0) + /// The photo. + public PhotoMetadata(string title, string language, Photo photo) : base(title, language) { - if (string.IsNullOrEmpty(title)) + if (photo == null) { - throw new ArgumentNullException(nameof(title)); + throw new ArgumentNullException(nameof(photo)); } - this.Title = title; - - if (string.IsNullOrEmpty(language)) - { - throw new ArgumentNullException(nameof(language)); - } - - this.Language = language; - - if (_photo0 == null) - { - throw new ArgumentNullException(nameof(_photo0)); - } - - _photo0.PhotoMetadata.Add(this); - - Init(); + photo.PhotoMetadata.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public static PhotoMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Photo _photo0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected PhotoMetadata() { - return new PhotoMetadata(title, language, dateadded, datemodified, _photo0); } - - /************************************************************************* - * Properties - *************************************************************************/ - - /************************************************************************* - * Navigation properties - *************************************************************************/ } } - diff --git a/Jellyfin.Data/Entities/Libraries/Rating.cs b/Jellyfin.Data/Entities/Libraries/Rating.cs index 31bee165af..ba054a39e0 100644 --- a/Jellyfin.Data/Entities/Libraries/Rating.cs +++ b/Jellyfin.Data/Entities/Libraries/Rating.cs @@ -1,194 +1,78 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Rating + /// + /// An entity representing a rating for an entity. + /// + public class Rating : IHasConcurrencyToken { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected Rating() + /// The value. + /// The metadata. + public Rating(double value, Metadata metadata) { - Init(); - } + Value = value; - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static Rating CreateRatingUnsafe() - { - return new Rating(); - } - - /// - /// Public constructor with required data. - /// - /// - /// - public Rating(double value, Metadata _metadata0) - { - this.Value = value; - - if (_metadata0 == null) + if (metadata == null) { - throw new ArgumentNullException(nameof(_metadata0)); + throw new ArgumentNullException(nameof(metadata)); } - _metadata0.Ratings.Add(this); - - Init(); + metadata.Ratings.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - /// - public static Rating Create(double value, Metadata _metadata0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected Rating() { - return new Rating(value, _metadata0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; - /// - /// When provided in a partial class, allows value of Id to be changed before setting. - /// - partial void SetId(int oldValue, ref int newValue); /// - /// When provided in a partial class, allows value of Id to be changed before returning. + /// Gets or sets the id. /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } + public int Id { get; protected set; } /// - /// Backing field for Value. - /// - protected double _Value; - /// - /// When provided in a partial class, allows value of Value to be changed before setting. + /// Gets or sets the value. /// - partial void SetValue(double oldValue, ref double newValue); - /// - /// When provided in a partial class, allows value of Value to be changed before returning. - /// - partial void GetValue(ref double result); - - /// + /// /// Required. - /// - [Required] - public double Value - { - get - { - double value = _Value; - GetValue(ref value); - return _Value = value; - } + /// + public double Value { get; set; } - set - { - double oldValue = _Value; - SetValue(oldValue, ref value); - if (oldValue != value) - { - _Value = value; - } - } - } - - /// - /// Backing field for Votes. - /// - protected int? _Votes; - /// - /// When provided in a partial class, allows value of Votes to be changed before setting. - /// - partial void SetVotes(int? oldValue, ref int? newValue); /// - /// When provided in a partial class, allows value of Votes to be changed before returning. + /// Gets or sets the number of votes. /// - partial void GetVotes(ref int? result); - - public int? Votes - { - get - { - int? value = _Votes; - GetVotes(ref value); - return _Votes = value; - } + public int? Votes { get; set; } - set - { - int? oldValue = _Votes; - SetVotes(oldValue, ref value); - if (oldValue != value) - { - _Votes = value; - } - } - } + /// + [ConcurrencyCheck] + public uint RowVersion { get; set; } /// - /// Required, ConcurrenyToken. + /// Gets or sets the rating type. + /// If this is null it's the internal user rating. /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + public virtual RatingSource RatingType { get; set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - - /// - /// If this is NULL it's the internal user rating. - /// - [ForeignKey("RatingSource_RatingType_Id")] - public virtual RatingSource RatingType { get; set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/RatingSource.cs b/Jellyfin.Data/Entities/Libraries/RatingSource.cs index 8204e9ff23..549f418042 100644 --- a/Jellyfin.Data/Entities/Libraries/RatingSource.cs +++ b/Jellyfin.Data/Entities/Libraries/RatingSource.cs @@ -1,239 +1,92 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { /// /// This is the entity to store review ratings, not age ratings. /// - public partial class RatingSource + public class RatingSource : IHasConcurrencyToken { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected RatingSource() + /// The minimum value. + /// The maximum value. + /// The rating. + public RatingSource(double minimumValue, double maximumValue, Rating rating) { - Init(); - } + MinimumValue = minimumValue; + MaximumValue = maximumValue; - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static RatingSource CreateRatingSourceUnsafe() - { - return new RatingSource(); - } - - /// - /// Public constructor with required data. - /// - /// - /// - /// - public RatingSource(double maximumvalue, double minimumvalue, Rating _rating0) - { - this.MaximumValue = maximumvalue; - - this.MinimumValue = minimumvalue; - - if (_rating0 == null) + if (rating == null) { - throw new ArgumentNullException(nameof(_rating0)); + throw new ArgumentNullException(nameof(rating)); } - _rating0.RatingType = this; - - Init(); + rating.RatingType = this; } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - /// - /// - public static RatingSource Create(double maximumvalue, double minimumvalue, Rating _rating0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected RatingSource() { - return new RatingSource(maximumvalue, minimumvalue, _rating0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; /// - /// When provided in a partial class, allows value of Id to be changed before setting. + /// Gets or sets the id. /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } - - /// - /// Backing field for Name. - /// - protected string _Name; - /// - /// When provided in a partial class, allows value of Name to be changed before setting. - /// - partial void SetName(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Name to be changed before returning. - /// - partial void GetName(ref string result); + public int Id { get; protected set; } /// - /// Max length = 1024 + /// Gets or sets the name. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Name - { - get - { - string value = _Name; - GetName(ref value); - return _Name = value; - } - - set - { - string oldValue = _Name; - SetName(oldValue, ref value); - if (oldValue != value) - { - _Name = value; - } - } - } + public string Name { get; set; } /// - /// Backing field for MaximumValue. + /// Gets or sets the minimum value. /// - protected double _MaximumValue; - /// - /// When provided in a partial class, allows value of MaximumValue to be changed before setting. - /// - partial void SetMaximumValue(double oldValue, ref double newValue); - /// - /// When provided in a partial class, allows value of MaximumValue to be changed before returning. - /// - partial void GetMaximumValue(ref double result); - - /// + /// /// Required. - /// - [Required] - public double MaximumValue - { - get - { - double value = _MaximumValue; - GetMaximumValue(ref value); - return _MaximumValue = value; - } - - set - { - double oldValue = _MaximumValue; - SetMaximumValue(oldValue, ref value); - if (oldValue != value) - { - _MaximumValue = value; - } - } - } + /// + public double MinimumValue { get; set; } /// - /// Backing field for MinimumValue. + /// Gets or sets the maximum value. /// - protected double _MinimumValue; - /// - /// When provided in a partial class, allows value of MinimumValue to be changed before setting. - /// - partial void SetMinimumValue(double oldValue, ref double newValue); - /// - /// When provided in a partial class, allows value of MinimumValue to be changed before returning. - /// - partial void GetMinimumValue(ref double result); - - /// + /// /// Required. - /// - [Required] - public double MinimumValue - { - get - { - double value = _MinimumValue; - GetMinimumValue(ref value); - return _MinimumValue = value; - } + /// + public double MaximumValue { get; set; } - set - { - double oldValue = _MinimumValue; - SetMinimumValue(oldValue, ref value); - if (oldValue != value) - { - _MinimumValue = value; - } - } - } + /// + [ConcurrencyCheck] + public uint RowVersion { get; set; } /// - /// Required, ConcurrenyToken. + /// Gets or sets the metadata source. /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + public virtual MetadataProviderId Source { get; set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("MetadataProviderId_Source_Id")] - public virtual MetadataProviderId Source { get; set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/Release.cs b/Jellyfin.Data/Entities/Libraries/Release.cs index 4b42d65ec5..43c7080d79 100644 --- a/Jellyfin.Data/Entities/Libraries/Release.cs +++ b/Jellyfin.Data/Entities/Libraries/Release.cs @@ -1,219 +1,84 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Release + /// + /// An entity representing a release for a library item, eg. Director's cut vs. standard. + /// + public class Release : IHasConcurrencyToken { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected Release() - { - MediaFiles = new HashSet(); - Chapters = new HashSet(); - - Init(); - } - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. + /// Initializes a new instance of the class. /// - public static Release CreateReleaseUnsafe() - { - return new Release(); - } - - /// - /// Public constructor with required data. - /// - /// - /// - /// - /// - /// - /// - /// - public Release(string name, Movie _movie0, Episode _episode1, Track _track2, CustomItem _customitem3, Book _book4, Photo _photo5) + /// The name of this release. + /// The owner of this release. + public Release(string name, IHasReleases owner) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } - this.Name = name; + Name = name; - if (_movie0 == null) - { - throw new ArgumentNullException(nameof(_movie0)); - } - - _movie0.Releases.Add(this); - - if (_episode1 == null) - { - throw new ArgumentNullException(nameof(_episode1)); - } + owner?.Releases.Add(this); - _episode1.Releases.Add(this); - - if (_track2 == null) - { - throw new ArgumentNullException(nameof(_track2)); - } - - _track2.Releases.Add(this); - - if (_customitem3 == null) - { - throw new ArgumentNullException(nameof(_customitem3)); - } - - _customitem3.Releases.Add(this); - - if (_book4 == null) - { - throw new ArgumentNullException(nameof(_book4)); - } - - _book4.Releases.Add(this); - - if (_photo5 == null) - { - throw new ArgumentNullException(nameof(_photo5)); - } - - _photo5.Releases.Add(this); - - this.MediaFiles = new HashSet(); - this.Chapters = new HashSet(); - - Init(); + MediaFiles = new HashSet(); + Chapters = new HashSet(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// - /// - /// - /// - /// - /// - /// - public static Release Create(string name, Movie _movie0, Episode _episode1, Track _track2, CustomItem _customitem3, Book _book4, Photo _photo5) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected Release() { - return new Release(name, _movie0, _episode1, _track2, _customitem3, _book4, _photo5); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Id. - /// - internal int _Id; /// - /// When provided in a partial class, allows value of Id to be changed before setting. + /// Gets or sets the id. /// - partial void SetId(int oldValue, ref int newValue); - /// - /// When provided in a partial class, allows value of Id to be changed before returning. - /// - partial void GetId(ref int result); - - /// + /// /// Identity, Indexed, Required. - /// - [Key] - [Required] + /// [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id - { - get - { - int value = _Id; - GetId(ref value); - return _Id = value; - } - - protected set - { - int oldValue = _Id; - SetId(oldValue, ref value); - if (oldValue != value) - { - _Id = value; - } - } - } - - /// - /// Backing field for Name. - /// - protected string _Name; - /// - /// When provided in a partial class, allows value of Name to be changed before setting. - /// - partial void SetName(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Name to be changed before returning. - /// - partial void GetName(ref string result); + public int Id { get; protected set; } /// - /// Required, Max length = 1024 + /// Gets or sets the name. /// + /// + /// Required, Max length = 1024. + /// [Required] [MaxLength(1024)] [StringLength(1024)] - public string Name - { - get - { - string value = _Name; - GetName(ref value); - return _Name = value; - } + public string Name { get; set; } - set - { - string oldValue = _Name; - SetName(oldValue, ref value); - if (oldValue != value) - { - _Name = value; - } - } - } + /// + [ConcurrencyCheck] + public uint RowVersion { get; set; } /// - /// Required, ConcurrenyToken. + /// Gets or sets a collection containing the media files for this release. /// - [ConcurrencyCheck] - [Required] - public uint RowVersion { get; set; } + public virtual ICollection MediaFiles { get; protected set; } + + /// + /// Gets or sets a collection containing the chapters for this release. + /// + public virtual ICollection Chapters { get; protected set; } + /// public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("MediaFile_MediaFiles_Id")] - public virtual ICollection MediaFiles { get; protected set; } - - [ForeignKey("Chapter_Chapters_Id")] - public virtual ICollection Chapters { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/Season.cs b/Jellyfin.Data/Entities/Libraries/Season.cs index 90885f0e97..eef788bad2 100644 --- a/Jellyfin.Data/Entities/Libraries/Season.cs +++ b/Jellyfin.Data/Entities/Libraries/Season.cs @@ -1,119 +1,53 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities.Libraries { - public partial class Season : LibraryItem + /// + /// An entity representing a season. + /// + public class Season : LibraryItem { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected Season() + /// The series. + public Season(Series series) { - // NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - - SeasonMetadata = new HashSet(); - Episodes = new HashSet(); - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static Season CreateSeasonUnsafe() - { - return new Season(); - } - - /// - /// Public constructor with required data. - /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - /// - public Season(Guid urlid, DateTime dateadded, Series _series0) - { - // NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - - this.UrlId = urlid; - - if (_series0 == null) + if (series == null) { - throw new ArgumentNullException(nameof(_series0)); + throw new ArgumentNullException(nameof(series)); } - _series0.Seasons.Add(this); - - this.SeasonMetadata = new HashSet(); - this.Episodes = new HashSet(); + series.Seasons.Add(this); - Init(); + Episodes = new HashSet(); + SeasonMetadata = new HashSet(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - /// - public static Season Create(Guid urlid, DateTime dateadded, Series _series0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected Season() { - return new Season(urlid, dateadded, _series0); } - /************************************************************************* - * Properties - *************************************************************************/ - /// - /// Backing field for SeasonNumber. + /// Gets or sets the season number. /// - protected int? _SeasonNumber; - /// - /// When provided in a partial class, allows value of SeasonNumber to be changed before setting. - /// - partial void SetSeasonNumber(int? oldValue, ref int? newValue); + public int? SeasonNumber { get; set; } + /// - /// When provided in a partial class, allows value of SeasonNumber to be changed before returning. + /// Gets or sets the season metadata. /// - partial void GetSeasonNumber(ref int? result); - - public int? SeasonNumber - { - get - { - int? value = _SeasonNumber; - GetSeasonNumber(ref value); - return _SeasonNumber = value; - } - - set - { - int? oldValue = _SeasonNumber; - SetSeasonNumber(oldValue, ref value); - if (oldValue != value) - { - _SeasonNumber = value; - } - } - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("SeasonMetadata_SeasonMetadata_Id")] public virtual ICollection SeasonMetadata { get; protected set; } - [ForeignKey("Episode_Episodes_Id")] + /// + /// Gets or sets a collection containing the number of episodes. + /// public virtual ICollection Episodes { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs b/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs index 28105fe2cc..eedeb089e8 100644 --- a/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/SeasonMetadata.cs @@ -1,122 +1,47 @@ -#pragma warning disable CS1591 - using System; using System.ComponentModel.DataAnnotations; namespace Jellyfin.Data.Entities.Libraries { - public partial class SeasonMetadata : Metadata + /// + /// An entity that holds metadata for seasons. + /// + public class SeasonMetadata : Metadata { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected SeasonMetadata() - { - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static SeasonMetadata CreateSeasonMetadataUnsafe() - { - return new SeasonMetadata(); - } - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// /// The title or name of the object. /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public SeasonMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Season _season0) + /// The season. + public SeasonMetadata(string title, string language, Season season) : base(title, language) { - if (string.IsNullOrEmpty(title)) - { - throw new ArgumentNullException(nameof(title)); - } - - this.Title = title; - - if (string.IsNullOrEmpty(language)) - { - throw new ArgumentNullException(nameof(language)); - } - - this.Language = language; - - if (_season0 == null) + if (season == null) { - throw new ArgumentNullException(nameof(_season0)); + throw new ArgumentNullException(nameof(season)); } - _season0.SeasonMetadata.Add(this); - - Init(); + season.SeasonMetadata.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public static SeasonMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Season _season0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected SeasonMetadata() { - return new SeasonMetadata(title, language, dateadded, datemodified, _season0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Outline. - /// - protected string _Outline; - /// - /// When provided in a partial class, allows value of Outline to be changed before setting. - /// - partial void SetOutline(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Outline to be changed before returning. - /// - partial void GetOutline(ref string result); - /// - /// Max length = 1024 + /// Gets or sets the outline. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Outline - { - get - { - string value = _Outline; - GetOutline(ref value); - return _Outline = value; - } - - set - { - string oldValue = _Outline; - SetOutline(oldValue, ref value); - if (oldValue != value) - { - _Outline = value; - } - } - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ + public string Outline { get; set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/Series.cs b/Jellyfin.Data/Entities/Libraries/Series.cs index a137f0f687..e959c1fe00 100644 --- a/Jellyfin.Data/Entities/Libraries/Series.cs +++ b/Jellyfin.Data/Entities/Libraries/Series.cs @@ -1,165 +1,46 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities.Libraries { - public partial class Series : LibraryItem + /// + /// An entity representing a a series. + /// + public class Series : LibraryItem { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected Series() + public Series() { - SeriesMetadata = new HashSet(); + DateAdded = DateTime.UtcNow; Seasons = new HashSet(); - - Init(); + SeriesMetadata = new HashSet(); } /// - /// Public constructor with required data. + /// Gets or sets the days of week. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public Series(Guid urlid, DateTime dateadded) - { - this.UrlId = urlid; - - this.SeriesMetadata = new HashSet(); - this.Seasons = new HashSet(); - - Init(); - } + public DayOfWeek? AirsDayOfWeek { get; set; } /// - /// Static create function (for use in LINQ queries, etc.) + /// Gets or sets the time the show airs, ignore the date portion. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - public static Series Create(Guid urlid, DateTime dateadded) - { - return new Series(urlid, dateadded); - } + public DateTimeOffset? AirsTime { get; set; } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for AirsDayOfWeek. - /// - protected DayOfWeek? _AirsDayOfWeek; /// - /// When provided in a partial class, allows value of AirsDayOfWeek to be changed before setting. + /// Gets or sets the date the series first aired. /// - partial void SetAirsDayOfWeek(DayOfWeek? oldValue, ref DayOfWeek? newValue); - /// - /// When provided in a partial class, allows value of AirsDayOfWeek to be changed before returning. - /// - partial void GetAirsDayOfWeek(ref DayOfWeek? result); + public DateTime? FirstAired { get; set; } - public DayOfWeek? AirsDayOfWeek - { - get - { - DayOfWeek? value = _AirsDayOfWeek; - GetAirsDayOfWeek(ref value); - return _AirsDayOfWeek = value; - } - - set - { - DayOfWeek? oldValue = _AirsDayOfWeek; - SetAirsDayOfWeek(oldValue, ref value); - if (oldValue != value) - { - _AirsDayOfWeek = value; - } - } - } - - /// - /// Backing field for AirsTime. - /// - protected DateTimeOffset? _AirsTime; /// - /// When provided in a partial class, allows value of AirsTime to be changed before setting. + /// Gets or sets a collection containing the series metadata. /// - partial void SetAirsTime(DateTimeOffset? oldValue, ref DateTimeOffset? newValue); - /// - /// When provided in a partial class, allows value of AirsTime to be changed before returning. - /// - partial void GetAirsTime(ref DateTimeOffset? result); - - /// - /// The time the show airs, ignore the date portion. - /// - public DateTimeOffset? AirsTime - { - get - { - DateTimeOffset? value = _AirsTime; - GetAirsTime(ref value); - return _AirsTime = value; - } - - set - { - DateTimeOffset? oldValue = _AirsTime; - SetAirsTime(oldValue, ref value); - if (oldValue != value) - { - _AirsTime = value; - } - } - } + public virtual ICollection SeriesMetadata { get; protected set; } /// - /// Backing field for FirstAired. - /// - protected DateTimeOffset? _FirstAired; - /// - /// When provided in a partial class, allows value of FirstAired to be changed before setting. + /// Gets or sets a collection containing the seasons. /// - partial void SetFirstAired(DateTimeOffset? oldValue, ref DateTimeOffset? newValue); - /// - /// When provided in a partial class, allows value of FirstAired to be changed before returning. - /// - partial void GetFirstAired(ref DateTimeOffset? result); - - public DateTimeOffset? FirstAired - { - get - { - DateTimeOffset? value = _FirstAired; - GetFirstAired(ref value); - return _FirstAired = value; - } - - set - { - DateTimeOffset? oldValue = _FirstAired; - SetFirstAired(oldValue, ref value); - if (oldValue != value) - { - _FirstAired = value; - } - } - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("SeriesMetadata_SeriesMetadata_Id")] - public virtual ICollection SeriesMetadata { get; protected set; } - - [ForeignKey("Season_Seasons_Id")] public virtual ICollection Seasons { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs b/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs index 6e61da1e6c..898f3006dc 100644 --- a/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/SeriesMetadata.cs @@ -1,244 +1,91 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class SeriesMetadata : Metadata + /// + /// An entity representing series metadata. + /// + public class SeriesMetadata : Metadata, IHasCompanies { - partial void Init(); - - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected SeriesMetadata() - { - Networks = new HashSet(); - - Init(); - } - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static SeriesMetadata CreateSeriesMetadataUnsafe() - { - return new SeriesMetadata(); - } - - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// /// The title or name of the object. /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public SeriesMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Series _series0) + /// The series. + public SeriesMetadata(string title, string language, Series series) : base(title, language) { - if (string.IsNullOrEmpty(title)) - { - throw new ArgumentNullException(nameof(title)); - } - - this.Title = title; - - if (string.IsNullOrEmpty(language)) - { - throw new ArgumentNullException(nameof(language)); - } - - this.Language = language; - - if (_series0 == null) + if (series == null) { - throw new ArgumentNullException(nameof(_series0)); + throw new ArgumentNullException(nameof(series)); } - _series0.SeriesMetadata.Add(this); - - this.Networks = new HashSet(); + series.SeriesMetadata.Add(this); - Init(); + Networks = new HashSet(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public static SeriesMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Series _series0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected SeriesMetadata() { - return new SeriesMetadata(title, language, dateadded, datemodified, _series0); } - /************************************************************************* - * Properties - *************************************************************************/ - - /// - /// Backing field for Outline. - /// - protected string _Outline; - /// - /// When provided in a partial class, allows value of Outline to be changed before setting. - /// - partial void SetOutline(string oldValue, ref string newValue); /// - /// When provided in a partial class, allows value of Outline to be changed before returning. - /// - partial void GetOutline(ref string result); - - /// - /// Max length = 1024 + /// Gets or sets the outline. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Outline - { - get - { - string value = _Outline; - GetOutline(ref value); - return _Outline = value; - } - - set - { - string oldValue = _Outline; - SetOutline(oldValue, ref value); - if (oldValue != value) - { - _Outline = value; - } - } - } + public string Outline { get; set; } /// - /// Backing field for Plot. - /// - protected string _Plot; - /// - /// When provided in a partial class, allows value of Plot to be changed before setting. - /// - partial void SetPlot(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Plot to be changed before returning. - /// - partial void GetPlot(ref string result); - - /// - /// Max length = 65535 + /// Gets or sets the plot. /// + /// + /// Max length = 65535. + /// [MaxLength(65535)] [StringLength(65535)] - public string Plot - { - get - { - string value = _Plot; - GetPlot(ref value); - return _Plot = value; - } + public string Plot { get; set; } - set - { - string oldValue = _Plot; - SetPlot(oldValue, ref value); - if (oldValue != value) - { - _Plot = value; - } - } - } - - /// - /// Backing field for Tagline. - /// - protected string _Tagline; /// - /// When provided in a partial class, allows value of Tagline to be changed before setting. - /// - partial void SetTagline(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Tagline to be changed before returning. - /// - partial void GetTagline(ref string result); - - /// - /// Max length = 1024 + /// Gets or sets the tagline. /// + /// + /// Max length = 1024. + /// [MaxLength(1024)] [StringLength(1024)] - public string Tagline - { - get - { - string value = _Tagline; - GetTagline(ref value); - return _Tagline = value; - } - - set - { - string oldValue = _Tagline; - SetTagline(oldValue, ref value); - if (oldValue != value) - { - _Tagline = value; - } - } - } - - /// - /// Backing field for Country. - /// - protected string _Country; - /// - /// When provided in a partial class, allows value of Country to be changed before setting. - /// - partial void SetCountry(string oldValue, ref string newValue); - /// - /// When provided in a partial class, allows value of Country to be changed before returning. - /// - partial void GetCountry(ref string result); + public string Tagline { get; set; } /// - /// Max length = 2 + /// Gets or sets the country code. /// + /// + /// Max length = 2. + /// [MaxLength(2)] [StringLength(2)] - public string Country - { - get - { - string value = _Country; - GetCountry(ref value); - return _Country = value; - } + public string Country { get; set; } - set - { - string oldValue = _Country; - SetCountry(oldValue, ref value); - if (oldValue != value) - { - _Country = value; - } - } - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - [ForeignKey("Company_Networks_Id")] + /// + /// Gets or sets a collection containing the networks. + /// public virtual ICollection Networks { get; protected set; } + + /// + [NotMapped] + public ICollection Companies => Networks; } } - diff --git a/Jellyfin.Data/Entities/Libraries/Track.cs b/Jellyfin.Data/Entities/Libraries/Track.cs index cdcc22d71a..09ce82a9b4 100644 --- a/Jellyfin.Data/Entities/Libraries/Track.cs +++ b/Jellyfin.Data/Entities/Libraries/Track.cs @@ -1,120 +1,52 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities.Libraries { - public partial class Track : LibraryItem + /// + /// An entity representing a track. + /// + public class Track : LibraryItem, IHasReleases { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. + /// Initializes a new instance of the class. /// - protected Track() + /// The album. + public Track(MusicAlbum album) { - // NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - - Releases = new HashSet(); - TrackMetadata = new HashSet(); - - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static Track CreateTrackUnsafe() - { - return new Track(); - } - - /// - /// Public constructor with required data. - /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - /// - public Track(Guid urlid, DateTime dateadded, MusicAlbum _musicalbum0) - { - // NOTE: This class has one-to-one associations with LibraryRoot, LibraryItem and CollectionItem. - // One-to-one associations are not validated in constructors since this causes a scenario where each one must be constructed before the other. - - this.UrlId = urlid; - - if (_musicalbum0 == null) + if (album == null) { - throw new ArgumentNullException(nameof(_musicalbum0)); + throw new ArgumentNullException(nameof(album)); } - _musicalbum0.Tracks.Add(this); - - this.Releases = new HashSet(); - this.TrackMetadata = new HashSet(); + album.Tracks.Add(this); - Init(); + Releases = new HashSet(); + TrackMetadata = new HashSet(); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// This is whats gets displayed in the Urls and API requests. This could also be a string. - /// The date the object was added. - /// - public static Track Create(Guid urlid, DateTime dateadded, MusicAlbum _musicalbum0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected Track() { - return new Track(urlid, dateadded, _musicalbum0); } - /************************************************************************* - * Properties - *************************************************************************/ - /// - /// Backing field for TrackNumber. + /// Gets or sets the track number. /// - protected int? _TrackNumber; - /// - /// When provided in a partial class, allows value of TrackNumber to be changed before setting. - /// - partial void SetTrackNumber(int? oldValue, ref int? newValue); - /// - /// When provided in a partial class, allows value of TrackNumber to be changed before returning. - /// - partial void GetTrackNumber(ref int? result); + public int? TrackNumber { get; set; } - public int? TrackNumber - { - get - { - int? value = _TrackNumber; - GetTrackNumber(ref value); - return _TrackNumber = value; - } - - set - { - int? oldValue = _TrackNumber; - SetTrackNumber(oldValue, ref value); - if (oldValue != value) - { - _TrackNumber = value; - } - } - } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - - [ForeignKey("Release_Releases_Id")] + /// public virtual ICollection Releases { get; protected set; } - [ForeignKey("TrackMetadata_TrackMetadata_Id")] + /// + /// Gets or sets a collection containing the track metadata. + /// public virtual ICollection TrackMetadata { get; protected set; } } } - diff --git a/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs b/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs index 5c356c768e..048068a1a3 100644 --- a/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs +++ b/Jellyfin.Data/Entities/Libraries/TrackMetadata.cs @@ -1,83 +1,36 @@ -#pragma warning disable CS1591 - using System; namespace Jellyfin.Data.Entities.Libraries { - public partial class TrackMetadata : Metadata + /// + /// An entity holding metadata for a track. + /// + public class TrackMetadata : Metadata { - partial void Init(); - /// - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// - protected TrackMetadata() - { - Init(); - } - - /// - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// - public static TrackMetadata CreateTrackMetadataUnsafe() - { - return new TrackMetadata(); - } - - /// - /// Public constructor with required data. + /// Initializes a new instance of the class. /// /// The title or name of the object. /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public TrackMetadata(string title, string language, DateTime dateadded, DateTime datemodified, Track _track0) + /// The track. + public TrackMetadata(string title, string language, Track track) : base(title, language) { - if (string.IsNullOrEmpty(title)) - { - throw new ArgumentNullException(nameof(title)); - } - - this.Title = title; - - if (string.IsNullOrEmpty(language)) - { - throw new ArgumentNullException(nameof(language)); - } - - this.Language = language; - - if (_track0 == null) + if (track == null) { - throw new ArgumentNullException(nameof(_track0)); + throw new ArgumentNullException(nameof(track)); } - _track0.TrackMetadata.Add(this); - - Init(); + track.TrackMetadata.Add(this); } /// - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the class. /// - /// The title or name of the object. - /// ISO-639-3 3-character language codes. - /// The date the object was added. - /// The date the object was last modified. - /// - public static TrackMetadata Create(string title, string language, DateTime dateadded, DateTime datemodified, Track _track0) + /// + /// Default constructor. Protected due to required properties, but present because EF needs it. + /// + protected TrackMetadata() { - return new TrackMetadata(title, language, dateadded, datemodified, _track0); } - - /************************************************************************* - * Properties - *************************************************************************/ - - /************************************************************************* - * Navigation properties - *************************************************************************/ } } - diff --git a/Jellyfin.Data/Entities/Permission.cs b/Jellyfin.Data/Entities/Permission.cs index af3270a880..c0f67f8363 100644 --- a/Jellyfin.Data/Entities/Permission.cs +++ b/Jellyfin.Data/Entities/Permission.cs @@ -3,13 +3,14 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities { /// /// An entity representing whether the associated user has a specific permission. /// - public partial class Permission : ISavingChanges + public partial class Permission : IHasConcurrencyToken { /// /// Initializes a new instance of the class. diff --git a/Jellyfin.Data/Entities/Preference.cs b/Jellyfin.Data/Entities/Preference.cs index 0ca9d7eff4..1797f0a401 100644 --- a/Jellyfin.Data/Entities/Preference.cs +++ b/Jellyfin.Data/Entities/Preference.cs @@ -2,13 +2,14 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities { /// /// An entity representing a preference attached to a user or group. /// - public class Preference : ISavingChanges + public class Preference : IHasConcurrencyToken { /// /// Initializes a new instance of the class. diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index 8c720d85be..7ea1f44986 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -8,13 +8,14 @@ using System.Globalization; using System.Linq; using System.Text.Json.Serialization; using Jellyfin.Data.Enums; +using Jellyfin.Data.Interfaces; namespace Jellyfin.Data.Entities { /// /// An entity representing a user. /// - public partial class User : IHasPermissions, ISavingChanges + public partial class User : IHasPermissions, IHasConcurrencyToken { /// /// The values being delimited here are Guids, so commas work as they do not appear in Guids. diff --git a/Jellyfin.Data/IHasPermissions.cs b/Jellyfin.Data/IHasPermissions.cs deleted file mode 100644 index 3be72259ad..0000000000 --- a/Jellyfin.Data/IHasPermissions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Data.Entities; -using Jellyfin.Data.Enums; - -namespace Jellyfin.Data -{ - /// - /// An abstraction representing an entity that has permissions. - /// - public interface IHasPermissions - { - /// - /// Gets a collection containing this entity's permissions. - /// - ICollection Permissions { get; } - - /// - /// Checks whether this entity has the specified permission kind. - /// - /// The kind of permission. - /// true if this entity has the specified permission, false otherwise. - bool HasPermission(PermissionKind kind); - - /// - /// Sets the specified permission to the provided value. - /// - /// The kind of permission. - /// The value to set. - void SetPermission(PermissionKind kind, bool value); - } -} diff --git a/Jellyfin.Data/ISavingChanges.cs b/Jellyfin.Data/ISavingChanges.cs deleted file mode 100644 index f392dae6a0..0000000000 --- a/Jellyfin.Data/ISavingChanges.cs +++ /dev/null @@ -1,9 +0,0 @@ -#pragma warning disable CS1591 - -namespace Jellyfin.Data -{ - public interface ISavingChanges - { - void OnSavingChanges(); - } -} diff --git a/Jellyfin.Data/Interfaces/IHasArtwork.cs b/Jellyfin.Data/Interfaces/IHasArtwork.cs new file mode 100644 index 0000000000..a4d9c54af4 --- /dev/null +++ b/Jellyfin.Data/Interfaces/IHasArtwork.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Jellyfin.Data.Entities.Libraries; + +namespace Jellyfin.Data.Interfaces +{ + /// + /// An interface abstracting an entity that has artwork. + /// + public interface IHasArtwork + { + /// + /// Gets a collection containing this entity's artwork. + /// + ICollection Artwork { get; } + } +} diff --git a/Jellyfin.Data/Interfaces/IHasCompanies.cs b/Jellyfin.Data/Interfaces/IHasCompanies.cs new file mode 100644 index 0000000000..8f19ce04fa --- /dev/null +++ b/Jellyfin.Data/Interfaces/IHasCompanies.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Jellyfin.Data.Entities.Libraries; + +namespace Jellyfin.Data.Interfaces +{ + /// + /// An abstraction representing an entity that has companies. + /// + public interface IHasCompanies + { + /// + /// Gets a collection containing this entity's companies. + /// + ICollection Companies { get; } + } +} diff --git a/Jellyfin.Data/Interfaces/IHasConcurrencyToken.cs b/Jellyfin.Data/Interfaces/IHasConcurrencyToken.cs new file mode 100644 index 0000000000..2c4091493e --- /dev/null +++ b/Jellyfin.Data/Interfaces/IHasConcurrencyToken.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Data.Interfaces +{ + /// + /// An interface abstracting an entity that has a concurrency token. + /// + public interface IHasConcurrencyToken + { + /// + /// Gets the version of this row. Acts as a concurrency token. + /// + uint RowVersion { get; } + + /// + /// Called when saving changes to this entity. + /// + void OnSavingChanges(); + } +} diff --git a/Jellyfin.Data/Interfaces/IHasPermissions.cs b/Jellyfin.Data/Interfaces/IHasPermissions.cs new file mode 100644 index 0000000000..3be72259ad --- /dev/null +++ b/Jellyfin.Data/Interfaces/IHasPermissions.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; + +namespace Jellyfin.Data +{ + /// + /// An abstraction representing an entity that has permissions. + /// + public interface IHasPermissions + { + /// + /// Gets a collection containing this entity's permissions. + /// + ICollection Permissions { get; } + + /// + /// Checks whether this entity has the specified permission kind. + /// + /// The kind of permission. + /// true if this entity has the specified permission, false otherwise. + bool HasPermission(PermissionKind kind); + + /// + /// Sets the specified permission to the provided value. + /// + /// The kind of permission. + /// The value to set. + void SetPermission(PermissionKind kind, bool value); + } +} diff --git a/Jellyfin.Data/Interfaces/IHasReleases.cs b/Jellyfin.Data/Interfaces/IHasReleases.cs new file mode 100644 index 0000000000..3b615893ed --- /dev/null +++ b/Jellyfin.Data/Interfaces/IHasReleases.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Jellyfin.Data.Entities.Libraries; + +namespace Jellyfin.Data.Interfaces +{ + /// + /// An abstraction representing an entity that has releases. + /// + public interface IHasReleases + { + /// + /// Gets a collection containing this entity's releases. + /// + ICollection Releases { get; } + } +} diff --git a/Jellyfin.Server.Implementations/JellyfinDb.cs b/Jellyfin.Server.Implementations/JellyfinDb.cs index 7d864ebc69..08e4db3880 100644 --- a/Jellyfin.Server.Implementations/JellyfinDb.cs +++ b/Jellyfin.Server.Implementations/JellyfinDb.cs @@ -2,8 +2,8 @@ using System; using System.Linq; -using Jellyfin.Data; using Jellyfin.Data.Entities; +using Jellyfin.Data.Interfaces; using Microsoft.EntityFrameworkCore; namespace Jellyfin.Server.Implementations @@ -130,7 +130,7 @@ namespace Jellyfin.Server.Implementations foreach (var saveEntity in ChangeTracker.Entries() .Where(e => e.State == EntityState.Modified) .Select(entry => entry.Entity) - .OfType()) + .OfType()) { saveEntity.OnSavingChanges(); } -- cgit v1.2.3