New Backoffice: Health check controller (#13543)

* Adding health check controllers - getAll & getGroupByName

* Adding HealthCheckGroup mapper

* Adding viewModels

* Adding a factory for building a health check group with result view model

* Registering the mapper and factory

* Updating OpenApi.json

* Remove unnecessary checks - we instantiate the target before calling the Map()

* Adding ProducesResponseType for GetAll()

* Fixing usings

* Making checks required for a health check group

* Adding OK() around result to be explicit

* Adding default values to skip and take

* Adding Umbraco.Code comments

* Removing ? from HealthCheckGroupWithResultViewModel return type

* Move the grouping creation to the factory

* Adding Actions[] for each health check + mapping

* Defaulting ValueRequired to false

* Refactoring routes - from health-check to health-check-group

* Move to HealthCheckGroup folder

* Fix OpenApi.json

* Changing class name and making Key of HealthCheckActionViewModel non-nullable

* Fixing namespace

* Migrating ExecuteAction endpoint

* Add execute-action endpoint to OpenApi.json

* Use Task.FromResult() around the action result

* Fixing namespaces and swagger group name

* Fixing naming of the key in the health check action

* Fix tag names in OpenApi.json
This commit is contained in:
Elitsa Marinovska
2022-12-19 13:50:18 +01:00
committed by GitHub
parent adfc38503c
commit fef793326f
19 changed files with 937 additions and 169 deletions

View File

@@ -0,0 +1,64 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.HealthChecks;
using Umbraco.Cms.Core.Mapping;
namespace Umbraco.Cms.Api.Management.Controllers.HealthCheck;
public class ExecuteActionHealthCheckController : HealthCheckControllerBase
{
private readonly HealthCheckCollection _healthChecks;
private readonly IUmbracoMapper _umbracoMapper;
private readonly IList<Guid> _disabledCheckIds;
public ExecuteActionHealthCheckController(
HealthCheckCollection healthChecks,
IOptions<HealthChecksSettings> healthChecksSettings,
IUmbracoMapper umbracoMapper)
{
_healthChecks = healthChecks;
_disabledCheckIds = healthChecksSettings.Value
.DisabledChecks
.Select(x => x.Id)
.ToList();
_umbracoMapper = umbracoMapper;
}
/// <summary>
/// Executes a given action from a HealthCheck.
/// </summary>
/// <param name="action">The action to be executed.</param>
/// <returns>The result of a health check after the health check action is performed.</returns>
[HttpPost("execute-action")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(HealthCheckResultViewModel), StatusCodes.Status200OK)]
public async Task<ActionResult<HealthCheckResultViewModel>> ExecuteAction(HealthCheckActionViewModel action)
{
Guid healthCheckKey = action.HealthCheckKey;
Core.HealthChecks.HealthCheck? healthCheck = _healthChecks
.Where(x => _disabledCheckIds.Contains(healthCheckKey) == false)
.FirstOrDefault(x => x.Id == healthCheckKey);
if (healthCheck is null)
{
var invalidModelProblem = new ProblemDetails
{
Title = "Health Check Not Found",
Detail = $"No health check found with key = {healthCheckKey}",
Status = StatusCodes.Status400BadRequest,
Type = "Error",
};
return await Task.FromResult(BadRequest(invalidModelProblem));
}
HealthCheckStatus result = healthCheck.ExecuteAction(_umbracoMapper.Map<HealthCheckAction>(action)!);
return await Task.FromResult(Ok(_umbracoMapper.Map<HealthCheckResultViewModel>(result)));
}
}

View File

@@ -0,0 +1,45 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
using Umbraco.Cms.Core.HealthChecks;
using Umbraco.Cms.Core.Mapping;
namespace Umbraco.Cms.Api.Management.Controllers.HealthCheck.Group;
public class AllHealthCheckGroupController : HealthCheckGroupControllerBase
{
private readonly HealthCheckCollection _healthChecks;
private readonly IHealthCheckGroupWithResultViewModelFactory _healthCheckGroupWithResultViewModelFactory;
private readonly IUmbracoMapper _umbracoMapper;
public AllHealthCheckGroupController(
HealthCheckCollection healthChecks,
IHealthCheckGroupWithResultViewModelFactory healthCheckGroupWithResultViewModelFactory,
IUmbracoMapper umbracoMapper)
{
_healthChecks = healthChecks;
_healthCheckGroupWithResultViewModelFactory = healthCheckGroupWithResultViewModelFactory;
_umbracoMapper = umbracoMapper;
}
/// <summary>
/// Gets a paginated grouped list of all health checks without checking the result of each health check.
/// </summary>
/// <param name="skip">The amount of items to skip.</param>
/// <param name="take">The amount of items to take.</param>
/// <returns>The paged result of health checks, grouped by health check group name.</returns>
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<HealthCheckGroupViewModel>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedViewModel<HealthCheckGroupViewModel>>> All(int skip = 0, int take = 100)
{
IEnumerable<IGrouping<string?, Core.HealthChecks.HealthCheck>> groups = _healthCheckGroupWithResultViewModelFactory
.CreateGroupingFromHealthCheckCollection(_healthChecks)
.Skip(skip)
.Take(take);
return await Task.FromResult(Ok(_umbracoMapper.Map<PagedViewModel<HealthCheckGroupViewModel>>(groups)));
}
}

View File

@@ -0,0 +1,47 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
using Umbraco.Cms.Core.HealthChecks;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Management.Controllers.HealthCheck.Group;
public class ByNameWithResultHealthCheckGroupController : HealthCheckGroupControllerBase
{
private readonly HealthCheckCollection _healthChecks;
private readonly IHealthCheckGroupWithResultViewModelFactory _healthCheckGroupWithResultViewModelFactory;
public ByNameWithResultHealthCheckGroupController(
HealthCheckCollection healthChecks,
IHealthCheckGroupWithResultViewModelFactory healthCheckGroupWithResultViewModelFactory)
{
_healthChecks = healthChecks;
_healthCheckGroupWithResultViewModelFactory = healthCheckGroupWithResultViewModelFactory;
}
/// <summary>
/// Gets a health check group with all its health checks by a group name.
/// </summary>
/// <param name="name">The name of the group.</param>
/// <remarks>The health check result(s) will be included as part of the health checks.</remarks>
/// <returns>The health check group or not found result.</returns>
[HttpGet("{name}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(NotFoundResult), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(HealthCheckGroupWithResultViewModel), StatusCodes.Status200OK)]
public async Task<ActionResult<HealthCheckGroupWithResultViewModel>> ByName(string name)
{
IEnumerable<IGrouping<string?, Core.HealthChecks.HealthCheck>> groups = _healthCheckGroupWithResultViewModelFactory
.CreateGroupingFromHealthCheckCollection(_healthChecks);
IGrouping<string?, Core.HealthChecks.HealthCheck>? group = groups.FirstOrDefault(x => x.Key.InvariantEquals(name.Trim()));
if (group is null)
{
return await Task.FromResult(NotFound());
}
return await Task.FromResult(Ok(_healthCheckGroupWithResultViewModelFactory.CreateHealthCheckGroupWithResultViewModel(group)));
}
}

View File

@@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Routing;
using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Api.Management.Controllers.HealthCheck.Group;
[ApiController]
[VersionedApiBackOfficeRoute($"{Constants.HealthChecks.RoutePath.HealthCheck}-group")]
[ApiExplorerSettings(GroupName = "Health Check")]
[ApiVersion("1.0")]
public abstract class HealthCheckGroupControllerBase : ManagementApiControllerBase
{
}

View File

@@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Routing;
using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Api.Management.Controllers.HealthCheck;
[ApiController]
[VersionedApiBackOfficeRoute($"{Constants.HealthChecks.RoutePath.HealthCheck}")]
[ApiExplorerSettings(GroupName = "Health Check")]
[ApiVersion("1.0")]
public abstract class HealthCheckControllerBase : ManagementApiControllerBase
{
}

View File

@@ -1,4 +1,4 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.New.Cms.Core.Factories;
@@ -9,11 +9,13 @@ public static class FactoryBuilderExtensions
{
internal static IUmbracoBuilder AddFactories(this IUmbracoBuilder builder)
{
builder.Services.AddTransient<IModelsBuilderViewModelFactory, ModelsBuilderViewModelFactory>();
builder.Services.AddTransient<IRelationViewModelFactory, RelationViewModelFactory>();
builder.Services.AddTransient<IDictionaryFactory, DictionaryFactory>();
builder.Services.AddTransient<IHealthCheckGroupWithResultViewModelFactory, HealthCheckGroupWithResultViewModelFactory>();
builder.Services.AddTransient<IModelsBuilderViewModelFactory, ModelsBuilderViewModelFactory>();
builder.Services.AddTransient<IRedirectUrlStatusViewModelFactory, RedirectUrlStatusViewModelFactory>();
builder.Services.AddTransient<IRedirectUrlViewModelFactory, RedirectUrlViewModelFactory>();
builder.Services.AddTransient<IRelationViewModelFactory, RelationViewModelFactory>();
return builder;
}
}

View File

@@ -1,7 +1,8 @@
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Api.Management.Mapping.Culture;
using Umbraco.Cms.Api.Management.Mapping.Dictionary;
using Umbraco.Cms.Api.Management.Mapping.HealthCheck;
using Umbraco.Cms.Api.Management.Mapping.Installer;
using Umbraco.Cms.Api.Management.Mapping.Languages;
using Umbraco.Cms.Api.Management.Mapping.Relation;
@@ -21,7 +22,8 @@ public static class MappingBuilderExtensions
.Add<RelationViewModelsMapDefinition>()
.Add<LanguageViewModelsMapDefinition>()
.Add<InstallerViewModelsMapDefinition>()
.Add<CultureViewModelMapDefinition>();
.Add<CultureViewModelMapDefinition>()
.Add<HealthCheckViewModelsMapDefinition>();
return builder;
}

View File

@@ -0,0 +1,74 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.HealthChecks;
using Umbraco.Cms.Core.Mapping;
namespace Umbraco.Cms.Api.Management.Factories;
public class HealthCheckGroupWithResultViewModelFactory : IHealthCheckGroupWithResultViewModelFactory
{
private readonly HealthChecksSettings _healthChecksSettings;
private readonly ILogger<IHealthCheckGroupWithResultViewModelFactory> _logger;
private readonly IUmbracoMapper _umbracoMapper;
public HealthCheckGroupWithResultViewModelFactory(
IOptions<HealthChecksSettings> healthChecksSettings,
ILogger<IHealthCheckGroupWithResultViewModelFactory> logger,
IUmbracoMapper umbracoMapper)
{
_healthChecksSettings = healthChecksSettings.Value;
_logger = logger;
_umbracoMapper = umbracoMapper;
}
public IEnumerable<IGrouping<string?, HealthCheck>> CreateGroupingFromHealthCheckCollection(HealthCheckCollection healthChecks)
{
IList<Guid> disabledCheckIds = _healthChecksSettings.DisabledChecks
.Select(x => x.Id)
.ToList();
IEnumerable<IGrouping<string?, HealthCheck>> groups = healthChecks
.Where(x => disabledCheckIds.Contains(x.Id) == false)
.GroupBy(x => x.Group)
.OrderBy(x => x.Key);
return groups;
}
public HealthCheckGroupWithResultViewModel CreateHealthCheckGroupWithResultViewModel(IGrouping<string?, HealthCheck> healthCheckGroup)
{
var healthChecks = new List<HealthCheckWithResultViewModel>();
foreach (HealthCheck healthCheck in healthCheckGroup)
{
healthChecks.Add(CreateHealthCheckWithResultViewModel(healthCheck));
}
var healthCheckGroupViewModel = new HealthCheckGroupWithResultViewModel
{
Name = healthCheckGroup.Key,
Checks = healthChecks
};
return healthCheckGroupViewModel;
}
public HealthCheckWithResultViewModel CreateHealthCheckWithResultViewModel(HealthCheck healthCheck)
{
_logger.LogDebug("Running health check: " + healthCheck.Name);
IEnumerable<HealthCheckStatus> results = healthCheck.GetStatus().Result;
var healthCheckViewModel = new HealthCheckWithResultViewModel
{
Key = healthCheck.Id,
Name = healthCheck.Name,
Description = healthCheck.Description,
Results = _umbracoMapper.MapEnumerable<HealthCheckStatus, HealthCheckResultViewModel>(results)
};
return healthCheckViewModel;
}
}

View File

@@ -0,0 +1,13 @@
using Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
using Umbraco.Cms.Core.HealthChecks;
namespace Umbraco.Cms.Api.Management.Factories;
public interface IHealthCheckGroupWithResultViewModelFactory
{
IEnumerable<IGrouping<string?, HealthCheck>> CreateGroupingFromHealthCheckCollection(HealthCheckCollection healthChecks);
HealthCheckGroupWithResultViewModel CreateHealthCheckGroupWithResultViewModel(IGrouping<string?, HealthCheck> healthCheckGroup);
HealthCheckWithResultViewModel CreateHealthCheckWithResultViewModel(HealthCheck healthCheck);
}

View File

@@ -0,0 +1,80 @@
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
using Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
using Umbraco.Cms.Core.HealthChecks;
using Umbraco.Cms.Core.Mapping;
namespace Umbraco.Cms.Api.Management.Mapping.HealthCheck;
public class HealthCheckViewModelsMapDefinition : IMapDefinition
{
public void DefineMaps(IUmbracoMapper mapper)
{
mapper.Define<HealthCheckActionViewModel, HealthCheckAction>((source, context) => new HealthCheckAction(), Map);
mapper.Define<HealthCheckAction, HealthCheckActionViewModel>((source, context) => new HealthCheckActionViewModel() { ValueRequired = false }, Map);
mapper.Define<HealthCheckStatus, HealthCheckResultViewModel>((source, context) => new HealthCheckResultViewModel() { Message = string.Empty }, Map);
mapper.Define<Core.HealthChecks.HealthCheck, HealthCheckViewModel>((source, context) => new HealthCheckViewModel() { Name = string.Empty }, Map);
mapper.Define<IGrouping<string?, Core.HealthChecks.HealthCheck>, HealthCheckGroupViewModel>((source, context) => new HealthCheckGroupViewModel() { Checks = new List<HealthCheckViewModel>() }, Map);
mapper.Define<IEnumerable<IGrouping<string?, Core.HealthChecks.HealthCheck>>, PagedViewModel<HealthCheckGroupViewModel>>((source, context) => new PagedViewModel<HealthCheckGroupViewModel>(), Map);
}
// Umbraco.Code.MapAll -ActionParameters
private static void Map(HealthCheckActionViewModel source, HealthCheckAction target, MapperContext context)
{
target.Alias = source.Alias;
target.HealthCheckId = source.HealthCheckKey;
target.Name = source.Name;
target.Description = source.Description;
target.ValueRequired = source.ValueRequired;
target.ProvidedValueValidation = source.ProvidedValueValidation;
target.ProvidedValueValidationRegex = source.ProvidedValueValidationRegex;
target.ProvidedValue = source.ProvidedValue;
}
// Umbraco.Code.MapAll
private static void Map(HealthCheckAction source, HealthCheckActionViewModel target, MapperContext context)
{
if (source.HealthCheckId is not null)
{
target.HealthCheckKey = (Guid)source.HealthCheckId;
}
target.Alias = source.Alias;
target.Name = source.Name;
target.Description = source.Description;
target.ValueRequired = source.ValueRequired;
target.ProvidedValue = source.ProvidedValue;
target.ProvidedValueValidation = source.ProvidedValueValidation;
target.ProvidedValueValidationRegex = source.ProvidedValueValidationRegex;
}
// Umbraco.Code.MapAll
private static void Map(HealthCheckStatus source, HealthCheckResultViewModel target, MapperContext context)
{
target.Message = source.Message;
target.ResultType = source.ResultType;
target.ReadMoreLink = source.ReadMoreLink;
target.Actions = context.MapEnumerable<HealthCheckAction, HealthCheckActionViewModel>(source.Actions);
}
// Umbraco.Code.MapAll
private static void Map(Core.HealthChecks.HealthCheck source, HealthCheckViewModel target, MapperContext context)
{
target.Key = source.Id;
target.Name = source.Name;
target.Description = source.Description;
}
// Umbraco.Code.MapAll
private static void Map(IGrouping<string?, Core.HealthChecks.HealthCheck> source, HealthCheckGroupViewModel target, MapperContext context)
{
target.Name = source.Key;
target.Checks = context.MapEnumerable<Core.HealthChecks.HealthCheck, HealthCheckViewModel>(source.OrderBy(x => x.Name));
}
// Umbraco.Code.MapAll
private static void Map(IEnumerable<IGrouping<string?, Core.HealthChecks.HealthCheck>> source, PagedViewModel<HealthCheckGroupViewModel> target, MapperContext context)
{
target.Items = context.MapEnumerable<IGrouping<string?, Core.HealthChecks.HealthCheck>, HealthCheckGroupViewModel>(source);
target.Total = source.Count();
}
}

View File

@@ -1,4 +1,4 @@
using NPoco.FluentMappings;
using NPoco.FluentMappings;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Api.Management.ViewModels.Language;
@@ -50,16 +50,6 @@ public class LanguageViewModelsMapDefinition : IMapDefinition
private static void Map(PagedModel<ILanguage> source, PagedViewModel<LanguageViewModel> target, MapperContext context)
{
if (target is null)
{
throw new ArgumentNullException(nameof(target));
}
if (target is not PagedViewModel<LanguageViewModel> list)
{
throw new NotSupportedException($"{nameof(target)} must be a List<Language>.");
}
List<LanguageViewModel> temp = context.MapEnumerable<ILanguage, LanguageViewModel>(source.Items);
// Put the default language first in the list & then sort rest by a-z
@@ -74,7 +64,7 @@ public class LanguageViewModelsMapDefinition : IMapDefinition
languages.AddRange(temp.Where(x => x != defaultLang).OrderBy(x => x.Name));
}
list.Items = languages;
list.Total = source.Total;
target.Items = languages;
target.Total = source.Total;
}
}

View File

@@ -489,9 +489,7 @@
],
"operationId": "PostDictionaryUpload",
"requestBody": {
"content": {
}
"content": {}
},
"responses": {
"200": {
@@ -892,16 +890,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedRecycleBinItem"
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
@@ -911,6 +899,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedRecycleBinItem"
}
}
}
}
}
}
@@ -942,16 +940,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedRecycleBinItem"
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
@@ -961,6 +949,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedRecycleBinItem"
}
}
}
}
}
}
@@ -1134,6 +1132,125 @@
}
}
},
"/umbraco/management/api/v1/health-check-group": {
"get": {
"tags": [
"Health Check"
],
"operationId": "GetHealthCheckGroup",
"parameters": [
{
"name": "skip",
"in": "query",
"schema": {
"type": "integer",
"format": "int32",
"default": 0
}
},
{
"name": "take",
"in": "query",
"schema": {
"type": "integer",
"format": "int32",
"default": 100
}
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedHealthCheckGroup"
}
}
}
}
}
}
},
"/umbraco/management/api/v1/health-check-group/{name}": {
"get": {
"tags": [
"Health Check"
],
"operationId": "GetHealthCheckGroupByName",
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NotFoundResult"
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HealthCheckGroupWithResult"
}
}
}
}
}
}
},
"/umbraco/management/api/v1/health-check/execute-action": {
"post": {
"tags": [
"Health Check"
],
"operationId": "PostHealthCheckExecuteAction",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HealthCheckAction"
}
}
}
},
"responses": {
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HealthCheckResult"
}
}
}
}
}
}
},
"/umbraco/management/api/v1/help": {
"get": {
"tags": [
@@ -1181,16 +1298,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedHelpPage"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
@@ -1200,6 +1307,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedHelpPage"
}
}
}
}
}
}
@@ -1259,16 +1376,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Index"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
@@ -1278,6 +1385,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Index"
}
}
}
}
}
}
@@ -1299,16 +1416,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OkResult"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
@@ -1318,6 +1425,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OkResult"
}
}
}
}
}
}
@@ -1329,16 +1446,6 @@
],
"operationId": "GetInstallSettings",
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InstallSettings"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
@@ -1358,6 +1465,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InstallSettings"
}
}
}
}
}
}
@@ -1378,9 +1495,6 @@
}
},
"responses": {
"200": {
"description": "Success"
},
"400": {
"description": "Bad Request",
"content": {
@@ -1400,6 +1514,9 @@
}
}
}
},
"200": {
"description": "Success"
}
}
}
@@ -1420,9 +1537,6 @@
}
},
"responses": {
"200": {
"description": "Success"
},
"400": {
"description": "Bad Request",
"content": {
@@ -1432,6 +1546,9 @@
}
}
}
},
"200": {
"description": "Success"
}
}
}
@@ -1452,9 +1569,6 @@
}
},
"responses": {
"201": {
"description": "Created"
},
"400": {
"description": "Bad Request",
"content": {
@@ -1464,6 +1578,9 @@
}
}
}
},
"201": {
"description": "Created"
}
}
},
@@ -1522,16 +1639,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Language"
}
}
}
},
"404": {
"description": "Not Found",
"content": {
@@ -1541,6 +1648,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Language"
}
}
}
}
}
},
@@ -1561,9 +1678,6 @@
}
],
"responses": {
"200": {
"description": "Success"
},
"400": {
"description": "Bad Request",
"content": {
@@ -1583,6 +1697,9 @@
}
}
}
},
"200": {
"description": "Success"
}
}
},
@@ -1612,8 +1729,15 @@
}
},
"responses": {
"200": {
"description": "Success"
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NotFoundResult"
}
}
}
},
"400": {
"description": "Bad Request",
@@ -1625,15 +1749,8 @@
}
}
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NotFoundResult"
}
}
}
"200": {
"description": "Success"
}
}
}
@@ -1813,16 +1930,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedRecycleBinItem"
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
@@ -1832,6 +1939,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedRecycleBinItem"
}
}
}
}
}
}
@@ -1863,16 +1980,6 @@
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedRecycleBinItem"
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
@@ -1882,6 +1989,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedRecycleBinItem"
}
}
}
}
}
}
@@ -2489,6 +2606,16 @@
}
],
"responses": {
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
},
"200": {
"description": "Success",
"content": {
@@ -3037,16 +3164,6 @@
],
"operationId": "GetServerStatus",
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ServerStatus"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
@@ -3056,6 +3173,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ServerStatus"
}
}
}
}
}
}
@@ -3067,16 +3194,6 @@
],
"operationId": "GetServerVersion",
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Version"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
@@ -3086,6 +3203,16 @@
}
}
}
},
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Version"
}
}
}
}
}
}
@@ -3406,9 +3533,6 @@
}
},
"responses": {
"200": {
"description": "Success"
},
"400": {
"description": "Bad Request",
"content": {
@@ -3418,6 +3542,9 @@
}
}
}
},
"200": {
"description": "Success"
}
}
}
@@ -4984,6 +5111,144 @@
"type": "integer",
"format": "int32"
},
"HealthCheck": {
"type": "object",
"properties": {
"key": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"HealthCheckAction": {
"type": "object",
"properties": {
"healthCheckKey": {
"type": "string",
"format": "uuid"
},
"alias": {
"type": "string",
"nullable": true
},
"name": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
},
"valueRequired": {
"type": "boolean"
},
"providedValue": {
"type": "string",
"nullable": true
},
"providedValueValidation": {
"type": "string",
"nullable": true
},
"providedValueValidationRegex": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"HealthCheckGroup": {
"type": "object",
"properties": {
"name": {
"type": "string",
"nullable": true
},
"checks": {
"type": "array",
"items": {
"$ref": "#/components/schemas/HealthCheck"
},
"nullable": true
}
},
"additionalProperties": false
},
"HealthCheckGroupWithResult": {
"type": "object",
"properties": {
"name": {
"type": "string",
"nullable": true
},
"checks": {
"type": "array",
"items": {
"$ref": "#/components/schemas/HealthCheckWithResult"
},
"nullable": true
}
},
"additionalProperties": false
},
"HealthCheckResult": {
"type": "object",
"properties": {
"message": {
"type": "string",
"nullable": true
},
"resultType": {
"$ref": "#/components/schemas/StatusResultType"
},
"actions": {
"type": "array",
"items": {
"$ref": "#/components/schemas/HealthCheckAction"
},
"nullable": true
},
"readMoreLink": {
"type": "string",
"nullable": true
}
},
"additionalProperties": false
},
"HealthCheckWithResult": {
"type": "object",
"properties": {
"key": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string",
"nullable": true
},
"description": {
"type": "string",
"nullable": true
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/HealthCheckResult"
},
"nullable": true
}
},
"additionalProperties": false
},
"HelpPage": {
"type": "object",
"properties": {
@@ -5053,9 +5318,7 @@
},
"providerProperties": {
"type": "object",
"additionalProperties": {
},
"additionalProperties": {},
"nullable": true
}
},
@@ -5869,6 +6132,26 @@
},
"additionalProperties": false
},
"PagedHealthCheckGroup": {
"required": [
"items",
"total"
],
"type": "object",
"properties": {
"total": {
"type": "integer",
"format": "int64"
},
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/HealthCheckGroup"
}
}
},
"additionalProperties": false
},
"PagedHelpPage": {
"required": [
"items",
@@ -6181,9 +6464,7 @@
"nullable": true
}
},
"additionalProperties": {
}
"additionalProperties": {}
},
"ProfilingStatus": {
"type": "object",
@@ -6518,6 +6799,16 @@
},
"additionalProperties": false
},
"StatusResultType": {
"enum": [
"Success",
"Warning",
"Error",
"Info"
],
"type": "integer",
"format": "int32"
},
"StructLayoutAttribute": {
"type": "object",
"properties": {
@@ -7339,9 +7630,7 @@
"authorizationCode": {
"authorizationUrl": "/umbraco/management/api/v1.0/security/back-office/authorize",
"tokenUrl": "/umbraco/management/api/v1.0/security/back-office/token",
"scopes": {
}
"scopes": {}
}
}
}
@@ -7349,9 +7638,7 @@
},
"security": [
{
"OAuth": [
]
"OAuth": []
}
]
}

View File

@@ -0,0 +1,50 @@
namespace Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
public class HealthCheckActionViewModel
{
/// <summary>
/// Gets or sets the health check key.
/// </summary>
public Guid HealthCheckKey { get; set; }
/// <summary>
/// Gets or sets the alias.
/// </summary>
/// <remarks>
/// It is used by the Health Check instance to execute the action.
/// </remarks>
public string? Alias { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <remarks>
/// It is used to name the "Fix" button.
/// </remarks>
public string? Name { get; set; }
/// <summary>
/// Gets or sets the description.
/// </summary>
public string? Description { get; set; }
/// <summary>
/// Gets or sets a value indicating whether a value is required to rectify the issue.
/// </summary>
public required bool ValueRequired { get; set; }
/// <summary>
/// Gets or sets the value to rectify the issue.
/// </summary>
public string? ProvidedValue { get; set; }
/// <summary>
/// Gets or sets how the provided value is validated.
/// </summary>
public string? ProvidedValueValidation { get; set; }
/// <summary>
/// Gets or sets the regex to use when validating the provided value (if the value can be validated by a regex).
/// </summary>
public string? ProvidedValueValidationRegex { get; set; }
}

View File

@@ -0,0 +1,14 @@
namespace Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
public class HealthCheckGroupViewModel
{
/// <summary>
/// Gets or sets the name.
/// </summary>
public string? Name { get; set; }
/// <summary>
/// Gets or sets the health checks.
/// </summary>
public required List<HealthCheckViewModel> Checks { get; set; }
}

View File

@@ -0,0 +1,14 @@
namespace Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
public class HealthCheckGroupWithResultViewModel
{
/// <summary>
/// Gets or sets the name.
/// </summary>
public string? Name { get; set; }
/// <summary>
/// Gets or sets the health checks with the result(s) from each health check.
/// </summary>
public required List<HealthCheckWithResultViewModel> Checks { get; set; }
}

View File

@@ -0,0 +1,26 @@
using Umbraco.Cms.Core.HealthChecks;
namespace Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
public class HealthCheckResultViewModel
{
/// <summary>
/// Gets or sets the status message.
/// </summary>
public required string Message { get; set; }
/// <summary>
/// Gets or sets the status type.
/// </summary>
public StatusResultType ResultType { get; set; }
/// <summary>
/// Gets or sets the potential actions to take (if any).
/// </summary>
public IEnumerable<HealthCheckActionViewModel>? Actions { get; set; }
/// <summary>
/// This is optional but would allow a developer to get or set a link that is shown as a "Read more" button.
/// </summary>
public string? ReadMoreLink { get; set; }
}

View File

@@ -0,0 +1,19 @@
namespace Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
public class HealthCheckViewModel
{
/// <summary>
/// Gets or sets the key.
/// </summary>
public Guid Key { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
public required string Name { get; set; }
/// <summary>
/// Gets or sets the description.
/// </summary>
public string? Description { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace Umbraco.Cms.Api.Management.ViewModels.HealthCheck;
public class HealthCheckWithResultViewModel : HealthCheckViewModel
{
/// <summary>
/// Gets or sets the result(s) for a health check.
/// There can be several.
/// </summary>
public List<HealthCheckResultViewModel>? Results { get; set; }
}

View File

@@ -10,6 +10,11 @@ public static partial class Constants
/// </summary>
public static class HealthChecks
{
public static class RoutePath
{
public const string HealthCheck = "health-check";
}
public static class DocumentationLinks
{
public const string SmtpCheck = "https://umbra.co/healthchecks-smtp";