V14: Fix up install controller (#15646)
* Rename InstallVResponseModel to InstallRequestModel * Align SettingsInstallController * Rename split DatabaseInstallResponseModel in two * Change UserInstallResponseModel to UserInstallViewModel * Use PresentationModel instead of ViewModel * Use operation status pattern when validating database * Prepare for install to return a message * Begin updating steps * Make StepBase sharable between upgrade and install * Update steps * Use error message from install steps in install controller * Use error message from upgrade steps in upgrade controller * Use 500 for install/upgrade failed It's entirely likely that it has nothing to do with the request * Updated OpenApi.Json --------- Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.Builders;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Api.Management.Filters;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Install;
|
||||
|
||||
@@ -13,4 +17,32 @@ namespace Umbraco.Cms.Api.Management.Controllers.Install;
|
||||
[RequireRuntimeLevel(RuntimeLevel.Install)]
|
||||
public abstract class InstallControllerBase : ManagementApiControllerBase
|
||||
{
|
||||
protected IActionResult InstallOperationResult(InstallOperationStatus status, InstallationResult? result = null) =>
|
||||
status switch
|
||||
{
|
||||
InstallOperationStatus.Success => Ok(),
|
||||
InstallOperationStatus.UnknownDatabaseProvider => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Invalid database configuration")
|
||||
.WithDetail("The database provider is unknown.")
|
||||
.Build()),
|
||||
InstallOperationStatus.MissingConnectionString => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Invalid database configuration")
|
||||
.WithDetail("The connection string is missing.")
|
||||
.Build()),
|
||||
InstallOperationStatus.MissingProviderName => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Invalid database configuration")
|
||||
.WithDetail("The provider name is missing.")
|
||||
.Build()),
|
||||
InstallOperationStatus.DatabaseConnectionFailed => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Invalid database configuration")
|
||||
.WithDetail("Could not connect to the database.")
|
||||
.Build()),
|
||||
InstallOperationStatus.InstallFailed => StatusCode(StatusCodes.Status500InternalServerError, new ProblemDetailsBuilder()
|
||||
.WithTitle("Install failed")
|
||||
.WithDetail(result?.ErrorMessage ?? "An unknown error occurred.")
|
||||
.Build()),
|
||||
_ => StatusCode(StatusCodes.Status500InternalServerError, new ProblemDetailsBuilder()
|
||||
.WithTitle("Unknown install operation status.")
|
||||
.Build()),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,10 +28,9 @@ public class SettingsInstallController : InstallControllerBase
|
||||
|
||||
[HttpGet("settings")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status428PreconditionRequired)]
|
||||
[ProducesResponseType(typeof(InstallSettingsResponseModel), StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<InstallSettingsResponseModel>> Settings()
|
||||
public async Task<IActionResult> Settings()
|
||||
{
|
||||
// Register that the install has started
|
||||
await _installHelper.SetInstallStatusAsync(false, string.Empty);
|
||||
@@ -39,6 +38,6 @@ public class SettingsInstallController : InstallControllerBase
|
||||
InstallSettingsModel installSettings = _installSettingsFactory.GetInstallSettings();
|
||||
InstallSettingsResponseModel responseModel = _mapper.Map<InstallSettingsResponseModel>(installSettings)!;
|
||||
|
||||
return responseModel;
|
||||
return Ok(responseModel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Hosting;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Installer;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
using Umbraco.Cms.Core.Services.Installer;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Install;
|
||||
|
||||
@@ -16,31 +15,24 @@ public class SetupInstallController : InstallControllerBase
|
||||
{
|
||||
private readonly IUmbracoMapper _mapper;
|
||||
private readonly IInstallService _installService;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
public SetupInstallController(
|
||||
IUmbracoMapper mapper,
|
||||
IInstallService installService,
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IHostingEnvironment hostingEnvironment)
|
||||
IInstallService installService)
|
||||
{
|
||||
_mapper = mapper;
|
||||
_installService = installService;
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
_globalSettings = globalSettings.Value;
|
||||
}
|
||||
|
||||
[HttpPost("setup")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status428PreconditionRequired)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> Setup(InstallVResponseModel installData)
|
||||
public async Task<IActionResult> Setup(InstallRequestModel installData)
|
||||
{
|
||||
InstallData data = _mapper.Map<InstallData>(installData)!;
|
||||
await _installService.Install(data);
|
||||
Attempt<InstallationResult?, InstallOperationStatus> result = await _installService.InstallAsync(data);
|
||||
|
||||
return Ok();
|
||||
return InstallOperationResult(result.Status, result.Result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ using Umbraco.Cms.Core.Install.Models;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Infrastructure.Migrations.Install;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Installer;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Install;
|
||||
|
||||
@@ -26,25 +28,13 @@ public class ValidateDatabaseInstallController : InstallControllerBase
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> ValidateDatabase(DatabaseInstallResponseModel responseModel)
|
||||
public async Task<IActionResult> ValidateDatabase(DatabaseInstallRequestModel viewModel)
|
||||
{
|
||||
DatabaseModel databaseModel = _mapper.Map<DatabaseModel>(responseModel)!;
|
||||
DatabaseModel databaseModel = _mapper.Map<DatabaseModel>(viewModel)!;
|
||||
|
||||
var success = _databaseBuilder.ConfigureDatabaseConnection(databaseModel, true);
|
||||
Attempt<InstallOperationStatus> attempt = await _databaseBuilder.ValidateDatabaseConnectionAsync(databaseModel);
|
||||
|
||||
if (success)
|
||||
{
|
||||
return await Task.FromResult(Ok());
|
||||
}
|
||||
|
||||
var invalidModelProblem = new ProblemDetails
|
||||
{
|
||||
Title = "Invalid database configuration",
|
||||
Detail = "The provided database configuration is invalid",
|
||||
Status = StatusCodes.Status400BadRequest,
|
||||
Type = "Error",
|
||||
};
|
||||
|
||||
return await Task.FromResult(BadRequest(invalidModelProblem));
|
||||
return InstallOperationResult(attempt.Result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
using Umbraco.Cms.Core.Services.Installer;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Upgrade;
|
||||
|
||||
@@ -19,7 +22,7 @@ public class AuthorizeUpgradeController : UpgradeControllerBase
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
|
||||
public async Task<IActionResult> Authorize()
|
||||
{
|
||||
await _upgradeService.Upgrade();
|
||||
return Ok();
|
||||
Attempt<InstallationResult?, UpgradeOperationStatus> result = await _upgradeService.UpgradeAsync();
|
||||
return UpgradeOperationResult(result.Status, result.Result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.Builders;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Api.Management.Filters;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Upgrade;
|
||||
@@ -14,5 +18,16 @@ namespace Umbraco.Cms.Api.Management.Controllers.Upgrade;
|
||||
[Authorize(Policy = "New" + AuthorizationPolicies.RequireAdminAccess)]
|
||||
public abstract class UpgradeControllerBase : ManagementApiControllerBase
|
||||
{
|
||||
|
||||
protected IActionResult UpgradeOperationResult(UpgradeOperationStatus status, InstallationResult? result = null) =>
|
||||
status switch
|
||||
{
|
||||
UpgradeOperationStatus.Success => Ok(),
|
||||
UpgradeOperationStatus.UpgradeFailed => StatusCode(StatusCodes.Status500InternalServerError, new ProblemDetailsBuilder()
|
||||
.WithTitle("Upgrade failed")
|
||||
.WithDetail(result?.ErrorMessage ?? "An unknown error occurred.")
|
||||
.Build()),
|
||||
_ => StatusCode(StatusCodes.Status500InternalServerError, new ProblemDetailsBuilder()
|
||||
.WithTitle("Unknown upgrade operation status.")
|
||||
.Build()),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ public class InstallerViewModelsMapDefinition : IMapDefinition
|
||||
{
|
||||
public void DefineMaps(IUmbracoMapper mapper)
|
||||
{
|
||||
mapper.Define<InstallVResponseModel, InstallData>((source, context) => new InstallData(), Map);
|
||||
mapper.Define<UserInstallResponseModel, UserInstallData>((source, context) => new UserInstallData(), Map);
|
||||
mapper.Define<DatabaseInstallResponseModel, DatabaseInstallData>((source, context) => new DatabaseInstallData(), Map);
|
||||
mapper.Define<DatabaseInstallResponseModel, DatabaseModel>((source, context) => new DatabaseModel(), Map);
|
||||
mapper.Define<InstallRequestModel, InstallData>((source, context) => new InstallData(), Map);
|
||||
mapper.Define<UserInstallPresentationModel, UserInstallData>((source, context) => new UserInstallData(), Map);
|
||||
mapper.Define<DatabaseInstallPresentationModel, DatabaseInstallData>((source, context) => new DatabaseInstallData(), Map);
|
||||
mapper.Define<DatabaseInstallPresentationModel, DatabaseModel>((source, context) => new DatabaseModel(), Map);
|
||||
mapper.Define<DatabaseInstallData, DatabaseModel>((source, context) => new DatabaseModel(), Map);
|
||||
mapper.Define<InstallSettingsModel, InstallSettingsResponseModel>((source, context) => new InstallSettingsResponseModel(), Map);
|
||||
mapper.Define<UserSettingsModel, UserSettingsViewModel>((source, context) => new UserSettingsViewModel(), Map);
|
||||
mapper.Define<UserSettingsModel, UserSettingsPresentationModel>((source, context) => new UserSettingsPresentationModel(), Map);
|
||||
mapper.Define<IDatabaseProviderMetadata, DatabaseSettingsModel>((source, context) => new DatabaseSettingsModel(), Map);
|
||||
mapper.Define<DatabaseSettingsModel, DatabaseSettingsPresentationModel>((source, context) => new DatabaseSettingsPresentationModel(), Map);
|
||||
mapper.Define<ConsentLevelModel, ConsentLevelPresentationModel>((source, context) => new ConsentLevelPresentationModel(), Map);
|
||||
@@ -33,7 +33,7 @@ public class InstallerViewModelsMapDefinition : IMapDefinition
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private void Map(DatabaseInstallResponseModel source, DatabaseModel target, MapperContext context)
|
||||
private void Map(DatabaseInstallPresentationModel source, DatabaseModel target, MapperContext context)
|
||||
{
|
||||
target.ConnectionString = source.ConnectionString;
|
||||
target.DatabaseName = source.Name ?? string.Empty;
|
||||
@@ -47,7 +47,7 @@ public class InstallerViewModelsMapDefinition : IMapDefinition
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(InstallVResponseModel source, InstallData target, MapperContext context)
|
||||
private static void Map(InstallRequestModel source, InstallData target, MapperContext context)
|
||||
{
|
||||
target.TelemetryLevel = source.TelemetryLevel;
|
||||
target.User = context.Map<UserInstallData>(source.User)!;
|
||||
@@ -55,7 +55,7 @@ public class InstallerViewModelsMapDefinition : IMapDefinition
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(UserInstallResponseModel source, UserInstallData target, MapperContext context)
|
||||
private static void Map(UserInstallPresentationModel source, UserInstallData target, MapperContext context)
|
||||
{
|
||||
target.Email = source.Email;
|
||||
target.Name = source.Name;
|
||||
@@ -64,7 +64,7 @@ public class InstallerViewModelsMapDefinition : IMapDefinition
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(DatabaseInstallResponseModel source, DatabaseInstallData target, MapperContext context)
|
||||
private static void Map(DatabaseInstallPresentationModel source, DatabaseInstallData target, MapperContext context)
|
||||
{
|
||||
target.Id = source.Id;
|
||||
target.ProviderName = source.ProviderName;
|
||||
@@ -94,12 +94,12 @@ public class InstallerViewModelsMapDefinition : IMapDefinition
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(InstallSettingsModel source, InstallSettingsResponseModel target, MapperContext context)
|
||||
{
|
||||
target.User = context.Map<UserSettingsViewModel>(source.UserSettings)!;
|
||||
target.User = context.Map<UserSettingsPresentationModel>(source.UserSettings)!;
|
||||
target.Databases = context.MapEnumerable<DatabaseSettingsModel, DatabaseSettingsPresentationModel>(source.DatabaseSettings);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(UserSettingsModel source, UserSettingsViewModel target, MapperContext context)
|
||||
private static void Map(UserSettingsModel source, UserSettingsPresentationModel target, MapperContext context)
|
||||
{
|
||||
target.MinCharLength = source.PasswordSettings.MinCharLength;
|
||||
target.MinNonAlphaNumericLength = source.PasswordSettings.MinNonAlphaNumericLength;
|
||||
|
||||
@@ -7207,26 +7207,6 @@
|
||||
],
|
||||
"operationId": "GetInstallSettings",
|
||||
"responses": {
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"428": {
|
||||
"description": "Client Error",
|
||||
"content": {
|
||||
@@ -7294,7 +7274,7 @@
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/InstallVResponseModel"
|
||||
"$ref": "#/components/schemas/InstallRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7303,7 +7283,7 @@
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/InstallVResponseModel"
|
||||
"$ref": "#/components/schemas/InstallRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7312,7 +7292,7 @@
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/InstallVResponseModel"
|
||||
"$ref": "#/components/schemas/InstallRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7320,26 +7300,6 @@
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"428": {
|
||||
"description": "Client Error",
|
||||
"content": {
|
||||
@@ -7378,7 +7338,7 @@
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DatabaseInstallResponseModel"
|
||||
"$ref": "#/components/schemas/DatabaseInstallRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7387,7 +7347,7 @@
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DatabaseInstallResponseModel"
|
||||
"$ref": "#/components/schemas/DatabaseInstallRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7396,7 +7356,7 @@
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DatabaseInstallResponseModel"
|
||||
"$ref": "#/components/schemas/DatabaseInstallRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -23764,7 +23724,7 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"DatabaseInstallResponseModel": {
|
||||
"DatabaseInstallPresentationModel": {
|
||||
"required": [
|
||||
"id",
|
||||
"providerName",
|
||||
@@ -23810,6 +23770,15 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"DatabaseInstallRequestModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DatabaseInstallPresentationModel"
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"DatabaseSettingsPresentationModel": {
|
||||
"required": [
|
||||
"defaultDatabaseName",
|
||||
@@ -25325,6 +25294,37 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"InstallRequestModel": {
|
||||
"required": [
|
||||
"database",
|
||||
"telemetryLevel",
|
||||
"user"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"user": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/UserInstallPresentationModel"
|
||||
}
|
||||
]
|
||||
},
|
||||
"database": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DatabaseInstallPresentationModel"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/DatabaseInstallRequestModel"
|
||||
}
|
||||
]
|
||||
},
|
||||
"telemetryLevel": {
|
||||
"$ref": "#/components/schemas/TelemetryLevelModel"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"InstallSettingsResponseModel": {
|
||||
"required": [
|
||||
"databases",
|
||||
@@ -25335,7 +25335,7 @@
|
||||
"user": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/UserSettingsModel"
|
||||
"$ref": "#/components/schemas/UserSettingsPresentationModel"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -25352,34 +25352,6 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"InstallVResponseModel": {
|
||||
"required": [
|
||||
"database",
|
||||
"telemetryLevel",
|
||||
"user"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"user": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/UserInstallResponseModel"
|
||||
}
|
||||
]
|
||||
},
|
||||
"database": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DatabaseInstallResponseModel"
|
||||
}
|
||||
]
|
||||
},
|
||||
"telemetryLevel": {
|
||||
"$ref": "#/components/schemas/TelemetryLevelModel"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"InviteUserRequestModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
@@ -29563,7 +29535,7 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UserInstallResponseModel": {
|
||||
"UserInstallPresentationModel": {
|
||||
"required": [
|
||||
"email",
|
||||
"name",
|
||||
@@ -29766,7 +29738,7 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UserSettingsModel": {
|
||||
"UserSettingsPresentationModel": {
|
||||
"required": [
|
||||
"consentLevels",
|
||||
"minCharLength",
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Installer;
|
||||
|
||||
public class DatabaseInstallResponseModel
|
||||
public class DatabaseInstallPresentationModel
|
||||
{
|
||||
[Required]
|
||||
public Guid Id { get; set; }
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Installer;
|
||||
|
||||
public class DatabaseInstallRequestModel : DatabaseInstallPresentationModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -4,13 +4,13 @@ using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Installer;
|
||||
|
||||
public class InstallVResponseModel
|
||||
public class InstallRequestModel
|
||||
{
|
||||
[Required]
|
||||
public UserInstallResponseModel User { get; set; } = null!;
|
||||
public UserInstallPresentationModel User { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
public DatabaseInstallResponseModel Database { get; set; } = null!;
|
||||
public DatabaseInstallPresentationModel Database { get; set; } = null!;
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public TelemetryLevel TelemetryLevel { get; set; } = TelemetryLevel.Basic;
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Installer;
|
||||
public class InstallSettingsResponseModel
|
||||
{
|
||||
[Required]
|
||||
public UserSettingsViewModel User { get; set; } = null!;
|
||||
public UserSettingsPresentationModel User { get; set; } = null!;
|
||||
|
||||
public IEnumerable<DatabaseSettingsPresentationModel> Databases { get; set; } = Enumerable.Empty<DatabaseSettingsPresentationModel>();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Installer;
|
||||
|
||||
public class UserInstallResponseModel
|
||||
public class UserInstallPresentationModel
|
||||
{
|
||||
[Required]
|
||||
[StringLength(255)]
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Installer;
|
||||
|
||||
public class UserSettingsViewModel
|
||||
public class UserSettingsPresentationModel
|
||||
{
|
||||
public int MinCharLength { get; set; }
|
||||
|
||||
@@ -12,7 +12,7 @@ public interface IInstallStep
|
||||
/// </summary>
|
||||
/// <param name="model">InstallData model containing the data provided by the installer UI.</param>
|
||||
/// <returns></returns>
|
||||
Task ExecuteAsync(InstallData model);
|
||||
Task<Attempt<InstallationResult>> ExecuteAsync(InstallData model);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the step is required to execute.
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Umbraco.Cms.Core.Installer;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
|
||||
namespace Umbraco.Cms.Core.Installer;
|
||||
|
||||
/// <summary>
|
||||
/// Defines a step that's required to upgrade Umbraco.
|
||||
@@ -8,7 +10,7 @@ public interface IUpgradeStep
|
||||
/// <summary>
|
||||
/// Executes the upgrade step.
|
||||
/// </summary>
|
||||
Task ExecuteAsync();
|
||||
Task<Attempt<InstallationResult>> ExecuteAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the step is required to execute.
|
||||
|
||||
12
src/Umbraco.Core/Installer/StepBase.cs
Normal file
12
src/Umbraco.Core/Installer/StepBase.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
|
||||
namespace Umbraco.Cms.Core.Installer;
|
||||
|
||||
public abstract class StepBase
|
||||
{
|
||||
protected Attempt<InstallationResult> FailWithMessage(string message)
|
||||
=> Attempt<InstallationResult>.Fail(new InstallationResult { ErrorMessage = message });
|
||||
|
||||
|
||||
protected Attempt<InstallationResult> Success() => Attempt<InstallationResult>.Succeed(new InstallationResult());
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Models.Installer;
|
||||
|
||||
namespace Umbraco.Cms.Core.Installer.Steps;
|
||||
|
||||
public class FilePermissionsStep : IInstallStep, IUpgradeStep
|
||||
public class FilePermissionsStep : StepBase, IInstallStep, IUpgradeStep
|
||||
{
|
||||
private readonly IFilePermissionHelper _filePermissionHelper;
|
||||
private readonly ILocalizedTextService _localizedTextService;
|
||||
@@ -18,11 +18,11 @@ public class FilePermissionsStep : IInstallStep, IUpgradeStep
|
||||
_localizedTextService = localizedTextService;
|
||||
}
|
||||
|
||||
public Task ExecuteAsync(InstallData _) => Execute();
|
||||
public Task<Attempt<InstallationResult>> ExecuteAsync(InstallData _) => Execute();
|
||||
|
||||
public Task ExecuteAsync() => Execute();
|
||||
public Task<Attempt<InstallationResult>> ExecuteAsync() => Execute();
|
||||
|
||||
private Task Execute()
|
||||
private Task<Attempt<InstallationResult>> Execute()
|
||||
{
|
||||
// validate file permissions
|
||||
var permissionsOk =
|
||||
@@ -33,10 +33,11 @@ public class FilePermissionsStep : IInstallStep, IUpgradeStep
|
||||
report.ToDictionary(x => _localizedTextService.Localize("permissions", x.Key), x => x.Value);
|
||||
if (permissionsOk == false)
|
||||
{
|
||||
throw new InstallException("Permission check failed", "permissionsreport", new { errors = translatedErrors });
|
||||
IEnumerable<string> errorstring = translatedErrors.Select(x => $"{x.Key}: {string.Join(", ", x.Value)}");
|
||||
return Task.FromResult(FailWithMessage("Permission check failed:\n " + string.Join("\n", errorstring)));
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
return Task.FromResult(Success());
|
||||
}
|
||||
|
||||
public Task<bool> RequiresExecutionAsync(InstallData model) => ShouldExecute();
|
||||
|
||||
@@ -3,17 +3,21 @@ using Umbraco.Cms.Core.Models.Installer;
|
||||
|
||||
namespace Umbraco.Cms.Core.Installer.Steps;
|
||||
|
||||
public class RestartRuntimeStep : IInstallStep, IUpgradeStep
|
||||
public class RestartRuntimeStep : StepBase, IInstallStep, IUpgradeStep
|
||||
{
|
||||
private readonly IRuntime _runtime;
|
||||
|
||||
public RestartRuntimeStep(IRuntime runtime) => _runtime = runtime;
|
||||
|
||||
public async Task ExecuteAsync(InstallData _) => await Execute();
|
||||
public async Task<Attempt<InstallationResult>> ExecuteAsync(InstallData _) => await Execute();
|
||||
|
||||
public async Task ExecuteAsync() => await Execute();
|
||||
public async Task<Attempt<InstallationResult>> ExecuteAsync() => await Execute();
|
||||
|
||||
private async Task Execute() => await _runtime.RestartAsync();
|
||||
private async Task<Attempt<InstallationResult>> Execute()
|
||||
{
|
||||
await _runtime.RestartAsync();
|
||||
return Success();
|
||||
}
|
||||
|
||||
public Task<bool> RequiresExecutionAsync(InstallData _) => ShouldExecute();
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Install.Models;
|
||||
using Umbraco.Cms.Core.Telemetry;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
|
||||
namespace Umbraco.Cms.Core.Installer.Steps;
|
||||
|
||||
public class TelemetryIdentifierStep : IInstallStep, IUpgradeStep
|
||||
public class TelemetryIdentifierStep : StepBase, IInstallStep, IUpgradeStep
|
||||
{
|
||||
private readonly IOptions<GlobalSettings> _globalSettings;
|
||||
private readonly ISiteIdentifierService _siteIdentifierService;
|
||||
@@ -19,14 +18,14 @@ public class TelemetryIdentifierStep : IInstallStep, IUpgradeStep
|
||||
_siteIdentifierService = siteIdentifierService;
|
||||
}
|
||||
|
||||
public Task ExecuteAsync(InstallData _) => Execute();
|
||||
public Task<Attempt<InstallationResult>> ExecuteAsync(InstallData _) => Execute();
|
||||
|
||||
public Task ExecuteAsync() => Execute();
|
||||
public Task<Attempt<InstallationResult>> ExecuteAsync() => Execute();
|
||||
|
||||
private Task Execute()
|
||||
private Task<Attempt<InstallationResult>> Execute()
|
||||
{
|
||||
_siteIdentifierService.TryCreateSiteIdentifier(out _);
|
||||
return Task.CompletedTask;
|
||||
return Task.FromResult(Success());
|
||||
}
|
||||
|
||||
public Task<bool> RequiresExecutionAsync(InstallData _) => ShouldExecute();
|
||||
|
||||
9
src/Umbraco.Core/Models/Installer/InstallationResult.cs
Normal file
9
src/Umbraco.Core/Models/Installer/InstallationResult.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Umbraco.Cms.Core.Models.Installer;
|
||||
|
||||
public class InstallationResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets ore sets a string specifying why the installation failed.
|
||||
/// </summary>
|
||||
public string? ErrorMessage { get; set; }
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Umbraco.Cms.Core.Installer;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Installer;
|
||||
|
||||
@@ -10,5 +11,5 @@ public interface IInstallService
|
||||
/// </summary>
|
||||
/// <param name="model">InstallData containing the required data used to install</param>
|
||||
/// <returns></returns>
|
||||
Task Install(InstallData model);
|
||||
Task<Attempt<InstallationResult?, InstallOperationStatus>> InstallAsync(InstallData model);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Umbraco.Cms.Core.Installer;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Installer;
|
||||
|
||||
@@ -7,5 +9,5 @@ public interface IUpgradeService
|
||||
/// <summary>
|
||||
/// Runs all the steps in the <see cref="UpgradeStepCollection"/>, upgrading Umbraco.
|
||||
/// </summary>
|
||||
Task Upgrade();
|
||||
Task<Attempt<InstallationResult?, UpgradeOperationStatus>> UpgradeAsync();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Installer;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Installer;
|
||||
|
||||
@@ -23,7 +22,7 @@ public class InstallService : IInstallService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task Install(InstallData model)
|
||||
public async Task<Attempt<InstallationResult?, InstallOperationStatus>> InstallAsync(InstallData model)
|
||||
{
|
||||
if (_runtimeState.Level != RuntimeLevel.Install)
|
||||
{
|
||||
@@ -32,16 +31,19 @@ public class InstallService : IInstallService
|
||||
|
||||
try
|
||||
{
|
||||
await RunSteps(model);
|
||||
Attempt<InstallationResult?> result = await RunStepsAsync(model);
|
||||
return result.Success
|
||||
? Attempt.SucceedWithStatus(InstallOperationStatus.Success, result.Result)
|
||||
: Attempt.FailWithStatus(InstallOperationStatus.InstallFailed, result.Result);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, "Encountered an error when running the install steps");
|
||||
_logger.LogError(exception, "Encountered an unexpected error when running the install steps");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunSteps(InstallData model)
|
||||
private async Task<Attempt<InstallationResult?>> RunStepsAsync(InstallData model)
|
||||
{
|
||||
foreach (IInstallStep step in _installSteps)
|
||||
{
|
||||
@@ -54,8 +56,25 @@ public class InstallService : IInstallService
|
||||
}
|
||||
|
||||
_logger.LogInformation("Running {StepName}", stepName);
|
||||
await step.ExecuteAsync(model);
|
||||
Attempt<InstallationResult> result = await step.ExecuteAsync(model);
|
||||
|
||||
if (result.Success is false)
|
||||
{
|
||||
if (result.Result?.ErrorMessage is not null)
|
||||
{
|
||||
_logger.LogError("Failed {StepName}, with the message: {Message}", stepName, result.Result?.ErrorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Failed {StepName}", stepName);
|
||||
}
|
||||
|
||||
return Attempt.Fail(result.Result);
|
||||
}
|
||||
|
||||
_logger.LogInformation("Finished {StepName}", stepName);
|
||||
}
|
||||
|
||||
return Attempt<InstallationResult?>.Succeed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Installer;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Installer;
|
||||
|
||||
@@ -22,7 +22,7 @@ public class UpgradeService : IUpgradeService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task Upgrade()
|
||||
public async Task<Attempt<InstallationResult?, UpgradeOperationStatus>> UpgradeAsync()
|
||||
{
|
||||
if (_runtimeState.Level != RuntimeLevel.Upgrade)
|
||||
{
|
||||
@@ -32,16 +32,19 @@ public class UpgradeService : IUpgradeService
|
||||
|
||||
try
|
||||
{
|
||||
await RunSteps();
|
||||
Attempt<InstallationResult?> result = await RunStepsAsync();
|
||||
return result.Success
|
||||
? Attempt.SucceedWithStatus(UpgradeOperationStatus.Success, result.Result)
|
||||
: Attempt.FailWithStatus(UpgradeOperationStatus.UpgradeFailed, result.Result);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, "Encountered an error when running the upgrade steps");
|
||||
_logger.LogError(exception, "Encountered an unexpected error when running the upgrade steps");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunSteps()
|
||||
private async Task<Attempt<InstallationResult?>> RunStepsAsync()
|
||||
{
|
||||
foreach (IUpgradeStep step in _upgradeSteps)
|
||||
{
|
||||
@@ -54,8 +57,25 @@ public class UpgradeService : IUpgradeService
|
||||
}
|
||||
|
||||
_logger.LogInformation("Running {StepName}", stepName);
|
||||
await step.ExecuteAsync();
|
||||
Attempt<InstallationResult> result = await step.ExecuteAsync();
|
||||
|
||||
if (result.Success is false)
|
||||
{
|
||||
if (result.Result?.ErrorMessage is not null)
|
||||
{
|
||||
_logger.LogError("Failed {StepName}, with the message: {Message}", stepName, result.Result?.ErrorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Failed {StepName}", stepName);
|
||||
}
|
||||
|
||||
return Attempt.Fail(result.Result);
|
||||
}
|
||||
|
||||
_logger.LogInformation("Finished {StepName}", stepName);
|
||||
}
|
||||
|
||||
return Attempt<InstallationResult?>.Succeed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
public enum InstallOperationStatus
|
||||
{
|
||||
Success,
|
||||
UnknownDatabaseProvider,
|
||||
MissingConnectionString,
|
||||
MissingProviderName,
|
||||
DatabaseConnectionFailed,
|
||||
InstallFailed,
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
public enum UpgradeOperationStatus
|
||||
{
|
||||
Success,
|
||||
UpgradeFailed,
|
||||
}
|
||||
@@ -4,8 +4,8 @@ using System.Text;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Install.Models;
|
||||
using Umbraco.Cms.Core.Installer;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
@@ -20,7 +20,7 @@ using HttpResponseMessage = System.Net.Http.HttpResponseMessage;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Installer.Steps;
|
||||
|
||||
public class CreateUserStep : IInstallStep
|
||||
public class CreateUserStep : StepBase, IInstallStep
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly DatabaseBuilder _databaseBuilder;
|
||||
@@ -54,12 +54,12 @@ public class CreateUserStep : IInstallStep
|
||||
_metricsConsentService = metricsConsentService;
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(InstallData model)
|
||||
public async Task<Attempt<InstallationResult>> ExecuteAsync(InstallData model)
|
||||
{
|
||||
IUser? admin = _userService.GetUserById(Constants.Security.SuperUserId);
|
||||
if (admin == null)
|
||||
if (admin is null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not find the super user!");
|
||||
return FailWithMessage("Could not find the super user");
|
||||
}
|
||||
|
||||
UserInstallData user = model.User;
|
||||
@@ -72,21 +72,21 @@ public class CreateUserStep : IInstallStep
|
||||
BackOfficeIdentityUser? membershipUser = await _userManager.FindByIdAsync(Constants.Security.SuperUserIdAsString);
|
||||
if (membershipUser == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
return FailWithMessage(
|
||||
$"No user found in membership provider with id of {Constants.Security.SuperUserIdAsString}.");
|
||||
}
|
||||
|
||||
//To change the password here we actually need to reset it since we don't have an old one to use to change
|
||||
// To change the password here we actually need to reset it since we don't have an old one to use to change
|
||||
var resetToken = await _userManager.GeneratePasswordResetTokenAsync(membershipUser);
|
||||
if (string.IsNullOrWhiteSpace(resetToken))
|
||||
{
|
||||
throw new InvalidOperationException("Could not reset password: unable to generate internal reset token");
|
||||
return FailWithMessage("Could not reset password: unable to generate internal reset token");
|
||||
}
|
||||
|
||||
IdentityResult resetResult = await _userManager.ChangePasswordWithResetAsync(membershipUser.Id, resetToken, user.Password.Trim());
|
||||
if (!resetResult.Succeeded)
|
||||
{
|
||||
throw new InvalidOperationException("Could not reset password: " + string.Join(", ", resetResult.Errors.ToErrorMessage()));
|
||||
return FailWithMessage("Could not reset password: " + string.Join(", ", resetResult.Errors.ToErrorMessage()));
|
||||
}
|
||||
|
||||
_metricsConsentService.SetConsentLevel(model.TelemetryLevel);
|
||||
@@ -104,6 +104,8 @@ public class CreateUserStep : IInstallStep
|
||||
}
|
||||
catch { /* fail in silence */ }
|
||||
}
|
||||
|
||||
return Success();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Install;
|
||||
using Umbraco.Cms.Core.Install.Models;
|
||||
using Umbraco.Cms.Core.Installer;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
@@ -11,7 +11,7 @@ using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Installer.Steps;
|
||||
|
||||
public class DatabaseConfigureStep : IInstallStep
|
||||
public class DatabaseConfigureStep : StepBase, IInstallStep
|
||||
{
|
||||
private readonly IOptionsMonitor<ConnectionStrings> _connectionStrings;
|
||||
private readonly DatabaseBuilder _databaseBuilder;
|
||||
@@ -30,26 +30,21 @@ public class DatabaseConfigureStep : IInstallStep
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public Task ExecuteAsync(InstallData model)
|
||||
public Task<Attempt<InstallationResult>> ExecuteAsync(InstallData model)
|
||||
{
|
||||
DatabaseModel databaseModel = _mapper.Map<DatabaseModel>(model.Database)!;
|
||||
|
||||
if (!_databaseBuilder.ConfigureDatabaseConnection(databaseModel, false))
|
||||
{
|
||||
throw new InstallException("Could not connect to the database");
|
||||
return Task.FromResult(FailWithMessage("Could not connect to the database"));
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
return Task.FromResult(Success());
|
||||
}
|
||||
|
||||
public Task<bool> RequiresExecutionAsync(InstallData model)
|
||||
{
|
||||
// If the connection string is already present in config we don't need to configure it again
|
||||
if (_connectionStrings.CurrentValue.IsConnectionStringConfigured())
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
return Task.FromResult(true);
|
||||
return Task.FromResult(_connectionStrings.CurrentValue.IsConnectionStringConfigured() is false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ using Umbraco.Cms.Infrastructure.Migrations.Install;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Installer.Steps;
|
||||
|
||||
public class DatabaseInstallStep : IInstallStep, IUpgradeStep
|
||||
public class DatabaseInstallStep : StepBase, IInstallStep, IUpgradeStep
|
||||
{
|
||||
private readonly IRuntimeState _runtime;
|
||||
private readonly DatabaseBuilder _databaseBuilder;
|
||||
@@ -18,11 +18,11 @@ public class DatabaseInstallStep : IInstallStep, IUpgradeStep
|
||||
_databaseBuilder = databaseBuilder;
|
||||
}
|
||||
|
||||
public Task ExecuteAsync(InstallData _) => Execute();
|
||||
public Task<Attempt<InstallationResult>> ExecuteAsync(InstallData _) => Execute();
|
||||
|
||||
public Task ExecuteAsync() => Execute();
|
||||
public Task<Attempt<InstallationResult>> ExecuteAsync() => Execute();
|
||||
|
||||
private Task Execute()
|
||||
private Task<Attempt<InstallationResult>> Execute()
|
||||
{
|
||||
|
||||
if (_runtime.Reason == RuntimeLevelReason.InstallMissingDatabase)
|
||||
@@ -34,10 +34,10 @@ public class DatabaseInstallStep : IInstallStep, IUpgradeStep
|
||||
|
||||
if (result?.Success == false)
|
||||
{
|
||||
throw new InstallException("The database failed to install. ERROR: " + result.Message);
|
||||
return Task.FromResult(FailWithMessage("The database failed to install. ERROR: " + result.Message));
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
return Task.FromResult(Success());
|
||||
}
|
||||
|
||||
public Task<bool> RequiresExecutionAsync(InstallData _) => ShouldExecute();
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
using Umbraco.Cms.Core.Install;
|
||||
using Umbraco.Cms.Core.Installer;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Migrations.Install;
|
||||
using Umbraco.Cms.Infrastructure.Migrations.PostMigrations;
|
||||
using Umbraco.Cms.Infrastructure.Migrations.Upgrade;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Installer.Steps;
|
||||
|
||||
public class DatabaseUpgradeStep : IInstallStep, IUpgradeStep
|
||||
public class DatabaseUpgradeStep : StepBase, IInstallStep, IUpgradeStep
|
||||
{
|
||||
private readonly DatabaseBuilder _databaseBuilder;
|
||||
private readonly IRuntimeState _runtime;
|
||||
@@ -33,11 +31,11 @@ public class DatabaseUpgradeStep : IInstallStep, IUpgradeStep
|
||||
_keyValueService = keyValueService;
|
||||
}
|
||||
|
||||
public Task ExecuteAsync(InstallData _) => Execute();
|
||||
public Task<Attempt<InstallationResult>> ExecuteAsync(InstallData _) => ExecuteInternalAsync();
|
||||
|
||||
public Task ExecuteAsync() => Execute();
|
||||
public Task<Attempt<InstallationResult>> ExecuteAsync() => ExecuteInternalAsync();
|
||||
|
||||
private Task Execute()
|
||||
private Task<Attempt<InstallationResult>> ExecuteInternalAsync()
|
||||
{
|
||||
_logger.LogInformation("Running 'Upgrade' service");
|
||||
|
||||
@@ -48,10 +46,10 @@ public class DatabaseUpgradeStep : IInstallStep, IUpgradeStep
|
||||
|
||||
if (result?.Success == false)
|
||||
{
|
||||
throw new InstallException("The database failed to upgrade. ERROR: " + result.Message);
|
||||
return Task.FromResult(FailWithMessage("The database failed to upgrade. ERROR: " + result.Message));
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
return Task.FromResult(Success());
|
||||
}
|
||||
|
||||
public Task<bool> RequiresExecutionAsync(InstallData model) => ShouldExecute();
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Installer;
|
||||
using Umbraco.Cms.Core.Models.Installer;
|
||||
using Umbraco.Cms.Infrastructure.Install;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Installer.Steps;
|
||||
|
||||
public class RegisterInstallCompleteStep : IInstallStep, IUpgradeStep
|
||||
public class RegisterInstallCompleteStep : StepBase, IInstallStep, IUpgradeStep
|
||||
{
|
||||
private readonly InstallHelper _installHelper;
|
||||
|
||||
public RegisterInstallCompleteStep(InstallHelper installHelper) => _installHelper = installHelper;
|
||||
|
||||
public Task ExecuteAsync(InstallData _) => Execute();
|
||||
public Task<Attempt<InstallationResult>> ExecuteAsync(InstallData _) => Execute();
|
||||
|
||||
public Task ExecuteAsync() => Execute();
|
||||
public Task<Attempt<InstallationResult>> ExecuteAsync() => Execute();
|
||||
|
||||
private Task Execute() => _installHelper.SetInstallStatusAsync(true, string.Empty);
|
||||
private async Task<Attempt<InstallationResult>> Execute()
|
||||
{
|
||||
await _installHelper.SetInstallStatusAsync(true, string.Empty);
|
||||
return Success();
|
||||
}
|
||||
|
||||
public Task<bool> RequiresExecutionAsync(InstallData _) => ShouldExecute();
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ using Umbraco.Cms.Core.Install.Models;
|
||||
using Umbraco.Cms.Core.Migrations;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Infrastructure.Migrations.Notifications;
|
||||
using Umbraco.Cms.Infrastructure.Migrations.Upgrade;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
@@ -231,6 +232,36 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install
|
||||
return true;
|
||||
}
|
||||
|
||||
public Task<Attempt<InstallOperationStatus>> ValidateDatabaseConnectionAsync(DatabaseModel databaseSettings)
|
||||
{
|
||||
IDatabaseProviderMetadata? providerMeta = _databaseProviderMetadata.FirstOrDefault(x => x.Id == databaseSettings.DatabaseProviderMetadataId);
|
||||
|
||||
if (providerMeta is null)
|
||||
{
|
||||
return Task.FromResult(Attempt.Fail(InstallOperationStatus.UnknownDatabaseProvider));
|
||||
}
|
||||
|
||||
var connectionString = providerMeta.GenerateConnectionString(databaseSettings);
|
||||
var providerName = databaseSettings.ProviderName ?? providerMeta.ProviderName;
|
||||
|
||||
if (string.IsNullOrEmpty(connectionString))
|
||||
{
|
||||
return Task.FromResult(Attempt.Fail(InstallOperationStatus.MissingConnectionString));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(providerName))
|
||||
{
|
||||
return Task.FromResult(Attempt.Fail(InstallOperationStatus.MissingProviderName));
|
||||
}
|
||||
|
||||
if (providerMeta.RequiresConnectionTest && CanConnect(connectionString, providerName) is false)
|
||||
{
|
||||
return Task.FromResult(Attempt.Fail(InstallOperationStatus.DatabaseConnectionFailed));
|
||||
}
|
||||
|
||||
return Task.FromResult(Attempt.Succeed(InstallOperationStatus.Success));
|
||||
}
|
||||
|
||||
private void Configure(bool installMissingDatabase)
|
||||
{
|
||||
_databaseFactory.Configure(_connectionStrings.CurrentValue);
|
||||
|
||||
Reference in New Issue
Block a user