From ff4ee7ab9c41f9756e1db6f25f701c8ca69cecf2 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Wed, 27 Feb 2013 15:25:45 -0500 Subject: combined usermanager and userdata manager --- BDInfo/Properties/AssemblyInfo.cs | 3 +- MediaBrowser.Api/Images/ImageService.cs | 28 +- .../Library/LibraryStructureService.cs | 32 +- MediaBrowser.Api/Playback/BaseStreamingService.cs | 12 +- .../Playback/Progressive/AudioService.cs | 5 +- .../Progressive/BaseProgressiveStreamingService.cs | 5 +- .../Playback/Progressive/VideoService.cs | 5 +- MediaBrowser.Api/Streaming/BaseStreamingHandler.cs | 5 +- .../UserLibrary/BaseItemsByNameService.cs | 20 +- MediaBrowser.Api/UserLibrary/GenresService.cs | 5 + MediaBrowser.Api/UserLibrary/ItemsService.cs | 20 +- MediaBrowser.Api/UserLibrary/PersonsService.cs | 5 + MediaBrowser.Api/UserLibrary/StudiosService.cs | 6 + MediaBrowser.Api/UserLibrary/UserLibraryService.cs | 102 ++-- MediaBrowser.Api/UserLibrary/YearsService.cs | 5 + MediaBrowser.Api/UserService.cs | 44 +- MediaBrowser.Controller/Entities/BaseItem.cs | 4 +- MediaBrowser.Controller/Entities/Folder.cs | 6 +- MediaBrowser.Controller/Entities/User.cs | 15 +- MediaBrowser.Controller/Kernel.cs | 79 +-- MediaBrowser.Controller/Library/DtoBuilder.cs | 18 +- MediaBrowser.Controller/Library/IUserManager.cs | 169 ++++++ MediaBrowser.Controller/Library/LibraryManager.cs | 9 +- MediaBrowser.Controller/Library/UserDataManager.cs | 226 ------- MediaBrowser.Controller/Library/UserManager.cs | 403 ------------- .../MediaBrowser.Controller.csproj | 3 +- .../Library/UserManager.cs | 650 +++++++++++++++++++++ .../MediaBrowser.Server.Implementations.csproj | 1 + MediaBrowser.ServerApplication/App.xaml.cs | 32 +- MediaBrowser.ServerApplication/ApplicationHost.cs | 4 + .../LibraryExplorer.xaml.cs | 4 +- MediaBrowser.ServerApplication/MainWindow.xaml.cs | 29 +- .../Api/DashboardInfoWebSocketListener.cs | 13 +- MediaBrowser.WebDashboard/Api/DashboardService.cs | 20 +- 34 files changed, 1086 insertions(+), 901 deletions(-) create mode 100644 MediaBrowser.Controller/Library/IUserManager.cs delete mode 100644 MediaBrowser.Controller/Library/UserDataManager.cs delete mode 100644 MediaBrowser.Controller/Library/UserManager.cs create mode 100644 MediaBrowser.Server.Implementations/Library/UserManager.cs diff --git a/BDInfo/Properties/AssemblyInfo.cs b/BDInfo/Properties/AssemblyInfo.cs index 9ea649662..39f1cc9d1 100644 --- a/BDInfo/Properties/AssemblyInfo.cs +++ b/BDInfo/Properties/AssemblyInfo.cs @@ -32,5 +32,4 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.0.*")] diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index c3e28770f..00e35428a 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -136,6 +136,20 @@ namespace MediaBrowser.Api.Images /// public class ImageService : BaseRestService { + /// + /// The _user manager + /// + private readonly IUserManager _userManager; + + /// + /// Initializes a new instance of the class. + /// + /// The user manager. + public ImageService(IUserManager userManager) + { + _userManager = userManager; + } + /// /// Gets the specified request. /// @@ -143,7 +157,7 @@ namespace MediaBrowser.Api.Images /// System.Object. public object Get(GetItemImage request) { - var item = DtoBuilder.GetItemByClientId(request.Id); + var item = DtoBuilder.GetItemByClientId(request.Id, _userManager); return GetImage(request, item); } @@ -155,9 +169,7 @@ namespace MediaBrowser.Api.Images /// System.Object. public object Get(GetUserImage request) { - var kernel = (Kernel)Kernel; - - var item = kernel.Users.First(i => i.Id == request.Id); + var item = _userManager.Users.First(i => i.Id == request.Id); return GetImage(request, item); } @@ -224,14 +236,12 @@ namespace MediaBrowser.Api.Images /// The request. public void Post(PostUserImage request) { - var kernel = (Kernel)Kernel; - var pathInfo = PathInfo.Parse(Request.PathInfo); var id = new Guid(pathInfo.GetArgumentValue(1)); request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue(3), true); - var item = kernel.Users.First(i => i.Id == id); + var item = _userManager.Users.First(i => i.Id == id); var task = PostImage(item, request.RequestStream, request.Type, Request.ContentType); @@ -244,9 +254,7 @@ namespace MediaBrowser.Api.Images /// The request. public void Delete(DeleteUserImage request) { - var kernel = (Kernel)Kernel; - - var item = kernel.Users.First(i => i.Id == request.Id); + var item = _userManager.Users.First(i => i.Id == request.Id); var task = item.DeleteImage(request.Type); diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index e495bc822..ef3b40478 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Implementations.HttpServer; using MediaBrowser.Controller; +using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; using ServiceStack.ServiceHost; using System; @@ -135,18 +136,25 @@ namespace MediaBrowser.Api.Library /// private readonly IServerApplicationPaths _appPaths; + /// + /// The _user manager + /// + private readonly IUserManager _userManager; + /// /// Initializes a new instance of the class. /// /// The app paths. + /// The user manager. /// appHost - public LibraryStructureService(IServerApplicationPaths appPaths) + public LibraryStructureService(IServerApplicationPaths appPaths, IUserManager userManager) { if (appPaths == null) { throw new ArgumentNullException("appPaths"); } + _userManager = userManager; _appPaths = appPaths; } @@ -167,7 +175,7 @@ namespace MediaBrowser.Api.Library } else { - var user = kernel.GetUserById(new Guid(request.UserId)); + var user = _userManager.GetUserById(new Guid(request.UserId)); var result = kernel.LibraryManager.GetVirtualFolders(user).ToList(); @@ -181,15 +189,13 @@ namespace MediaBrowser.Api.Library /// The request. public void Post(AddVirtualFolder request) { - var kernel = (Kernel)Kernel; - if (string.IsNullOrEmpty(request.UserId)) { LibraryHelpers.AddVirtualFolder(request.Name, null, _appPaths); } else { - var user = kernel.GetUserById(new Guid(request.UserId)); + var user = _userManager.GetUserById(new Guid(request.UserId)); LibraryHelpers.AddVirtualFolder(request.Name, user, _appPaths); } @@ -201,15 +207,13 @@ namespace MediaBrowser.Api.Library /// The request. public void Post(RenameVirtualFolder request) { - var kernel = (Kernel)Kernel; - if (string.IsNullOrEmpty(request.UserId)) { LibraryHelpers.RenameVirtualFolder(request.Name, request.NewName, null, _appPaths); } else { - var user = kernel.GetUserById(new Guid(request.UserId)); + var user = _userManager.GetUserById(new Guid(request.UserId)); LibraryHelpers.RenameVirtualFolder(request.Name, request.NewName, user, _appPaths); } @@ -221,15 +225,13 @@ namespace MediaBrowser.Api.Library /// The request. public void Delete(RemoveVirtualFolder request) { - var kernel = (Kernel)Kernel; - if (string.IsNullOrEmpty(request.UserId)) { LibraryHelpers.RemoveVirtualFolder(request.Name, null, _appPaths); } else { - var user = kernel.GetUserById(new Guid(request.UserId)); + var user = _userManager.GetUserById(new Guid(request.UserId)); LibraryHelpers.RemoveVirtualFolder(request.Name, user, _appPaths); } @@ -241,15 +243,13 @@ namespace MediaBrowser.Api.Library /// The request. public void Post(AddMediaPath request) { - var kernel = (Kernel)Kernel; - if (string.IsNullOrEmpty(request.UserId)) { LibraryHelpers.AddMediaPath(request.Name, request.Path, null, _appPaths); } else { - var user = kernel.GetUserById(new Guid(request.UserId)); + var user = _userManager.GetUserById(new Guid(request.UserId)); LibraryHelpers.AddMediaPath(request.Name, request.Path, user, _appPaths); } @@ -261,15 +261,13 @@ namespace MediaBrowser.Api.Library /// The request. public void Delete(RemoveMediaPath request) { - var kernel = (Kernel)Kernel; - if (string.IsNullOrEmpty(request.UserId)) { LibraryHelpers.RemoveMediaPath(request.Name, request.Path, null, _appPaths); } else { - var user = kernel.GetUserById(new Guid(request.UserId)); + var user = _userManager.GetUserById(new Guid(request.UserId)); LibraryHelpers.RemoveMediaPath(request.Name, request.Path, user, _appPaths); } diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index b31b9b861..b7d299afe 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -29,6 +29,12 @@ namespace MediaBrowser.Api.Playback /// The application paths. protected IServerApplicationPaths ApplicationPaths { get; set; } + /// + /// Gets or sets the user manager. + /// + /// The user manager. + protected IUserManager UserManager { get; set; } + /// /// Gets the server kernel. /// @@ -42,9 +48,11 @@ namespace MediaBrowser.Api.Playback /// Initializes a new instance of the class. /// /// The app paths. - protected BaseStreamingService(IServerApplicationPaths appPaths) + /// The user manager. + protected BaseStreamingService(IServerApplicationPaths appPaths, IUserManager userManager) { ApplicationPaths = appPaths; + UserManager = userManager; } /// @@ -606,7 +614,7 @@ namespace MediaBrowser.Api.Playback /// StreamState. protected StreamState GetState(StreamRequest request) { - var item = DtoBuilder.GetItemByClientId(request.Id); + var item = DtoBuilder.GetItemByClientId(request.Id, UserManager); var media = (IHasMediaStreams)item; diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index 850e8ff3b..8f831a504 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller; +using MediaBrowser.Controller.Library; using ServiceStack.ServiceHost; using System.Collections.Generic; @@ -27,8 +28,8 @@ namespace MediaBrowser.Api.Playback.Progressive /// Initializes a new instance of the class. /// /// The app paths. - public AudioService(IServerApplicationPaths appPaths) - : base(appPaths) + public AudioService(IServerApplicationPaths appPaths, IUserManager userManager) + : base(appPaths, userManager) { } diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 62ca74df9..f02b37b6c 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; using System.IO; using System.Threading.Tasks; @@ -17,8 +18,8 @@ namespace MediaBrowser.Api.Playback.Progressive /// Initializes a new instance of the class. /// /// The app paths. - protected BaseProgressiveStreamingService(IServerApplicationPaths appPaths) - : base(appPaths) + protected BaseProgressiveStreamingService(IServerApplicationPaths appPaths, IUserManager userManager) + : base(appPaths, userManager) { } diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index cb02518d1..8dca6b24c 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using System; +using MediaBrowser.Controller.Library; using ServiceStack.ServiceHost; namespace MediaBrowser.Api.Playback.Progressive @@ -33,8 +34,8 @@ namespace MediaBrowser.Api.Playback.Progressive /// Initializes a new instance of the class. /// /// The app paths. - public VideoService(IServerApplicationPaths appPaths) - : base(appPaths) + public VideoService(IServerApplicationPaths appPaths, IUserManager userManager) + : base(appPaths, userManager) { } diff --git a/MediaBrowser.Api/Streaming/BaseStreamingHandler.cs b/MediaBrowser.Api/Streaming/BaseStreamingHandler.cs index 8c5fd34b1..27ccdeb15 100644 --- a/MediaBrowser.Api/Streaming/BaseStreamingHandler.cs +++ b/MediaBrowser.Api/Streaming/BaseStreamingHandler.cs @@ -221,10 +221,7 @@ namespace MediaBrowser.Api.Streaming /// The library item. protected TBaseItemType LibraryItem { - get - { - return _libraryItem ?? (_libraryItem = (TBaseItemType)DtoBuilder.GetItemByClientId(QueryString["id"])); - } + get { return _libraryItem; } } /// diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 1448886cf..3cb17ff35 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -20,6 +20,20 @@ namespace MediaBrowser.Api.UserLibrary public abstract class BaseItemsByNameService : BaseRestService where TItemType : BaseItem { + /// + /// The _user manager + /// + protected readonly IUserManager UserManager; + + /// + /// Initializes a new instance of the class. + /// + /// The user manager. + protected BaseItemsByNameService(IUserManager userManager) + { + UserManager = userManager; + } + /// /// Gets the specified request. /// @@ -27,11 +41,9 @@ namespace MediaBrowser.Api.UserLibrary /// Task{ItemsResult}. protected async Task GetResult(GetItemsByName request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.UserId); + var user = UserManager.GetUserById(request.UserId); - var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, user.Id); + var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, UserManager, user.Id); IEnumerable items; diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs index 5d72236fa..1c002a7c9 100644 --- a/MediaBrowser.Api/UserLibrary/GenresService.cs +++ b/MediaBrowser.Api/UserLibrary/GenresService.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; using ServiceStack.ServiceHost; using System; using System.Collections.Generic; @@ -23,6 +24,10 @@ namespace MediaBrowser.Api.UserLibrary /// public class GenresService : BaseItemsByNameService { + public GenresService(IUserManager userManager) : base(userManager) + { + } + /// /// Gets the specified request. /// diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 6218f06b1..efc97651b 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -145,6 +145,20 @@ namespace MediaBrowser.Api.UserLibrary /// public class ItemsService : BaseRestService { + /// + /// The _user manager + /// + private readonly IUserManager _userManager; + + /// + /// Initializes a new instance of the class. + /// + /// The user manager. + public ItemsService(IUserManager userManager) + { + _userManager = userManager; + } + /// /// Gets the specified request. /// @@ -164,9 +178,7 @@ namespace MediaBrowser.Api.UserLibrary /// Task{ItemsResult}. private async Task GetItems(GetItems request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.UserId); + var user = _userManager.GetUserById(request.UserId); var items = GetItemsToSerialize(request, user); @@ -209,7 +221,7 @@ namespace MediaBrowser.Api.UserLibrary /// private IEnumerable GetItemsToSerialize(GetItems request, User user) { - var item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.ParentId, user.Id); + var item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.ParentId, _userManager, user.Id); // Default list type = children diff --git a/MediaBrowser.Api/UserLibrary/PersonsService.cs b/MediaBrowser.Api/UserLibrary/PersonsService.cs index 181d511a6..4528cb2bc 100644 --- a/MediaBrowser.Api/UserLibrary/PersonsService.cs +++ b/MediaBrowser.Api/UserLibrary/PersonsService.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; using ServiceStack.ServiceHost; using System; using System.Collections.Generic; @@ -28,6 +29,10 @@ namespace MediaBrowser.Api.UserLibrary /// public class PersonsService : BaseItemsByNameService { + public PersonsService(IUserManager userManager) : base(userManager) + { + } + /// /// Gets the specified request. /// diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs index 8b1824d83..cfb0179a2 100644 --- a/MediaBrowser.Api/UserLibrary/StudiosService.cs +++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; using ServiceStack.ServiceHost; using System; using System.Collections.Generic; @@ -22,6 +23,11 @@ namespace MediaBrowser.Api.UserLibrary /// public class StudiosService : BaseItemsByNameService { + public StudiosService(IUserManager userManager) + : base(userManager) + { + } + /// /// Gets the specified request. /// diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index fd9b0e78a..1ca72b24f 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -312,12 +312,17 @@ namespace MediaBrowser.Api.UserLibrary /// private readonly IJsonSerializer _jsonSerializer; + /// + /// The _user manager + /// + private readonly IUserManager _userManager; + /// /// Initializes a new instance of the class. /// /// The json serializer. /// jsonSerializer - public UserLibraryService(IJsonSerializer jsonSerializer) + public UserLibraryService(IJsonSerializer jsonSerializer, IUserManager userManager) : base() { if (jsonSerializer == null) @@ -326,6 +331,7 @@ namespace MediaBrowser.Api.UserLibrary } _jsonSerializer = jsonSerializer; + _userManager = userManager; } /// @@ -335,11 +341,9 @@ namespace MediaBrowser.Api.UserLibrary /// System.Object. public object Get(GetSpecialFeatures request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.UserId); + var user = _userManager.GetUserById(request.UserId); - var item = DtoBuilder.GetItemByClientId(request.Id, user.Id); + var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, user.Id); // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); @@ -360,11 +364,9 @@ namespace MediaBrowser.Api.UserLibrary /// System.Object. public object Get(GetLocalTrailers request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.UserId); + var user = _userManager.GetUserById(request.UserId); - var item = DtoBuilder.GetItemByClientId(request.Id, user.Id); + var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, user.Id); // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); @@ -383,11 +385,9 @@ namespace MediaBrowser.Api.UserLibrary /// System.Object. public object Get(GetItem request) { - var kernel = (Kernel)Kernel; + var user = _userManager.GetUserById(request.UserId); - var user = kernel.GetUserById(request.UserId); - - var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, user.Id); + var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, user.Id); // Get everything var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); @@ -408,9 +408,9 @@ namespace MediaBrowser.Api.UserLibrary { var kernel = (Kernel)Kernel; - var user = kernel.GetUserById(request.UserId); + var user = _userManager.GetUserById(request.UserId); - var item = DtoBuilder.GetItemByClientId(request.Id, user.Id); + var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, user.Id); var result = kernel.IntroProviders.SelectMany(i => i.GetIntros(item, user)); @@ -431,9 +431,9 @@ namespace MediaBrowser.Api.UserLibrary var kernel = (Kernel)Kernel; - var user = kernel.GetUserById(userId); + var user = _userManager.GetUserById(userId); - var item = (Folder)DtoBuilder.GetItemByClientId(itemId, user.Id); + var item = (Folder)DtoBuilder.GetItemByClientId(itemId, _userManager, user.Id); var displayPreferences = _jsonSerializer.DeserializeFromStream(request.RequestStream); @@ -448,11 +448,9 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public void Post(MarkFavoriteItem request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.UserId); + var user = _userManager.GetUserById(request.UserId); - var item = (Folder)DtoBuilder.GetItemByClientId(request.Id, user.Id); + var item = (Folder)DtoBuilder.GetItemByClientId(request.Id, _userManager, user.Id); // Get the user data for this item var data = item.GetUserData(user, true); @@ -460,7 +458,7 @@ namespace MediaBrowser.Api.UserLibrary // Set favorite status data.IsFavorite = true; - var task = kernel.UserDataManager.SaveUserDataForItem(user, item, data); + var task = _userManager.SaveUserDataForItem(user, item, data); Task.WaitAll(task); } @@ -471,11 +469,9 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public void Delete(UnmarkFavoriteItem request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.UserId); + var user = _userManager.GetUserById(request.UserId); - var item = (Folder)DtoBuilder.GetItemByClientId(request.Id, user.Id); + var item = (Folder)DtoBuilder.GetItemByClientId(request.Id, _userManager, user.Id); // Get the user data for this item var data = item.GetUserData(user, true); @@ -483,7 +479,7 @@ namespace MediaBrowser.Api.UserLibrary // Set favorite status data.IsFavorite = false; - var task = kernel.UserDataManager.SaveUserDataForItem(user, item, data); + var task = _userManager.SaveUserDataForItem(user, item, data); Task.WaitAll(task); } @@ -494,18 +490,16 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public void Delete(DeleteUserItemRating request) { - var kernel = (Kernel)Kernel; + var user = _userManager.GetUserById(request.UserId); - var user = kernel.GetUserById(request.UserId); - - var item = (Folder)DtoBuilder.GetItemByClientId(request.Id, user.Id); + var item = (Folder)DtoBuilder.GetItemByClientId(request.Id, _userManager, user.Id); // Get the user data for this item var data = item.GetUserData(user, true); data.Rating = null; - var task = kernel.UserDataManager.SaveUserDataForItem(user, item, data); + var task = _userManager.SaveUserDataForItem(user, item, data); Task.WaitAll(task); } @@ -516,18 +510,16 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public void Post(UpdateUserItemRating request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.UserId); + var user = _userManager.GetUserById(request.UserId); - var item = (Folder)DtoBuilder.GetItemByClientId(request.Id, user.Id); + var item = (Folder)DtoBuilder.GetItemByClientId(request.Id, _userManager, user.Id); // Get the user data for this item var data = item.GetUserData(user, true); data.Likes = request.Likes; - var task = kernel.UserDataManager.SaveUserDataForItem(user, item, data); + var task = _userManager.SaveUserDataForItem(user, item, data); Task.WaitAll(task); } @@ -538,9 +530,7 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public void Post(MarkPlayedItem request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.UserId); + var user = _userManager.GetUserById(request.UserId); var task = UpdatePlayedStatus(user, request.Id, true); @@ -553,13 +543,11 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public void Post(OnPlaybackStart request) { - var kernel = (Kernel)Kernel; + var user = _userManager.GetUserById(request.UserId); - var user = kernel.GetUserById(request.UserId); + var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, user.Id); - var item = DtoBuilder.GetItemByClientId(request.Id, user.Id); - - kernel.UserDataManager.OnPlaybackStart(user, item, ClientType.Other, string.Empty); + _userManager.OnPlaybackStart(user, item, ClientType.Other, string.Empty); } /// @@ -568,13 +556,11 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public void Post(OnPlaybackProgress request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.UserId); + var user = _userManager.GetUserById(request.UserId); - var item = DtoBuilder.GetItemByClientId(request.Id, user.Id); + var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, user.Id); - var task = kernel.UserDataManager.OnPlaybackProgress(user, item, request.PositionTicks, ClientType.Other, string.Empty); + var task = _userManager.OnPlaybackProgress(user, item, request.PositionTicks, ClientType.Other, string.Empty); Task.WaitAll(task); } @@ -585,13 +571,11 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public void Post(OnPlaybackStopped request) { - var kernel = (Kernel)Kernel; + var user = _userManager.GetUserById(request.UserId); - var user = kernel.GetUserById(request.UserId); + var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, user.Id); - var item = DtoBuilder.GetItemByClientId(request.Id, user.Id); - - var task = kernel.UserDataManager.OnPlaybackStopped(user, item, request.PositionTicks, ClientType.Other, string.Empty); + var task = _userManager.OnPlaybackStopped(user, item, request.PositionTicks, ClientType.Other, string.Empty); Task.WaitAll(task); } @@ -602,9 +586,7 @@ namespace MediaBrowser.Api.UserLibrary /// The request. public void Delete(MarkUnplayedItem request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.UserId); + var user = _userManager.GetUserById(request.UserId); var task = UpdatePlayedStatus(user, request.Id, false); @@ -620,9 +602,9 @@ namespace MediaBrowser.Api.UserLibrary /// Task. private Task UpdatePlayedStatus(User user, string itemId, bool wasPlayed) { - var item = DtoBuilder.GetItemByClientId(itemId, user.Id); + var item = DtoBuilder.GetItemByClientId(itemId, _userManager, user.Id); - return item.SetPlayedStatus(user, wasPlayed); + return item.SetPlayedStatus(user, wasPlayed, _userManager); } } } diff --git a/MediaBrowser.Api/UserLibrary/YearsService.cs b/MediaBrowser.Api/UserLibrary/YearsService.cs index 14fa645af..8112b2da9 100644 --- a/MediaBrowser.Api/UserLibrary/YearsService.cs +++ b/MediaBrowser.Api/UserLibrary/YearsService.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; using ServiceStack.ServiceHost; using System; using System.Collections.Generic; @@ -29,6 +30,10 @@ namespace MediaBrowser.Api.UserLibrary /// private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + public YearsService(IUserManager userManager) : base(userManager) + { + } + /// /// Gets the specified request. /// diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 5a9f22bbe..730242063 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -145,13 +145,18 @@ namespace MediaBrowser.Api /// private readonly IJsonSerializer _jsonSerializer; + /// + /// The _user manager + /// + private readonly IUserManager _userManager; + /// /// Initializes a new instance of the class. /// /// The XML serializer. /// The json serializer. /// xmlSerializer - public UserService(IXmlSerializer xmlSerializer, IJsonSerializer jsonSerializer) + public UserService(IXmlSerializer xmlSerializer, IJsonSerializer jsonSerializer, IUserManager userManager) : base() { if (jsonSerializer == null) @@ -166,6 +171,7 @@ namespace MediaBrowser.Api _jsonSerializer = jsonSerializer; _xmlSerializer = xmlSerializer; + _userManager = userManager; } /// @@ -179,7 +185,7 @@ namespace MediaBrowser.Api var dtoBuilder = new DtoBuilder(Logger); - var result = kernel.Users.OrderBy(u => u.Name).Select(dtoBuilder.GetDtoUser).ToList(); + var result = _userManager.Users.OrderBy(u => u.Name).Select(dtoBuilder.GetDtoUser).ToList(); return ToOptimizedResult(result); } @@ -191,9 +197,7 @@ namespace MediaBrowser.Api /// System.Object. public object Get(GetUser request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.Id); + var user = _userManager.GetUserById(request.Id); if (user == null) { @@ -211,16 +215,14 @@ namespace MediaBrowser.Api /// The request. public void Delete(DeleteUser request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.Id); + var user = _userManager.GetUserById(request.Id); if (user == null) { throw new ResourceNotFoundException("User not found"); } - var task = kernel.UserManager.DeleteUser(user); + var task = _userManager.DeleteUser(user); Task.WaitAll(task); } @@ -231,16 +233,14 @@ namespace MediaBrowser.Api /// The request. public void Post(AuthenticateUser request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.Id); + var user = _userManager.GetUserById(request.Id); if (user == null) { throw new ResourceNotFoundException("User not found"); } - var success = kernel.UserManager.AuthenticateUser(user, request.Password).Result; + var success = _userManager.AuthenticateUser(user, request.Password).Result; if (!success) { @@ -255,9 +255,7 @@ namespace MediaBrowser.Api /// The request. public void Post(UpdateUserPassword request) { - var kernel = (Kernel)Kernel; - - var user = kernel.GetUserById(request.Id); + var user = _userManager.GetUserById(request.Id); if (user == null) { @@ -266,20 +264,20 @@ namespace MediaBrowser.Api if (request.ResetPassword) { - var task = user.ResetPassword(); + var task = user.ResetPassword(_userManager); Task.WaitAll(task); } else { - var success = kernel.UserManager.AuthenticateUser(user, request.CurrentPassword).Result; + var success = _userManager.AuthenticateUser(user, request.CurrentPassword).Result; if (!success) { throw new ResourceNotFoundException("Invalid user or password entered."); } - var task = user.ChangePassword(request.NewPassword); + var task = user.ChangePassword(request.NewPassword, _userManager); Task.WaitAll(task); } @@ -296,13 +294,11 @@ namespace MediaBrowser.Api var pathInfo = PathInfo.Parse(Request.PathInfo); var id = new Guid(pathInfo.GetArgumentValue(1)); - var kernel = (Kernel)Kernel; - var dtoUser = _jsonSerializer.DeserializeFromStream(request.RequestStream); - var user = kernel.GetUserById(id); + var user = _userManager.GetUserById(id); - var task = user.Name.Equals(dtoUser.Name, StringComparison.Ordinal) ? kernel.UserManager.UpdateUser(user) : kernel.UserManager.RenameUser(user, dtoUser.Name); + var task = user.Name.Equals(dtoUser.Name, StringComparison.Ordinal) ? _userManager.UpdateUser(user) : _userManager.RenameUser(user, dtoUser.Name); Task.WaitAll(task); @@ -320,7 +316,7 @@ namespace MediaBrowser.Api var dtoUser = _jsonSerializer.DeserializeFromStream(request.RequestStream); - var newUser = kernel.UserManager.CreateUser(dtoUser.Name).Result; + var newUser = _userManager.CreateUser(dtoUser.Name).Result; var result = new DtoBuilder(Logger).GetDtoUser(newUser); 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 /// if set to true [was played]. /// Task. /// - 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); } /// 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 /// The user. /// if set to true [was played]. /// Task. - 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 /// public class User : BaseItem { + internal static IUserManager UserManager { get; set; } + /// /// The _root folder path /// @@ -236,7 +239,7 @@ namespace MediaBrowser.Controller.Entities /// The new name. /// Task. /// - 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. /// /// Task. - public Task ResetPassword() + public Task ResetPassword(IUserManager userManager) { - return ChangePassword(string.Empty); + return ChangePassword(string.Empty, userManager); } /// @@ -435,11 +438,11 @@ namespace MediaBrowser.Controller.Entities /// /// The new password. /// Task. - 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; @@ -51,12 +48,6 @@ namespace MediaBrowser.Controller /// The image manager. public ImageManager ImageManager { get; private set; } - /// - /// Gets the user manager. - /// - /// The user manager. - public UserManager UserManager { get; private set; } - /// /// Gets the FFMPEG controller. /// @@ -81,47 +72,6 @@ namespace MediaBrowser.Controller /// The provider manager. public ProviderManager ProviderManager { get; private set; } - /// - /// Gets the user data manager. - /// - /// The user data manager. - public UserDataManager UserDataManager { get; private set; } - - /// - /// The _users - /// - private IEnumerable _users; - /// - /// The _user lock - /// - private object _usersSyncLock = new object(); - /// - /// The _users initialized - /// - private bool _usersInitialized; - /// - /// Gets the users. - /// - /// The users. - public IEnumerable 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; - } - } - } - /// /// The _root folder /// @@ -304,13 +254,14 @@ namespace MediaBrowser.Controller /// protected override void FindParts() { + // For now there's no real way to inject this properly + User.UserManager = ApplicationHost.Resolve(); + 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().RefreshUsersMetadata(CancellationToken.None).ConfigureAwait(false); } /// @@ -453,30 +403,15 @@ namespace MediaBrowser.Controller FileSystemManager.StartWatchers(); } - /// - /// Gets a User by Id - /// - /// The id. - /// User. - /// - public User GetUserById(Guid id) - { - if (id == Guid.Empty) - { - throw new ArgumentNullException(); - } - - return Users.FirstOrDefault(u => u.Id == id); - } - /// /// Finds a library item by Id and UserId. /// /// The id. /// The user id. + /// The user manager. /// BaseItem. /// id - 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 /// The id. /// The user id. /// BaseItem. - 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 /// The id. /// The user id. /// BaseItem. - 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 + { + /// + /// Gets the users. + /// + /// The users. + IEnumerable Users { get; } + + /// + /// Gets the active connections. + /// + /// The active connections. + IEnumerable ConnectedUsers { get; } + + /// + /// Occurs when [playback start]. + /// + event EventHandler PlaybackStart; + + /// + /// Occurs when [playback progress]. + /// + event EventHandler PlaybackProgress; + + /// + /// Occurs when [playback stopped]. + /// + event EventHandler PlaybackStopped; + + /// + /// Occurs when [user updated]. + /// + event EventHandler> UserUpdated; + + /// + /// Occurs when [user deleted]. + /// + event EventHandler> UserDeleted; + + /// + /// Gets a User by Id + /// + /// The id. + /// User. + /// + User GetUserById(Guid id); + + /// + /// Authenticates a User and returns a result indicating whether or not it succeeded + /// + /// The user. + /// The password. + /// Task{System.Boolean}. + /// user + Task AuthenticateUser(User user, string password); + + /// + /// Logs the user activity. + /// + /// The user. + /// Type of the client. + /// Name of the device. + /// Task. + /// user + Task LogUserActivity(User user, ClientType clientType, string deviceName); + + /// + /// Loads the users from the repository + /// + /// IEnumerable{User}. + IEnumerable LoadUsers(); + + /// + /// Refreshes metadata for each user + /// + /// The cancellation token. + /// if set to true [force]. + /// Task. + Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false); + + /// + /// Renames the user. + /// + /// The user. + /// The new name. + /// Task. + /// user + /// + Task RenameUser(User user, string newName); + + /// + /// Updates the user. + /// + /// The user. + /// user + /// + Task UpdateUser(User user); + + /// + /// Creates the user. + /// + /// The name. + /// User. + /// name + /// + Task CreateUser(string name); + + /// + /// Deletes the user. + /// + /// The user. + /// Task. + /// user + /// + Task DeleteUser(User user); + + /// + /// Used to report that playback has started for an item + /// + /// The user. + /// The item. + /// Type of the client. + /// Name of the device. + /// + void OnPlaybackStart(User user, BaseItem item, ClientType clientType, string deviceName); + + /// + /// Used to report playback progress for an item + /// + /// The user. + /// The item. + /// The position ticks. + /// Type of the client. + /// Name of the device. + /// Task. + /// + Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName); + + /// + /// Used to report that playback has ended for an item + /// + /// The user. + /// The item. + /// The position ticks. + /// Type of the client. + /// Name of the device. + /// Task. + /// + Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName); + + /// + /// Saves user data for an item + /// + /// The user. + /// The item. + /// The data. + 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 /// private readonly ITaskManager _taskManager; + private readonly IUserManager _userManager; + /// /// Gets or sets the kernel. /// @@ -76,11 +78,12 @@ namespace MediaBrowser.Controller.Library /// The kernel. /// The logger. /// The task manager. - 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 { }, 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 { }, cancellationToken)); + var userCollectionFolderTasks = _userManager.Users.AsParallel().Select(user => user.ValidateCollectionFolders(new Progress { }, 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 { }, 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 -{ - /// - /// Class UserDataManager - /// - public class UserDataManager : BaseManager - { - #region Events - /// - /// Occurs when [playback start]. - /// - public event EventHandler PlaybackStart; - /// - /// Occurs when [playback progress]. - /// - public event EventHandler PlaybackProgress; - /// - /// Occurs when [playback stopped]. - /// - public event EventHandler PlaybackStopped; - #endregion - - /// - /// The _logger - /// - private readonly ILogger _logger; - - /// - /// Initializes a new instance of the class. - /// - /// The kernel. - /// The logger. - public UserDataManager(Kernel kernel, ILogger logger) - : base(kernel) - { - _logger = logger; - } - - /// - /// Used to report that playback has started for an item - /// - /// The user. - /// The item. - /// Type of the client. - /// Name of the device. - /// - 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); - } - - /// - /// Used to report playback progress for an item - /// - /// The user. - /// The item. - /// The position ticks. - /// Type of the client. - /// Name of the device. - /// Task. - /// - 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); - } - - /// - /// Used to report that playback has ended for an item - /// - /// The user. - /// The item. - /// The position ticks. - /// Type of the client. - /// Name of the device. - /// Task. - /// - 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); - } - - /// - /// Updates playstate position for an item but does not save - /// - /// The item - /// User data for the item - /// The current playback position - /// Whether or not to increment playcount - 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; - } - } - - /// - /// Saves user data for an item - /// - /// The user. - /// The item. - /// The data. - 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 -{ - /// - /// Class UserManager - /// - public class UserManager : BaseManager - { - /// - /// The _active connections - /// - private readonly ConcurrentBag _activeConnections = - new ConcurrentBag(); - - /// - /// Gets all connections. - /// - /// All connections. - public IEnumerable AllConnections - { - get { return _activeConnections.Where(c => Kernel.GetUserById(c.UserId) != null).OrderByDescending(c => c.LastActivityDate); } - } - - /// - /// Gets the active connections. - /// - /// The active connections. - public IEnumerable ActiveConnections - { - get { return AllConnections.Where(c => (DateTime.UtcNow - c.LastActivityDate).TotalMinutes <= 10); } - } - - /// - /// The _logger - /// - private readonly ILogger _logger; - - /// - /// Initializes a new instance of the class. - /// - /// The kernel. - /// The logger. - public UserManager(Kernel kernel, ILogger logger) - : base(kernel) - { - _logger = logger; - } - - #region UserUpdated Event - /// - /// Occurs when [user updated]. - /// - public event EventHandler> UserUpdated; - - /// - /// Called when [user updated]. - /// - /// The user. - internal void OnUserUpdated(User user) - { - EventHelper.QueueEventIfNotNull(UserUpdated, this, new GenericEventArgs { Argument = user }, _logger); - - // Notify connected ui's - Kernel.ServerManager.SendWebSocketMessage("UserUpdated", new DtoBuilder(_logger).GetDtoUser(user)); - } - #endregion - - #region UserDeleted Event - /// - /// Occurs when [user deleted]. - /// - public event EventHandler> UserDeleted; - /// - /// Called when [user deleted]. - /// - /// The user. - internal void OnUserDeleted(User user) - { - EventHelper.QueueEventIfNotNull(UserDeleted, this, new GenericEventArgs { Argument = user }, _logger); - - // Notify connected ui's - Kernel.ServerManager.SendWebSocketMessage("UserDeleted", user.Id.ToString()); - } - #endregion - - /// - /// Authenticates a User and returns a result indicating whether or not it succeeded - /// - /// The user. - /// The password. - /// Task{System.Boolean}. - /// user - public async Task 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; - } - - /// - /// Logs the user activity. - /// - /// The user. - /// Type of the client. - /// Name of the device. - /// Task. - /// user - 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); - } - - /// - /// Updates the now playing item id. - /// - /// The user. - /// Type of the client. - /// Name of the device. - /// The item. - /// The current position ticks. - 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); - } - - /// - /// Removes the now playing item id. - /// - /// The user. - /// Type of the client. - /// Name of the device. - /// The item. - 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; - } - } - - /// - /// Logs the connection. - /// - /// The user id. - /// Type of the client. - /// Name of the device. - /// The last activity date. - private void LogConnection(Guid userId, ClientType clientType, string deviceName, DateTime lastActivityDate) - { - GetConnection(userId, clientType, deviceName).LastActivityDate = lastActivityDate; - } - - /// - /// Gets the connection. - /// - /// The user id. - /// Type of the client. - /// Name of the device. - /// ClientConnectionInfo. - 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; - } - - /// - /// Loads the users from the repository - /// - /// IEnumerable{User}. - internal IEnumerable 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; - } - - /// - /// Refreshes metadata for each user - /// - /// The cancellation token. - /// if set to true [force]. - /// Task. - public Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false) - { - var tasks = Kernel.Users.Select(user => user.RefreshMetadata(cancellationToken, forceRefresh: force)).ToList(); - - return Task.WhenAll(tasks); - } - - /// - /// Renames the user. - /// - /// The user. - /// The new name. - /// Task. - /// user - /// - 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); - } - - /// - /// Updates the user. - /// - /// The user. - /// user - /// - 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); - } - - /// - /// Creates the user. - /// - /// The name. - /// User. - /// name - /// - public async Task 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; - } - - /// - /// Deletes the user. - /// - /// The user. - /// Task. - /// user - /// - 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; - } - - /// - /// Instantiates the new user. - /// - /// The name. - /// User. - 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 @@ + - - diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs new file mode 100644 index 000000000..5ea955fac --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -0,0 +1,650 @@ +using MediaBrowser.Common.Events; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Connectivity; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Library +{ + /// + /// Class UserManager + /// + public class UserManager : IUserManager + { + /// + /// The _active connections + /// + private readonly ConcurrentBag _activeConnections = + new ConcurrentBag(); + + /// + /// The _users + /// + private IEnumerable _users; + /// + /// The _user lock + /// + private object _usersSyncLock = new object(); + /// + /// The _users initialized + /// + private bool _usersInitialized; + /// + /// Gets the users. + /// + /// The users. + public IEnumerable 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, LoadUsers); + return _users; + } + internal set + { + _users = value; + + if (value == null) + { + _usersInitialized = false; + } + } + } + + /// + /// Gets all connections. + /// + /// All connections. + private IEnumerable AllConnections + { + get { return _activeConnections.Where(c => GetUserById(c.UserId) != null).OrderByDescending(c => c.LastActivityDate); } + } + + /// + /// Gets the active connections. + /// + /// The active connections. + public IEnumerable ConnectedUsers + { + get { return AllConnections.Where(c => (DateTime.UtcNow - c.LastActivityDate).TotalMinutes <= 10); } + } + + /// + /// The _logger + /// + private readonly ILogger _logger; + + private Kernel Kernel { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The kernel. + /// The logger. + public UserManager(Kernel kernel, ILogger logger) + { + _logger = logger; + Kernel = kernel; + } + + #region Events + /// + /// Occurs when [playback start]. + /// + public event EventHandler PlaybackStart; + /// + /// Occurs when [playback progress]. + /// + public event EventHandler PlaybackProgress; + /// + /// Occurs when [playback stopped]. + /// + public event EventHandler PlaybackStopped; + #endregion + + #region UserUpdated Event + /// + /// Occurs when [user updated]. + /// + public event EventHandler> UserUpdated; + + /// + /// Called when [user updated]. + /// + /// The user. + private void OnUserUpdated(User user) + { + EventHelper.QueueEventIfNotNull(UserUpdated, this, new GenericEventArgs { Argument = user }, _logger); + + // Notify connected ui's + Kernel.ServerManager.SendWebSocketMessage("UserUpdated", new DtoBuilder(_logger).GetDtoUser(user)); + } + #endregion + + #region UserDeleted Event + /// + /// Occurs when [user deleted]. + /// + public event EventHandler> UserDeleted; + /// + /// Called when [user deleted]. + /// + /// The user. + private void OnUserDeleted(User user) + { + EventHelper.QueueEventIfNotNull(UserDeleted, this, new GenericEventArgs { Argument = user }, _logger); + + // Notify connected ui's + Kernel.ServerManager.SendWebSocketMessage("UserDeleted", user.Id.ToString()); + } + #endregion + + /// + /// Gets a User by Id + /// + /// The id. + /// User. + /// + public User GetUserById(Guid id) + { + if (id == Guid.Empty) + { + throw new ArgumentNullException(); + } + + return Users.FirstOrDefault(u => u.Id == id); + } + + /// + /// Authenticates a User and returns a result indicating whether or not it succeeded + /// + /// The user. + /// The password. + /// Task{System.Boolean}. + /// user + public async Task 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; + } + + /// + /// Logs the user activity. + /// + /// The user. + /// Type of the client. + /// Name of the device. + /// Task. + /// user + 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); + } + + /// + /// Updates the now playing item id. + /// + /// The user. + /// Type of the client. + /// Name of the device. + /// The item. + /// The current position ticks. + private 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); + } + + /// + /// Removes the now playing item id. + /// + /// The user. + /// Type of the client. + /// Name of the device. + /// The item. + private 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; + } + } + + /// + /// Logs the connection. + /// + /// The user id. + /// Type of the client. + /// Name of the device. + /// The last activity date. + private void LogConnection(Guid userId, ClientType clientType, string deviceName, DateTime lastActivityDate) + { + GetConnection(userId, clientType, deviceName).LastActivityDate = lastActivityDate; + } + + /// + /// Gets the connection. + /// + /// The user id. + /// Type of the client. + /// Name of the device. + /// ClientConnectionInfo. + 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; + } + + /// + /// Loads the users from the repository + /// + /// IEnumerable{User}. + public IEnumerable 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; + } + + /// + /// Refreshes metadata for each user + /// + /// The cancellation token. + /// if set to true [force]. + /// Task. + public Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false) + { + var tasks = Users.Select(user => user.RefreshMetadata(cancellationToken, forceRefresh: force)).ToList(); + + return Task.WhenAll(tasks); + } + + /// + /// Renames the user. + /// + /// The user. + /// The new name. + /// Task. + /// user + /// + public async Task RenameUser(User user, string newName) + { + if (user == null) + { + throw new ArgumentNullException("user"); + } + + if (string.IsNullOrEmpty(newName)) + { + throw new ArgumentNullException("newName"); + } + + if (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); + } + + /// + /// Updates the user. + /// + /// The user. + /// user + /// + public async Task UpdateUser(User user) + { + if (user == null) + { + throw new ArgumentNullException("user"); + } + + if (user.Id == Guid.Empty || !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); + } + + /// + /// Creates the user. + /// + /// The name. + /// User. + /// name + /// + public async Task CreateUser(string name) + { + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException("name"); + } + + if (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 = Users.ToList(); + list.Add(user); + Users = list; + + await Kernel.UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false); + + return user; + } + + /// + /// Deletes the user. + /// + /// The user. + /// Task. + /// user + /// + public async Task DeleteUser(User user) + { + if (user == null) + { + throw new ArgumentNullException("user"); + } + + if (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 (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 + Users = null; + } + + /// + /// Instantiates the new user. + /// + /// The name. + /// User. + private User InstantiateNewUser(string name) + { + return new User + { + Name = name, + Id = ("MBUser" + name).GetMD5(), + DateCreated = DateTime.UtcNow, + DateModified = DateTime.UtcNow + }; + } + /// + /// Used to report that playback has started for an item + /// + /// The user. + /// The item. + /// Type of the client. + /// Name of the device. + /// + public void OnPlaybackStart(User user, BaseItem item, ClientType clientType, string deviceName) + { + if (user == null) + { + throw new ArgumentNullException(); + } + if (item == null) + { + throw new ArgumentNullException(); + } + + 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); + } + + /// + /// Used to report playback progress for an item + /// + /// The user. + /// The item. + /// The position ticks. + /// Type of the client. + /// Name of the device. + /// Task. + /// + 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(); + } + + 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); + } + + /// + /// Used to report that playback has ended for an item + /// + /// The user. + /// The item. + /// The position ticks. + /// Type of the client. + /// Name of the device. + /// Task. + /// + 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(); + } + + 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); + } + + /// + /// Updates playstate position for an item but does not save + /// + /// The item + /// User data for the item + /// The current playback position + /// Whether or not to increment playcount + 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; + } + } + + /// + /// Saves user data for an item + /// + /// The user. + /// The item. + /// The data. + public Task SaveUserDataForItem(User user, BaseItem item, UserItemData data) + { + item.AddOrUpdateUserData(user, data); + + return Kernel.UserDataRepository.SaveUserData(item, CancellationToken.None); + } + + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index ec29ca4d3..4fba9da43 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -50,6 +50,7 @@ Properties\SharedVersion.cs + diff --git a/MediaBrowser.ServerApplication/App.xaml.cs b/MediaBrowser.ServerApplication/App.xaml.cs index 1199aeaf1..81ea869b8 100644 --- a/MediaBrowser.ServerApplication/App.xaml.cs +++ b/MediaBrowser.ServerApplication/App.xaml.cs @@ -1,6 +1,7 @@ using MediaBrowser.ClickOnce; using MediaBrowser.Common.Kernel; using MediaBrowser.Controller; +using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Server.Uninstall; using Microsoft.Win32; @@ -277,21 +278,24 @@ namespace MediaBrowser.ServerApplication /// /// Opens the dashboard. /// - public static void OpenDashboard() + public static void OpenDashboard(User loggedInUser) { - OpenDashboardPage("dashboard.html"); + OpenDashboardPage("dashboard.html", loggedInUser); } /// /// Opens the dashboard page. /// /// The page. - public static void OpenDashboardPage(string page) + public static void OpenDashboardPage(string page, User loggedInUser) { var url = "http://localhost:" + Controller.Kernel.Instance.Configuration.HttpServerPortNumber + "/" + Controller.Kernel.Instance.WebApplicationName + "/dashboard/" + page; - url = AddAutoLoginToDashboardUrl(url); + if (loggedInUser != null) + { + url = AddAutoLoginToDashboardUrl(url, loggedInUser); + } OpenUrl(url); } @@ -300,21 +304,17 @@ namespace MediaBrowser.ServerApplication /// Adds the auto login to dashboard URL. /// /// The URL. + /// The user. /// System.String. - public static string AddAutoLoginToDashboardUrl(string url) + public static string AddAutoLoginToDashboardUrl(string url, User user) { - var user = Controller.Kernel.Instance.Users.FirstOrDefault(u => u.Configuration.IsAdministrator); - - if (user != null) + if (url.IndexOf('?') == -1) { - if (url.IndexOf('?') == -1) - { - url += "?u=" + user.Id; - } - else - { - url += "&u=" + user.Id; - } + url += "?u=" + user.Id; + } + else + { + url += "&u=" + user.Id; } return url; diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 8205018ab..0d8411d2c 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -14,6 +14,7 @@ using MediaBrowser.Common.Kernel; using MediaBrowser.Common.Net; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller; +using MediaBrowser.Controller.Library; using MediaBrowser.IsoMounter; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; @@ -22,6 +23,7 @@ using MediaBrowser.Model.Serialization; using MediaBrowser.Model.System; using MediaBrowser.Model.Updates; using MediaBrowser.Server.Implementations; +using MediaBrowser.Server.Implementations.Library; using MediaBrowser.ServerApplication.Implementations; using System; using System.Collections.Generic; @@ -118,6 +120,8 @@ namespace MediaBrowser.ServerApplication RegisterSingleInstance(this); + RegisterSingleInstance(new UserManager(Kernel, Logger)); + RegisterSingleInstance(ServerApplicationPaths); RegisterSingleInstance(new PismoIsoManager(Logger)); RegisterSingleInstance(new BdInfoExaminer()); diff --git a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs index cb5c62ff0..b88b64988 100644 --- a/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs +++ b/MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs @@ -39,14 +39,14 @@ namespace MediaBrowser.ServerApplication /// /// Initializes a new instance of the class. /// - public LibraryExplorer(IJsonSerializer jsonSerializer, ILogger logger, IApplicationHost appHost) + public LibraryExplorer(IJsonSerializer jsonSerializer, ILogger logger, IApplicationHost appHost, IUserManager userManager) { _logger = logger; _jsonSerializer = jsonSerializer; InitializeComponent(); lblVersion.Content = "Version: " + appHost.ApplicationVersion; - foreach (var user in Kernel.Instance.Users) + foreach (var user in userManager.Users) ddlProfile.Items.Add(user); ddlProfile.Items.Insert(0,new User {Name = "Physical"}); ddlProfile.SelectedIndex = 0; diff --git a/MediaBrowser.ServerApplication/MainWindow.xaml.cs b/MediaBrowser.ServerApplication/MainWindow.xaml.cs index 1189e73d7..dbb3c9842 100644 --- a/MediaBrowser.ServerApplication/MainWindow.xaml.cs +++ b/MediaBrowser.ServerApplication/MainWindow.xaml.cs @@ -40,11 +40,6 @@ namespace MediaBrowser.ServerApplication /// The new item timer. private Timer NewItemTimer { get; set; } - /// - /// The _json serializer - /// - private readonly IJsonSerializer _jsonSerializer; - /// /// The _logger /// @@ -67,18 +62,13 @@ namespace MediaBrowser.ServerApplication /// The logger. /// The app host. /// logger - public MainWindow(IJsonSerializer jsonSerializer, ILogManager logManager, IApplicationHost appHost) + public MainWindow(ILogManager logManager, IApplicationHost appHost) { - if (jsonSerializer == null) - { - throw new ArgumentNullException("jsonSerializer"); - } if (logManager == null) { throw new ArgumentNullException("logManager"); } - _jsonSerializer = jsonSerializer; _logger = logManager.GetLogger("MainWindow"); _appHost = appHost; _logManager = logManager; @@ -255,7 +245,9 @@ namespace MediaBrowser.ServerApplication /// private void LaunchStartupWizard() { - App.OpenDashboardPage("wizardStart.html"); + var user = _appHost.Resolve().Users.FirstOrDefault(u => u.Configuration.IsAdministrator); + + App.OpenDashboardPage("wizardStart.html", user); } /// @@ -265,8 +257,8 @@ namespace MediaBrowser.ServerApplication /// The instance containing the event data. void cmdApiDocs_Click(object sender, EventArgs e) { - App.OpenUrl("http://localhost:" + Controller.Kernel.Instance.Configuration.HttpServerPortNumber + "/" + - Controller.Kernel.Instance.WebApplicationName + "/metadata"); + App.OpenUrl("http://localhost:" + Kernel.Instance.Configuration.HttpServerPortNumber + "/" + + Kernel.Instance.WebApplicationName + "/metadata"); } /// @@ -301,7 +293,8 @@ namespace MediaBrowser.ServerApplication /// The instance containing the event data. private void cmOpenExplorer_click(object sender, RoutedEventArgs e) { - (new LibraryExplorer(_jsonSerializer, _logger, _appHost)).Show(); + var explorer = (LibraryExplorer)_appHost.CreateInstance(typeof(LibraryExplorer)); + explorer.Show(); } /// @@ -311,7 +304,8 @@ namespace MediaBrowser.ServerApplication /// The instance containing the event data. private void cmOpenDashboard_click(object sender, RoutedEventArgs e) { - App.OpenDashboard(); + var user = _appHost.Resolve().Users.FirstOrDefault(u => u.Configuration.IsAdministrator); + App.OpenDashboard(user); } /// @@ -331,7 +325,8 @@ namespace MediaBrowser.ServerApplication /// The instance containing the event data. private void cmdBrowseLibrary_click(object sender, RoutedEventArgs e) { - App.OpenDashboardPage("index.html"); + var user = _appHost.Resolve().Users.FirstOrDefault(u => u.Configuration.IsAdministrator); + App.OpenDashboardPage("index.html", user); } /// diff --git a/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs b/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs index 9d42b10ae..93b23b943 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Kernel; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller; +using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; using System.ComponentModel.Composition; using System.Threading.Tasks; @@ -33,16 +34,24 @@ namespace MediaBrowser.WebDashboard.Api /// The task manager. private readonly ITaskManager _taskManager; + /// + /// The _user manager + /// + private readonly IUserManager _userManager; + /// /// Initializes a new instance of the class. /// /// The kernel. /// The logger. - public DashboardInfoWebSocketListener(Kernel kernel, ILogger logger, ITaskManager taskManager) + /// The task manager. + /// The user manager. + public DashboardInfoWebSocketListener(Kernel kernel, ILogger logger, ITaskManager taskManager, IUserManager userManager) : base(logger) { _kernel = kernel; _taskManager = taskManager; + _userManager = userManager; } /// @@ -52,7 +61,7 @@ namespace MediaBrowser.WebDashboard.Api /// Task{IEnumerable{TaskInfo}}. protected override Task GetDataToSend(object state) { - return Task.FromResult(DashboardService.GetDashboardInfo(_kernel, Logger, _taskManager)); + return Task.FromResult(DashboardService.GetDashboardInfo(_kernel, Logger, _taskManager, _userManager)); } } } diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index e37924d4c..18ca7ef24 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -84,13 +84,20 @@ namespace MediaBrowser.WebDashboard.Api /// The task manager. private readonly ITaskManager _taskManager; + /// + /// The _user manager + /// + private readonly IUserManager _userManager; + /// /// Initializes a new instance of the class. /// /// The task manager. - public DashboardService(ITaskManager taskManager) + /// The user manager. + public DashboardService(ITaskManager taskManager, IUserManager userManager) { _taskManager = taskManager; + _userManager = userManager; } /// @@ -102,7 +109,7 @@ namespace MediaBrowser.WebDashboard.Api { var kernel = (Kernel)Kernel; - return GetDashboardInfo(kernel, Logger, _taskManager); + return GetDashboardInfo(kernel, Logger, _taskManager, _userManager); } /// @@ -111,10 +118,11 @@ namespace MediaBrowser.WebDashboard.Api /// The kernel. /// The logger. /// The task manager. + /// The user manager. /// DashboardInfo. - public static DashboardInfo GetDashboardInfo(Kernel kernel, ILogger logger, ITaskManager taskManager) + public static DashboardInfo GetDashboardInfo(Kernel kernel, ILogger logger, ITaskManager taskManager, IUserManager userManager) { - var connections = kernel.UserManager.ActiveConnections.ToArray(); + var connections = userManager.ConnectedUsers.ToArray(); var dtoBuilder = new DtoBuilder(logger); @@ -130,7 +138,7 @@ namespace MediaBrowser.WebDashboard.Api ActiveConnections = connections, - Users = kernel.Users.Where(u => connections.Any(c => c.UserId == u.Id)).Select(dtoBuilder.GetDtoUser).ToArray() + Users = userManager.Users.Where(u => connections.Any(c => c.UserId == u.Id)).Select(dtoBuilder.GetDtoUser).ToArray() }; } @@ -353,6 +361,7 @@ namespace MediaBrowser.WebDashboard.Api /// /// Gets the common CSS. /// + /// The version. /// System.String. private static string GetCommonCss(Version version) { @@ -373,6 +382,7 @@ namespace MediaBrowser.WebDashboard.Api /// /// Gets the common javascript. /// + /// The version. /// System.String. private static string GetCommonJavascript(Version version) { -- cgit v1.2.3