diff options
Diffstat (limited to 'MediaBrowser.Controller')
| -rw-r--r-- | MediaBrowser.Controller/Entities/BaseItem.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Folder.cs | 6 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/User.cs | 15 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Kernel.cs | 79 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/DtoBuilder.cs | 18 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/IUserManager.cs | 169 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/LibraryManager.cs | 9 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/UserDataManager.cs | 226 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/UserManager.cs | 403 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaBrowser.Controller.csproj | 3 |
10 files changed, 206 insertions, 726 deletions
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 8535f85c2..e462ac9e2 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1205,7 +1205,7 @@ namespace MediaBrowser.Controller.Entities /// <param name="wasPlayed">if set to <c>true</c> [was played].</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException"></exception> - public virtual Task SetPlayedStatus(User user, bool wasPlayed) + public virtual Task SetPlayedStatus(User user, bool wasPlayed, IUserManager userManager) { if (user == null) { @@ -1235,7 +1235,7 @@ namespace MediaBrowser.Controller.Entities data.Played = wasPlayed; - return Kernel.Instance.UserDataManager.SaveUserDataForItem(user, this, data); + return userManager.SaveUserDataForItem(user, this, data); } /// <summary> diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index b2be96b71..28075b9a1 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -962,12 +962,12 @@ namespace MediaBrowser.Controller.Entities /// <param name="user">The user.</param> /// <param name="wasPlayed">if set to <c>true</c> [was played].</param> /// <returns>Task.</returns> - public override async Task SetPlayedStatus(User user, bool wasPlayed) + public override async Task SetPlayedStatus(User user, bool wasPlayed, IUserManager userManager) { - await base.SetPlayedStatus(user, wasPlayed).ConfigureAwait(false); + await base.SetPlayedStatus(user, wasPlayed, userManager).ConfigureAwait(false); // Now sweep through recursively and update status - var tasks = GetChildren(user).Select(c => c.SetPlayedStatus(user, wasPlayed)); + var tasks = GetChildren(user).Select(c => c.SetPlayedStatus(user, wasPlayed, userManager)); await Task.WhenAll(tasks).ConfigureAwait(false); } diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index 5abd3e5a8..7196b68b8 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Library; using MediaBrowser.Model.Configuration; using System; using System.IO; @@ -16,6 +17,8 @@ namespace MediaBrowser.Controller.Entities /// </summary> public class User : BaseItem { + internal static IUserManager UserManager { get; set; } + /// <summary> /// The _root folder path /// </summary> @@ -236,7 +239,7 @@ namespace MediaBrowser.Controller.Entities /// <param name="newName">The new name.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException"></exception> - internal Task Rename(string newName) + public Task Rename(string newName) { if (string.IsNullOrEmpty(newName)) { @@ -364,7 +367,7 @@ namespace MediaBrowser.Controller.Entities { cancellationToken.ThrowIfCancellationRequested(); - await Kernel.Instance.UserManager.UpdateUser(this).ConfigureAwait(false); + await UserManager.UpdateUser(this).ConfigureAwait(false); } return changed; @@ -425,9 +428,9 @@ namespace MediaBrowser.Controller.Entities /// Resets the password by clearing it. /// </summary> /// <returns>Task.</returns> - public Task ResetPassword() + public Task ResetPassword(IUserManager userManager) { - return ChangePassword(string.Empty); + return ChangePassword(string.Empty, userManager); } /// <summary> @@ -435,11 +438,11 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <param name="newPassword">The new password.</param> /// <returns>Task.</returns> - public Task ChangePassword(string newPassword) + public Task ChangePassword(string newPassword, IUserManager userManager) { Password = string.IsNullOrEmpty(newPassword) ? string.Empty : newPassword.GetMD5().ToString(); - return Kernel.Instance.UserManager.UpdateUser(this); + return userManager.UpdateUser(this); } } } diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index 6703012be..e41b7c487 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -1,8 +1,5 @@ using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Plugins; using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Common.Security; -using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; @@ -52,12 +49,6 @@ namespace MediaBrowser.Controller public ImageManager ImageManager { get; private set; } /// <summary> - /// Gets the user manager. - /// </summary> - /// <value>The user manager.</value> - public UserManager UserManager { get; private set; } - - /// <summary> /// Gets the FFMPEG controller. /// </summary> /// <value>The FFMPEG controller.</value> @@ -82,47 +73,6 @@ namespace MediaBrowser.Controller public ProviderManager ProviderManager { get; private set; } /// <summary> - /// Gets the user data manager. - /// </summary> - /// <value>The user data manager.</value> - public UserDataManager UserDataManager { get; private set; } - - /// <summary> - /// The _users - /// </summary> - private IEnumerable<User> _users; - /// <summary> - /// The _user lock - /// </summary> - private object _usersSyncLock = new object(); - /// <summary> - /// The _users initialized - /// </summary> - private bool _usersInitialized; - /// <summary> - /// Gets the users. - /// </summary> - /// <value>The users.</value> - public IEnumerable<User> Users - { - get - { - // Call ToList to exhaust the stream because we'll be iterating over this multiple times - LazyInitializer.EnsureInitialized(ref _users, ref _usersInitialized, ref _usersSyncLock, UserManager.LoadUsers); - return _users; - } - internal set - { - _users = value; - - if (value == null) - { - _usersInitialized = false; - } - } - } - - /// <summary> /// The _root folder /// </summary> private AggregateFolder _rootFolder; @@ -304,13 +254,14 @@ namespace MediaBrowser.Controller /// </summary> protected override void FindParts() { + // For now there's no real way to inject this properly + User.UserManager = ApplicationHost.Resolve<IUserManager>(); + InstallationManager = (InstallationManager)ApplicationHost.CreateInstance(typeof(InstallationManager)); FFMpegManager = (FFMpegManager)ApplicationHost.CreateInstance(typeof(FFMpegManager)); LibraryManager = (LibraryManager)ApplicationHost.CreateInstance(typeof(LibraryManager)); - UserManager = (UserManager)ApplicationHost.CreateInstance(typeof(UserManager)); ImageManager = (ImageManager)ApplicationHost.CreateInstance(typeof(ImageManager)); ProviderManager = (ProviderManager)ApplicationHost.CreateInstance(typeof(ProviderManager)); - UserDataManager = (UserDataManager)ApplicationHost.CreateInstance(typeof(UserDataManager)); SecurityManager = (PluginSecurityManager)ApplicationHost.CreateInstance(typeof(PluginSecurityManager)); base.FindParts(); @@ -337,7 +288,6 @@ namespace MediaBrowser.Controller protected override async Task ReloadInternal() { // Reset these so that they can be lazy loaded again - Users = null; RootFolder = null; await base.ReloadInternal().ConfigureAwait(false); @@ -346,7 +296,7 @@ namespace MediaBrowser.Controller ReloadFileSystemManager(); - await UserManager.RefreshUsersMetadata(CancellationToken.None).ConfigureAwait(false); + await ApplicationHost.Resolve<IUserManager>().RefreshUsersMetadata(CancellationToken.None).ConfigureAwait(false); } /// <summary> @@ -454,29 +404,14 @@ namespace MediaBrowser.Controller } /// <summary> - /// Gets a User by Id - /// </summary> - /// <param name="id">The id.</param> - /// <returns>User.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - public User GetUserById(Guid id) - { - if (id == Guid.Empty) - { - throw new ArgumentNullException(); - } - - return Users.FirstOrDefault(u => u.Id == id); - } - - /// <summary> /// Finds a library item by Id and UserId. /// </summary> /// <param name="id">The id.</param> /// <param name="userId">The user id.</param> + /// <param name="userManager">The user manager.</param> /// <returns>BaseItem.</returns> /// <exception cref="System.ArgumentNullException">id</exception> - public BaseItem GetItemById(Guid id, Guid userId) + public BaseItem GetItemById(Guid id, Guid userId, IUserManager userManager) { if (id == Guid.Empty) { @@ -488,7 +423,7 @@ namespace MediaBrowser.Controller throw new ArgumentNullException("userId"); } - var user = GetUserById(userId); + var user = userManager.GetUserById(userId); var userRoot = user.RootFolder; return userRoot.FindItemById(id, user); diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Library/DtoBuilder.cs index 8cf9d5b57..30a14bf97 100644 --- a/MediaBrowser.Controller/Library/DtoBuilder.cs +++ b/MediaBrowser.Controller/Library/DtoBuilder.cs @@ -823,7 +823,7 @@ namespace MediaBrowser.Controller.Library /// <param name="id">The id.</param> /// <param name="userId">The user id.</param> /// <returns>BaseItem.</returns> - public static BaseItem GetItemByClientId(string id, Guid? userId = null) + public static BaseItem GetItemByClientId(string id, IUserManager userManager, Guid? userId = null) { var isIdEmpty = string.IsNullOrEmpty(id); @@ -835,7 +835,7 @@ namespace MediaBrowser.Controller.Library { if (userId.HasValue) { - return GetIndexFolder(id, userId.Value); + return GetIndexFolder(id, userId.Value, userManager); } } @@ -844,8 +844,8 @@ namespace MediaBrowser.Controller.Library if (userId.HasValue) { item = isIdEmpty - ? Kernel.Instance.GetUserById(userId.Value).RootFolder - : Kernel.Instance.GetItemById(new Guid(id), userId.Value); + ? userManager.GetUserById(userId.Value).RootFolder + : Kernel.Instance.GetItemById(new Guid(id), userId.Value, userManager); } else if (!isIndexFolder) { @@ -855,9 +855,9 @@ namespace MediaBrowser.Controller.Library // If we still don't find it, look within individual user views if (item == null && !userId.HasValue) { - foreach (var user in Kernel.Instance.Users) + foreach (var user in userManager.Users) { - item = GetItemByClientId(id, user.Id); + item = GetItemByClientId(id, userManager, user.Id); if (item != null) { @@ -875,9 +875,9 @@ namespace MediaBrowser.Controller.Library /// <param name="id">The id.</param> /// <param name="userId">The user id.</param> /// <returns>BaseItem.</returns> - private static BaseItem GetIndexFolder(string id, Guid userId) + private static BaseItem GetIndexFolder(string id, Guid userId, IUserManager userManager) { - var user = Kernel.Instance.GetUserById(userId); + var user = userManager.GetUserById(userId); var stringSeparators = new[] { IndexFolderDelimeter }; @@ -885,7 +885,7 @@ namespace MediaBrowser.Controller.Library var values = id.Split(stringSeparators, StringSplitOptions.None).ToList(); // Get the top folder normally using the first id - var folder = GetItemByClientId(values[0], userId) as Folder; + var folder = GetItemByClientId(values[0], userManager, userId) as Folder; values.RemoveAt(0); diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs new file mode 100644 index 000000000..ea4f03330 --- /dev/null +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -0,0 +1,169 @@ +using MediaBrowser.Common.Events; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Connectivity; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Library +{ + public interface IUserManager + { + /// <summary> + /// Gets the users. + /// </summary> + /// <value>The users.</value> + IEnumerable<User> Users { get; } + + /// <summary> + /// Gets the active connections. + /// </summary> + /// <value>The active connections.</value> + IEnumerable<ClientConnectionInfo> ConnectedUsers { get; } + + /// <summary> + /// Occurs when [playback start]. + /// </summary> + event EventHandler<PlaybackProgressEventArgs> PlaybackStart; + + /// <summary> + /// Occurs when [playback progress]. + /// </summary> + event EventHandler<PlaybackProgressEventArgs> PlaybackProgress; + + /// <summary> + /// Occurs when [playback stopped]. + /// </summary> + event EventHandler<PlaybackProgressEventArgs> PlaybackStopped; + + /// <summary> + /// Occurs when [user updated]. + /// </summary> + event EventHandler<GenericEventArgs<User>> UserUpdated; + + /// <summary> + /// Occurs when [user deleted]. + /// </summary> + event EventHandler<GenericEventArgs<User>> UserDeleted; + + /// <summary> + /// Gets a User by Id + /// </summary> + /// <param name="id">The id.</param> + /// <returns>User.</returns> + /// <exception cref="System.ArgumentNullException"></exception> + User GetUserById(Guid id); + + /// <summary> + /// Authenticates a User and returns a result indicating whether or not it succeeded + /// </summary> + /// <param name="user">The user.</param> + /// <param name="password">The password.</param> + /// <returns>Task{System.Boolean}.</returns> + /// <exception cref="System.ArgumentNullException">user</exception> + Task<bool> AuthenticateUser(User user, string password); + + /// <summary> + /// Logs the user activity. + /// </summary> + /// <param name="user">The user.</param> + /// <param name="clientType">Type of the client.</param> + /// <param name="deviceName">Name of the device.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException">user</exception> + Task LogUserActivity(User user, ClientType clientType, string deviceName); + + /// <summary> + /// Loads the users from the repository + /// </summary> + /// <returns>IEnumerable{User}.</returns> + IEnumerable<User> LoadUsers(); + + /// <summary> + /// Refreshes metadata for each user + /// </summary> + /// <param name="cancellationToken">The cancellation token.</param> + /// <param name="force">if set to <c>true</c> [force].</param> + /// <returns>Task.</returns> + Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false); + + /// <summary> + /// Renames the user. + /// </summary> + /// <param name="user">The user.</param> + /// <param name="newName">The new name.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException">user</exception> + /// <exception cref="System.ArgumentException"></exception> + Task RenameUser(User user, string newName); + + /// <summary> + /// Updates the user. + /// </summary> + /// <param name="user">The user.</param> + /// <exception cref="System.ArgumentNullException">user</exception> + /// <exception cref="System.ArgumentException"></exception> + Task UpdateUser(User user); + + /// <summary> + /// Creates the user. + /// </summary> + /// <param name="name">The name.</param> + /// <returns>User.</returns> + /// <exception cref="System.ArgumentNullException">name</exception> + /// <exception cref="System.ArgumentException"></exception> + Task<User> CreateUser(string name); + + /// <summary> + /// Deletes the user. + /// </summary> + /// <param name="user">The user.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException">user</exception> + /// <exception cref="System.ArgumentException"></exception> + Task DeleteUser(User user); + + /// <summary> + /// Used to report that playback has started for an item + /// </summary> + /// <param name="user">The user.</param> + /// <param name="item">The item.</param> + /// <param name="clientType">Type of the client.</param> + /// <param name="deviceName">Name of the device.</param> + /// <exception cref="System.ArgumentNullException"></exception> + void OnPlaybackStart(User user, BaseItem item, ClientType clientType, string deviceName); + + /// <summary> + /// Used to report playback progress for an item + /// </summary> + /// <param name="user">The user.</param> + /// <param name="item">The item.</param> + /// <param name="positionTicks">The position ticks.</param> + /// <param name="clientType">Type of the client.</param> + /// <param name="deviceName">Name of the device.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException"></exception> + Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName); + + /// <summary> + /// Used to report that playback has ended for an item + /// </summary> + /// <param name="user">The user.</param> + /// <param name="item">The item.</param> + /// <param name="positionTicks">The position ticks.</param> + /// <param name="clientType">Type of the client.</param> + /// <param name="deviceName">Name of the device.</param> + /// <returns>Task.</returns> + /// <exception cref="System.ArgumentNullException"></exception> + Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName); + + /// <summary> + /// Saves user data for an item + /// </summary> + /// <param name="user">The user.</param> + /// <param name="item">The item.</param> + /// <param name="data">The data.</param> + Task SaveUserDataForItem(User user, BaseItem item, UserItemData data); + } +} diff --git a/MediaBrowser.Controller/Library/LibraryManager.cs b/MediaBrowser.Controller/Library/LibraryManager.cs index 53f4af4b2..5dbf5c72d 100644 --- a/MediaBrowser.Controller/Library/LibraryManager.cs +++ b/MediaBrowser.Controller/Library/LibraryManager.cs @@ -64,6 +64,8 @@ namespace MediaBrowser.Controller.Library /// </summary> private readonly ITaskManager _taskManager; + private readonly IUserManager _userManager; + /// <summary> /// Gets or sets the kernel. /// </summary> @@ -76,11 +78,12 @@ namespace MediaBrowser.Controller.Library /// <param name="kernel">The kernel.</param> /// <param name="logger">The logger.</param> /// <param name="taskManager">The task manager.</param> - public LibraryManager(Kernel kernel, ILogger logger, ITaskManager taskManager) + public LibraryManager(Kernel kernel, ILogger logger, ITaskManager taskManager, IUserManager userManager) { Kernel = kernel; _logger = logger; _taskManager = taskManager; + _userManager = userManager; kernel.ConfigurationUpdated += kernel_ConfigurationUpdated; } @@ -490,13 +493,13 @@ namespace MediaBrowser.Controller.Library await Kernel.RootFolder.ValidateChildren(new Progress<double> { }, cancellationToken, recursive: false); // Validate only the collection folders for each user, just to make them available as quickly as possible - var userCollectionFolderTasks = Kernel.Users.AsParallel().Select(user => user.ValidateCollectionFolders(new Progress<double> { }, cancellationToken)); + var userCollectionFolderTasks = _userManager.Users.AsParallel().Select(user => user.ValidateCollectionFolders(new Progress<double> { }, cancellationToken)); await Task.WhenAll(userCollectionFolderTasks).ConfigureAwait(false); // Now validate the entire media library await Kernel.RootFolder.ValidateChildren(progress, cancellationToken, recursive: true).ConfigureAwait(false); - foreach (var user in Kernel.Users) + foreach (var user in _userManager.Users) { await user.ValidateMediaLibrary(new Progress<double> { }, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Controller/Library/UserDataManager.cs b/MediaBrowser.Controller/Library/UserDataManager.cs deleted file mode 100644 index bda5d0383..000000000 --- a/MediaBrowser.Controller/Library/UserDataManager.cs +++ /dev/null @@ -1,226 +0,0 @@ -using MediaBrowser.Common.Events; -using MediaBrowser.Common.Kernel; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Connectivity; -using MediaBrowser.Model.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.Library -{ - /// <summary> - /// Class UserDataManager - /// </summary> - public class UserDataManager : BaseManager<Kernel> - { - #region Events - /// <summary> - /// Occurs when [playback start]. - /// </summary> - public event EventHandler<PlaybackProgressEventArgs> PlaybackStart; - /// <summary> - /// Occurs when [playback progress]. - /// </summary> - public event EventHandler<PlaybackProgressEventArgs> PlaybackProgress; - /// <summary> - /// Occurs when [playback stopped]. - /// </summary> - public event EventHandler<PlaybackProgressEventArgs> PlaybackStopped; - #endregion - - /// <summary> - /// The _logger - /// </summary> - private readonly ILogger _logger; - - /// <summary> - /// Initializes a new instance of the <see cref="UserDataManager" /> class. - /// </summary> - /// <param name="kernel">The kernel.</param> - /// <param name="logger">The logger.</param> - public UserDataManager(Kernel kernel, ILogger logger) - : base(kernel) - { - _logger = logger; - } - - /// <summary> - /// Used to report that playback has started for an item - /// </summary> - /// <param name="user">The user.</param> - /// <param name="item">The item.</param> - /// <param name="clientType">Type of the client.</param> - /// <param name="deviceName">Name of the device.</param> - /// <exception cref="System.ArgumentNullException"></exception> - public void OnPlaybackStart(User user, BaseItem item, ClientType clientType, string deviceName) - { - if (user == null) - { - throw new ArgumentNullException(); - } - if (item == null) - { - throw new ArgumentNullException(); - } - - Kernel.UserManager.UpdateNowPlayingItemId(user, clientType, deviceName, item); - - // Nothing to save here - // Fire events to inform plugins - EventHelper.QueueEventIfNotNull(PlaybackStart, this, new PlaybackProgressEventArgs - { - Argument = item, - User = user - }, _logger); - } - - /// <summary> - /// Used to report playback progress for an item - /// </summary> - /// <param name="user">The user.</param> - /// <param name="item">The item.</param> - /// <param name="positionTicks">The position ticks.</param> - /// <param name="clientType">Type of the client.</param> - /// <param name="deviceName">Name of the device.</param> - /// <returns>Task.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - public async Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName) - { - if (user == null) - { - throw new ArgumentNullException(); - } - if (item == null) - { - throw new ArgumentNullException(); - } - - Kernel.UserManager.UpdateNowPlayingItemId(user, clientType, deviceName, item, positionTicks); - - if (positionTicks.HasValue) - { - var data = item.GetUserData(user, true); - - UpdatePlayState(item, data, positionTicks.Value, false); - await SaveUserDataForItem(user, item, data).ConfigureAwait(false); - } - - EventHelper.QueueEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs - { - Argument = item, - User = user, - PlaybackPositionTicks = positionTicks - }, _logger); - } - - /// <summary> - /// Used to report that playback has ended for an item - /// </summary> - /// <param name="user">The user.</param> - /// <param name="item">The item.</param> - /// <param name="positionTicks">The position ticks.</param> - /// <param name="clientType">Type of the client.</param> - /// <param name="deviceName">Name of the device.</param> - /// <returns>Task.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - public async Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName) - { - if (user == null) - { - throw new ArgumentNullException(); - } - if (item == null) - { - throw new ArgumentNullException(); - } - - Kernel.UserManager.RemoveNowPlayingItemId(user, clientType, deviceName, item); - - var data = item.GetUserData(user, true); - - if (positionTicks.HasValue) - { - UpdatePlayState(item, data, positionTicks.Value, true); - } - else - { - // If the client isn't able to report this, then we'll just have to make an assumption - data.PlayCount++; - data.Played = true; - } - - await SaveUserDataForItem(user, item, data).ConfigureAwait(false); - - EventHelper.QueueEventIfNotNull(PlaybackStopped, this, new PlaybackProgressEventArgs - { - Argument = item, - User = user, - PlaybackPositionTicks = positionTicks - }, _logger); - } - - /// <summary> - /// Updates playstate position for an item but does not save - /// </summary> - /// <param name="item">The item</param> - /// <param name="data">User data for the item</param> - /// <param name="positionTicks">The current playback position</param> - /// <param name="incrementPlayCount">Whether or not to increment playcount</param> - private void UpdatePlayState(BaseItem item, UserItemData data, long positionTicks, bool incrementPlayCount) - { - // If a position has been reported, and if we know the duration - if (positionTicks > 0 && item.RunTimeTicks.HasValue && item.RunTimeTicks > 0) - { - var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100; - - // Don't track in very beginning - if (pctIn < Kernel.Configuration.MinResumePct) - { - positionTicks = 0; - incrementPlayCount = false; - } - - // If we're at the end, assume completed - else if (pctIn > Kernel.Configuration.MaxResumePct || positionTicks >= item.RunTimeTicks.Value) - { - positionTicks = 0; - data.Played = true; - } - - else - { - // Enforce MinResumeDuration - var durationSeconds = TimeSpan.FromTicks(item.RunTimeTicks.Value).TotalSeconds; - - if (durationSeconds < Kernel.Configuration.MinResumeDurationSeconds) - { - positionTicks = 0; - data.Played = true; - } - } - } - - data.PlaybackPositionTicks = positionTicks; - - if (incrementPlayCount) - { - data.PlayCount++; - data.LastPlayedDate = DateTime.UtcNow; - } - } - - /// <summary> - /// Saves user data for an item - /// </summary> - /// <param name="user">The user.</param> - /// <param name="item">The item.</param> - /// <param name="data">The data.</param> - public Task SaveUserDataForItem(User user, BaseItem item, UserItemData data) - { - item.AddOrUpdateUserData(user, data); - - return Kernel.UserDataRepository.SaveUserData(item, CancellationToken.None); - } - } -} diff --git a/MediaBrowser.Controller/Library/UserManager.cs b/MediaBrowser.Controller/Library/UserManager.cs deleted file mode 100644 index 5340e70be..000000000 --- a/MediaBrowser.Controller/Library/UserManager.cs +++ /dev/null @@ -1,403 +0,0 @@ -using MediaBrowser.Common.Events; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Kernel; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Connectivity; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.Logging; - -namespace MediaBrowser.Controller.Library -{ - /// <summary> - /// Class UserManager - /// </summary> - public class UserManager : BaseManager<Kernel> - { - /// <summary> - /// The _active connections - /// </summary> - private readonly ConcurrentBag<ClientConnectionInfo> _activeConnections = - new ConcurrentBag<ClientConnectionInfo>(); - - /// <summary> - /// Gets all connections. - /// </summary> - /// <value>All connections.</value> - public IEnumerable<ClientConnectionInfo> AllConnections - { - get { return _activeConnections.Where(c => Kernel.GetUserById(c.UserId) != null).OrderByDescending(c => c.LastActivityDate); } - } - - /// <summary> - /// Gets the active connections. - /// </summary> - /// <value>The active connections.</value> - public IEnumerable<ClientConnectionInfo> ActiveConnections - { - get { return AllConnections.Where(c => (DateTime.UtcNow - c.LastActivityDate).TotalMinutes <= 10); } - } - - /// <summary> - /// The _logger - /// </summary> - private readonly ILogger _logger; - - /// <summary> - /// Initializes a new instance of the <see cref="UserManager" /> class. - /// </summary> - /// <param name="kernel">The kernel.</param> - /// <param name="logger">The logger.</param> - public UserManager(Kernel kernel, ILogger logger) - : base(kernel) - { - _logger = logger; - } - - #region UserUpdated Event - /// <summary> - /// Occurs when [user updated]. - /// </summary> - public event EventHandler<GenericEventArgs<User>> UserUpdated; - - /// <summary> - /// Called when [user updated]. - /// </summary> - /// <param name="user">The user.</param> - internal void OnUserUpdated(User user) - { - EventHelper.QueueEventIfNotNull(UserUpdated, this, new GenericEventArgs<User> { Argument = user }, _logger); - - // Notify connected ui's - Kernel.ServerManager.SendWebSocketMessage("UserUpdated", new DtoBuilder(_logger).GetDtoUser(user)); - } - #endregion - - #region UserDeleted Event - /// <summary> - /// Occurs when [user deleted]. - /// </summary> - public event EventHandler<GenericEventArgs<User>> UserDeleted; - /// <summary> - /// Called when [user deleted]. - /// </summary> - /// <param name="user">The user.</param> - internal void OnUserDeleted(User user) - { - EventHelper.QueueEventIfNotNull(UserDeleted, this, new GenericEventArgs<User> { Argument = user }, _logger); - - // Notify connected ui's - Kernel.ServerManager.SendWebSocketMessage("UserDeleted", user.Id.ToString()); - } - #endregion - - /// <summary> - /// Authenticates a User and returns a result indicating whether or not it succeeded - /// </summary> - /// <param name="user">The user.</param> - /// <param name="password">The password.</param> - /// <returns>Task{System.Boolean}.</returns> - /// <exception cref="System.ArgumentNullException">user</exception> - public async Task<bool> AuthenticateUser(User user, string password) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - password = password ?? string.Empty; - var existingPassword = string.IsNullOrEmpty(user.Password) ? string.Empty.GetMD5().ToString() : user.Password; - - var success = password.GetMD5().ToString().Equals(existingPassword); - - // Update LastActivityDate and LastLoginDate, then save - if (success) - { - user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow; - await UpdateUser(user).ConfigureAwait(false); - } - - _logger.Info("Authentication request for {0} {1}.", user.Name, (success ? "has succeeded" : "has been denied")); - - return success; - } - - /// <summary> - /// Logs the user activity. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="clientType">Type of the client.</param> - /// <param name="deviceName">Name of the device.</param> - /// <returns>Task.</returns> - /// <exception cref="System.ArgumentNullException">user</exception> - public Task LogUserActivity(User user, ClientType clientType, string deviceName) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - var activityDate = DateTime.UtcNow; - - user.LastActivityDate = activityDate; - - LogConnection(user.Id, clientType, deviceName, activityDate); - - // Save this directly. No need to fire off all the events for this. - return Kernel.UserRepository.SaveUser(user, CancellationToken.None); - } - - /// <summary> - /// Updates the now playing item id. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="clientType">Type of the client.</param> - /// <param name="deviceName">Name of the device.</param> - /// <param name="item">The item.</param> - /// <param name="currentPositionTicks">The current position ticks.</param> - public void UpdateNowPlayingItemId(User user, ClientType clientType, string deviceName, BaseItem item, long? currentPositionTicks = null) - { - var conn = GetConnection(user.Id, clientType, deviceName); - - conn.NowPlayingPositionTicks = currentPositionTicks; - conn.NowPlayingItem = DtoBuilder.GetBaseItemInfo(item); - } - - /// <summary> - /// Removes the now playing item id. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="clientType">Type of the client.</param> - /// <param name="deviceName">Name of the device.</param> - /// <param name="item">The item.</param> - public void RemoveNowPlayingItemId(User user, ClientType clientType, string deviceName, BaseItem item) - { - var conn = GetConnection(user.Id, clientType, deviceName); - - if (conn.NowPlayingItem != null && conn.NowPlayingItem.Id.Equals(item.Id.ToString())) - { - conn.NowPlayingItem = null; - conn.NowPlayingPositionTicks = null; - } - } - - /// <summary> - /// Logs the connection. - /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="clientType">Type of the client.</param> - /// <param name="deviceName">Name of the device.</param> - /// <param name="lastActivityDate">The last activity date.</param> - private void LogConnection(Guid userId, ClientType clientType, string deviceName, DateTime lastActivityDate) - { - GetConnection(userId, clientType, deviceName).LastActivityDate = lastActivityDate; - } - - /// <summary> - /// Gets the connection. - /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="clientType">Type of the client.</param> - /// <param name="deviceName">Name of the device.</param> - /// <returns>ClientConnectionInfo.</returns> - private ClientConnectionInfo GetConnection(Guid userId, ClientType clientType, string deviceName) - { - var conn = _activeConnections.FirstOrDefault(c => c.UserId == userId && c.ClientType == clientType && string.Equals(deviceName, c.DeviceName, StringComparison.OrdinalIgnoreCase)); - - if (conn == null) - { - conn = new ClientConnectionInfo - { - UserId = userId, - ClientType = clientType, - DeviceName = deviceName - }; - - _activeConnections.Add(conn); - } - - return conn; - } - - /// <summary> - /// Loads the users from the repository - /// </summary> - /// <returns>IEnumerable{User}.</returns> - internal IEnumerable<User> LoadUsers() - { - var users = Kernel.UserRepository.RetrieveAllUsers().ToList(); - - // There always has to be at least one user. - if (users.Count == 0) - { - var name = Environment.UserName; - - var user = InstantiateNewUser(name); - - var task = Kernel.UserRepository.SaveUser(user, CancellationToken.None); - - // Hate having to block threads - Task.WaitAll(task); - - users.Add(user); - } - - return users; - } - - /// <summary> - /// Refreshes metadata for each user - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="force">if set to <c>true</c> [force].</param> - /// <returns>Task.</returns> - public Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false) - { - var tasks = Kernel.Users.Select(user => user.RefreshMetadata(cancellationToken, forceRefresh: force)).ToList(); - - return Task.WhenAll(tasks); - } - - /// <summary> - /// Renames the user. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="newName">The new name.</param> - /// <returns>Task.</returns> - /// <exception cref="System.ArgumentNullException">user</exception> - /// <exception cref="System.ArgumentException"></exception> - public async Task RenameUser(User user, string newName) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - if (string.IsNullOrEmpty(newName)) - { - throw new ArgumentNullException("newName"); - } - - if (Kernel.Users.Any(u => u.Id != user.Id && u.Name.Equals(newName, StringComparison.OrdinalIgnoreCase))) - { - throw new ArgumentException(string.Format("A user with the name '{0}' already exists.", newName)); - } - - if (user.Name.Equals(newName, StringComparison.Ordinal)) - { - throw new ArgumentException("The new and old names must be different."); - } - - await user.Rename(newName); - - OnUserUpdated(user); - } - - /// <summary> - /// Updates the user. - /// </summary> - /// <param name="user">The user.</param> - /// <exception cref="System.ArgumentNullException">user</exception> - /// <exception cref="System.ArgumentException"></exception> - public async Task UpdateUser(User user) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - if (user.Id == Guid.Empty || !Kernel.Users.Any(u => u.Id.Equals(user.Id))) - { - throw new ArgumentException(string.Format("User with name '{0}' and Id {1} does not exist.", user.Name, user.Id)); - } - - user.DateModified = DateTime.UtcNow; - - await Kernel.UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false); - - OnUserUpdated(user); - } - - /// <summary> - /// Creates the user. - /// </summary> - /// <param name="name">The name.</param> - /// <returns>User.</returns> - /// <exception cref="System.ArgumentNullException">name</exception> - /// <exception cref="System.ArgumentException"></exception> - public async Task<User> CreateUser(string name) - { - if (string.IsNullOrEmpty(name)) - { - throw new ArgumentNullException("name"); - } - - if (Kernel.Users.Any(u => u.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) - { - throw new ArgumentException(string.Format("A user with the name '{0}' already exists.", name)); - } - - var user = InstantiateNewUser(name); - - var list = Kernel.Users.ToList(); - list.Add(user); - Kernel.Users = list; - - await Kernel.UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false); - - return user; - } - - /// <summary> - /// Deletes the user. - /// </summary> - /// <param name="user">The user.</param> - /// <returns>Task.</returns> - /// <exception cref="System.ArgumentNullException">user</exception> - /// <exception cref="System.ArgumentException"></exception> - public async Task DeleteUser(User user) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - if (Kernel.Users.FirstOrDefault(u => u.Id == user.Id) == null) - { - throw new ArgumentException(string.Format("The user cannot be deleted because there is no user with the Name {0} and Id {1}.", user.Name, user.Id)); - } - - if (Kernel.Users.Count() == 1) - { - throw new ArgumentException(string.Format("The user '{0}' be deleted because there must be at least one user in the system.", user.Name)); - } - - await Kernel.UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false); - - OnUserDeleted(user); - - // Force this to be lazy loaded again - Kernel.Users = null; - } - - /// <summary> - /// Instantiates the new user. - /// </summary> - /// <param name="name">The name.</param> - /// <returns>User.</returns> - private User InstantiateNewUser(string name) - { - return new User - { - Name = name, - Id = ("MBUser" + name).GetMD5(), - DateCreated = DateTime.UtcNow, - DateModified = DateTime.UtcNow - }; - } - } -} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 6ab70f47c..6648c6458 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -113,9 +113,8 @@ <Compile Include="IServerApplicationPaths.cs" /> <Compile Include="Library\ChildrenChangedEventArgs.cs" /> <Compile Include="Library\DtoBuilder.cs" /> + <Compile Include="Library\IUserManager.cs" /> <Compile Include="Library\Profiler.cs" /> - <Compile Include="Library\UserDataManager.cs" /> - <Compile Include="Library\UserManager.cs" /> <Compile Include="Localization\AURatingsDictionary.cs" /> <Compile Include="Localization\BaseStrings.cs" /> <Compile Include="Localization\GBRatingsDictionary.cs" /> |
