diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs index 96f45cd1ba..a319eb5a9e 100644 --- a/src/Umbraco.Core/Constants-Web.cs +++ b/src/Umbraco.Core/Constants-Web.cs @@ -53,6 +53,8 @@ public static class Mvc { public const string InstallArea = "UmbracoInstall"; + + public const string BackOfficeArea = "UmbracoBackOffice"; } } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs index 429b2e625a..f29cede61b 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs @@ -10,23 +10,22 @@ using Umbraco.Web.WebAssets; namespace Umbraco.Web.BackOffice.Controllers { + [Area(Umbraco.Core.Constants.Web.Mvc.BackOfficeArea)] public class BackOfficeController : Controller { private readonly IRuntimeMinifier _runtimeMinifier; private readonly IGlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; - public BackOfficeController(IRuntimeMinifier runtimeMinifier, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IUmbracoApplicationLifetime umbracoApplicationLifetime) + public BackOfficeController(IRuntimeMinifier runtimeMinifier, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { _runtimeMinifier = runtimeMinifier; _globalSettings = globalSettings; _hostingEnvironment = hostingEnvironment; - _umbracoApplicationLifetime = umbracoApplicationLifetime; } - // GET - public IActionResult Index() + [HttpGet] + public IActionResult Default() { return View(); } @@ -36,6 +35,7 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// [MinifyJavaScriptResult(Order = 0)] + [HttpGet] public async Task Application() { var result = await _runtimeMinifier.GetScriptForLoadingBackOfficeAsync(_globalSettings, _hostingEnvironment); diff --git a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeApplicationBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeApplicationBuilderExtensions.cs index d1cec6ea3d..4f0ba8097d 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeApplicationBuilderExtensions.cs @@ -1,7 +1,8 @@ using System; using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; using SixLabors.ImageSharp.Web.DependencyInjection; -using Umbraco.Extensions; +using Umbraco.Web.BackOffice.Routing; namespace Umbraco.Extensions { @@ -15,18 +16,8 @@ namespace Umbraco.Extensions app.UseEndpoints(endpoints => { - // TODO: This is temporary, 'umbraco' cannot be hard coded, needs to use GetUmbracoMvcArea() - // but actually we need to route all back office stuff in a back office area like we do in v8 - - // TODO: We will also need to detect runtime state here and redirect to the installer, - // Potentially switch this to dynamic routing so we can essentially disable/overwrite the back office routes to redirect to install - // when required, example https://www.strathweb.com/2019/08/dynamic-controller-routing-in-asp-net-core-3-0/ - - endpoints.MapControllerRoute("Backoffice", "/umbraco/{Action}", new - { - Controller = "BackOffice", - Action = "Default" - }); + var backOfficeRoutes = app.ApplicationServices.GetRequiredService(); + backOfficeRoutes.CreateRoutes(endpoints); }); app.UseUmbracoRuntimeMinification(); diff --git a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs new file mode 100644 index 0000000000..9acb8a6e36 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs @@ -0,0 +1,55 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Hosting; +using Umbraco.Extensions; +using Umbraco.Web.BackOffice.Controllers; +using Umbraco.Web.Common.Routing; + +namespace Umbraco.Web.BackOffice.Routing +{ + public class BackOfficeAreaRoutes : IAreaRoutes + { + private readonly IGlobalSettings _globalSettings; + private readonly IHostingEnvironment _hostingEnvironment; + + public BackOfficeAreaRoutes(IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + { + _globalSettings = globalSettings; + _hostingEnvironment = hostingEnvironment; + } + + public void CreateRoutes(IEndpointRouteBuilder endpoints) + { + var umbracoPath = _globalSettings.GetUmbracoMvcArea(_hostingEnvironment); + + // TODO: We need to auto-route "Umbraco Api Controllers" for the back office + + // TODO: We will also need to detect runtime state here and redirect to the installer, + // Potentially switch this to dynamic routing so we can essentially disable/overwrite the back office routes to redirect to install + // when required, example https://www.strathweb.com/2019/08/dynamic-controller-routing-in-asp-net-core-3-0/ + + endpoints.MapAreaControllerRoute( + "Umbraco_back_office", // TODO: Same name as before but we should change these so they have a convention + Constants.Web.Mvc.BackOfficeArea, + $"{umbracoPath}/{{Action}}/{{id?}}", + new { controller = ControllerExtensions.GetControllerName(), action = "Default" }, + // Limit the action/id to only allow characters - this is so this route doesn't hog all other + // routes like: /umbraco/channels/word.aspx, etc... + // (Not that we have to worry about too many of those these days, there still might be a need for these constraints). + new + { + action = @"[a-zA-Z]*", + id = @"[a-zA-Z]*" + }); + + endpoints.MapAreaControllerRoute( + "Umbraco_preview", // TODO: Same name as before but we should change these so they have a convention + Constants.Web.Mvc.BackOfficeArea, + $"{umbracoPath}/preview/{{Action}}/{{editor?}}", + // TODO: Change this to use ControllerExtensions.GetControllerName once the PreviewController is moved to Umbraco.Web.BackOffice.Controllers + new { controller = "Preview", action = "Index" }); + } + } +} diff --git a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs new file mode 100644 index 0000000000..73fa06f1c7 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs @@ -0,0 +1,14 @@ +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Web.BackOffice.Routing; + +namespace Umbraco.Web.BackOffice.Runtime +{ + public class BackOfficeComposer : IComposer + { + public void Compose(Composition composition) + { + composition.RegisterUnique(); + } + } +} diff --git a/src/Umbraco.Web.Common/Extensions/ControllerExtensions.cs b/src/Umbraco.Web.Common/Extensions/ControllerExtensions.cs index a70088f6c2..cc52349699 100644 --- a/src/Umbraco.Web.Common/Extensions/ControllerExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ControllerExtensions.cs @@ -10,7 +10,7 @@ namespace Umbraco.Extensions /// /// /// - internal static string GetControllerName(Type controllerType) + public static string GetControllerName(Type controllerType) { if (!controllerType.Name.EndsWith("Controller")) { @@ -24,7 +24,7 @@ namespace Umbraco.Extensions /// /// /// - internal static string GetControllerName(this Controller controllerInstance) + public static string GetControllerName(this Controller controllerInstance) { return GetControllerName(controllerInstance.GetType()); } @@ -35,7 +35,7 @@ namespace Umbraco.Extensions /// /// /// - internal static string GetControllerName() + public static string GetControllerName() { return GetControllerName(typeof(T)); } diff --git a/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs new file mode 100644 index 0000000000..23d558b04b --- /dev/null +++ b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs @@ -0,0 +1,32 @@ +using System; +using Umbraco.Core; +using Microsoft.AspNetCore.Routing; +using System.Reflection; + +namespace Umbraco.Extensions +{ + public static class LinkGeneratorExtensions + { + /// + /// Return the back office url if the back office is installed + /// + /// + /// + public static string GetBackOfficeUrl(this LinkGenerator linkGenerator) + { + + Type backOfficeControllerType; + try + { + backOfficeControllerType = Assembly.Load("Umbraco.Web.BackOffice")?.GetType("Umbraco.Web.BackOffice.Controllers.BackOfficeController"); + if (backOfficeControllerType == null) return "/"; // this would indicate that the installer is installed without the back office + } + catch (Exception) + { + return "/"; // this would indicate that the installer is installed without the back office + } + + return linkGenerator.GetPathByAction("Default", ControllerExtensions.GetControllerName(backOfficeControllerType), new { area = Constants.Web.Mvc.BackOfficeArea }); + } + } +} diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoInstallApplicationBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoInstallApplicationBuilderExtensions.cs index 1173015865..f878070cd6 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoInstallApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoInstallApplicationBuilderExtensions.cs @@ -1,10 +1,6 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; -using Umbraco.Core.Logging; -using Umbraco.Web; +using Umbraco.Web.Common.Install; namespace Umbraco.Extensions { @@ -19,60 +15,14 @@ namespace Umbraco.Extensions { app.UseEndpoints(endpoints => { - var runtime = app.ApplicationServices.GetRequiredService(); - var logger = app.ApplicationServices.GetRequiredService(); - var uriUtility = app.ApplicationServices.GetRequiredService(); - switch (runtime.Level) - { - case RuntimeLevel.Install: - case RuntimeLevel.Upgrade: - - var installPath = uriUtility.ToAbsolute(Constants.SystemDirectories.Install).EnsureEndsWith('/'); - - endpoints.MapAreaControllerRoute( - "umbraco-install-api", - Umbraco.Core.Constants.Web.Mvc.InstallArea, - $"{installPath}api/{{Action}}", - new { controller = "InstallApi" }); - - endpoints.MapAreaControllerRoute( - "umbraco-install", - Umbraco.Core.Constants.Web.Mvc.InstallArea, - $"{installPath}{{controller}}/{{Action}}", - new { controller = "Install", action = "Index" }); - - // TODO: Potentially switch this to dynamic routing so we can essentially disable/overwrite the back office routes to redirect to install, - // example https://www.strathweb.com/2019/08/dynamic-controller-routing-in-asp-net-core-3-0/ - - // register catch all because if we are in install/upgrade mode then we'll catch everything and redirect - endpoints.MapGet("{*url}", context => - { - var uri = context.Request.GetEncodedUrl(); - // redirect to install - ReportRuntime(logger, runtime.Level, "Umbraco must install or upgrade."); - - var installUrl = $"{installPath}?redir=true&url={uri}"; - context.Response.Redirect(installUrl, false); - return Task.CompletedTask; - }); - - break; - } + var backOfficeRoutes = app.ApplicationServices.GetRequiredService(); + backOfficeRoutes.CreateRoutes(endpoints); }); return app; } - private static bool _reported; - private static RuntimeLevel _reportedLevel; - - private static void ReportRuntime(ILogger logger, RuntimeLevel level, string message) - { - if (_reported && _reportedLevel == level) return; - _reported = true; - _reportedLevel = level; - logger.Warn(typeof(UmbracoInstallApplicationBuilderExtensions), message); - } + } } diff --git a/src/Umbraco.Web.Common/Extensions/IUrlHelperExtensions.cs b/src/Umbraco.Web.Common/Extensions/UrlHelperExtensions.cs similarity index 84% rename from src/Umbraco.Web.Common/Extensions/IUrlHelperExtensions.cs rename to src/Umbraco.Web.Common/Extensions/UrlHelperExtensions.cs index c53e13f3b9..c54c370f4e 100644 --- a/src/Umbraco.Web.Common/Extensions/IUrlHelperExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UrlHelperExtensions.cs @@ -4,14 +4,39 @@ using System.Linq.Expressions; using Microsoft.AspNetCore.Mvc; using Umbraco.Core; using Umbraco.Web.Common.Controllers; -using Umbraco.Extensions; using Umbraco.Web.WebApi; -using Microsoft.AspNetCore.Mvc.Routing; +using Umbraco.Web.Common.Install; namespace Umbraco.Extensions { - public static class HttpUrlHelperExtensions + + public static class UrlHelperExtensions { + + /// + /// Return the back office url if the back office is installed + /// + /// + /// + public static string GetBackOfficeUrl(this IUrlHelper url) + { + var backOfficeControllerType = Type.GetType("Umbraco.Web.BackOffice.Controllers"); + if (backOfficeControllerType == null) return "/"; // this would indicate that the installer is installed without the back office + return url.Action("Default", ControllerExtensions.GetControllerName(backOfficeControllerType), new { area = Constants.Web.Mvc.BackOfficeArea }); + } + + /// + /// Return the installer API url + /// + /// + /// + public static string GetInstallerApiUrl(this IUrlHelper url) + { + // there is no default action here so we need to get it by action and trim the action + return url.Action("GetSetup", ControllerExtensions.GetControllerName(), new { area = Constants.Web.Mvc.InstallArea }) + .TrimEnd("GetSetup"); + } + /// /// Return the Url for a Web Api service /// diff --git a/src/Umbraco.Web.Common/Install/HttpInstallAuthorizeAttribute.cs b/src/Umbraco.Web.Common/Install/HttpInstallAuthorizeAttribute.cs deleted file mode 100644 index 8ee59105e4..0000000000 --- a/src/Umbraco.Web.Common/Install/HttpInstallAuthorizeAttribute.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.DependencyInjection; -using Umbraco.Core; -using Umbraco.Core.Logging; - -namespace Umbraco.Web.Install -{ - /// - /// Ensures authorization occurs for the installer if it has already completed. - /// If install has not yet occurred then the authorization is successful. - /// - public class HttpInstallAuthorizeAttribute : TypeFilterAttribute - { - public HttpInstallAuthorizeAttribute() : base(typeof(HttpInstallAuthorizeFilter)) - { - } - - private class HttpInstallAuthorizeFilter : IAuthorizationFilter - { - public void OnAuthorization(AuthorizationFilterContext authorizationFilterContext) - { - var serviceProvider = authorizationFilterContext.HttpContext.RequestServices; - var runtimeState = serviceProvider.GetService(); - var umbracoContext = serviceProvider.GetService(); - var logger = serviceProvider.GetService(); - - if (!IsAllowed(runtimeState, umbracoContext, logger)) - { - authorizationFilterContext.Result = new ForbidResult(); - } - - } - - private static bool IsAllowed(IRuntimeState runtimeState, IUmbracoContext umbracoContext, ILogger logger) - { - try - { - // if not configured (install or upgrade) then we can continue - // otherwise we need to ensure that a user is logged in - return runtimeState.Level == RuntimeLevel.Install - || runtimeState.Level == RuntimeLevel.Upgrade - || (umbracoContext?.Security?.ValidateCurrentUser() ?? false); - } - catch (Exception ex) - { - logger.Error(ex, "An error occurred determining authorization"); - return false; - } - } - } - } - -} diff --git a/src/Umbraco.Web.Common/Install/InstallApiController.cs b/src/Umbraco.Web.Common/Install/InstallApiController.cs index 2d22de730b..d5f330f113 100644 --- a/src/Umbraco.Web.Common/Install/InstallApiController.cs +++ b/src/Umbraco.Web.Common/Install/InstallApiController.cs @@ -23,7 +23,7 @@ namespace Umbraco.Web.Common.Install [UmbracoApiController] [TypeFilter(typeof(HttpResponseExceptionFilter))] [TypeFilter(typeof(AngularJsonOnlyConfigurationAttribute))] - [HttpInstallAuthorize] + [Web.Install.InstallAuthorize] [Area(Umbraco.Core.Constants.Web.Mvc.InstallArea)] public class InstallApiController : ControllerBase { diff --git a/src/Umbraco.Web.Common/Install/InstallAreaRoutes.cs b/src/Umbraco.Web.Common/Install/InstallAreaRoutes.cs new file mode 100644 index 0000000000..b5578c5d4f --- /dev/null +++ b/src/Umbraco.Web.Common/Install/InstallAreaRoutes.cs @@ -0,0 +1,93 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Routing; +using System.Threading.Tasks; +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Extensions; +using Umbraco.Web.Common.Routing; + +namespace Umbraco.Web.Common.Install +{ + + public class InstallAreaRoutes : IAreaRoutes + { + private readonly IRuntimeState _runtime; + private readonly ILogger _logger; + private readonly UriUtility _uriUtility; + private readonly LinkGenerator _linkGenerator; + + public InstallAreaRoutes(IRuntimeState runtime, ILogger logger, UriUtility uriUtility, LinkGenerator linkGenerator) + { + _runtime = runtime; + _logger = logger; + _uriUtility = uriUtility; + _linkGenerator = linkGenerator; + } + + public void CreateRoutes(IEndpointRouteBuilder endpoints) + { + var installPath = _uriUtility.ToAbsolute(Umbraco.Core.Constants.SystemDirectories.Install).EnsureEndsWith('/'); + + switch (_runtime.Level) + { + case RuntimeLevel.Install: + case RuntimeLevel.Upgrade: + endpoints.MapAreaControllerRoute( + "umbraco-install-api", + Umbraco.Core.Constants.Web.Mvc.InstallArea, + $"{installPath}api/{{Action}}", + new { controller = ControllerExtensions.GetControllerName() }); + + endpoints.MapAreaControllerRoute( + "umbraco-install", + Umbraco.Core.Constants.Web.Mvc.InstallArea, + $"{installPath}{{controller}}/{{Action}}", + new { controller = ControllerExtensions.GetControllerName(), action = "Index" }); + + // TODO: Potentially switch this to dynamic routing so we can essentially disable/overwrite the back office routes to redirect to install, + // example https://www.strathweb.com/2019/08/dynamic-controller-routing-in-asp-net-core-3-0/ + + // register catch all because if we are in install/upgrade mode then we'll catch everything and redirect + endpoints.MapGet("{*url}", context => + { + var uri = context.Request.GetEncodedUrl(); + // redirect to install + ReportRuntime(_logger, _runtime.Level, "Umbraco must install or upgrade."); + + var installUrl = $"{installPath}?redir=true&url={uri}"; + context.Response.Redirect(installUrl, false); + return Task.CompletedTask; + }); + break; + case RuntimeLevel.Run: + + // when we are in run mode redirect to the back office if the installer endpoint is hit + endpoints.MapGet($"{installPath}{{controller?}}/{{Action?}}", context => + { + // redirect to umbraco + context.Response.Redirect(_linkGenerator.GetBackOfficeUrl(), false); + return Task.CompletedTask; + }); + + break; + case RuntimeLevel.BootFailed: + case RuntimeLevel.Unknown: + case RuntimeLevel.Boot: + break; + + } + } + + private static bool _reported; + private static RuntimeLevel _reportedLevel; + + private static void ReportRuntime(ILogger logger, RuntimeLevel level, string message) + { + if (_reported && _reportedLevel == level) return; + _reported = true; + _reportedLevel = level; + logger.Warn(typeof(UmbracoInstallApplicationBuilderExtensions), message); + } + } +} diff --git a/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs b/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs index c92256c315..f7172e61b7 100644 --- a/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs +++ b/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs @@ -3,34 +3,37 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.Hosting; +using Umbraco.Core.Logging; -namespace Umbraco.Web.Common.Install +namespace Umbraco.Web.Install { + /// + /// Ensures authorization occurs for the installer if it has already completed. + /// If install has not yet occurred then the authorization is successful. + /// public class InstallAuthorizeAttribute : TypeFilterAttribute { - public InstallAuthorizeAttribute() : base(typeof(InstallAuthorizeFilter)) + public InstallAuthorizeAttribute() : base(typeof(HttpInstallAuthorizeFilter)) { } - private class InstallAuthorizeFilter : IAuthorizationFilter + private class HttpInstallAuthorizeFilter : IAuthorizationFilter { - public void OnAuthorization(AuthorizationFilterContext context) + public void OnAuthorization(AuthorizationFilterContext authorizationFilterContext) { - var sp = context.HttpContext.RequestServices; - var runtimeState = sp.GetRequiredService(); - var umbracoContextAccessor = sp.GetRequiredService(); - var globalSettings = sp.GetRequiredService(); - var hostingEnvironment = sp.GetRequiredService(); + var serviceProvider = authorizationFilterContext.HttpContext.RequestServices; + var runtimeState = serviceProvider.GetService(); + var umbracoContext = serviceProvider.GetService(); + var logger = serviceProvider.GetService(); - if (!IsAllowed(runtimeState, umbracoContextAccessor)) + if (!IsAllowed(runtimeState, umbracoContext, logger)) { - context.Result = new RedirectResult(globalSettings.GetBackOfficePath(hostingEnvironment)); + authorizationFilterContext.Result = new ForbidResult(); } + } - private bool IsAllowed(IRuntimeState runtimeState, IUmbracoContextAccessor umbracoContextAccessor) + private static bool IsAllowed(IRuntimeState runtimeState, IUmbracoContext umbracoContext, ILogger logger) { try { @@ -38,13 +41,15 @@ namespace Umbraco.Web.Common.Install // otherwise we need to ensure that a user is logged in return runtimeState.Level == RuntimeLevel.Install || runtimeState.Level == RuntimeLevel.Upgrade - || umbracoContextAccessor.UmbracoContext.Security.ValidateCurrentUser(); + || (umbracoContext?.Security?.ValidateCurrentUser() ?? false); } - catch (Exception) + catch (Exception ex) { + logger.Error(ex, "An error occurred determining authorization"); return false; } } } } + } diff --git a/src/Umbraco.Web.Common/Install/InstallController.cs b/src/Umbraco.Web.Common/Install/InstallController.cs index a5e035b4d0..729d297e31 100644 --- a/src/Umbraco.Web.Common/Install/InstallController.cs +++ b/src/Umbraco.Web.Common/Install/InstallController.cs @@ -51,8 +51,10 @@ namespace Umbraco.Web.Common.Install [TypeFilter(typeof(StatusCodeResultAttribute), Arguments = new object []{System.Net.HttpStatusCode.ServiceUnavailable})] public async Task Index() { + var umbracoPath = Url.GetBackOfficeUrl(); + if (_runtime.Level == RuntimeLevel.Run) - return Redirect(_globalSettings.UmbracoPath.EnsureEndsWith('/')); + return Redirect(umbracoPath); if (_runtime.Level == RuntimeLevel.Upgrade) { @@ -69,8 +71,8 @@ namespace Umbraco.Web.Common.Install } } - // gen the install base urlAddUmbracoCore - ViewData.SetInstallApiBaseUrl(Url.GetUmbracoApiService("GetSetup", "InstallApi", Umbraco.Core.Constants.Web.Mvc.InstallArea).TrimEnd("GetSetup")); + // gen the install base url + ViewData.SetInstallApiBaseUrl(Url.GetInstallerApiUrl()); // get the base umbraco folder ViewData.SetUmbracoBaseFolder(_hostingEnvironment.ToAbsolute(_globalSettings.UmbracoPath)); diff --git a/src/Umbraco.Web.Common/Install/InstallerComposer.cs b/src/Umbraco.Web.Common/Install/InstallerComposer.cs new file mode 100644 index 0000000000..d71a7a571e --- /dev/null +++ b/src/Umbraco.Web.Common/Install/InstallerComposer.cs @@ -0,0 +1,13 @@ +using Umbraco.Core; +using Umbraco.Core.Composing; + +namespace Umbraco.Web.Common.Install +{ + public class InstallerComposer : IComposer + { + public void Compose(Composition composition) + { + composition.RegisterUnique(); + } + } +} diff --git a/src/Umbraco.Web.Common/Routing/IAreaRoutes.cs b/src/Umbraco.Web.Common/Routing/IAreaRoutes.cs new file mode 100644 index 0000000000..b561abc4dd --- /dev/null +++ b/src/Umbraco.Web.Common/Routing/IAreaRoutes.cs @@ -0,0 +1,16 @@ +using Microsoft.AspNetCore.Routing; + +namespace Umbraco.Web.Common.Routing +{ + /// + /// Used to create routes for a route area + /// + public interface IAreaRoutes + { + // TODO: It could be possible to just get all collections of IAreaRoutes and route them all instead of relying + // on individual ext methods. This would reduce the amount of code in Startup, but could also mean there's less control over startup + // if someone wanted that. Maybe we can just have both. + + void CreateRoutes(IEndpointRouteBuilder endpoints); + } +} diff --git a/src/Umbraco.Web.UI.NetCore/Areas/UmbracoBackOffice/Views/BackOffice/Default.cshtml b/src/Umbraco.Web.UI.NetCore/Areas/UmbracoBackOffice/Views/BackOffice/Default.cshtml new file mode 100644 index 0000000000..cf205b3373 --- /dev/null +++ b/src/Umbraco.Web.UI.NetCore/Areas/UmbracoBackOffice/Views/BackOffice/Default.cshtml @@ -0,0 +1,17 @@ +@{ + Layout = null; +} + + + + + + + + +

Hello!

+ +

TODO: Import the default.cshtml back office page

+ + +