From e5d57bd82f9a089b7c19ea357efd2b8b34fd418b Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Tue, 2 Jul 2019 12:21:54 +0200 Subject: [PATCH] Move StartupWizard to ASP.NET Web Api --- .../ApplicationHost.cs | 15 +- .../Emby.Server.Implementations.csproj | 2 + Emby.Server.Implementations/MvcRoutePrefix.cs | 48 +++++++ Jellyfin.Api/Controllers/StartupController.cs | 88 ++++++++++++ Jellyfin.Api/Jellyfin.Api.csproj | 18 +++ .../Models/Startup/StartupConfiguration.cs | 9 ++ Jellyfin.Api/Models/Startup/StartupUser.cs | 8 ++ MediaBrowser.Api/StartupWizardService.cs | 135 ------------------ MediaBrowser.sln | 11 +- 9 files changed, 192 insertions(+), 142 deletions(-) create mode 100644 Emby.Server.Implementations/MvcRoutePrefix.cs create mode 100644 Jellyfin.Api/Controllers/StartupController.cs create mode 100644 Jellyfin.Api/Jellyfin.Api.csproj create mode 100644 Jellyfin.Api/Models/Startup/StartupConfiguration.cs create mode 100644 Jellyfin.Api/Models/Startup/StartupUser.cs diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index fef461b9ac..a9c4e1fdc9 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -108,6 +108,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -611,8 +612,6 @@ namespace Emby.Server.Implementations await RegisterResources(serviceCollection).ConfigureAwait(false); - FindParts(); - string contentRoot = ServerConfigurationManager.Configuration.DashboardSourcePath; if (string.IsNullOrEmpty(contentRoot)) { @@ -657,6 +656,14 @@ namespace Emby.Server.Implementations { services.AddResponseCompression(); services.AddHttpContextAccessor(); + services.AddMvc(opts => + { + opts.UseGeneralRoutePrefix("emby", "emby/emby", "api/v{version:apiVersion}"); + }) + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) + .AddApplicationPart(Assembly.Load("Jellyfin.Api")); + services.AddApiVersioning(opt => opt.ReportApiVersions = true); + services.TryAdd(serviceCollection); }) .Configure(app => { @@ -666,10 +673,14 @@ namespace Emby.Server.Implementations // TODO app.UseMiddleware(); app.Use(ExecuteWebsocketHandlerAsync); + app.UseMvc(); app.Use(ExecuteHttpHandlerAsync); }) .Build(); + _serviceProvider = host.Services; + FindParts(); + try { await host.StartAsync().ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 45607dc098..23e35f77e1 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -3,6 +3,7 @@ + @@ -25,6 +26,7 @@ + diff --git a/Emby.Server.Implementations/MvcRoutePrefix.cs b/Emby.Server.Implementations/MvcRoutePrefix.cs new file mode 100644 index 0000000000..fb26ae09da --- /dev/null +++ b/Emby.Server.Implementations/MvcRoutePrefix.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ApplicationModels; + +namespace Emby.Server.Implementations +{ + public static class MvcRoutePrefix + { + public static void UseGeneralRoutePrefix(this MvcOptions opts, params string[] prefixes) + { + opts.Conventions.Insert(0, new RoutePrefixConvention(prefixes)); + } + + internal class RoutePrefixConvention : IApplicationModelConvention + { + private readonly AttributeRouteModel[] _routePrefixes; + + public RoutePrefixConvention(IEnumerable prefixes) + { + _routePrefixes = prefixes.Select(p => new AttributeRouteModel(new RouteAttribute(p))).ToArray(); + } + + public void Apply(ApplicationModel application) + { + foreach (var controller in application.Controllers) + { + if (controller.Selectors == null) + { + continue; + } + + var newSelectors = new List(); + foreach (var selector in controller.Selectors) + { + newSelectors.AddRange(_routePrefixes.Select(routePrefix => new SelectorModel(selector) + { + AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(routePrefix, selector.AttributeRouteModel) + })); + } + + controller.Selectors.Clear(); + newSelectors.ForEach(selector => controller.Selectors.Add(selector)); + } + } + } + } +} diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs new file mode 100644 index 0000000000..c17b534ebf --- /dev/null +++ b/Jellyfin.Api/Controllers/StartupController.cs @@ -0,0 +1,88 @@ +using System.Linq; +using System.Threading.Tasks; +using Jellyfin.Api.Models.Startup; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Library; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Controllers +{ + [ApiVersion("1")] + [Route("[controller]")] + public class StartupController : ControllerBase + { + private readonly IServerConfigurationManager _config; + private readonly IUserManager _userManager; + + public StartupController(IServerConfigurationManager config, IUserManager userManager) + { + _config = config; + _userManager = userManager; + } + + [HttpPost("Complete")] + public void Post() + { + _config.Configuration.IsStartupWizardCompleted = true; + _config.SetOptimalValues(); + _config.SaveConfiguration(); + } + + [HttpGet("Configuration")] + public StartupConfiguration Get() + { + var result = new StartupConfiguration + { + UICulture = _config.Configuration.UICulture, + MetadataCountryCode = _config.Configuration.MetadataCountryCode, + PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage + }; + + return result; + } + + [HttpPost("Configuration")] + public void UpdateInitial([FromForm] string uiCulture, [FromForm] string metadataCountryCode, [FromForm] string preferredMetadataLanguage) + { + _config.Configuration.UICulture = uiCulture; + _config.Configuration.MetadataCountryCode = metadataCountryCode; + _config.Configuration.PreferredMetadataLanguage = preferredMetadataLanguage; + _config.SaveConfiguration(); + } + + [HttpPost("RemoteAccess")] + public void Post([FromForm] bool enableRemoteAccess, [FromForm] bool enableAutomaticPortMapping) + { + _config.Configuration.EnableRemoteAccess = enableRemoteAccess; + _config.Configuration.EnableUPnP = enableAutomaticPortMapping; + _config.SaveConfiguration(); + } + + [HttpGet("User")] + public StartupUser GetUser() + { + var user = _userManager.Users.First(); + + return new StartupUser + { + Name = user.Name, + Password = user.Password + }; + } + + [HttpPost("User")] + public async Task Post([FromForm] StartupUser startupUser) + { + var user = _userManager.Users.First(); + + user.Name = startupUser.Name; + + _userManager.UpdateUser(user); + + if (!string.IsNullOrEmpty(startupUser.Password)) + { + await _userManager.ChangePassword(user, startupUser.Password).ConfigureAwait(false); + } + } + } +} diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj new file mode 100644 index 0000000000..7a7e49e302 --- /dev/null +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -0,0 +1,18 @@ + + + + netstandard2.0 + Library + + + + + + + + + + + + + diff --git a/Jellyfin.Api/Models/Startup/StartupConfiguration.cs b/Jellyfin.Api/Models/Startup/StartupConfiguration.cs new file mode 100644 index 0000000000..08dd59a177 --- /dev/null +++ b/Jellyfin.Api/Models/Startup/StartupConfiguration.cs @@ -0,0 +1,9 @@ +namespace Jellyfin.Api.Models.Startup +{ + public class StartupConfiguration + { + public string UICulture { get; set; } + public string MetadataCountryCode { get; set; } + public string PreferredMetadataLanguage { get; set; } + } +} diff --git a/Jellyfin.Api/Models/Startup/StartupUser.cs b/Jellyfin.Api/Models/Startup/StartupUser.cs new file mode 100644 index 0000000000..93a09e865b --- /dev/null +++ b/Jellyfin.Api/Models/Startup/StartupUser.cs @@ -0,0 +1,8 @@ +namespace Jellyfin.Api.Models.Startup +{ + public class StartupUser + { + public string Name { get; set; } + public string Password { get; set; } + } +} diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 3a9eb7a55e..e69de29bb2 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -1,135 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Api -{ - [Route("/Startup/Complete", "POST", Summary = "Reports that the startup wizard has been completed", IsHidden = true)] - public class ReportStartupWizardComplete : IReturnVoid - { - } - - [Route("/Startup/Configuration", "GET", Summary = "Gets initial server configuration", IsHidden = true)] - public class GetStartupConfiguration : IReturn - { - } - - [Route("/Startup/Configuration", "POST", Summary = "Updates initial server configuration", IsHidden = true)] - public class UpdateStartupConfiguration : StartupConfiguration, IReturnVoid - { - } - - [Route("/Startup/RemoteAccess", "POST", Summary = "Updates initial server configuration", IsHidden = true)] - public class UpdateRemoteAccessConfiguration : IReturnVoid - { - public bool EnableRemoteAccess { get; set; } - public bool EnableAutomaticPortMapping { get; set; } - } - - [Route("/Startup/User", "GET", Summary = "Gets initial user info", IsHidden = true)] - public class GetStartupUser : IReturn - { - } - - [Route("/Startup/User", "POST", Summary = "Updates initial user info", IsHidden = true)] - public class UpdateStartupUser : StartupUser - { - } - - [Authenticated(AllowBeforeStartupWizard = true, Roles = "Admin")] - public class StartupWizardService : BaseApiService - { - private readonly IServerConfigurationManager _config; - private readonly IServerApplicationHost _appHost; - private readonly IUserManager _userManager; - private readonly IMediaEncoder _mediaEncoder; - private readonly IHttpClient _httpClient; - - public StartupWizardService(IServerConfigurationManager config, IHttpClient httpClient, IServerApplicationHost appHost, IUserManager userManager, IMediaEncoder mediaEncoder) - { - _config = config; - _appHost = appHost; - _userManager = userManager; - _mediaEncoder = mediaEncoder; - _httpClient = httpClient; - } - - public void Post(ReportStartupWizardComplete request) - { - _config.Configuration.IsStartupWizardCompleted = true; - _config.SetOptimalValues(); - _config.SaveConfiguration(); - } - - public object Get(GetStartupConfiguration request) - { - var result = new StartupConfiguration - { - UICulture = _config.Configuration.UICulture, - MetadataCountryCode = _config.Configuration.MetadataCountryCode, - PreferredMetadataLanguage = _config.Configuration.PreferredMetadataLanguage - }; - - return result; - } - - public void Post(UpdateStartupConfiguration request) - { - _config.Configuration.UICulture = request.UICulture; - _config.Configuration.MetadataCountryCode = request.MetadataCountryCode; - _config.Configuration.PreferredMetadataLanguage = request.PreferredMetadataLanguage; - _config.SaveConfiguration(); - } - - public void Post(UpdateRemoteAccessConfiguration request) - { - _config.Configuration.EnableRemoteAccess = request.EnableRemoteAccess; - _config.Configuration.EnableUPnP = request.EnableAutomaticPortMapping; - _config.SaveConfiguration(); - } - - public object Get(GetStartupUser request) - { - var user = _userManager.Users.First(); - - return new StartupUser - { - Name = user.Name, - Password = user.Password - }; - } - - public async Task Post(UpdateStartupUser request) - { - var user = _userManager.Users.First(); - - user.Name = request.Name; - - _userManager.UpdateUser(user); - - if (!string.IsNullOrEmpty(request.Password)) - { - await _userManager.ChangePassword(user, request.Password).ConfigureAwait(false); - } - } - } - - public class StartupConfiguration - { - public string UICulture { get; set; } - public string MetadataCountryCode { get; set; } - public string PreferredMetadataLanguage { get; set; } - } - - public class StartupUser - { - public string Name { get; set; } - public string Password { get; set; } - } -} diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 27c8c1668f..58bfb55f6f 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26730.3 @@ -51,6 +50,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Drawing.Skia", "Jellyfin.Drawing.Skia\Jellyfin.Drawing.Skia.csproj", "{154872D9-6C12-4007-96E3-8F70A58386CE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Api", "Jellyfin.Api\Jellyfin.Api.csproj", "{DFBEFB4C-DA19-4143-98B7-27320C7F7163}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Common.Tests", "tests\Jellyfin.Common.Tests\Jellyfin.Common.Tests.csproj", "{DF194677-DFD3-42AF-9F75-D44D5A416478}" @@ -89,10 +90,6 @@ Global {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Debug|Any CPU.Build.0 = Debug|Any CPU {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Any CPU.ActiveCfg = Release|Any CPU {442B5058-DCAF-4263-BB6A-F21E31120A1B}.Release|Any CPU.Build.0 = Release|Any CPU - {4A4402D4-E910-443B-B8FC-2C18286A2CA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A4402D4-E910-443B-B8FC-2C18286A2CA0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A4402D4-E910-443B-B8FC-2C18286A2CA0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A4402D4-E910-443B-B8FC-2C18286A2CA0}.Release|Any CPU.Build.0 = Release|Any CPU {23499896-B135-4527-8574-C26E926EA99E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {23499896-B135-4527-8574-C26E926EA99E}.Debug|Any CPU.Build.0 = Debug|Any CPU {23499896-B135-4527-8574-C26E926EA99E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -153,6 +150,10 @@ Global {154872D9-6C12-4007-96E3-8F70A58386CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {154872D9-6C12-4007-96E3-8F70A58386CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {154872D9-6C12-4007-96E3-8F70A58386CE}.Release|Any CPU.Build.0 = Release|Any CPU + {DFBEFB4C-DA19-4143-98B7-27320C7F7163}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFBEFB4C-DA19-4143-98B7-27320C7F7163}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFBEFB4C-DA19-4143-98B7-27320C7F7163}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFBEFB4C-DA19-4143-98B7-27320C7F7163}.Release|Any CPU.Build.0 = Release|Any CPU {DF194677-DFD3-42AF-9F75-D44D5A416478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DF194677-DFD3-42AF-9F75-D44D5A416478}.Debug|Any CPU.Build.0 = Debug|Any CPU {DF194677-DFD3-42AF-9F75-D44D5A416478}.Release|Any CPU.ActiveCfg = Release|Any CPU