From 0b04ae76da059e687710274ad46b8367cfd7a448 Mon Sep 17 00:00:00 2001 From: Mole Date: Thu, 15 Dec 2022 10:04:44 +0100 Subject: [PATCH] New backoffice: Redirect Url Management controller (#13572) * Add status endpoint * Refactor GetStatus to use a factory for the viewmodel * Move controllers to correct namespace * Add response type to GetStatus * Create query endpoint * Create GetAll endpoint * Add by key * Add delete by key * Rename enabled controller * Add SetEnabled endpoint * Update OpenApi.json * Replace query endpoint with a optional filter parameter * Use enum to enabled and disable url tracking * Update OpenApi.json * Add bad request response type to GetAll endpoint --- .../ByKeyRedirectUrlManagementController.cs | 38 ++ ...eteByKeyRedirectUrlManagementController.cs | 23 + .../GetAllRedirectUrlManagementController.cs | 43 ++ ...etStatusRedirectUrlManagementController.cs | 19 + .../RedirectUrlManagementBaseController.cs | 13 + ...etStatusRedirectUrlManagementController.cs | 53 ++ .../FactoryBuilderExtensions.cs | 2 + .../IRedirectUrlStatusViewModelFactory.cs | 8 + .../Factories/IRedirectUrlViewModelFactory.cs | 11 + .../RedirectUrlStatusViewModelFactory.cs | 38 ++ .../Factories/RedirectUrlViewModelFactory.cs | 42 ++ src/Umbraco.Cms.Api.Management/OpenApi.json | 516 +++++++++++++----- .../RedirectUrlStatusViewModel.cs | 10 + .../RedirectUrlViewModel.cs | 16 + .../ContentEditing/ContentRedirectUrl.cs | 1 + .../Mapping/RedirectUrlMapDefinition.cs | 1 + .../RedirectUrlManagement/RedirectStatus.cs | 7 + 17 files changed, 700 insertions(+), 141 deletions(-) create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/ByKeyRedirectUrlManagementController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/DeleteByKeyRedirectUrlManagementController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetAllRedirectUrlManagementController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetStatusRedirectUrlManagementController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/RedirectUrlManagementBaseController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/SetStatusRedirectUrlManagementController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Factories/IRedirectUrlStatusViewModelFactory.cs create mode 100644 src/Umbraco.Cms.Api.Management/Factories/IRedirectUrlViewModelFactory.cs create mode 100644 src/Umbraco.Cms.Api.Management/Factories/RedirectUrlStatusViewModelFactory.cs create mode 100644 src/Umbraco.Cms.Api.Management/Factories/RedirectUrlViewModelFactory.cs create mode 100644 src/Umbraco.Cms.Api.Management/ViewModels/RedirectUrlManagement/RedirectUrlStatusViewModel.cs create mode 100644 src/Umbraco.Cms.Api.Management/ViewModels/RedirectUrlManagement/RedirectUrlViewModel.cs create mode 100644 src/Umbraco.New.Cms.Core/Models/RedirectUrlManagement/RedirectStatus.cs diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/ByKeyRedirectUrlManagementController.cs b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/ByKeyRedirectUrlManagementController.cs new file mode 100644 index 0000000000..57e7f17df3 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/ByKeyRedirectUrlManagementController.cs @@ -0,0 +1,38 @@ +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.RedirectUrlManagement; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Controllers.RedirectUrlManagement; + +public class ByKeyRedirectUrlManagementController : RedirectUrlManagementBaseController +{ + private readonly IRedirectUrlService _redirectUrlService; + private readonly IRedirectUrlViewModelFactory _redirectUrlViewModelFactory; + + public ByKeyRedirectUrlManagementController( + IRedirectUrlService redirectUrlService, + IRedirectUrlViewModelFactory redirectUrlViewModelFactory) + { + _redirectUrlService = redirectUrlService; + _redirectUrlViewModelFactory = redirectUrlViewModelFactory; + } + + [HttpGet("{key:guid}")] + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public Task>> ByKey(Guid key, int skip, int take) + { + IRedirectUrl[] redirects = _redirectUrlService.GetContentRedirectUrls(key).ToArray(); + + IEnumerable viewModels = _redirectUrlViewModelFactory.CreateMany(redirects); + + return Task.FromResult>>(new PagedViewModel + { + Items = viewModels.Skip(skip).Take(take), + Total = redirects.Length, + }); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/DeleteByKeyRedirectUrlManagementController.cs b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/DeleteByKeyRedirectUrlManagementController.cs new file mode 100644 index 0000000000..fbab340a73 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/DeleteByKeyRedirectUrlManagementController.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Controllers.RedirectUrlManagement; + +public class DeleteByKeyRedirectUrlManagementController : RedirectUrlManagementBaseController +{ + private readonly IRedirectUrlService _redirectUrlService; + + public DeleteByKeyRedirectUrlManagementController(IRedirectUrlService redirectUrlService) + { + _redirectUrlService = redirectUrlService; + } + + [HttpDelete("{key:guid}")] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task DeleteByKey(Guid key) + { + _redirectUrlService.Delete(key); + return Ok(); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetAllRedirectUrlManagementController.cs b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetAllRedirectUrlManagementController.cs new file mode 100644 index 0000000000..8c375a416e --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetAllRedirectUrlManagementController.cs @@ -0,0 +1,43 @@ +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.Services.Paging; +using Umbraco.Cms.Api.Management.ViewModels.RedirectUrlManagement; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Controllers.RedirectUrlManagement; + +public class GetAllRedirectUrlManagementController : RedirectUrlManagementBaseController +{ + private readonly IRedirectUrlService _redirectUrlService; + private readonly IRedirectUrlViewModelFactory _redirectUrlViewModelFactory; + + public GetAllRedirectUrlManagementController( + IRedirectUrlService redirectUrlService, + IRedirectUrlViewModelFactory redirectUrlViewModelFactory) + { + _redirectUrlService = redirectUrlService; + _redirectUrlViewModelFactory = redirectUrlViewModelFactory; + } + + [HttpGet] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> GetAll(string? filter, int skip, int take) + { + if (PaginationService.ConvertSkipTakeToPaging(skip, take, out long pageNumber, out int pageSize, out ProblemDetails? error) is false) + { + return BadRequest(error); + } + + long total; + IEnumerable redirects = filter is null + ? _redirectUrlService.GetAllRedirectUrls(pageNumber, pageSize, out total) + : _redirectUrlService.SearchRedirectUrls(filter, pageNumber, pageSize, out total); + + IEnumerable redirectViewModels = _redirectUrlViewModelFactory.CreateMany(redirects); + return new PagedViewModel { Items = redirectViewModels, Total = total }; + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetStatusRedirectUrlManagementController.cs b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetStatusRedirectUrlManagementController.cs new file mode 100644 index 0000000000..779d95bc56 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetStatusRedirectUrlManagementController.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.Factories; +using Umbraco.Cms.Api.Management.ViewModels.RedirectUrlManagement; + +namespace Umbraco.Cms.Api.Management.Controllers.RedirectUrlManagement; + +public class GetStatusRedirectUrlManagementController : RedirectUrlManagementBaseController +{ + private readonly IRedirectUrlStatusViewModelFactory _redirectUrlStatusViewModelFactory; + + public GetStatusRedirectUrlManagementController( + IRedirectUrlStatusViewModelFactory redirectUrlStatusViewModelFactory) => + _redirectUrlStatusViewModelFactory = redirectUrlStatusViewModelFactory; + + [HttpGet("status")] + [ProducesResponseType(typeof(RedirectUrlStatusViewModel), 200)] + public Task> GetStatus() => + Task.FromResult>(_redirectUrlStatusViewModelFactory.CreateViewModel()); +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/RedirectUrlManagementBaseController.cs b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/RedirectUrlManagementBaseController.cs new file mode 100644 index 0000000000..0c8cc74822 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/RedirectUrlManagementBaseController.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.Routing; + +namespace Umbraco.Cms.Api.Management.Controllers.RedirectUrlManagement; + +[ApiController] +[VersionedApiBackOfficeRoute("redirect-management")] +[ApiExplorerSettings(GroupName = "Redirect Management")] +[ApiVersion("1.0")] +public class RedirectUrlManagementBaseController : ManagementApiControllerBase +{ + +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/SetStatusRedirectUrlManagementController.cs b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/SetStatusRedirectUrlManagementController.cs new file mode 100644 index 0000000000..d51e91a08d --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/SetStatusRedirectUrlManagementController.cs @@ -0,0 +1,53 @@ +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core.Configuration; +using Umbraco.Cms.Core.Security; +using Umbraco.New.Cms.Core.Models.RedirectUrlManagement; + +namespace Umbraco.Cms.Api.Management.Controllers.RedirectUrlManagement; + +public class SetStatusRedirectUrlManagementController : RedirectUrlManagementBaseController +{ + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; + private readonly IConfigManipulator _configManipulator; + + public SetStatusRedirectUrlManagementController( + IBackOfficeSecurityAccessor backOfficeSecurityAccessor, + IConfigManipulator configManipulator) + { + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; + _configManipulator = configManipulator; + } + + // TODO: Consider if we should even allow this, or only allow using the appsettings + // We generally don't want to edit the appsettings from our code. + // But maybe there is a valid use case for doing it on the fly. + [HttpPost("status")] + public async Task SetStatus([FromQuery] RedirectStatus status) + { + // TODO: uncomment this when auth is implemented. + // var userIsAdmin = _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.IsAdmin(); + // if (userIsAdmin is null or false) + // { + // return Unauthorized(); + // } + + var enable = status switch + { + RedirectStatus.Enabled => true, + RedirectStatus.Disabled => false + }; + + // For now I'm not gonna change this to limit breaking, but it's weird to have a "disabled" switch, + // since you're essentially negating the boolean from the get go, + // it's much easier to reason with enabled = false == disabled. + _configManipulator.SaveDisableRedirectUrlTracking(!enable); + + // Taken from the existing implementation in RedirectUrlManagementController + // TODO this is ridiculous, but we need to ensure the configuration is reloaded, before this request is ended. + // otherwise we can read the old value in GetEnableState. + // The value is equal to JsonConfigurationSource.ReloadDelay + Thread.Sleep(250); + + return Ok(); + } +} diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/FactoryBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/FactoryBuilderExtensions.cs index 08d35d57d4..834a1cab7b 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/FactoryBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/FactoryBuilderExtensions.cs @@ -12,6 +12,8 @@ public static class FactoryBuilderExtensions builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); return builder; } } diff --git a/src/Umbraco.Cms.Api.Management/Factories/IRedirectUrlStatusViewModelFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/IRedirectUrlStatusViewModelFactory.cs new file mode 100644 index 0000000000..95b5a2614a --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Factories/IRedirectUrlStatusViewModelFactory.cs @@ -0,0 +1,8 @@ +using Umbraco.Cms.Api.Management.ViewModels.RedirectUrlManagement; + +namespace Umbraco.Cms.Api.Management.Factories; + +public interface IRedirectUrlStatusViewModelFactory +{ + RedirectUrlStatusViewModel CreateViewModel(); +} diff --git a/src/Umbraco.Cms.Api.Management/Factories/IRedirectUrlViewModelFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/IRedirectUrlViewModelFactory.cs new file mode 100644 index 0000000000..9ce0eb4c27 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Factories/IRedirectUrlViewModelFactory.cs @@ -0,0 +1,11 @@ +using Umbraco.Cms.Api.Management.ViewModels.RedirectUrlManagement; +using Umbraco.Cms.Core.Models; + +namespace Umbraco.Cms.Api.Management.Factories; + +public interface IRedirectUrlViewModelFactory +{ + RedirectUrlViewModel Create(IRedirectUrl source); + + IEnumerable CreateMany(IEnumerable sources); +} diff --git a/src/Umbraco.Cms.Api.Management/Factories/RedirectUrlStatusViewModelFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/RedirectUrlStatusViewModelFactory.cs new file mode 100644 index 0000000000..1db6772e39 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Factories/RedirectUrlStatusViewModelFactory.cs @@ -0,0 +1,38 @@ +using Microsoft.Extensions.Options; +using Umbraco.Cms.Api.Management.ViewModels.RedirectUrlManagement; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Security; +using Umbraco.Extensions; +using Umbraco.New.Cms.Core.Models.RedirectUrlManagement; + +namespace Umbraco.Cms.Api.Management.Factories; + +public class RedirectUrlStatusViewModelFactory : IRedirectUrlStatusViewModelFactory +{ + private readonly IOptionsMonitor _webRoutingSettings; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; + + public RedirectUrlStatusViewModelFactory( + IOptionsMonitor webRoutingSettings, + IBackOfficeSecurityAccessor backOfficeSecurityAccessor) + { + _webRoutingSettings = webRoutingSettings; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; + } + + public RedirectUrlStatusViewModel CreateViewModel() + { + RedirectStatus status = _webRoutingSettings.CurrentValue.DisableRedirectUrlTracking switch + { + true => RedirectStatus.Disabled, + false => RedirectStatus.Enabled + }; + + return new RedirectUrlStatusViewModel + { + Status = status, + // TODO: Ensure that CurrentUser can be found when we use the new auth. + UserIsAdmin = _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.IsAdmin() ?? false, + }; + } +} diff --git a/src/Umbraco.Cms.Api.Management/Factories/RedirectUrlViewModelFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/RedirectUrlViewModelFactory.cs new file mode 100644 index 0000000000..b2da370586 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Factories/RedirectUrlViewModelFactory.cs @@ -0,0 +1,42 @@ +using Umbraco.Cms.Api.Management.ViewModels.RedirectUrlManagement; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Routing; + +namespace Umbraco.Cms.Api.Management.Factories; + +public class RedirectUrlViewModelFactory : IRedirectUrlViewModelFactory +{ + private readonly IPublishedUrlProvider _publishedUrlProvider; + + public RedirectUrlViewModelFactory(IPublishedUrlProvider publishedUrlProvider) + { + _publishedUrlProvider = publishedUrlProvider; + } + + public RedirectUrlViewModel Create(IRedirectUrl source) + { + var destinationUrl = source.ContentId > 0 + ? _publishedUrlProvider.GetUrl(source.ContentId, culture: source.Culture) + : "#"; + + var originalUrl = _publishedUrlProvider.GetUrlFromRoute(source.ContentId, source.Url, source.Culture); + + return new RedirectUrlViewModel + { + OriginalUrl = originalUrl, + DestinationUrl = destinationUrl, + ContentKey = source.ContentKey, + Created = source.CreateDateUtc, + Culture = source.Culture, + Key = source.Key, + }; + } + + public IEnumerable CreateMany(IEnumerable sources) + { + foreach (IRedirectUrl source in sources) + { + yield return Create(source); + } + } +} diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index e7d0038ea1..b59dce47d7 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -489,7 +489,9 @@ ], "operationId": "PostDictionaryUpload", "requestBody": { - "content": { } + "content": { + + } }, "responses": { "200": { @@ -890,16 +892,6 @@ } ], "responses": { - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, "200": { "description": "Success", "content": { @@ -909,6 +901,16 @@ } } } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } } } @@ -940,16 +942,6 @@ } ], "responses": { - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, "200": { "description": "Success", "content": { @@ -959,6 +951,16 @@ } } } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } } } @@ -1179,16 +1181,6 @@ } ], "responses": { - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, "200": { "description": "Success", "content": { @@ -1198,6 +1190,16 @@ } } } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } } } @@ -1257,16 +1259,6 @@ } ], "responses": { - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, "200": { "description": "Success", "content": { @@ -1276,6 +1268,16 @@ } } } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } } } @@ -1297,16 +1299,6 @@ } ], "responses": { - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, "200": { "description": "Success", "content": { @@ -1316,6 +1308,16 @@ } } } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } } } @@ -1327,6 +1329,16 @@ ], "operationId": "GetInstallSettings", "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallSettings" + } + } + } + }, "400": { "description": "Bad Request", "content": { @@ -1346,16 +1358,6 @@ } } } - }, - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InstallSettings" - } - } - } } } } @@ -1376,6 +1378,9 @@ } }, "responses": { + "200": { + "description": "Success" + }, "400": { "description": "Bad Request", "content": { @@ -1395,9 +1400,6 @@ } } } - }, - "200": { - "description": "Success" } } } @@ -1418,6 +1420,9 @@ } }, "responses": { + "200": { + "description": "Success" + }, "400": { "description": "Bad Request", "content": { @@ -1427,9 +1432,6 @@ } } } - }, - "200": { - "description": "Success" } } } @@ -1450,6 +1452,9 @@ } }, "responses": { + "201": { + "description": "Created" + }, "400": { "description": "Bad Request", "content": { @@ -1459,9 +1464,6 @@ } } } - }, - "201": { - "description": "Created" } } }, @@ -1520,16 +1522,6 @@ } ], "responses": { - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotFoundResult" - } - } - } - }, "200": { "description": "Success", "content": { @@ -1539,6 +1531,16 @@ } } } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundResult" + } + } + } } } }, @@ -1559,6 +1561,9 @@ } ], "responses": { + "200": { + "description": "Success" + }, "400": { "description": "Bad Request", "content": { @@ -1578,9 +1583,6 @@ } } } - }, - "200": { - "description": "Success" } } }, @@ -1610,15 +1612,8 @@ } }, "responses": { - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotFoundResult" - } - } - } + "200": { + "description": "Success" }, "400": { "description": "Bad Request", @@ -1630,8 +1625,15 @@ } } }, - "200": { - "description": "Success" + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundResult" + } + } + } } } } @@ -1811,16 +1813,6 @@ } ], "responses": { - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, "200": { "description": "Success", "content": { @@ -1830,6 +1822,16 @@ } } } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } } } @@ -1861,16 +1863,6 @@ } ], "responses": { - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, "200": { "description": "Success", "content": { @@ -1880,6 +1872,16 @@ } } } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } } } @@ -2455,6 +2457,160 @@ } } }, + "/umbraco/management/api/v1/redirect-management": { + "get": { + "tags": [ + "Redirect Management" + ], + "operationId": "GetRedirectManagement", + "parameters": [ + { + "name": "filter", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedRedirectUrl" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/redirect-management/{key}": { + "get": { + "tags": [ + "Redirect Management" + ], + "operationId": "GetRedirectManagementByKey", + "parameters": [ + { + "name": "key", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedRedirectUrl" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Redirect Management" + ], + "operationId": "DeleteRedirectManagementByKey", + "parameters": [ + { + "name": "key", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/umbraco/management/api/v1/redirect-management/status": { + "get": { + "tags": [ + "Redirect Management" + ], + "operationId": "GetRedirectManagementStatus", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RedirectUrlStatus" + } + } + } + } + } + }, + "post": { + "tags": [ + "Redirect Management" + ], + "operationId": "PostRedirectManagementStatus", + "parameters": [ + { + "name": "status", + "in": "query", + "schema": { + "$ref": "#/components/schemas/RedirectStatus" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, "/umbraco/management/api/v1/tree/relation-type/item": { "get": { "tags": [ @@ -2881,16 +3037,6 @@ ], "operationId": "GetServerStatus", "responses": { - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, "200": { "description": "Success", "content": { @@ -2900,6 +3046,16 @@ } } } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } } } @@ -2911,16 +3067,6 @@ ], "operationId": "GetServerVersion", "responses": { - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, "200": { "description": "Success", "content": { @@ -2930,6 +3076,16 @@ } } } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } } } @@ -3250,6 +3406,9 @@ } }, "responses": { + "200": { + "description": "Success" + }, "400": { "description": "Bad Request", "content": { @@ -3259,9 +3418,6 @@ } } } - }, - "200": { - "description": "Success" } } } @@ -4897,7 +5053,9 @@ }, "providerProperties": { "type": "object", - "additionalProperties": { }, + "additionalProperties": { + + }, "nullable": true } }, @@ -5791,6 +5949,26 @@ }, "additionalProperties": false }, + "PagedRedirectUrl": { + "required": [ + "items", + "total" + ], + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RedirectUrl" + } + } + }, + "additionalProperties": false + }, "PagedRelation": { "required": [ "items", @@ -6003,7 +6181,9 @@ "nullable": true } }, - "additionalProperties": { } + "additionalProperties": { + + } }, "ProfilingStatus": { "type": "object", @@ -6125,6 +6305,56 @@ }, "additionalProperties": false }, + "RedirectStatus": { + "enum": [ + "Enabled", + "Disabled" + ], + "type": "integer", + "format": "int32" + }, + "RedirectUrl": { + "type": "object", + "properties": { + "key": { + "type": "string", + "format": "uuid" + }, + "originalUrl": { + "type": "string", + "nullable": true + }, + "destinationUrl": { + "type": "string", + "nullable": true + }, + "created": { + "type": "string", + "format": "date-time" + }, + "contentKey": { + "type": "string", + "format": "uuid" + }, + "culture": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "RedirectUrlStatus": { + "type": "object", + "properties": { + "status": { + "$ref": "#/components/schemas/RedirectStatus" + }, + "userIsAdmin": { + "type": "boolean" + } + }, + "additionalProperties": false + }, "Relation": { "type": "object", "properties": { @@ -7109,7 +7339,9 @@ "authorizationCode": { "authorizationUrl": "/umbraco/management/api/v1.0/security/back-office/authorize", "tokenUrl": "/umbraco/management/api/v1.0/security/back-office/token", - "scopes": { } + "scopes": { + + } } } } @@ -7117,7 +7349,9 @@ }, "security": [ { - "OAuth": [ ] + "OAuth": [ + + ] } ] } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/RedirectUrlManagement/RedirectUrlStatusViewModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/RedirectUrlManagement/RedirectUrlStatusViewModel.cs new file mode 100644 index 0000000000..0efa0ef843 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/RedirectUrlManagement/RedirectUrlStatusViewModel.cs @@ -0,0 +1,10 @@ +using Umbraco.New.Cms.Core.Models.RedirectUrlManagement; + +namespace Umbraco.Cms.Api.Management.ViewModels.RedirectUrlManagement; + +public class RedirectUrlStatusViewModel +{ + public RedirectStatus Status { get; set; } + + public bool UserIsAdmin { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/RedirectUrlManagement/RedirectUrlViewModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/RedirectUrlManagement/RedirectUrlViewModel.cs new file mode 100644 index 0000000000..6840ae1c19 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/RedirectUrlManagement/RedirectUrlViewModel.cs @@ -0,0 +1,16 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.RedirectUrlManagement; + +public class RedirectUrlViewModel +{ + public Guid Key { get; set; } + + public required string OriginalUrl { get; set; } + + public required string DestinationUrl { get; set; } + + public DateTime Created { get; set; } + + public Guid ContentKey { get; set; } + + public string? Culture { get; set; } +} diff --git a/src/Umbraco.Core/Models/ContentEditing/ContentRedirectUrl.cs b/src/Umbraco.Core/Models/ContentEditing/ContentRedirectUrl.cs index 62bf29ce82..eef4e80976 100644 --- a/src/Umbraco.Core/Models/ContentEditing/ContentRedirectUrl.cs +++ b/src/Umbraco.Core/Models/ContentEditing/ContentRedirectUrl.cs @@ -2,6 +2,7 @@ using System.Runtime.Serialization; namespace Umbraco.Cms.Core.Models.ContentEditing; +[Obsolete("Will be replace in new backoffice in V13, RedirectUrlViewModel will be used instead.")] [DataContract(Name = "contentRedirectUrl", Namespace = "")] public class ContentRedirectUrl { diff --git a/src/Umbraco.Core/Models/Mapping/RedirectUrlMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/RedirectUrlMapDefinition.cs index 148470c706..8cdc24b18d 100644 --- a/src/Umbraco.Core/Models/Mapping/RedirectUrlMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/RedirectUrlMapDefinition.cs @@ -4,6 +4,7 @@ using Umbraco.Cms.Core.Routing; namespace Umbraco.Cms.Core.Models.Mapping; +[Obsolete("Will no longer be used with new backoffice, use IRedirectUrlViewModelFactory instead")] public class RedirectUrlMapDefinition : IMapDefinition { private readonly IPublishedUrlProvider _publishedUrlProvider; diff --git a/src/Umbraco.New.Cms.Core/Models/RedirectUrlManagement/RedirectStatus.cs b/src/Umbraco.New.Cms.Core/Models/RedirectUrlManagement/RedirectStatus.cs new file mode 100644 index 0000000000..04fd70d7e5 --- /dev/null +++ b/src/Umbraco.New.Cms.Core/Models/RedirectUrlManagement/RedirectStatus.cs @@ -0,0 +1,7 @@ +namespace Umbraco.New.Cms.Core.Models.RedirectUrlManagement; + +public enum RedirectStatus +{ + Enabled, + Disabled, +}