From 3d3f6b5021242c2253fba7db924e0b97b6f95bdc Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Wed, 11 Sep 2024 17:08:50 +0200 Subject: [PATCH] Add endpoint for upgrade checks (#17026) * Fix upgrade check repo, so it's able to check more than once :) * Add VersionCheckPeriod to server configuration output * Add upgrade check endpoint * Obsolete unused response model * Update OpenAPI JSON --- .../Server/ConfigurationServerController.cs | 17 ++++- .../Server/UpgradeCheckServerController.cs | 45 +++++++++++++ src/Umbraco.Cms.Api.Management/OpenApi.json | 64 ++++++++++++++++++- .../ServerConfigurationResponseModel.cs | 2 + .../Server/UpgradeCheckResponseModel.cs | 10 +++ .../ViewModels/Server/VersionResponseModel.cs | 1 + .../Repositories/UpgradeCheckRepository.cs | 6 +- 7 files changed, 137 insertions(+), 8 deletions(-) create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/Server/UpgradeCheckServerController.cs create mode 100644 src/Umbraco.Cms.Api.Management/ViewModels/Server/UpgradeCheckResponseModel.cs diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Server/ConfigurationServerController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Server/ConfigurationServerController.cs index 1107f499af..048ed55206 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Server/ConfigurationServerController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Server/ConfigurationServerController.cs @@ -1,9 +1,11 @@ using Asp.Versioning; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Api.Management.ViewModels.Server; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; namespace Umbraco.Cms.Api.Management.Controllers.Server; @@ -11,8 +13,20 @@ namespace Umbraco.Cms.Api.Management.Controllers.Server; public class ConfigurationServerController : ServerControllerBase { private readonly SecuritySettings _securitySettings; + private readonly GlobalSettings _globalSettings; - public ConfigurationServerController(IOptions securitySettings) => _securitySettings = securitySettings.Value; + [Obsolete("Use the constructor that accepts all arguments. Will be removed in V16.")] + public ConfigurationServerController(IOptions securitySettings) + : this(securitySettings, StaticServiceProvider.Instance.GetRequiredService>()) + { + } + + [ActivatorUtilitiesConstructor] + public ConfigurationServerController(IOptions securitySettings, IOptions globalSettings) + { + _securitySettings = securitySettings.Value; + _globalSettings = globalSettings.Value; + } [HttpGet("configuration")] [MapToApiVersion("1.0")] @@ -22,6 +36,7 @@ public class ConfigurationServerController : ServerControllerBase var responseModel = new ServerConfigurationResponseModel { AllowPasswordReset = _securitySettings.AllowPasswordReset, + VersionCheckPeriod = _globalSettings.VersionCheckPeriod }; return Task.FromResult(Ok(responseModel)); diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Server/UpgradeCheckServerController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Server/UpgradeCheckServerController.cs new file mode 100644 index 0000000000..10a3894457 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Server/UpgradeCheckServerController.cs @@ -0,0 +1,45 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.ViewModels.Server; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Configuration; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Web.Common.Authorization; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Api.Management.Controllers.Server; + +[ApiVersion("1.0")] +[Authorize(Policy = AuthorizationPolicies.RequireAdminAccess)] +public class UpgradeCheckServerController : ServerControllerBase +{ + private readonly IUpgradeService _upgradeService; + private readonly IUmbracoVersion _umbracoVersion; + + public UpgradeCheckServerController(IUpgradeService upgradeService, IUmbracoVersion umbracoVersion) + { + _upgradeService = upgradeService; + _umbracoVersion = umbracoVersion; + } + + [HttpGet("upgrade-check")] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(UpgradeCheckResponseModel), StatusCodes.Status200OK)] + public async Task UpgradeCheck(CancellationToken cancellationToken) + { + UpgradeResult upgradeResult = await _upgradeService.CheckUpgrade(_umbracoVersion.SemanticVersion); + + var responseModel = new UpgradeCheckResponseModel + { + Type = upgradeResult.UpgradeType, + Comment = upgradeResult.Comment, + Url = upgradeResult.UpgradeUrl.IsNullOrWhiteSpace() + ? string.Empty + : $"{upgradeResult.UpgradeUrl}?version={_umbracoVersion.Version.ToString(3)}" + }; + + return Ok(responseModel); + } +} diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index 62bf741f9b..e5e2f04d42 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -25176,6 +25176,41 @@ ] } }, + "/umbraco/management/api/v1/server/upgrade-check": { + "get": { + "tags": [ + "Server" + ], + "operationId": "GetServerUpgradeCheck", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/UpgradeCheckResponseModel" + } + ] + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user do not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/item/static-file": { "get": { "tags": [ @@ -42446,12 +42481,17 @@ }, "ServerConfigurationResponseModel": { "required": [ - "allowPasswordReset" + "allowPasswordReset", + "versionCheckPeriod" ], "type": "object", "properties": { "allowPasswordReset": { "type": "boolean" + }, + "versionCheckPeriod": { + "type": "integer", + "format": "int32" } }, "additionalProperties": false @@ -44514,6 +44554,26 @@ }, "additionalProperties": false }, + "UpgradeCheckResponseModel": { + "required": [ + "comment", + "type", + "url" + ], + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "comment": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false + }, "UpgradeSettingsResponseModel": { "required": [ "currentState", @@ -45275,4 +45335,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Server/ServerConfigurationResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Server/ServerConfigurationResponseModel.cs index f759cdca32..a424a24798 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Server/ServerConfigurationResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Server/ServerConfigurationResponseModel.cs @@ -3,4 +3,6 @@ public class ServerConfigurationResponseModel { public bool AllowPasswordReset { get; set; } + + public int VersionCheckPeriod { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Server/UpgradeCheckResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Server/UpgradeCheckResponseModel.cs new file mode 100644 index 0000000000..0c84f0a837 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Server/UpgradeCheckResponseModel.cs @@ -0,0 +1,10 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.Server; + +public class UpgradeCheckResponseModel +{ + public required string Type { get; init; } + + public required string Comment { get; init; } + + public required string Url { get; init; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Server/VersionResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Server/VersionResponseModel.cs index f53e8f17d0..d421d99095 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Server/VersionResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Server/VersionResponseModel.cs @@ -2,6 +2,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Server; +[Obsolete("Not used. Will be removed in V15.")] public class VersionResponseModel { [Required] diff --git a/src/Umbraco.Core/Persistence/Repositories/UpgradeCheckRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UpgradeCheckRepository.cs index 9cf0d52251..e6190b049a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/UpgradeCheckRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/UpgradeCheckRepository.cs @@ -16,14 +16,10 @@ public class UpgradeCheckRepository : IUpgradeCheckRepository { try { - if (_httpClient == null) - { - _httpClient = new HttpClient(); - } + _httpClient ??= new HttpClient { Timeout = TimeSpan.FromSeconds(1) }; using var content = new StringContent(_jsonSerializer.Serialize(new CheckUpgradeDto(version)), Encoding.UTF8, "application/json"); - _httpClient.Timeout = TimeSpan.FromSeconds(1); using HttpResponseMessage task = await _httpClient.PostAsync(RestApiUpgradeChecklUrl, content); var json = await task.Content.ReadAsStringAsync(); UpgradeResult? result = _jsonSerializer.Deserialize(json);