From 140d45b4906a479744da47b8c1eb11725405c6fa Mon Sep 17 00:00:00 2001 From: Sven Geusens Date: Mon, 15 Apr 2024 16:13:26 +0200 Subject: [PATCH 1/4] Added All Segments service with backing noopService --- .../Segment/AllSegmentController.cs | 50 +++++++++++++++++++ .../Segment/SegmentControllerBase.cs | 19 +++++++ .../SegmentBuilderExtensions.cs | 15 ++++++ .../UmbracoBuilderExtensions.cs | 3 +- .../Mapping/Segment/SegmentMapDefinition.cs | 19 +++++++ .../Segment/SegmentResponseModel.cs | 12 +++++ .../DependencyInjection/UmbracoBuilder.cs | 3 ++ src/Umbraco.Core/Models/Segment.cs | 8 +++ src/Umbraco.Core/Services/ISegmentService.cs | 9 ++++ .../Services/NoopSegmentService.cs | 14 ++++++ .../OperationStatus/SegmentOperationStatus.cs | 6 +++ 11 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/Segment/AllSegmentController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/Segment/SegmentControllerBase.cs create mode 100644 src/Umbraco.Cms.Api.Management/DependencyInjection/SegmentBuilderExtensions.cs create mode 100644 src/Umbraco.Cms.Api.Management/Mapping/Segment/SegmentMapDefinition.cs create mode 100644 src/Umbraco.Cms.Api.Management/ViewModels/Segment/SegmentResponseModel.cs create mode 100644 src/Umbraco.Core/Models/Segment.cs create mode 100644 src/Umbraco.Core/Services/ISegmentService.cs create mode 100644 src/Umbraco.Core/Services/NoopSegmentService.cs create mode 100644 src/Umbraco.Core/Services/OperationStatus/SegmentOperationStatus.cs diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Segment/AllSegmentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Segment/AllSegmentController.cs new file mode 100644 index 000000000000..f3920a9fd105 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Segment/AllSegmentController.cs @@ -0,0 +1,50 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Common.ViewModels.Pagination; +using Umbraco.Cms.Api.Management.ViewModels.Segment; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Mapping; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.OperationStatus; +using Umbraco.Cms.Web.Common.Authorization; + +namespace Umbraco.Cms.Api.Management.Controllers.Segment; + +[ApiVersion("1.0")] +[Authorize(Policy = AuthorizationPolicies.SectionAccessSettings)] +public class AllSegmentController : SegmentControllerBase +{ + private readonly ISegmentService _segmentService; + private readonly IUmbracoMapper _umbracoMapper; + + public AllSegmentController(ISegmentService segmentService, IUmbracoMapper umbracoMapper) + { + _segmentService = segmentService; + _umbracoMapper = umbracoMapper; + } + + [HttpGet] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] + public async Task GetAll(CancellationToken cancellationToken, int skip = 0, int take = 100) + { + Attempt?, SegmentOperationStatus> pagedAttempt = await _segmentService.GetPagedSegmentsAsync(skip, take); + + if (pagedAttempt.Success == false) + { + return MapFailure(pagedAttempt.Status); + } + + var viewModel = new PagedViewModel + { + Items = _umbracoMapper.MapEnumerable(pagedAttempt.Result!.Items), + Total = pagedAttempt.Result!.Total, + }; + + return Ok(viewModel); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Segment/SegmentControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Segment/SegmentControllerBase.cs new file mode 100644 index 000000000000..9149392ccdc9 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Segment/SegmentControllerBase.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.Routing; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Api.Management.Controllers.Segment; + +[VersionedApiBackOfficeRoute("segment")] +[ApiExplorerSettings(GroupName = "Segment")] +public abstract class SegmentControllerBase : ManagementApiControllerBase +{ + protected IActionResult MapFailure(SegmentOperationStatus status) + => OperationStatusResult(status, problemDetailsBuilder => status switch + { + _ => StatusCode(StatusCodes.Status500InternalServerError, problemDetailsBuilder + .WithTitle("Unknown segment operation status.") + .Build()), + }); +} diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/SegmentBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/SegmentBuilderExtensions.cs new file mode 100644 index 000000000000..17b9f2ae998b --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/SegmentBuilderExtensions.cs @@ -0,0 +1,15 @@ +using Umbraco.Cms.Api.Management.Mapping.Segment; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Mapping; + +namespace Umbraco.Cms.Api.Management.DependencyInjection; + +internal static class SegmentBuilderExtensions +{ + internal static IUmbracoBuilder AddSegment(this IUmbracoBuilder builder) + { + builder.WithCollectionBuilder().Add(); + + return builder; + } +} diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/UmbracoBuilderExtensions.cs index d6dabeb0c3f2..58a3434e6c4a 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/UmbracoBuilderExtensions.cs @@ -67,7 +67,8 @@ public static IUmbracoBuilder AddUmbracoManagementApi(this IUmbracoBuilder build .AddPreview() .AddPasswordConfiguration() .AddSupplemenataryLocalizedTextFileSources() - .AddUserData(); + .AddUserData() + .AddSegment(); services .ConfigureOptions() diff --git a/src/Umbraco.Cms.Api.Management/Mapping/Segment/SegmentMapDefinition.cs b/src/Umbraco.Cms.Api.Management/Mapping/Segment/SegmentMapDefinition.cs new file mode 100644 index 000000000000..8c6b0097d2bf --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Mapping/Segment/SegmentMapDefinition.cs @@ -0,0 +1,19 @@ +using Umbraco.Cms.Api.Management.ViewModels.Segment; +using Umbraco.Cms.Core.Mapping; + +namespace Umbraco.Cms.Api.Management.Mapping.Segment; + +public class SegmentMapDefinition : IMapDefinition +{ + public void DefineMaps(IUmbracoMapper mapper) + { + mapper.Define((_, _) => new SegmentResponseModel(), Map); + } + + // Umbraco.Code.MapAll + private static void Map(Core.Models.Segment source, SegmentResponseModel target, MapperContext context) + { + target.Name = source.Name; + target.Alias = source.Alias; + } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Segment/SegmentResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Segment/SegmentResponseModel.cs new file mode 100644 index 000000000000..f29f41514087 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Segment/SegmentResponseModel.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace Umbraco.Cms.Api.Management.ViewModels.Segment; + +public class SegmentResponseModel +{ + [Required] + public string Name { get; set; } = string.Empty; + + [Required] + public string Alias { get; set; } = string.Empty; +} diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index 5191f03837dd..1d2c08e79055 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -390,6 +390,9 @@ private void AddCoreServices() Services.AddSingleton(); Services.AddSingleton(); Services.AddSingleton(); + + // Segments + Services.AddUnique(); } } } diff --git a/src/Umbraco.Core/Models/Segment.cs b/src/Umbraco.Core/Models/Segment.cs new file mode 100644 index 000000000000..117b886d647f --- /dev/null +++ b/src/Umbraco.Core/Models/Segment.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Cms.Core.Models; + +public class Segment +{ + public required string Name { get; set; } + + public required string Alias { get; set; } +} diff --git a/src/Umbraco.Core/Services/ISegmentService.cs b/src/Umbraco.Core/Services/ISegmentService.cs new file mode 100644 index 000000000000..f5af487a7369 --- /dev/null +++ b/src/Umbraco.Core/Services/ISegmentService.cs @@ -0,0 +1,9 @@ +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Core.Services; + +public interface ISegmentService +{ + Task?, SegmentOperationStatus>> GetPagedSegmentsAsync(int skip = 0, int take = 100); +} diff --git a/src/Umbraco.Core/Services/NoopSegmentService.cs b/src/Umbraco.Core/Services/NoopSegmentService.cs new file mode 100644 index 000000000000..90a3076db4c2 --- /dev/null +++ b/src/Umbraco.Core/Services/NoopSegmentService.cs @@ -0,0 +1,14 @@ +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Core.Services; + +public class NoopSegmentService : ISegmentService +{ + public async Task?, SegmentOperationStatus>> GetPagedSegmentsAsync(int skip = 0, int take = 100) + { + return await Task.FromResult(Attempt.SucceedWithStatus?, SegmentOperationStatus>( + SegmentOperationStatus.Success, + new PagedModel { Total = 0, Items = Enumerable.Empty() })); + } +} diff --git a/src/Umbraco.Core/Services/OperationStatus/SegmentOperationStatus.cs b/src/Umbraco.Core/Services/OperationStatus/SegmentOperationStatus.cs new file mode 100644 index 000000000000..e911fef7e7cc --- /dev/null +++ b/src/Umbraco.Core/Services/OperationStatus/SegmentOperationStatus.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Core.Services.OperationStatus; + +public enum SegmentOperationStatus +{ + Success, +} From 5bf75444c3f4a4e6685831fff5dcd21c6a8798ae Mon Sep 17 00:00:00 2001 From: Sven Geusens Date: Tue, 16 Apr 2024 09:28:49 +0200 Subject: [PATCH 2/4] Add openapi spec --- src/Umbraco.Cms.Api.Management/OpenApi.json | 439 +++++++++++++++++++- 1 file changed, 432 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index 3544bf9cd763..826a64c0b81d 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -4270,6 +4270,54 @@ ] } }, + "/umbraco/management/api/v1/tree/document-blueprint/ancestors": { + "get": { + "tags": [ + "Document Blueprint" + ], + "operationId": "GetTreeDocumentBlueprintAncestors", + "parameters": [ + { + "name": "descendantId", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentBlueprintTreeItemResponseModel" + } + ] + } + } + } + } + }, + "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/tree/document-blueprint/children": { "get": { "tags": [ @@ -4911,6 +4959,84 @@ ] } }, + "/umbraco/management/api/v1/document-type/{id}/blueprint": { + "get": { + "tags": [ + "Document Type" + ], + "operationId": "GetDocumentTypeByIdBlueprint", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "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": { + "oneOf": [ + { + "$ref": "#/components/schemas/PagedDocumentTypeBlueprintItemResponseModel" + } + ] + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ProblemDetails" + } + ] + } + } + } + }, + "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/document-type/{id}/composition-references": { "get": { "tags": [ @@ -9276,6 +9402,58 @@ ] } }, + "/umbraco/management/api/v1/document/urls": { + "get": { + "tags": [ + "Document" + ], + "operationId": "GetDocumentUrls", + "parameters": [ + { + "name": "id", + "in": "query", + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentUrlInfoResponseModel" + } + ] + } + } + } + } + }, + "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/document/validate": { "post": { "tags": [ @@ -15717,6 +15895,58 @@ ] } }, + "/umbraco/management/api/v1/media/urls": { + "get": { + "tags": [ + "Media" + ], + "operationId": "GetMediaUrls", + "parameters": [ + { + "name": "id", + "in": "query", + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaUrlInfoResponseModel" + } + ] + } + } + } + } + }, + "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/media/validate": { "post": { "tags": [ @@ -23741,6 +23971,75 @@ } } }, + "/umbraco/management/api/v1/segment": { + "get": { + "tags": [ + "Segment" + ], + "operationId": "GetSegment", + "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": { + "oneOf": [ + { + "$ref": "#/components/schemas/PagedSegmentResponseModel" + } + ] + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ProblemDetails" + } + ] + } + } + } + }, + "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/server/configuration": { "get": { "tags": [ @@ -34254,8 +34553,7 @@ "required": [ "canBeChanged", "documentListViewId", - "mediaListViewId", - "memberListViewId" + "mediaListViewId" ], "type": "object", "properties": { @@ -34269,10 +34567,6 @@ "mediaListViewId": { "type": "string", "format": "uuid" - }, - "memberListViewId": { - "type": "string", - "format": "uuid" } }, "additionalProperties": false @@ -34942,6 +35236,23 @@ }, "additionalProperties": false }, + "DocumentTypeBlueprintItemResponseModel": { + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + }, + "additionalProperties": false + }, "DocumentTypeCleanupModel": { "required": [ "preventCleanup" @@ -35440,6 +35751,30 @@ }, "additionalProperties": false }, + "DocumentUrlInfoResponseModel": { + "required": [ + "id", + "urlInfos" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "urlInfos": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentUrlInfoModel" + } + ] + } + } + }, + "additionalProperties": false + }, "DocumentValueModel": { "required": [ "alias" @@ -37297,6 +37632,30 @@ }, "additionalProperties": false }, + "MediaUrlInfoResponseModel": { + "required": [ + "id", + "urlInfos" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "urlInfos": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaUrlInfoModel" + } + ] + } + } + }, + "additionalProperties": false + }, "MediaValueModel": { "required": [ "alias" @@ -38626,6 +38985,30 @@ }, "additionalProperties": false }, + "PagedDocumentTypeBlueprintItemResponseModel": { + "required": [ + "items", + "total" + ], + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeBlueprintItemResponseModel" + } + ] + } + } + }, + "additionalProperties": false + }, "PagedDocumentTypeTreeItemResponseModel": { "required": [ "items", @@ -39544,6 +39927,30 @@ }, "additionalProperties": false }, + "PagedSegmentResponseModel": { + "required": [ + "items", + "total" + ], + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/SegmentResponseModel" + } + ] + } + } + }, + "additionalProperties": false + }, "PagedTagResponseModel": { "required": [ "items", @@ -40519,6 +40926,24 @@ }, "additionalProperties": false }, + "SegmentResponseModel": { + "required": [ + "alias", + "name" + ], + "type": "object", + "properties": { + "name": { + "minLength": 1, + "type": "string" + }, + "alias": { + "minLength": 1, + "type": "string" + } + }, + "additionalProperties": false + }, "ServerConfigurationItemResponseModel": { "required": [ "data", @@ -43251,4 +43676,4 @@ } } } -} +} \ No newline at end of file From 8877b84475dee5f7903a2196f12f0b669479932d Mon Sep 17 00:00:00 2001 From: Sven Geusens Date: Thu, 18 Apr 2024 10:49:15 +0200 Subject: [PATCH 3/4] Apply suggestions from code review Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> --- .../Controllers/Segment/AllSegmentController.cs | 2 +- .../ViewModels/Segment/SegmentResponseModel.cs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Segment/AllSegmentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Segment/AllSegmentController.cs index f3920a9fd105..48542c6b31fe 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Segment/AllSegmentController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Segment/AllSegmentController.cs @@ -34,7 +34,7 @@ public async Task GetAll(CancellationToken cancellationToken, int { Attempt?, SegmentOperationStatus> pagedAttempt = await _segmentService.GetPagedSegmentsAsync(skip, take); - if (pagedAttempt.Success == false) + if (pagedAttempt.Success is false) { return MapFailure(pagedAttempt.Status); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Segment/SegmentResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Segment/SegmentResponseModel.cs index f29f41514087..4932104206de 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Segment/SegmentResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Segment/SegmentResponseModel.cs @@ -4,9 +4,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Segment; public class SegmentResponseModel { - [Required] - public string Name { get; set; } = string.Empty; + public required string Name { get; set; } = string.Empty; - [Required] - public string Alias { get; set; } = string.Empty; + public required string Alias { get; set; } = string.Empty; } From af9b2024e952855a9f0b3a74c903b5a6e8972952 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Thu, 18 Apr 2024 10:57:36 +0200 Subject: [PATCH 4/4] Fix ctor --- .../Mapping/Segment/SegmentMapDefinition.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Umbraco.Cms.Api.Management/Mapping/Segment/SegmentMapDefinition.cs b/src/Umbraco.Cms.Api.Management/Mapping/Segment/SegmentMapDefinition.cs index 8c6b0097d2bf..903d46011904 100644 --- a/src/Umbraco.Cms.Api.Management/Mapping/Segment/SegmentMapDefinition.cs +++ b/src/Umbraco.Cms.Api.Management/Mapping/Segment/SegmentMapDefinition.cs @@ -5,10 +5,7 @@ namespace Umbraco.Cms.Api.Management.Mapping.Segment; public class SegmentMapDefinition : IMapDefinition { - public void DefineMaps(IUmbracoMapper mapper) - { - mapper.Define((_, _) => new SegmentResponseModel(), Map); - } + public void DefineMaps(IUmbracoMapper mapper) => mapper.Define((_, _) => new SegmentResponseModel { Name = string.Empty, Alias = string.Empty }, Map); // Umbraco.Code.MapAll private static void Map(Core.Models.Segment source, SegmentResponseModel target, MapperContext context)