diff --git a/.github/New BackOffice - README.md b/.github/New BackOffice - README.md
new file mode 100644
index 0000000000..3d04ef2e36
--- /dev/null
+++ b/.github/New BackOffice - README.md
@@ -0,0 +1,18 @@
+# New Backoffice
+
+> **Warning**:
+> This is an early WIP, and is set not to be packable since we don't want to release this yet. There will be breaking changes in these projects
+
+This solution folder contains the projects for the new BackOffice. If you're looking to fix or improve the existing CMS, this is not the place to do it, although we do very much appreciate your efforts.
+
+### Project structure
+
+Since the new backoffice API is still very much a work in progress we've created new projects for the new backoffice API:
+
+* Umbrao.Cms.ManagementApi - The "presentation layer" for the management API
+* "New" versions of existing projects, should be merged with the existing projects when the new API is released:
+ * Umbraco.New.Cms.Core
+ * Umbraco.New.Cms.Infrastructure
+ * Umbraco.New.Cms.Web.Common
+
+This also means that we have to use "InternalsVisibleTo" for the new projects since these should be able to access the internal classes since they will when they get merged.
diff --git a/.github/config/codeql-config.yml b/.github/config/codeql-config.yml
index 77b390d392..bc9f75e77e 100644
--- a/.github/config/codeql-config.yml
+++ b/.github/config/codeql-config.yml
@@ -5,4 +5,5 @@ paths:
paths-ignore:
- '**/node_modules'
- - 'src/Umbraco.Web.UI/wwwroot'
\ No newline at end of file
+ - 'src/Umbraco.Web.UI/wwwroot'
+ - 'src/Umbraco.Cms.StaticAssets/wwwroot'
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 7bb75f0780..a3ffc10a1d 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -11,6 +11,10 @@ jobs:
CodeQL-Build:
runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
steps:
- name: Checkout repository
@@ -20,12 +24,12 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v1
+ uses: github/codeql-action/init@v2
with:
config-file: ./.github/config/codeql-config.yml
- name: Setup dotnet
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v2
with:
dotnet-version: '7.x'
include-prerelease: true
@@ -34,4 +38,4 @@ jobs:
run: dotnet build umbraco.sln -c SkipTests
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
+ uses: github/codeql-action/analyze@v2
diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/NewInstallController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/NewInstallController.cs
new file mode 100644
index 0000000000..94029edad4
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/Controllers/NewInstallController.cs
@@ -0,0 +1,111 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using Umbraco.Cms.Core;
+using Umbraco.Cms.Core.Configuration.Models;
+using Umbraco.Cms.Core.Hosting;
+using Umbraco.Cms.Core.Install.Models;
+using Umbraco.Cms.Core.Mapping;
+using Umbraco.Cms.Infrastructure.Install;
+using Umbraco.Cms.Infrastructure.Migrations.Install;
+using Umbraco.Cms.ManagementApi.Filters;
+using Umbraco.Cms.ManagementApi.ViewModels.Installer;
+using Umbraco.Extensions;
+using Umbraco.New.Cms.Core.Factories;
+using Umbraco.New.Cms.Core.Models.Installer;
+using Umbraco.New.Cms.Core.Services.Installer;
+using Umbraco.New.Cms.Web.Common.Routing;
+
+namespace Umbraco.Cms.ManagementApi.Controllers;
+
+[ApiController]
+[ApiVersion("1.0")]
+[BackOfficeRoute("api/v{version:apiVersion}/install")]
+[RequireRuntimeLevel(RuntimeLevel.Install)]
+public class NewInstallController : Controller
+{
+ private readonly IUmbracoMapper _mapper;
+ private readonly IInstallSettingsFactory _installSettingsFactory;
+ private readonly IInstallService _installService;
+ private readonly GlobalSettings _globalSettings;
+ private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly InstallHelper _installHelper;
+ private readonly DatabaseBuilder _databaseBuilder;
+
+ public NewInstallController(
+ IUmbracoMapper mapper,
+ IInstallSettingsFactory installSettingsFactory,
+ IInstallService installService,
+ IOptions globalSettings,
+ IHostingEnvironment hostingEnvironment,
+ InstallHelper installHelper,
+ DatabaseBuilder databaseBuilder)
+ {
+ _mapper = mapper;
+ _installSettingsFactory = installSettingsFactory;
+ _installService = installService;
+ _globalSettings = globalSettings.Value;
+ _hostingEnvironment = hostingEnvironment;
+ _installHelper = installHelper;
+ _databaseBuilder = databaseBuilder;
+ }
+
+ [HttpGet("settings")]
+ [MapToApiVersion("1.0")]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status428PreconditionRequired)]
+ [ProducesResponseType(typeof(InstallSettingsViewModel), StatusCodes.Status200OK)]
+ public async Task> Settings()
+ {
+ // Register that the install has started
+ await _installHelper.SetInstallStatusAsync(false, string.Empty);
+
+ InstallSettingsModel installSettings = _installSettingsFactory.GetInstallSettings();
+ InstallSettingsViewModel viewModel = _mapper.Map(installSettings)!;
+
+ return viewModel;
+ }
+
+ [HttpPost("setup")]
+ [MapToApiVersion("1.0")]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status428PreconditionRequired)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public async Task Setup(InstallViewModel installData)
+ {
+ InstallData data = _mapper.Map(installData)!;
+ await _installService.Install(data);
+
+ var backOfficePath = _globalSettings.GetBackOfficePath(_hostingEnvironment);
+ return Created(backOfficePath, null);
+ }
+
+ [HttpPost("validateDatabase")]
+ [MapToApiVersion("1.0")]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public async Task ValidateDatabase(DatabaseInstallViewModel viewModel)
+ {
+ // TODO: Async - We need to figure out what we want to do with async endpoints that doesn't do anything async
+ // We want these to be async for future use (Ideally we'll have more async things),
+ // But we need to figure out how we want to handle it in the meantime? use Task.FromResult or?
+ DatabaseModel databaseModel = _mapper.Map(viewModel)!;
+
+ var success = _databaseBuilder.ConfigureDatabaseConnection(databaseModel, true);
+
+ if (success)
+ {
+ return Ok();
+ }
+
+ var invalidModelProblem = new ProblemDetails
+ {
+ Title = "Invalid database configuration",
+ Detail = "The provided database configuration is invalid",
+ Status = StatusCodes.Status400BadRequest,
+ Type = "Error",
+ };
+
+ return BadRequest(invalidModelProblem);
+ }
+}
diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Server/ServerControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Server/ServerControllerBase.cs
new file mode 100644
index 0000000000..cdb4921ba3
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/Controllers/Server/ServerControllerBase.cs
@@ -0,0 +1,13 @@
+using Microsoft.AspNetCore.Mvc;
+using NSwag.Annotations;
+using Umbraco.New.Cms.Web.Common.Routing;
+
+namespace Umbraco.Cms.ManagementApi.Controllers.Server;
+
+[ApiController]
+[BackOfficeRoute("api/v{version:apiVersion}/server")]
+[OpenApiTag("Server")]
+public abstract class ServerControllerBase : Controller
+{
+
+}
diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Server/StatusServerController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Server/StatusServerController.cs
new file mode 100644
index 0000000000..875e685c27
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/Controllers/Server/StatusServerController.cs
@@ -0,0 +1,21 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Umbraco.Cms.Core.Services;
+using Umbraco.Cms.ManagementApi.ViewModels.Server;
+
+namespace Umbraco.Cms.ManagementApi.Controllers.Server;
+
+[ApiVersion("1.0")]
+public class StatusServerController : ServerControllerBase
+{
+ private readonly IRuntimeState _runtimeState;
+
+ public StatusServerController(IRuntimeState runtimeState) => _runtimeState = runtimeState;
+
+ [HttpGet("status")]
+ [MapToApiVersion("1.0")]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(typeof(ServerStatusViewModel), StatusCodes.Status200OK)]
+ public async Task> Get() =>
+ new ServerStatusViewModel { ServerStatus = _runtimeState.Level };
+}
diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Server/VersionServerController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Server/VersionServerController.cs
new file mode 100644
index 0000000000..fbd4f271e7
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/Controllers/Server/VersionServerController.cs
@@ -0,0 +1,22 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Umbraco.Cms.Core.Configuration;
+using Umbraco.Cms.ManagementApi.ViewModels.Server;
+using Umbraco.Extensions;
+
+namespace Umbraco.Cms.ManagementApi.Controllers.Server;
+
+[ApiVersion("1.0")]
+public class VersionServerController : ServerControllerBase
+{
+ private readonly IUmbracoVersion _umbracoVersion;
+
+ public VersionServerController(IUmbracoVersion umbracoVersion) => _umbracoVersion = umbracoVersion;
+
+ [HttpGet("version")]
+ [MapToApiVersion("1.0")]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(typeof(VersionViewModel), StatusCodes.Status200OK)]
+ public async Task> Get() =>
+ new VersionViewModel { Version = _umbracoVersion.SemanticVersion.ToSemanticStringWithoutBuild() };
+}
diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/UpgradeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/UpgradeController.cs
new file mode 100644
index 0000000000..29164adfb2
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/Controllers/UpgradeController.cs
@@ -0,0 +1,60 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Umbraco.Cms.Core;
+using Umbraco.Cms.Core.Mapping;
+using Umbraco.Cms.ManagementApi.Filters;
+using Umbraco.Cms.ManagementApi.ViewModels.Installer;
+using Umbraco.New.Cms.Core.Factories;
+using Umbraco.New.Cms.Core.Models.Installer;
+using Umbraco.New.Cms.Core.Services.Installer;
+using Umbraco.New.Cms.Web.Common.Routing;
+
+namespace Umbraco.Cms.ManagementApi.Controllers;
+
+// TODO: This needs to be an authorized controller.
+[ApiController]
+[ApiVersion("1.0")]
+[RequireRuntimeLevel(RuntimeLevel.Upgrade)]
+[BackOfficeRoute("api/v{version:apiVersion}/upgrade")]
+public class UpgradeController : Controller
+{
+ private readonly IUpgradeSettingsFactory _upgradeSettingsFactory;
+ private readonly IUpgradeService _upgradeService;
+ private readonly IUmbracoMapper _mapper;
+
+ public UpgradeController(
+ IUpgradeSettingsFactory upgradeSettingsFactory,
+ IUpgradeService upgradeService,
+ IUmbracoMapper mapper)
+ {
+ _upgradeSettingsFactory = upgradeSettingsFactory;
+ _upgradeService = upgradeService;
+ _mapper = mapper;
+ }
+
+ [HttpPost("authorize")]
+ [MapToApiVersion("1.0")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status428PreconditionRequired)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
+ public async Task Authorize()
+ {
+ await _upgradeService.Upgrade();
+ return Ok();
+ }
+
+ [HttpGet("settings")]
+ [MapToApiVersion("1.0")]
+ [ProducesResponseType(typeof(UpgradeSettingsViewModel), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status428PreconditionRequired)]
+ public async Task> Settings()
+ {
+ // TODO: Async - We need to figure out what we want to do with async endpoints that doesn't do anything async
+ // We want these to be async for future use (Ideally we'll have more async things),
+ // But we need to figure out how we want to handle it in the meantime? use Task.FromResult or?
+ UpgradeSettingsModel upgradeSettings = _upgradeSettingsFactory.GetUpgradeSettings();
+ UpgradeSettingsViewModel viewModel = _mapper.Map(upgradeSettings)!;
+
+ return viewModel;
+ }
+}
diff --git a/src/Umbraco.Cms.ManagementApi/DependencyInjection/InstallerBuilderExtensions.cs b/src/Umbraco.Cms.ManagementApi/DependencyInjection/InstallerBuilderExtensions.cs
new file mode 100644
index 0000000000..385cd1ff51
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/DependencyInjection/InstallerBuilderExtensions.cs
@@ -0,0 +1,79 @@
+using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.Mapping;
+using Umbraco.Cms.ManagementApi.Mapping.Installer;
+using Umbraco.New.Cms.Core.Factories;
+using Umbraco.New.Cms.Core.Installer;
+using Umbraco.New.Cms.Core.Installer.Steps;
+using Umbraco.New.Cms.Core.Services.Installer;
+using Umbraco.New.Cms.Infrastructure.Factories.Installer;
+using Umbraco.New.Cms.Infrastructure.Installer.Steps;
+using Umbraco.New.Cms.Web.Common.Installer;
+
+namespace Umbraco.Cms.ManagementApi.DependencyInjection;
+
+public static class InstallerBuilderExtensions
+{
+ internal static IUmbracoBuilder AddNewInstaller(this IUmbracoBuilder builder)
+ {
+ IServiceCollection services = builder.Services;
+
+ builder.WithCollectionBuilder()
+ .Add();
+
+ services.AddTransient();
+ services.AddTransient();
+ services.AddTransient();
+
+ builder.AddInstallSteps();
+ services.AddTransient();
+
+ return builder;
+ }
+
+ internal static IUmbracoBuilder AddUpgrader(this IUmbracoBuilder builder)
+ {
+ IServiceCollection services = builder.Services;
+
+ services.AddTransient();
+ builder.AddUpgradeSteps();
+ services.AddTransient();
+
+ return builder;
+ }
+
+ internal static IUmbracoBuilder AddInstallSteps(this IUmbracoBuilder builder)
+ {
+ builder.InstallSteps()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append();
+
+ return builder;
+ }
+
+ public static NewInstallStepCollectionBuilder InstallSteps(this IUmbracoBuilder builder)
+ => builder.WithCollectionBuilder();
+
+ internal static IUmbracoBuilder AddUpgradeSteps(this IUmbracoBuilder builder)
+ {
+ builder.UpgradeSteps()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append();
+
+ return builder;
+ }
+
+ public static UpgradeStepCollectionBuilder UpgradeSteps(this IUmbracoBuilder builder)
+ => builder.WithCollectionBuilder();
+}
diff --git a/src/Umbraco.Cms.ManagementApi/Filters/RequireRuntimeLevelAttribute.cs b/src/Umbraco.Cms.ManagementApi/Filters/RequireRuntimeLevelAttribute.cs
new file mode 100644
index 0000000000..0c6dfd8e93
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/Filters/RequireRuntimeLevelAttribute.cs
@@ -0,0 +1,36 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Cms.Core;
+using Umbraco.Cms.Core.Services;
+
+namespace Umbraco.Cms.ManagementApi.Filters;
+
+public class RequireRuntimeLevelAttribute : ActionFilterAttribute
+{
+ private readonly RuntimeLevel _requiredRuntimeLevel;
+
+ public RequireRuntimeLevelAttribute(RuntimeLevel requiredRuntimeLevel) =>
+ _requiredRuntimeLevel = requiredRuntimeLevel;
+
+ public override void OnActionExecuting(ActionExecutingContext context)
+ {
+ IRuntimeState runtimeState = context.HttpContext.RequestServices.GetRequiredService();
+ if (runtimeState.Level == _requiredRuntimeLevel)
+ {
+ return;
+ }
+
+ // We're not in the expected runtime level, so we need to short circuit
+ var problemDetails = new ProblemDetails
+ {
+ Title = "Invalid runtime level",
+ Detail = $"Runtime level {_requiredRuntimeLevel} is required",
+ Status = StatusCodes.Status428PreconditionRequired,
+ Type = "Error",
+ };
+
+ context.Result = new ObjectResult(problemDetails) { StatusCode = StatusCodes.Status428PreconditionRequired };
+ }
+}
diff --git a/src/Umbraco.Cms.ManagementApi/ManagementApiComposer.cs b/src/Umbraco.Cms.ManagementApi/ManagementApiComposer.cs
new file mode 100644
index 0000000000..1f57d99e4a
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ManagementApiComposer.cs
@@ -0,0 +1,133 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Diagnostics;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Versioning;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using NSwag.AspNetCore;
+using Umbraco.Cms.Core;
+using Umbraco.Cms.Core.Composing;
+using Umbraco.Cms.Core.Configuration.Models;
+using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.Hosting;
+using Umbraco.Cms.ManagementApi.DependencyInjection;
+using Umbraco.Cms.Web.Common.ApplicationBuilder;
+using Umbraco.Extensions;
+using Umbraco.New.Cms.Web.Common.Routing;
+
+namespace Umbraco.Cms.ManagementApi;
+
+public class ManagementApiComposer : IComposer
+{
+ private const string ApiTitle = "Umbraco Backoffice API";
+ private const string ApiAllName = "All";
+
+ private ApiVersion DefaultApiVersion => new(1, 0);
+
+ public void Compose(IUmbracoBuilder builder)
+ {
+ IServiceCollection services = builder.Services;
+
+ builder
+ .AddNewInstaller()
+ .AddUpgrader();
+
+ services.AddApiVersioning(options =>
+ {
+ options.DefaultApiVersion = DefaultApiVersion;
+ options.ReportApiVersions = true;
+ options.ApiVersionReader = new UrlSegmentApiVersionReader();
+ options.AssumeDefaultVersionWhenUnspecified = true;
+ options.UseApiBehavior = false;
+ });
+
+ services.AddOpenApiDocument(options =>
+ {
+ options.Title = ApiTitle;
+ options.Version = ApiAllName;
+ options.DocumentName = ApiAllName;
+ options.Description = "This shows all APIs available in this version of Umbraco - Including all the legacy apis that is available for backward compatibility";
+ });
+
+ services.AddVersionedApiExplorer(options =>
+ {
+ options.DefaultApiVersion = DefaultApiVersion;
+ options.GroupNameFormat = "'v'VVV";
+ options.SubstituteApiVersionInUrl = true;
+ options.AddApiVersionParametersWhenVersionNeutral = true;
+ options.AssumeDefaultVersionWhenUnspecified = true;
+ });
+
+ // Not super happy with this, but we need to know the UmbracoPath when registering the controller
+ // To be able to replace the route template token
+ // TODO this is fixed in Bjarkes PR for v10, and will need to be removed in v11 merge
+ GlobalSettings? globalSettings =
+ builder.Config.GetSection(Constants.Configuration.ConfigGlobal).Get();
+ var backofficePath = (globalSettings?.UmbracoPath ?? new GlobalSettings().UmbracoPath).TrimStart(Constants.CharArrays.TildeForwardSlash);
+
+ services.AddControllers(options =>
+ {
+ options.Conventions.Add(new UmbracoBackofficeToken(Constants.Web.AttributeRouting.BackOfficeToken, backofficePath));
+ });
+
+ builder.Services.Configure(options =>
+ {
+ options.AddFilter(new UmbracoPipelineFilter(
+ "BackofficeSwagger",
+ applicationBuilder =>
+ {
+ applicationBuilder.UseExceptionHandler(exceptionBuilder => exceptionBuilder.Run(async context =>
+ {
+ Exception? exception = context.Features.Get()?.Error;
+ if (exception is null)
+ {
+ return;
+ }
+
+ var response = new ProblemDetails
+ {
+ Title = exception.Message,
+ Detail = exception.StackTrace,
+ Status = StatusCodes.Status500InternalServerError,
+ Instance = exception.GetType().Name,
+ Type = "Error",
+ };
+ await context.Response.WriteAsJsonAsync(response);
+ }));
+ },
+ applicationBuilder =>
+ {
+ IServiceProvider provider = applicationBuilder.ApplicationServices;
+ GlobalSettings? settings = provider.GetRequiredService>().Value;
+ IHostingEnvironment hostingEnvironment = provider.GetRequiredService();
+ var officePath = settings.GetBackOfficePath(hostingEnvironment);
+
+ // serve documents (same as app.UseSwagger())
+ applicationBuilder.UseOpenApi(config =>
+ {
+ config.Path = $"{officePath}/swagger/{{documentName}}/swagger.json";
+ });
+
+ // Serve Swagger UI
+ applicationBuilder.UseSwaggerUi3(config =>
+ {
+ config.Path = officePath + "/swagger";
+ config.SwaggerRoutes.Clear();
+ var swaggerPath = $"{officePath}/swagger/{ApiAllName}/swagger.json";
+ config.SwaggerRoutes.Add(new SwaggerUi3Route(ApiAllName, swaggerPath));
+ });
+ },
+ applicationBuilder =>
+ {
+ applicationBuilder.UseEndpoints(endpoints =>
+ {
+ // Maps attribute routed controllers.
+ endpoints.MapControllers();
+ });
+ }
+ ));
+ });
+ }
+}
diff --git a/src/Umbraco.Cms.ManagementApi/Mapping/Installer/InstallerViewModelsMapDefinition.cs b/src/Umbraco.Cms.ManagementApi/Mapping/Installer/InstallerViewModelsMapDefinition.cs
new file mode 100644
index 0000000000..88c50a8715
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/Mapping/Installer/InstallerViewModelsMapDefinition.cs
@@ -0,0 +1,144 @@
+using Umbraco.Cms.Core.Install.Models;
+using Umbraco.Cms.Core.Mapping;
+using Umbraco.Cms.Infrastructure.Persistence;
+using Umbraco.Cms.ManagementApi.ViewModels.Installer;
+using Umbraco.New.Cms.Core.Models.Installer;
+
+namespace Umbraco.Cms.ManagementApi.Mapping.Installer;
+
+public class InstallerViewModelsMapDefinition : IMapDefinition
+{
+ public void DefineMaps(IUmbracoMapper mapper)
+ {
+ mapper.Define((source, context) => new InstallData(), Map);
+ mapper.Define((source, context) => new UserInstallData(), Map);
+ mapper.Define((source, context) => new DatabaseInstallData(), Map);
+ mapper.Define((source, context) => new DatabaseModel(), Map);
+ mapper.Define((source, context) => new DatabaseModel(), Map);
+ mapper.Define((source, context) => new InstallSettingsViewModel(), Map);
+ mapper.Define((source, context) => new UserSettingsViewModel(), Map);
+ mapper.Define((source, context) => new DatabaseSettingsModel(), Map);
+ mapper.Define((source, context) => new DatabaseSettingsViewModel(), Map);
+ mapper.Define((source, context) => new ConsentLevelViewModel(), Map);
+ mapper.Define((source, context) => new UpgradeSettingsViewModel(), Map);
+ }
+
+ // Umbraco.Code.MapAll
+ private void Map(UpgradeSettingsModel source, UpgradeSettingsViewModel target, MapperContext context)
+ {
+ target.CurrentState = source.CurrentState;
+ target.NewState = source.NewState;
+ target.NewVersion = source.NewVersion.ToString();
+ target.OldVersion = source.OldVersion.ToString();
+ }
+
+ // Umbraco.Code.MapAll
+ private void Map(DatabaseInstallViewModel source, DatabaseModel target, MapperContext context)
+ {
+ target.ConnectionString = source.ConnectionString;
+ target.DatabaseName = source.Name ?? string.Empty;
+ target.DatabaseProviderMetadataId = source.Id;
+ target.IntegratedAuth = source.UseIntegratedAuthentication;
+ target.Login = source.Username;
+ target.Password = source.Password;
+ target.ProviderName = source.ProviderName;
+ target.Server = source.Server!;
+ }
+
+ // Umbraco.Code.MapAll
+ private static void Map(InstallViewModel source, InstallData target, MapperContext context)
+ {
+ target.TelemetryLevel = source.TelemetryLevel;
+ target.User = context.Map(source.User)!;
+ target.Database = context.Map(source.Database)!;
+ }
+
+ // Umbraco.Code.MapAll
+ private static void Map(UserInstallViewModel source, UserInstallData target, MapperContext context)
+ {
+ target.Email = source.Email;
+ target.Name = source.Name;
+ target.Password = source.Password;
+ target.SubscribeToNewsletter = source.SubscribeToNewsletter;
+ }
+
+ // Umbraco.Code.MapAll
+ private static void Map(DatabaseInstallViewModel source, DatabaseInstallData target, MapperContext context)
+ {
+ target.Id = source.Id;
+ target.ProviderName = source.ProviderName;
+ target.Server = source.Server;
+ target.Name = source.Name;
+ target.Username = source.Username;
+ target.Password = source.Password;
+ target.UseIntegratedAuthentication = source.UseIntegratedAuthentication;
+ target.ConnectionString = source.ConnectionString;
+ }
+
+ // Umbraco.Code.MapAll
+ private static void Map(DatabaseInstallData source, DatabaseModel target, MapperContext context)
+ {
+ target.ConnectionString = source.ConnectionString;
+ target.DatabaseName = source.Name ?? string.Empty;
+ target.DatabaseProviderMetadataId = source.Id;
+ target.IntegratedAuth = source.UseIntegratedAuthentication;
+ target.Login = source.Username;
+ target.Password = source.Password;
+ target.ProviderName = source.ProviderName;
+ target.Server = source.Server!;
+ }
+
+ // Umbraco.Code.MapAll
+ private static void Map(InstallSettingsModel source, InstallSettingsViewModel target, MapperContext context)
+ {
+ target.User = context.Map(source.UserSettings)!;
+ target.Databases = context.MapEnumerable(source.DatabaseSettings);
+ }
+
+ // Umbraco.Code.MapAll
+ private static void Map(UserSettingsModel source, UserSettingsViewModel target, MapperContext context)
+ {
+ target.MinCharLength = source.PasswordSettings.MinCharLength;
+ target.MinNonAlphaNumericLength = source.PasswordSettings.MinNonAlphaNumericLength;
+ target.ConsentLevels = context.MapEnumerable(source.ConsentLevels);
+ }
+
+ // Umbraco.Code.MapAll
+ private static void Map(IDatabaseProviderMetadata source, DatabaseSettingsModel target, MapperContext context)
+ {
+ target.DefaultDatabaseName = source.DefaultDatabaseName;
+ target.DisplayName = source.DisplayName;
+ target.Id = source.Id;
+ target.ProviderName = source.ProviderName ?? string.Empty;
+ target.RequiresConnectionTest = source.RequiresConnectionTest;
+ target.RequiresCredentials = source.RequiresCredentials;
+ target.RequiresServer = source.RequiresServer;
+ target.ServerPlaceholder = source.ServerPlaceholder ?? string.Empty;
+ target.SortOrder = source.SortOrder;
+ target.SupportsIntegratedAuthentication = source.SupportsIntegratedAuthentication;
+ target.IsConfigured = false; // Defaults to false, we'll set this to true if needed,
+ }
+
+ // Umbraco.Code.MapAll
+ private static void Map(DatabaseSettingsModel source, DatabaseSettingsViewModel target, MapperContext context)
+ {
+ target.DefaultDatabaseName = source.DefaultDatabaseName;
+ target.DisplayName = source.DisplayName;
+ target.Id = source.Id;
+ target.IsConfigured = source.IsConfigured;
+ target.ProviderName = source.ProviderName;
+ target.RequiresConnectionTest = source.RequiresConnectionTest;
+ target.RequiresCredentials = source.RequiresCredentials;
+ target.RequiresServer = source.RequiresServer;
+ target.ServerPlaceholder = source.ServerPlaceholder;
+ target.SortOrder = source.SortOrder;
+ target.SupportsIntegratedAuthentication = source.SupportsIntegratedAuthentication;
+ }
+
+ // Umbraco.Code.MapAll
+ private static void Map(ConsentLevelModel source, ConsentLevelViewModel target, MapperContext context)
+ {
+ target.Description = source.Description;
+ target.Level = source.Level;
+ }
+}
diff --git a/src/Umbraco.Cms.ManagementApi/Umbraco.Cms.ManagementApi.csproj b/src/Umbraco.Cms.ManagementApi/Umbraco.Cms.ManagementApi.csproj
new file mode 100644
index 0000000000..b2ed549a52
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/Umbraco.Cms.ManagementApi.csproj
@@ -0,0 +1,29 @@
+
+
+
+ net7.0
+ enable
+ enable
+ nullable
+ Umbraco.Cms.ManagementApi
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+
+
+
diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/ConsentLevelViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/ConsentLevelViewModel.cs
new file mode 100644
index 0000000000..2774f5ba2e
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/ConsentLevelViewModel.cs
@@ -0,0 +1,16 @@
+using System.Runtime.Serialization;
+using System.Text.Json.Serialization;
+using Umbraco.Cms.Core.Models;
+
+namespace Umbraco.Cms.ManagementApi.ViewModels.Installer;
+
+[DataContract(Name = "consentLevels")]
+public class ConsentLevelViewModel
+{
+ [DataMember(Name = "level")]
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public TelemetryLevel Level { get; set; }
+
+ [DataMember(Name = "description")]
+ public string Description { get; set; } = string.Empty;
+}
diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/DatabaseInstallViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/DatabaseInstallViewModel.cs
new file mode 100644
index 0000000000..1bc2f4c3e9
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/DatabaseInstallViewModel.cs
@@ -0,0 +1,36 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using System.Runtime.Serialization;
+
+namespace Umbraco.Cms.ManagementApi.ViewModels.Installer;
+
+[DataContract(Name = "databaseInstall")]
+public class DatabaseInstallViewModel
+{
+ [DataMember(Name = "id")]
+ [Required]
+ public Guid Id { get; init; }
+
+ [DataMember(Name = "providerName")]
+ [Required]
+ public string? ProviderName { get; init; }
+
+ [DataMember(Name = "server")]
+ public string? Server { get; init; }
+
+ [DataMember(Name = "name")]
+ public string? Name { get; init; }
+
+ [DataMember(Name = "username")]
+ public string? Username { get; init; }
+
+ [DataMember(Name = "password")]
+ [PasswordPropertyText]
+ public string? Password { get; init; }
+
+ [DataMember(Name = "useIntegratedAuthentication")]
+ public bool UseIntegratedAuthentication { get; init; }
+
+ [DataMember(Name = "connectionString")]
+ public string? ConnectionString { get; init; }
+}
diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/DatabaseSettingsViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/DatabaseSettingsViewModel.cs
new file mode 100644
index 0000000000..0d2c45f105
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/DatabaseSettingsViewModel.cs
@@ -0,0 +1,40 @@
+using System.Runtime.Serialization;
+
+namespace Umbraco.Cms.ManagementApi.ViewModels.Installer;
+
+[DataContract(Name = "databaseSettings")]
+public class DatabaseSettingsViewModel
+{
+ [DataMember(Name = "id")]
+ public Guid Id { get; set; }
+
+ [DataMember(Name = "sortOrder")]
+ public int SortOrder { get; set; }
+
+ [DataMember(Name = "displayName")]
+ public string DisplayName { get; set; } = string.Empty;
+
+ [DataMember(Name = "defaultDatabaseName")]
+ public string DefaultDatabaseName { get; set; } = string.Empty;
+
+ [DataMember(Name = "providerName")]
+ public string ProviderName { get; set; } = string.Empty;
+
+ [DataMember(Name = "isConfigured")]
+ public bool IsConfigured { get; set; }
+
+ [DataMember(Name = "requiresServer")]
+ public bool RequiresServer { get; set; }
+
+ [DataMember(Name = "serverPlaceholder")]
+ public string ServerPlaceholder { get; set; } = string.Empty;
+
+ [DataMember(Name = "requiresCredentials")]
+ public bool RequiresCredentials { get; set; }
+
+ [DataMember(Name = "supportsIntegratedAuthentication")]
+ public bool SupportsIntegratedAuthentication { get; set; }
+
+ [DataMember(Name = "requiresConnectionTest")]
+ public bool RequiresConnectionTest { get; set; }
+}
diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/InstallSettingsViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/InstallSettingsViewModel.cs
new file mode 100644
index 0000000000..156aa73e3e
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/InstallSettingsViewModel.cs
@@ -0,0 +1,13 @@
+using System.Runtime.Serialization;
+
+namespace Umbraco.Cms.ManagementApi.ViewModels.Installer;
+
+[DataContract(Name = "installSettings")]
+public class InstallSettingsViewModel
+{
+ [DataMember(Name = "user")]
+ public UserSettingsViewModel User { get; set; } = null!;
+
+ [DataMember(Name = "databases")]
+ public IEnumerable Databases { get; set; } = Enumerable.Empty();
+}
diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/InstallViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/InstallViewModel.cs
new file mode 100644
index 0000000000..ed815a521d
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/InstallViewModel.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.DataAnnotations;
+using System.Runtime.Serialization;
+using System.Text.Json.Serialization;
+using Umbraco.Cms.Core.Models;
+
+namespace Umbraco.Cms.ManagementApi.ViewModels.Installer;
+
+public class InstallViewModel
+{
+ [DataMember(Name = "user")]
+ [Required]
+ public UserInstallViewModel User { get; init; } = null!;
+
+ [DataMember(Name = "database")]
+ [Required]
+ public DatabaseInstallViewModel Database { get; init; } = null!;
+
+ [DataMember(Name = "telemetryLevel")]
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public TelemetryLevel TelemetryLevel { get; init; } = TelemetryLevel.Basic;
+}
diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/UpgradeSettingsViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/UpgradeSettingsViewModel.cs
new file mode 100644
index 0000000000..8274246070
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/UpgradeSettingsViewModel.cs
@@ -0,0 +1,23 @@
+using System.Runtime.Serialization;
+
+namespace Umbraco.Cms.ManagementApi.ViewModels.Installer;
+
+[DataContract(Name = "upgradeSettingsViewModel")]
+public class UpgradeSettingsViewModel
+{
+ [DataMember(Name = "currentState")]
+ public string CurrentState { get; set; } = string.Empty;
+
+ [DataMember(Name = "newState")]
+ public string NewState { get; set; } = string.Empty;
+
+ [DataMember(Name = "newVersion")]
+ public string NewVersion { get; set; } = string.Empty;
+
+ [DataMember(Name = "oldVersion")]
+ public string OldVersion { get; set; } = string.Empty;
+
+ [DataMember(Name = "reportUrl")]
+ public string ReportUrl =>
+ $"https://our.umbraco.com/contribute/releases/compare?from={OldVersion}&to={NewVersion}¬es=1";
+}
diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/UserInstallViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/UserInstallViewModel.cs
new file mode 100644
index 0000000000..dbdb859f63
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/UserInstallViewModel.cs
@@ -0,0 +1,26 @@
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using System.Runtime.Serialization;
+
+namespace Umbraco.Cms.ManagementApi.ViewModels.Installer;
+
+public class UserInstallViewModel
+{
+ [DataMember(Name = "name")]
+ [Required]
+ [StringLength(255)]
+ public string Name { get; init; } = null!;
+
+ [DataMember(Name = "email")]
+ [Required]
+ [EmailAddress]
+ public string Email { get; init; } = null!;
+
+ [DataMember(Name = "password")]
+ [Required]
+ [PasswordPropertyText]
+ public string Password { get; init; } = null!;
+
+ [DataMember(Name = "subscribeToNewsletter")]
+ public bool SubscribeToNewsletter { get; init; }
+}
diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/UserSettingsViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/UserSettingsViewModel.cs
new file mode 100644
index 0000000000..b2be9e88c9
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Installer/UserSettingsViewModel.cs
@@ -0,0 +1,16 @@
+using System.Runtime.Serialization;
+
+namespace Umbraco.Cms.ManagementApi.ViewModels.Installer;
+
+[DataContract(Name = "user")]
+public class UserSettingsViewModel
+{
+ [DataMember(Name = "minCharLength")]
+ public int MinCharLength { get; set; }
+
+ [DataMember(Name = "minNonAlphaNumericLength")]
+ public int MinNonAlphaNumericLength { get; set; }
+
+ [DataMember(Name = "consentLevels")]
+ public IEnumerable ConsentLevels { get; set; } = Enumerable.Empty();
+}
diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Pagination/PagedViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Pagination/PagedViewModel.cs
new file mode 100644
index 0000000000..7d9760bda4
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Pagination/PagedViewModel.cs
@@ -0,0 +1,8 @@
+namespace Umbraco.Cms.ManagementApi.ViewModels.Pagination;
+
+public class PagedViewModel
+{
+ public long Total { get; set; }
+
+ public IEnumerable Items { get; set; } = Enumerable.Empty();
+}
diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Server/ServerStatusViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Server/ServerStatusViewModel.cs
new file mode 100644
index 0000000000..48cfed65c4
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Server/ServerStatusViewModel.cs
@@ -0,0 +1,10 @@
+using System.Text.Json.Serialization;
+using Umbraco.Cms.Core;
+
+namespace Umbraco.Cms.ManagementApi.ViewModels.Server;
+
+public class ServerStatusViewModel
+{
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public RuntimeLevel ServerStatus { get; set; }
+}
diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Server/VersionViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Server/VersionViewModel.cs
new file mode 100644
index 0000000000..41a55e64b7
--- /dev/null
+++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Server/VersionViewModel.cs
@@ -0,0 +1,6 @@
+namespace Umbraco.Cms.ManagementApi.ViewModels.Server;
+
+public class VersionViewModel
+{
+ public string Version { get; set; } = null!;
+}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs
index 0dbc62fb49..112d556712 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs
@@ -53,6 +53,11 @@ public class SqlAzureDatabaseProviderMetadata : IDatabaseProviderMetadata
///
public string GenerateConnectionString(DatabaseModel databaseModel)
{
+ if (databaseModel.Server is null)
+ {
+ throw new ArgumentNullException(nameof(databaseModel.Server));
+ }
+
var server = databaseModel.Server;
var databaseName = databaseModel.DatabaseName;
var user = databaseModel.Login;
@@ -89,7 +94,7 @@ public class SqlAzureDatabaseProviderMetadata : IDatabaseProviderMetadata
server = $"{server},1433";
}
- if (user.Contains("@") == false)
+ if (user?.Contains("@") == false)
{
var userDomain = server;
diff --git a/src/Umbraco.Cms/Umbraco.Cms.csproj b/src/Umbraco.Cms/Umbraco.Cms.csproj
index 815be058eb..ce43dc67fc 100644
--- a/src/Umbraco.Cms/Umbraco.Cms.csproj
+++ b/src/Umbraco.Cms/Umbraco.Cms.csproj
@@ -16,6 +16,10 @@
+
+
+
+
$(ProjectDir)appsettings-schema.json$(ProjectDir)../JsonSchema/
diff --git a/src/Umbraco.Core/Collections/DeepCloneableList.cs b/src/Umbraco.Core/Collections/DeepCloneableList.cs
index 301795281c..4f22ac094e 100644
--- a/src/Umbraco.Core/Collections/DeepCloneableList.cs
+++ b/src/Umbraco.Core/Collections/DeepCloneableList.cs
@@ -41,17 +41,7 @@ public class DeepCloneableList : List, IDeepCloneable, IRememberBeingDirty
// we are cloning once, so create a new list in none mode
// and deep clone all items into it
var newList = new DeepCloneableList(ListCloneBehavior.None);
- foreach (T item in this)
- {
- if (item is IDeepCloneable dc)
- {
- newList.Add((T)dc.DeepClone());
- }
- else
- {
- newList.Add(item);
- }
- }
+ DeepCloneHelper.CloneListItems, T>(this, newList);
return newList;
case ListCloneBehavior.None:
@@ -60,17 +50,7 @@ public class DeepCloneableList : List, IDeepCloneable, IRememberBeingDirty
case ListCloneBehavior.Always:
// always clone to new list
var newList2 = new DeepCloneableList(ListCloneBehavior.Always);
- foreach (T item in this)
- {
- if (item is IDeepCloneable dc)
- {
- newList2.Add((T)dc.DeepClone());
- }
- else
- {
- newList2.Add(item);
- }
- }
+ DeepCloneHelper.CloneListItems, T>(this, newList2);
return newList2;
default:
diff --git a/src/Umbraco.Core/Collections/EventClearingObservableCollection.cs b/src/Umbraco.Core/Collections/EventClearingObservableCollection.cs
index 579716456b..baf131ca80 100644
--- a/src/Umbraco.Core/Collections/EventClearingObservableCollection.cs
+++ b/src/Umbraco.Core/Collections/EventClearingObservableCollection.cs
@@ -1,5 +1,6 @@
using System.Collections.ObjectModel;
using System.Collections.Specialized;
+using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Core.Collections;
@@ -7,7 +8,7 @@ namespace Umbraco.Cms.Core.Collections;
/// Allows clearing all event handlers
///
///
-public class EventClearingObservableCollection : ObservableCollection, INotifyCollectionChanged
+public class EventClearingObservableCollection : ObservableCollection, INotifyCollectionChanged, IDeepCloneable
{
// need to explicitly implement with event accessor syntax in order to override in order to to clear
// c# events are weird, they do not behave the same way as other c# things that are 'virtual',
@@ -39,4 +40,12 @@ public class EventClearingObservableCollection : ObservableCollection event
///
public void ClearCollectionChangedEvents() => _changed = null;
+
+ public object DeepClone()
+ {
+ var clone = new EventClearingObservableCollection();
+ DeepCloneHelper.CloneListItems, TValue>(this, clone);
+
+ return clone;
+ }
}
diff --git a/src/Umbraco.Core/Configuration/Models/ContentSettings.cs b/src/Umbraco.Core/Configuration/Models/ContentSettings.cs
index f0532a7203..f4f3040b79 100644
--- a/src/Umbraco.Core/Configuration/Models/ContentSettings.cs
+++ b/src/Umbraco.Core/Configuration/Models/ContentSettings.cs
@@ -157,6 +157,7 @@ public class ContentSettings
internal const bool StaticHideBackOfficeLogo = false;
internal const bool StaticDisableDeleteWhenReferenced = false;
internal const bool StaticDisableUnpublishWhenReferenced = false;
+ internal const bool StaticAllowEditInvariantFromNonDefault = false;
///
/// Gets or sets a value for the content notification settings.
@@ -242,4 +243,10 @@ public class ContentSettings
/// Get or sets the model representing the global content version cleanup policy
///
public ContentVersionCleanupPolicySettings ContentVersionCleanupPolicy { get; set; } = new();
+
+ ///
+ /// Gets or sets a value indicating whether to allow editing invariant properties from a non-default language variation.
+ ///
+ [DefaultValue(StaticAllowEditInvariantFromNonDefault)]
+ public bool AllowEditInvariantFromNonDefault { get; set; } = StaticAllowEditInvariantFromNonDefault;
}
diff --git a/src/Umbraco.Core/Configuration/Models/SecuritySettings.cs b/src/Umbraco.Core/Configuration/Models/SecuritySettings.cs
index 586b3955c2..708f9b98c2 100644
--- a/src/Umbraco.Core/Configuration/Models/SecuritySettings.cs
+++ b/src/Umbraco.Core/Configuration/Models/SecuritySettings.cs
@@ -86,9 +86,10 @@ public class SecuritySettings
[DefaultValue(StaticUserBypassTwoFactorForExternalLogins)]
public bool UserBypassTwoFactorForExternalLogins { get; set; } = StaticUserBypassTwoFactorForExternalLogins;
- ///
- /// Gets or sets a value indicating whether to allow editing invariant properties from a non-default language variation.
- ///
- [DefaultValue(StaticAllowEditInvariantFromNonDefault)]
- public bool AllowEditInvariantFromNonDefault { get; set; } = StaticAllowEditInvariantFromNonDefault;
+ ///
+ /// Gets or sets a value indicating whether to allow editing invariant properties from a non-default language variation.
+ ///
+ [Obsolete("Use ContentSettings.AllowEditFromInvariant instead")]
+ [DefaultValue(StaticAllowEditInvariantFromNonDefault)]
+ public bool AllowEditInvariantFromNonDefault { get; set; } = StaticAllowEditInvariantFromNonDefault;
}
diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs
index bfbe4e56d5..bbeae780d8 100644
--- a/src/Umbraco.Core/Constants-Web.cs
+++ b/src/Umbraco.Core/Constants-Web.cs
@@ -63,6 +63,11 @@ public static partial class Constants
public const string AreaToken = "area";
}
+ public static class AttributeRouting
+ {
+ public const string BackOfficeToken = "umbracoBackOffice";
+ }
+
public static class EmailTypes
{
public const string HealthCheck = "HealthCheck";
diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs
index 4c7d6490e0..31ef06c400 100644
--- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs
+++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration;
@@ -102,6 +103,20 @@ public static partial class UmbracoBuilderExtensions
Constants.Configuration.NamedOptions.InstallDefaultData.MemberTypes,
builder.Config.GetSection($"{Constants.Configuration.ConfigInstallDefaultData}:{Constants.Configuration.NamedOptions.InstallDefaultData.MemberTypes}"));
+ // TODO: Remove this in V12
+ // This is to make the move of the AllowEditInvariantFromNonDefault setting from SecuritySettings to ContentSettings backwards compatible
+ // If there is a value in security settings, but no value in content setting we'll use that value, otherwise content settings always wins.
+ builder.Services.Configure(settings =>
+ {
+ var securitySettingsValue = builder.Config.GetSection($"{Constants.Configuration.ConfigSecurity}").GetValue(nameof(SecuritySettings.AllowEditInvariantFromNonDefault));
+ var contentSettingsValue = builder.Config.GetSection($"{Constants.Configuration.ConfigContent}").GetValue(nameof(ContentSettings.AllowEditInvariantFromNonDefault));
+
+ if (securitySettingsValue is not null && contentSettingsValue is null)
+ {
+ settings.AllowEditInvariantFromNonDefault = securitySettingsValue.Value;
+ }
+ });
+
return builder;
}
}
diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
index 9d314526a9..d806950584 100644
--- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
+++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
@@ -323,7 +323,7 @@ namespace Umbraco.Cms.Core.DependencyInjection
Services.AddUnique();
Services.AddUnique();
- Services.AddUnique();
+ Services.AddUnique(provider => new CultureImpactFactory(provider.GetRequiredService>()));
}
}
}
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/cs.xml b/src/Umbraco.Core/EmbeddedResources/Lang/cs.xml
index 939b515eeb..29b242d67e 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/cs.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/cs.xml
@@ -781,8 +781,8 @@
Stiskněte Následující pro pokračování. ]]>následující, pro pokračování konfiguračního průvodce]]>Heslo výchozího uživatele musí být změněno!]]>
- Výchozí uživatel byl deaktivován, nebo nemá přístup k umbracu!
Netřeba nic dalšího dělat. Klikněte na Následující pro pokračování.]]>
- Heslo výchozího uživatele bylo úspěšně změněno od doby instalace!
Netřeba nic dalšího dělat. Klikněte na Následující pro pokračování.]]>
+ Výchozí uživatel byl deaktivován, nebo nemá přístup k umbracu!
Netřeba nic dalšího dělat. Klikněte na Následující pro pokračování.]]>
+ Heslo výchozího uživatele bylo úspěšně změněno od doby instalace!
Netřeba nic dalšího dělat. Klikněte na Následující pro pokračování.]]>
Heslo je změněno!Mějte skvělý start, sledujte naše uváděcí videaNení nainstalováno.
@@ -797,7 +797,7 @@
Vaše nastavení oprávnění může být problém!
Můžete provozovat Umbraco bez potíží, ale nebudete smět vytvářet složky a instalovat balíčky, které jsou doporučené pro plné využívání všech možností umbraca.]]>
- Vaše nastavení oprívnění není připraveno pro umbraco!
+ Vaše nastavení oprívnění není připraveno pro Umbraco!
Abyste mohli Umbraco provozovat, budete muset aktualizovat Vaše nastavení oprávnění.]]>Vaše nastavení oprávnění je dokonalé!
@@ -838,7 +838,7 @@
Krok 3/5: Ověřování oprávnění k souborůmKrok 4/5: Kontrola zabezpečení umbracaKrok 5/5: Umbraco je připraveno a můžete začít
- Děkujeme, že jeste si vybrali umbraco
+ Děkujeme, že jeste si vybrali UmbracoProhlédněte si svůj nový web
Nainstalovali jste Runway, tak proč se nepodívat, jak Váš nový web vypadá.]]>Další pomoc a informace
@@ -1379,7 +1379,7 @@
Makro je konfigurovatelná součást, která je skvělá pro opakovaně použitelné části návrhu, kde potřebujete předat parametry, jako jsou galerie, formuláře a seznamy.
- Vložit pole stránky umbraco
+ Vložit pole stránky UmbracoZobrazuje hodnotu pojmenovaného pole z aktuální stránky s možnostmi upravit hodnotu nebo alternativní hodnoty.Částečná šablona
@@ -2132,7 +2132,7 @@
Profilování výkonu
Umbraco aktuálně běží v režimu ladění. To znamená, že můžete použít vestavěný profiler výkonu k vyhodnocení výkonu při vykreslování stránek.
Pokud chcete aktivovat profiler pro konkrétní vykreslení stránky, jednoduše při požadavku na stránku jednoduše přidejte umbDebug=true do URL.
Pokud chcete, aby byl profiler ve výchozím nastavení aktivován pro všechna vykreslení stránky, můžete použít přepínač níže. Ve vašem prohlížeči nastaví soubor cookie, který automaticky aktivuje profiler. Jinými slovy, profiler bude ve výchozím nastavení aktivní pouze ve vašem prohlížeči, ne v ostatních.
+
Umbraco aktuálně běží v režimu ladění. To znamená, že můžete použít vestavěný profiler výkonu k vyhodnocení výkonu při vykreslování stránek.
Pokud chcete aktivovat profiler pro konkrétní vykreslení stránky, jednoduše při požadavku na stránku jednoduše přidejte umbDebug=true do URL.
Pokud chcete, aby byl profiler ve výchozím nastavení aktivován pro všechna vykreslení stránky, můžete použít přepínač níže. Ve vašem prohlížeči nastaví soubor cookie, který automaticky aktivuje profiler. Jinými slovy, profiler bude ve výchozím nastavení aktivní pouze ve vašem prohlížeči, ne v ostatních.
]]>
Ve výchozím stavu aktivovat profiler
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml b/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml
index d0c6a45d27..e34cc2ab29 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml
@@ -449,13 +449,13 @@
Gweinyddu enwau gwesteiaCau'r ffenestr ymaYdych chi'n sicr eich bod eisiau dileu
- %0% yn seiliedig ar %1%]]>
+ %0% yn seiliedig ar %1%]]>Ydych chi'n sicr eich bod eisiau analluogiWyt ti'n siŵr fod ti eisiau dileu
- %0%]]>
- %0%]]>
+ %0%]]>
+ %0%]]>Ydych chi'n sicr?Ydych chi'n sicr?
@@ -546,8 +546,8 @@
Dewiswch ffurfweddiadDewiswch damaidBydd hyn yn dileu'r nod a'i holl ieithoedd. Os mai dim ond un iaith yr ydych am ei dileu, ewch i'w anghyhoedd yn lle.
- %0%.]]>
- %0% o'r grŵp %1%]]>
+ %0%.]]>
+ %0% o'r grŵp %1%]]>Ydw, dileu
@@ -965,7 +965,7 @@
nesaf i barhau gyda'r dewin ffurfwedd]]>Mae angen newid cyfrinair y defnyddiwr Diofyn!]]>
- Mae'r defnyddiwr Diofyn wedi'u analluogi neu does dim hawliau i Umbraco!
Does dim angen unrhyw weithredoedd pellach. Cliciwch Nesaf i barhau.]]>
+ Mae'r defnyddiwr Diofyn wedi'u analluogi neu does dim hawliau i Umbraco!
Does dim angen unrhyw weithredoedd pellach. Cliciwch Nesaf i barhau.]]>
Mae cyfrinair y defnyddiwr Diofyn wedi'i newid yn llwyddiannus ers y gosodiad!
Does dim angen unrhyw weithredoedd pellach. Cliciwch Nesaf i barhau.]]>
Mae'r cyfrinair wedi'i newid!Cewch gychwyn gwych, gwyliwch ein fideos rhaglith
@@ -2695,12 +2695,12 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang
Mae Umbraco yn rhedeg mewn modd dadfygio. Mae hyn yn golygu y gallwch chi ddefnyddio'r proffiliwr perfformiad adeiledig i asesu'r perfformiad wrth rendro tudalennau.
- OS ti eisiau actifadu'r proffiliwr am rendro tudalen penodol, bydd angen ychwanegu umbDebug=true i'r ymholiad wrth geisio am y tudalen
+ OS ti eisiau actifadu'r proffiliwr am rendro tudalen penodol, bydd angen ychwanegu umbDebug=true i'r ymholiad wrth geisio am y tudalen
Os ydych chi am i'r proffiliwr gael ei actifadu yn ddiofyn am bob rendrad tudalen, gallwch chi ddefnyddio'r togl isod.
Bydd e'n gosod cwci yn eich porwr, sydd wedyn yn actifadu'r proffiliwr yn awtomatig.
- Mewn geiriau eraill, bydd y proffiliwr dim ond yn actif yn ddiofyn yn eich porwr chi - nid porwr pawb eraill.
+ Mewn geiriau eraill, bydd y proffiliwr dim ond yn actif yn ddiofyn yn eich porwr chi - nid porwr pawb eraill.
]]>
@@ -2709,7 +2709,7 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang
- Ni ddylech chi fyth adael i safle cynhyrchu redeg yn y modd dadfygio. Mae'r modd dadfygio yn gallu cael ei diffodd trwy ychwanegu'r gosodiad debug="false" ar yr elfen <grynhoi /> yn web.config.
+ Ni ddylech chi fyth adael i safle cynhyrchu redeg yn y modd dadfygio. Mae'r modd dadfygio yn gallu cael ei diffodd trwy ychwanegu'r gosodiad debug="false" ar yr elfen <grynhoi /> yn web.config.
]]>
@@ -2719,7 +2719,7 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang
Mae Umbraco ddim yn rhedeg mewn modd dadfygio ar hyn o bryd, felly nid allwch chi ddefnyddio'r proffiliwer adeiledig. Dyma sut y dylai fod ar gyfer safle cynhyrchu.
- Mae'r modd dadfygio yn gallu cael ei throi arno gan ychwanegu'r gosodiad debug="true" ar yr elfen <grynhoi /> yn web.config.
+ Mae'r modd dadfygio yn gallu cael ei throi arno gan ychwanegu'r gosodiad debug="true" ar yr elfen <grynhoi /> yn web.config.
]]>
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/da.xml b/src/Umbraco.Core/EmbeddedResources/Lang/da.xml
index b03fa9d884..93b0f95af2 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/da.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/da.xml
@@ -465,7 +465,7 @@
Er du sikker på at du vil sletteEr du sikker på du vil deaktivereEr du sikker på at du vil fjerne
- %0%]]>
+ %0%]]>Er du sikker på at du vil forlade Umbraco?Er du sikker?Klip
@@ -556,8 +556,8 @@
Dette vil slette noden og alle dets sprog. Hvis du kun vil slette et sprog, så
afpublicér det i stedet.
- %0%]]>
- %0% fra gruppen]]>
+ %0%]]>
+ %0% fra %1% gruppen]]>Ja, fjern
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/en.xml b/src/Umbraco.Core/EmbeddedResources/Lang/en.xml
index e6ba39eb17..0a8b03b115 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/en.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/en.xml
@@ -469,10 +469,10 @@
Manage hostnamesClose this windowAre you sure you want to delete
- %0% of %1% items]]>
+ %0% of %1% items]]>Are you sure you want to disableAre you sure you want to remove
- %0%]]>
+ %0%]]>Are you sure?Are you sure?Cut
@@ -564,8 +564,8 @@
This will delete the node and all its languages. If you only want to delete one
language, you should unpublish the node in that language instead.
- %0%.]]>
- %0% from the %1% group]]>
+ %0%.]]>
+ %0% from the %1% group]]>Yes, removeYou are deleting the layoutModifying layout will result in loss of data for any existing content that is based on this configuration.
@@ -948,7 +948,7 @@
The Default users' password needs to be changed!]]>
- The Default user has been disabled or has no access to Umbraco!
No further actions needs to be taken. Click Next to proceed.]]>
+ The Default user has been disabled or has no access to Umbraco!
No further actions needs to be taken. Click Next to proceed.]]>
The Default user's password has been successfully changed since the installation!
No further actions needs to be taken. Click Next to proceed.]]>
The password is changed!
@@ -1873,7 +1873,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
Keep all versions newer than daysKeep latest version per day for daysPrevent cleanup
- NOTE! The cleanup of historically content versions are disabled globally. These settings will not take effect before it is enabled.]]>
+ NOTE! The cleanup of historically content versions are disabled globally. These settings will not take effect before it is enabled.]]>Add language
@@ -2611,12 +2611,12 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
Umbraco currently runs in debug mode. This means you can use the built-in performance profiler to assess the performance when rendering pages.
- If you want to activate the profiler for a specific page rendering, simply add umbDebug=true to the querystring when requesting the page.
+ If you want to activate the profiler for a specific page rendering, simply add umbDebug=true to the querystring when requesting the page.
If you want the profiler to be activated by default for all page renderings, you can use the toggle below.
It will set a cookie in your browser, which then activates the profiler automatically.
- In other words, the profiler will only be active by default in your browser - not everyone else's.
+ In other words, the profiler will only be active by default in your browser - not everyone else's.
]]>
@@ -2625,7 +2625,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
- You should never let a production site run in debug mode. Debug mode is turned off by setting Umbraco:CMS:Hosting:Debug to false in appsettings.json, appsettings.{Environment}.json or via an environment variable.
+ You should never let a production site run in debug mode. Debug mode is turned off by setting Umbraco:CMS:Hosting:Debug to false in appsettings.json, appsettings.{Environment}.json or via an environment variable.
]]>
@@ -2635,7 +2635,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
Umbraco currently does not run in debug mode, so you can't use the built-in profiler. This is how it should be for a production site.
- Debug mode is turned on by setting Umbraco:CMS:Hosting:Debug to true in appsettings.json, appsettings.{Environment}.json or via an environment variable.
+ Debug mode is turned on by setting Umbraco:CMS:Hosting:Debug to true in appsettings.json, appsettings.{Environment}.json or via an environment variable.
]]>
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml b/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml
index 70aa1c2d5c..88030198a3 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml
@@ -483,10 +483,10 @@
NameClose this windowAre you sure you want to delete
- %0% of %1% items]]>
+ %0% of %1% items]]>Are you sure you want to disableAre you sure you want to remove
- %0%]]>
+ %0%]]>Are you sure?Are you sure?Cut
@@ -579,8 +579,8 @@
This will delete the node and all its languages. If you only want to delete one
language, you should unpublish the node in that language instead.
- %0%.]]>
- %0% from the %1% group]]>
+ %0%.]]>
+ %0% from the %1% group]]>Yes, removeYou are deleting the layoutModifying layout will result in loss of data for any existing content that is based on this configuration.
@@ -975,7 +975,7 @@
The Default users' password needs to be changed!]]>
- The Default user has been disabled or has no access to Umbraco!
No further actions needs to be taken. Click Next to proceed.]]>
+ The Default user has been disabled or has no access to Umbraco!
No further actions needs to be taken. Click Next to proceed.]]>
The Default user's password has been successfully changed since the installation!
No further actions needs to be taken. Click Next to proceed.]]>
The password is changed!
@@ -1947,7 +1947,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
Keep all versions newer than daysKeep latest version per day for daysPrevent cleanup
- NOTE! The cleanup of historically content versions are disabled globally. These settings will not take effect before it is enabled.]]>
+ NOTE! The cleanup of historically content versions are disabled globally. These settings will not take effect before it is enabled.]]>Changing a data type with stored values is disabled. To allow this you can change the Umbraco:CMS:DataTypes:CanBeChanged setting in appsettings.json.
@@ -1967,7 +1967,11 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
Fall back languagenone
- %0% is shared across all languages.]]>
+ %0% is shared across languages and segments.]]>
+ %0% is shared across all languages.]]>
+ %0% is shared across all segments.]]>
+ Shared: Languages
+ Shared: SegmentsAdd parameter
@@ -2713,12 +2717,12 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
Umbraco currently runs in debug mode. This means you can use the built-in performance profiler to assess the performance when rendering pages.
- If you want to activate the profiler for a specific page rendering, simply add umbDebug=true to the querystring when requesting the page.
+ If you want to activate the profiler for a specific page rendering, simply add umbDebug=true to the querystring when requesting the page.
If you want the profiler to be activated by default for all page renderings, you can use the toggle below.
It will set a cookie in your browser, which then activates the profiler automatically.
- In other words, the profiler will only be active by default in your browser - not everyone else's.
+ In other words, the profiler will only be active by default in your browser - not everyone else's.
]]>
@@ -2727,7 +2731,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
- You should never let a production site run in debug mode. Debug mode is turned off by setting Umbraco:CMS:Hosting:Debug to false in appsettings.json, appsettings.{Environment}.json or via an environment variable.
+ You should never let a production site run in debug mode. Debug mode is turned off by setting Umbraco:CMS:Hosting:Debug to false in appsettings.json, appsettings.{Environment}.json or via an environment variable.
]]>
@@ -2737,7 +2741,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
Umbraco currently does not run in debug mode, so you can't use the built-in profiler. This is how it should be for a production site.
- Debug mode is turned on by setting Umbraco:CMS:Hosting:Debug to true in appsettings.json, appsettings.{Environment}.json or via an environment variable.
+ Debug mode is turned on by setting Umbraco:CMS:Hosting:Debug to true in appsettings.json, appsettings.{Environment}.json or via an environment variable.
]]>
@@ -2906,22 +2910,22 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
Aggregate data will be shared on a regular basis as well as learnings from these metrics.
Hopefully, you will help us collect some valuable data.
- We WILL NOT collect any personal data such as content, code, user information, and all data will be fully anonymized.
+ We WILL NOT collect any personal data such as content, code, user information, and all data will be fully anonymized.
]]>
We will only send an anonymized site ID to let us know that the site exists.
- We will send an anonymized site ID, umbraco version, and packages installed
+ We will send an anonymized site ID, Umbraco version, and packages installed
-
Anonymized site ID, umbraco version, and packages installed.
+
Anonymized site ID, Umbraco version, and packages installed.
Number of: Root nodes, Content nodes, Macros, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, and Property Editors in use.
System information: Webserver, server OS, server framework, server OS language, and database provider.
Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, and if you are in debug mode.
- We might change what we send on the Detailed level in the future. If so, it will be listed above.
- By choosing "Detailed" you agree to current and future anonymized information being collected.
+ We might change what we send on the Detailed level in the future. If so, it will be listed above.
+ By choosing "Detailed" you agree to current and future anonymized information being collected.
]]>
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/es.xml b/src/Umbraco.Core/EmbeddedResources/Lang/es.xml
index 2c64f3f9a6..3e59088ef9 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/es.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/es.xml
@@ -601,7 +601,7 @@
Pincha en Próximo para continuar. ]]>próximo para continuar con el asistente de configuración]]>La contraseña del usuario por defecto debe ser cambiada]]>
- El usuario por defecto ha sido deshabilitado o ha perdido el acceso a Umbraco!
Pincha en Próximo para continuar.]]>
+ El usuario por defecto ha sido deshabilitado o ha perdido el acceso a Umbraco!
Pincha en Próximo para continuar.]]>
¡La contraseña del usuario por defecto ha sido cambiada desde que se instaló!
No hay que realizar ninguna tarea más. Pulsa Siguiente para proseguir.]]>
¡La contraseña se ha cambiado!Ten un buen comienzo, visita nuestros videos de introducción
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/fr.xml b/src/Umbraco.Core/EmbeddedResources/Lang/fr.xml
index 9013a4473f..24d5f565e5 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/fr.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/fr.xml
@@ -390,7 +390,7 @@
NomFermer cette fenêtreÊtes-vous certain(e) de vouloir supprimer
- %0% des %1% éléments]]>
+ %0% des %1% éléments]]>Êtes-vous certain(e) de vouloir désactiverÊtes-vous certain(e)?Êtes-vous certain(e)?
@@ -799,7 +799,7 @@
poursuivre. ]]>
Suivant pour poursuivre la configuration]]>Le mot de passe par défaut doit être modifié !]]>
- L'utilisateur par défaut a été désactivé ou n'a pas accès à Umbraco!
Aucune autre action n'est requise. Cliquez sur Suivant pour poursuivre.]]>
+ L'utilisateur par défaut a été désactivé ou n'a pas accès à Umbraco!
Aucune autre action n'est requise. Cliquez sur Suivant pour poursuivre.]]>
Le mot de passe par défaut a été modifié avec succès depuis l'installation!
Aucune autre action n'est requise. Cliquez sur Suivant pour poursuivre.]]>
Le mot de passe a été modifié !Pour bien commencer, regardez nos vidéos d'introduction
@@ -2177,12 +2177,12 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à
Umbraco est actuellement exécuté en mode debug. Cela signifie que vous pouvez utiliser le profileur de performances intégré pour évaluer les performance lors du rendu des pages.
- Si vous souhaitez activer le profileur pour le rendu d'une page spécifique, ajoutez simplement umbDebug=true au querystring lorsque vous demandez la page.
+ Si vous souhaitez activer le profileur pour le rendu d'une page spécifique, ajoutez simplement umbDebug=true au querystring lorsque vous demandez la page.
Si vous souhaitez que le profileur soit activé par défaut pour tous les rendus de pages, vous pouvez utiliser le bouton bascule ci-dessous.
Cela créera un cookie dans votre browser, qui activera alors le profileur automatiquement.
- En d'autres termes, le profileur ne sera activé par défaut que dans votre browser - pas celui des autres.
+ En d'autres termes, le profileur ne sera activé par défaut que dans votre browser - pas celui des autres.
]]>
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/he.xml b/src/Umbraco.Core/EmbeddedResources/Lang/he.xml
index 0996c81ba0..c52961307d 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/he.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/he.xml
@@ -366,7 +366,7 @@
proceed. ]]>
next to continue the configuration wizard]]>The Default users’ password needs to be changed!]]>
- The Default user has been disabled or has no access to Umbraco!
No further actions needs to be taken. Click Next to proceed.]]>
+ The Default user has been disabled or has no access to Umbraco!
No further actions needs to be taken. Click Next to proceed.]]>
The Default user's password has been successfully changed since the installation!
No further actions needs to be taken. Click Next to proceed.]]>
הסיסמה שונתה!התחל מכאן, צפה בסרטוני ההדרכה עבור אומברקו
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/it.xml b/src/Umbraco.Core/EmbeddedResources/Lang/it.xml
index 23bff095a3..cea82fc4e0 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/it.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/it.xml
@@ -487,8 +487,8 @@
Sei sicuro di voler eliminareSei sicuro di voler disabilitareSei sicuro di voler rimuovere
- %0%]]>
- %0%]]>
+ %0%]]>
+ %0%]]>Taglia
@@ -574,8 +574,8 @@
Seleziona snippet
- %0%.]]>
- %0% dal gruppo %1%]]>
+ %0%.]]>
+ %0% dal gruppo %1%]]>Si, rimuovi
@@ -2767,12 +2767,12 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in
Umbraco attualmente funziona in modalità debug. Ciò significa che puoi utilizzare il profiler delle prestazioni integrato per valutare le prestazioni durante il rendering delle pagine.
- Se vuoi attivare il profiler per il rendering di una pagina specifica, aggiungi semplicemente umbDebug=true alla querystring quando richiedi la pagina.
+ Se vuoi attivare il profiler per il rendering di una pagina specifica, aggiungi semplicemente umbDebug=true alla querystring quando richiedi la pagina.
Se vuoi che il profiler sia attivato per impostazione predefinita per tutti i rendering di pagina, puoi utilizzare l'interruttore qui sotto.
Verrà impostato un cookie nel tuo browser, che quindi attiverà automaticamente il profiler.
- In altre parole, il profiler sarà attivo per impostazione predefinita solo nel tuo browser, non in quello di tutti gli altri.
+ In altre parole, il profiler sarà attivo per impostazione predefinita solo nel tuo browser, non in quello di tutti gli altri.
]]>
@@ -2781,7 +2781,7 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in
- Non dovresti mai lasciare che un sito di produzione venga eseguito in modalità debug. La modalità di debug viene disattivata impostando debug="false" nell'elemento <compilation /> nel file web.config.
+ Non dovresti mai lasciare che un sito di produzione venga eseguito in modalità debug. La modalità di debug viene disattivata impostando debug="false" nell'elemento <compilation /> nel file web.config.
]]>
@@ -2791,7 +2791,7 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in
Umbraco attualmente non viene eseguito in modalità debug, quindi non è possibile utilizzare il profiler integrato. Questo è come dovrebbe essere per un sito produttivo.
- La modalità di debug viene attivata impostando debug="true" nell'elemento <compilation /> in web.config.
+ La modalità di debug viene attivata impostando debug="true" nell'elemento <compilation /> in web.config.
パスワードは変更されました!始めに、ビデオによる解説を見ましょう
@@ -555,7 +555,7 @@ Runwayをインストールして作られた新しいウェブサイトがど
Umbraco Version 3Umbraco Version 4見る
- umbraco %0% の新規インストールまたは3.0からの更新について設定方法を案内します。
+ Umbraco %0% の新規インストールまたは3.0からの更新について設定方法を案内します。
"次へ"を押してウィザードを開始します。]]>
@@ -849,9 +849,9 @@ Runwayをインストールして作られた新しいウェブサイトがど
コンテンツ領域プレースホルダーの挿入ディクショナリ アイテムを挿入マクロの挿入
- umbraco ページフィールドの挿入
+ Umbraco ページフィールドの挿入マスターテンプレート
- umbraco テンプレートタグのクイックガイド
+ Umbraco テンプレートタグのクイックガイドテンプレート
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/ko.xml b/src/Umbraco.Core/EmbeddedResources/Lang/ko.xml
index 852d8765aa..6a20975bb1 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/ko.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/ko.xml
@@ -357,7 +357,7 @@
계속 진행하시려면 다음 을 누르세요. ]]>다음을 클릭하시면 설정마법사를 계속 진행합니다.]]>기본 사용자의 암호가 변경되어야 합니다!]]>
- 기본 사용자가 비활성화되었거나 Umbraco에 접근할 수 없습니다!
더 이상 과정이 필요없으시면 다음을 눌러주세요.]]>
+ 기본 사용자가 비활성화되었거나 Umbraco에 접근할 수 없습니다!
더 이상 과정이 필요없으시면 다음을 눌러주세요.]]>
설치후 기본사용자의 암호가 성공적으로 변경되었습니다!
더 이상 과정이 필요없으시면 다음을 눌러주세요.]]>
비밀번호가 변경되었습니다!편리한 시작을 위해, 소개 Video를 시청하세요
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/nb.xml b/src/Umbraco.Core/EmbeddedResources/Lang/nb.xml
index 30d2da3e4f..87bcb3138a 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/nb.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/nb.xml
@@ -420,7 +420,7 @@
Trykk Neste for å fortsette.]]>neste for å fortsette konfigurasjonsveiviseren]]>Passordet til standardbrukeren må endres!]]>
- Standardbrukeren har blitt deaktivert eller har ingen tilgang til Umbraco!
Ingen videre handling er nødvendig. Klikk neste for å fortsette.]]>
+ Standardbrukeren har blitt deaktivert eller har ingen tilgang til Umbraco!
Ingen videre handling er nødvendig. Klikk neste for å fortsette.]]>
Passordet til standardbrukeren har blitt forandret etter installasjonen!
Ingen videre handling er nødvendig. Klikk Neste for å fortsette.]]>
Passordet er blitt endret!Få en god start med våre introduksjonsvideoer
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/nl.xml b/src/Umbraco.Core/EmbeddedResources/Lang/nl.xml
index 163fd14199..28793081b7 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/nl.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/nl.xml
@@ -439,7 +439,7 @@
Weet je zeker dat je dit wilt verwijderenWeet je zeker dat je dit wilt uitschakelenWeet u zeker dat u wilt verwijderen
- %0% wil verwijderen]]>
+ %0% wil verwijderen]]>Weet je het zeker?Weet je het zeker?Knippen
@@ -529,8 +529,8 @@
Dit zal de node en al zijn talen verwijderen. Als je slechts één taal wil
verwijderen, moet je de node in die taal depubliceren.
- %0% verwijderen.]]>
- %0% verwijderen van de %1% groep]]>
+ %0% verwijderen.]]>
+ %0% verwijderen van de %1% groep]]>Ja, verwijderen
@@ -889,7 +889,7 @@
Het wachtwoord van de default gebruiker dient veranderd te worden!]]>
- De default gebruiker is geblokkeerd of heeft geen toegang tot Umbraco!
Geen verdere actie noodzakelijk. Klik Volgende om verder te gaan.]]>
+ De default gebruiker is geblokkeerd of heeft geen toegang tot Umbraco!
Geen verdere actie noodzakelijk. Klik Volgende om verder te gaan.]]>
Het wachtwoord van de default gebruiker is sinds installatie met succes veranderd.
Geen verdere actie noodzakelijk. Klik Volgende om verder te gaan.]]>
Het wachtwoord is veranderd!
@@ -2399,12 +2399,12 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je
Umbraco wordt uitgevoerd in de foutopsporingsmodus. Dit betekent dat u de ingebouwde prestatieprofiler kunt gebruiken om de prestaties te beoordelen bij het renderen van pagina's.
- Als je de profiler voor een specifieke paginaweergave wilt activeren, voeg je umbDebug=true toe aan de querystring wanneer je de pagina opvraagt.
+ Als je de profiler voor een specifieke paginaweergave wilt activeren, voeg je umbDebug=true toe aan de querystring wanneer je de pagina opvraagt.
Als je wil dat de profiler standaard wordt geactiveerd voor alle paginaweergaven, kun je de onderstaande schakelaar gebruiken.
Het plaatst een cookie in je browser, die vervolgens de profiler automatisch activeert.
- Met andere woorden, de profiler zal alleen voor jouw browser actief zijn, niet voor andere bezoekers.
+ Met andere woorden, de profiler zal alleen voor jouw browser actief zijn, niet voor andere bezoekers.
]]>
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/pt.xml b/src/Umbraco.Core/EmbeddedResources/Lang/pt.xml
index 39d0cfc4a1..25060a4bd3 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/pt.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/pt.xml
@@ -358,7 +358,7 @@
Pressione Próximo para prosseguir.]]>próximo para continuar com o assistente de configuração]]>A senha do usuário padrão precisa ser alterada!]]>
- O usuário padrão foi desabilitado ou não tem acesso à Umbraco!
Nenhuma ação posterior precisa ser tomada. Clique Próximo para prosseguir.]]>
+ O usuário padrão foi desabilitado ou não tem acesso à Umbraco!
Nenhuma ação posterior precisa ser tomada. Clique Próximo para prosseguir.]]>
A senha do usuário padrão foi alterada com sucesso desde a instalação!
Nenhuma ação posterior é necessária. Clique Próximo para prosseguir.]]>
Senha foi alterada!Comece com o pé direito, assista nossos vídeos introdutórios
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/sv.xml b/src/Umbraco.Core/EmbeddedResources/Lang/sv.xml
index af3f157bf4..fa359fbbbc 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/sv.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/sv.xml
@@ -493,7 +493,7 @@
Tryck Nästa för att fortsätta.]]>Nästa för att fortsätta med konfigurationsguiden]]>Lösenordet på standardanvändaren måste bytas!]]>
- Standardanvändaren har avaktiverats eller har inte åtkomst till Umbraco!
Du behöver inte göra något ytterligare här. Klicka Next för att fortsätta.]]>
+ Standardanvändaren har avaktiverats eller har inte åtkomst till Umbraco!
Du behöver inte göra något ytterligare här. Klicka Next för att fortsätta.]]>
Standardanvändarens lösenord har ändrats sedan installationen!
Du behöver inte göra något ytterligare här. Klicka Nästa för att fortsätta.]]>
Lösenordet är ändrat!Få en flygande start, kolla på våra introduktionsvideor
diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/tr.xml b/src/Umbraco.Core/EmbeddedResources/Lang/tr.xml
index 3ef3db0ad6..47549f5f40 100644
--- a/src/Umbraco.Core/EmbeddedResources/Lang/tr.xml
+++ b/src/Umbraco.Core/EmbeddedResources/Lang/tr.xml
@@ -393,7 +393,7 @@
Silmek istediğinizden emin misinizDevre dışı bırakmak istediğinizden emin misinizKaldırmak istediğinizden emin misiniz
- %0% kullanımını kaldırmak istediğinizden emin misiniz?]]>
+ %0% kullanımını kaldırmak istediğinizden emin misiniz?]]>Emin misiniz?Emin misiniz?Kes
@@ -471,8 +471,8 @@
Düzenleyici seçinSnippet seçinBu, düğümü ve tüm dillerini silecektir. Yalnızca bir dili silmek istiyorsanız, bunun yerine düğümü o dilde yayından kaldırmalısınız.
- %0% kullanıcısını kaldıracaktır.]]>
- %0% kullanıcısını %1% grubundan kaldıracak]]>
+ %0% kullanıcısını kaldıracaktır.]]>
+ %0% kullanıcısını %1% grubundan kaldıracak]]>Evet, kaldır
@@ -818,7 +818,7 @@
ileri 'yi tıklayın]]> Varsayılan kullanıcıların şifresinin değiştirilmesi gerekiyor! ]]>
- Varsayılan kullanıcı devre dışı bırakıldı veya Umbraco'ya erişimi yok!
Başka işlem yapılmasına gerek yok. Devam etmek için İleri 'yi tıklayın.]]>
+ Varsayılan kullanıcı devre dışı bırakıldı veya Umbraco'ya erişimi yok!
Başka işlem yapılmasına gerek yok. Devam etmek için İleri 'yi tıklayın.]]>
Varsayılan kullanıcının şifresi kurulumdan bu yana başarıyla değiştirildi!
Başka işlem yapılmasına gerek yok. Devam etmek için İleri 'yi tıklayın.]]>
Şifre değiştirildi!Harika bir başlangıç yapın, tanıtım videolarımızı izleyin
@@ -2289,12 +2289,12 @@ Web sitenizi yönetmek için, Umbraco'nun arka ofisini açın ve içerik eklemey
Umbraco şu anda hata ayıklama modunda çalışıyor. Bu, sayfaları işlerken performansı değerlendirmek için yerleşik performans profilleyicisini kullanabileceğiniz anlamına gelir.
- Profil oluşturucuyu belirli bir sayfa oluşturma için etkinleştirmek istiyorsanız, sayfayı talep ederken sorgu dizesine umbDebug=true eklemeniz yeterlidir.
+ Profil oluşturucuyu belirli bir sayfa oluşturma için etkinleştirmek istiyorsanız, sayfayı talep ederken sorgu dizesine umbDebug=true eklemeniz yeterlidir.
Profilcinin tüm sayfa görüntülemeleri için varsayılan olarak etkinleştirilmesini istiyorsanız, aşağıdaki geçişi kullanabilirsiniz.
Tarayıcınızda, profil oluşturucuyu otomatik olarak etkinleştiren bir çerez ayarlayacaktır.
- Başka bir deyişle, profil oluşturucu yalnızca tarayıcınızda varsayılan olarak etkin olacaktır - diğer herkesin değil.
+ Başka bir deyişle, profil oluşturucu yalnızca tarayıcınızda varsayılan olarak etkin olacaktır - diğer herkesin değil.
密碼已更改作為入門者,從視頻教程開始吧!安裝失敗。
diff --git a/src/Umbraco.Core/Install/InstallException.cs b/src/Umbraco.Core/Install/InstallException.cs
index 69e28db92c..fcb878c677 100644
--- a/src/Umbraco.Core/Install/InstallException.cs
+++ b/src/Umbraco.Core/Install/InstallException.cs
@@ -1,4 +1,4 @@
-using System.Runtime.Serialization;
+using System.Runtime.Serialization;
namespace Umbraco.Cms.Core.Install;
diff --git a/src/Umbraco.Core/Install/InstallStatusTracker.cs b/src/Umbraco.Core/Install/InstallStatusTracker.cs
index 5403ded3ae..f1f92ef46c 100644
--- a/src/Umbraco.Core/Install/InstallStatusTracker.cs
+++ b/src/Umbraco.Core/Install/InstallStatusTracker.cs
@@ -1,4 +1,4 @@
-using Umbraco.Cms.Core.Collections;
+using Umbraco.Cms.Core.Collections;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Install.Models;
using Umbraco.Cms.Core.Serialization;
@@ -9,6 +9,7 @@ namespace Umbraco.Cms.Core.Install;
///
/// An internal in-memory status tracker for the current installation
///
+[Obsolete("This will no longer be used with the new backoffice APi, instead all steps run in one go")]
public class InstallStatusTracker
{
private static ConcurrentHashSet _steps = new();
diff --git a/src/Umbraco.Core/Install/InstallSteps/FilePermissionsStep.cs b/src/Umbraco.Core/Install/InstallSteps/FilePermissionsStep.cs
index 40f54bab33..b6a08d55ae 100644
--- a/src/Umbraco.Core/Install/InstallSteps/FilePermissionsStep.cs
+++ b/src/Umbraco.Core/Install/InstallSteps/FilePermissionsStep.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Umbraco.
+// Copyright (c) Umbraco.
// See LICENSE for more details.
using Umbraco.Cms.Core.Install.Models;
@@ -10,6 +10,7 @@ namespace Umbraco.Cms.Core.Install.InstallSteps;
///
/// Represents a step in the installation that ensure all the required permissions on files and folders are correct.
///
+[Obsolete("Will be replace with a new step with the new backoffice")]
[InstallSetupStep(
InstallationType.NewInstall | InstallationType.Upgrade,
"Permissions",
diff --git a/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs b/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs
index c8962c5fb9..17b89d8ec0 100644
--- a/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs
+++ b/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs
@@ -1,4 +1,4 @@
-using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration;
@@ -9,6 +9,7 @@ using Umbraco.Cms.Web.Common.DependencyInjection;
namespace Umbraco.Cms.Core.Install.InstallSteps;
+[Obsolete("Will be replace with a new step with the new backoffice")]
[InstallSetupStep(
InstallationType.NewInstall | InstallationType.Upgrade,
"TelemetryIdConfiguration",
diff --git a/src/Umbraco.Core/Install/InstallSteps/UpgradeStep.cs b/src/Umbraco.Core/Install/InstallSteps/UpgradeStep.cs
index 763b69226e..c67b1fa5fb 100644
--- a/src/Umbraco.Core/Install/InstallSteps/UpgradeStep.cs
+++ b/src/Umbraco.Core/Install/InstallSteps/UpgradeStep.cs
@@ -1,4 +1,4 @@
-using Umbraco.Cms.Core.Configuration;
+using Umbraco.Cms.Core.Configuration;
using Umbraco.Cms.Core.Install.Models;
using Umbraco.Cms.Core.Semver;
using Umbraco.Cms.Core.Services;
@@ -8,6 +8,7 @@ namespace Umbraco.Cms.Core.Install.InstallSteps
///
/// This step is purely here to show the button to commence the upgrade
///
+ [Obsolete("Will be replace with a new step with the new backoffice")]
[InstallSetupStep(InstallationType.Upgrade, "Upgrade", "upgrade", 1, "Upgrading Umbraco to the latest and greatest version.")]
public class UpgradeStep : InstallSetupStep