diff --git a/src/Umbraco.Cms.Api.Management/Controllers/DataType/MoveDataTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/DataType/MoveDataTypeController.cs index 331a3120f2..abf79fd60a 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/DataType/MoveDataTypeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/DataType/MoveDataTypeController.cs @@ -22,7 +22,7 @@ public class MoveDataTypeController : DataTypeControllerBase _backOfficeSecurityAccessor = backOfficeSecurityAccessor; } - [HttpPost("{id:guid}/move")] + [HttpPut("{id:guid}/move")] [MapToApiVersion("1.0")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/MoveDictionaryController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/MoveDictionaryController.cs index ee089330cb..59e6fd90a4 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/MoveDictionaryController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/MoveDictionaryController.cs @@ -22,7 +22,7 @@ public class MoveDictionaryController : DictionaryControllerBase _backOfficeSecurityAccessor = backOfficeSecurityAccessor; } - [HttpPost("{id:guid}/move")] + [HttpPut("{id:guid}/move")] [MapToApiVersion("1.0")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] diff --git a/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/CopyDocumentTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/CopyDocumentTypeController.cs new file mode 100644 index 0000000000..94ff0c72d3 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/CopyDocumentTypeController.cs @@ -0,0 +1,33 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.ViewModels.DocumentType; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Api.Management.Controllers.DocumentType; + +[ApiVersion("1.0")] +public class CopyDocumentTypeController : DocumentTypeControllerBase +{ + private readonly IContentTypeService _contentTypeService; + + public CopyDocumentTypeController(IContentTypeService contentTypeService) + => _contentTypeService = contentTypeService; + + [HttpPost("{id:guid}/copy")] + [MapToApiVersion("1.0")] + [ProducesResponseType(StatusCodes.Status201Created)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] + public async Task Copy(Guid id, CopyDocumentTypeRequestModel copyDocumentTypeRequestModel) + { + Attempt result = await _contentTypeService.CopyAsync(id, copyDocumentTypeRequestModel.TargetId); + + return result.Success + ? CreatedAtAction(controller => nameof(controller.ByKey), result.Result!.Key) + : StructureOperationStatusResult(result.Status); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/DocumentTypeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/DocumentTypeControllerBase.cs index 3a2e954e8b..0e3f4ddb81 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/DocumentTypeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/DocumentTypeControllerBase.cs @@ -18,6 +18,9 @@ public abstract class DocumentTypeControllerBase : ManagementApiControllerBase protected IActionResult OperationStatusResult(ContentTypeOperationStatus status) => ContentTypeOperationStatusResult(status, "document"); + protected IActionResult StructureOperationStatusResult(ContentTypeStructureOperationStatus status) + => ContentTypeStructureOperationStatusResult(status, "document"); + internal static IActionResult ContentTypeOperationStatusResult(ContentTypeOperationStatus status, string type) => status switch { @@ -73,4 +76,26 @@ public abstract class DocumentTypeControllerBase : ManagementApiControllerBase .Build()), _ => new ObjectResult("Unknown content type operation status") { StatusCode = StatusCodes.Status500InternalServerError }, }; + + public static IActionResult ContentTypeStructureOperationStatusResult(ContentTypeStructureOperationStatus status, string type) => + status switch + { + ContentTypeStructureOperationStatus.Success => new OkResult(), + ContentTypeStructureOperationStatus.CancelledByNotification => new BadRequestObjectResult(new ProblemDetailsBuilder() + .WithTitle("Cancelled by notification") + .WithDetail($"A notification handler prevented the {type} type operation") + .Build()), + ContentTypeStructureOperationStatus.ContainerNotFound => new NotFoundObjectResult(new ProblemDetailsBuilder() + .WithTitle("Container not found") + .WithDetail("The specified container was not found") + .Build()), + ContentTypeStructureOperationStatus.NotAllowedByPath => new BadRequestObjectResult(new ProblemDetailsBuilder() + .WithTitle("Not allowed by path") + .WithDetail($"The {type} type operation cannot be performed due to not allowed path (i.e. a child of itself)")), + ContentTypeStructureOperationStatus.NotFound => new NotFoundObjectResult(new ProblemDetailsBuilder() + .WithTitle("Not Found") + .WithDetail($"The specified {type} type was not found") + .Build()), + _ => new ObjectResult("Unknown content type structure operation status") { StatusCode = StatusCodes.Status500InternalServerError } + }; } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/MoveDocumentTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/MoveDocumentTypeController.cs new file mode 100644 index 0000000000..792f387973 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/MoveDocumentTypeController.cs @@ -0,0 +1,33 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.ViewModels.DocumentType; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Api.Management.Controllers.DocumentType; + +[ApiVersion("1.0")] +public class MoveDocumentTypeController : DocumentTypeControllerBase +{ + private readonly IContentTypeService _contentTypeService; + + public MoveDocumentTypeController(IContentTypeService contentTypeService) + => _contentTypeService = contentTypeService; + + [HttpPut("{id:guid}/move")] + [MapToApiVersion("1.0")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] + public async Task Move(Guid id, MoveDocumentTypeRequestModel moveDocumentTypeRequestModel) + { + Attempt result = await _contentTypeService.MoveAsync(id, moveDocumentTypeRequestModel.TargetId); + + return result.Success + ? Ok() + : StructureOperationStatusResult(result.Status); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/MediaType/CopyMediaTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/CopyMediaTypeController.cs new file mode 100644 index 0000000000..a2847a1c28 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/CopyMediaTypeController.cs @@ -0,0 +1,33 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.ViewModels.MediaType; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Api.Management.Controllers.MediaType; + +[ApiVersion("1.0")] +public class CopyMediaTypeController : MediaTypeControllerBase +{ + private readonly IMediaTypeService _mediaTypeService; + + public CopyMediaTypeController(IMediaTypeService mediaTypeService) + => _mediaTypeService = mediaTypeService; + + [HttpPost("{id:guid}/copy")] + [MapToApiVersion("1.0")] + [ProducesResponseType(StatusCodes.Status201Created)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] + public async Task Copy(Guid id, CopyMediaTypeRequestModel copyMediaTypeRequestModel) + { + Attempt result = await _mediaTypeService.CopyAsync(id, copyMediaTypeRequestModel.TargetId); + + return result.Success + ? CreatedAtAction(controller => nameof(controller.ByKey), result.Result!.Key) + : StructureOperationStatusResult(result.Status); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/MediaType/MediaTypeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/MediaTypeControllerBase.cs index 74910e82a5..a5d9fc56cd 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/MediaType/MediaTypeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/MediaTypeControllerBase.cs @@ -16,4 +16,7 @@ public abstract class MediaTypeControllerBase : ManagementApiControllerBase { protected IActionResult OperationStatusResult(ContentTypeOperationStatus status) => DocumentTypeControllerBase.ContentTypeOperationStatusResult(status, "media"); + + protected IActionResult StructureOperationStatusResult(ContentTypeStructureOperationStatus status) + => DocumentTypeControllerBase.ContentTypeStructureOperationStatusResult(status, "media"); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/MediaType/MoveMediaTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/MoveMediaTypeController.cs new file mode 100644 index 0000000000..b6f608fd90 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/MoveMediaTypeController.cs @@ -0,0 +1,33 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.ViewModels.MediaType; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Api.Management.Controllers.MediaType; + +[ApiVersion("1.0")] +public class MoveMediaTypeController : MediaTypeControllerBase +{ + private readonly IMediaTypeService _mediaTypeService; + + public MoveMediaTypeController(IMediaTypeService mediaTypeService) + => _mediaTypeService = mediaTypeService; + + [HttpPut("{id:guid}/move")] + [MapToApiVersion("1.0")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] + public async Task Move(Guid id, MoveMediaTypeRequestModel moveMediaTypeRequestModel) + { + Attempt result = await _mediaTypeService.MoveAsync(id, moveMediaTypeRequestModel.TargetId); + + return result.Success + ? Ok() + : StructureOperationStatusResult(result.Status); + } +} diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index 114d0ce46c..158433df74 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -810,11 +810,11 @@ } }, "/umbraco/management/api/v1/data-type/{id}/move": { - "post": { + "put": { "tags": [ "Data Type" ], - "operationId": "PostDataTypeByIdMove", + "operationId": "PutDataTypeByIdMove", "parameters": [ { "name": "id", @@ -2120,11 +2120,11 @@ } }, "/umbraco/management/api/v1/dictionary/{id}/move": { - "post": { + "put": { "tags": [ "Dictionary" ], - "operationId": "PostDictionaryByIdMove", + "operationId": "PutDictionaryByIdMove", "parameters": [ { "name": "id", @@ -2986,6 +2986,222 @@ ] } }, + "/umbraco/management/api/v1/document-type/{id}/copy": { + "post": { + "tags": [ + "Document Type" + ], + "operationId": "PostDocumentTypeByIdCopy", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/CopyDocumentTypeRequestModel" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/CopyDocumentTypeRequestModel" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/CopyDocumentTypeRequestModel" + } + ] + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "headers": { + "Location": { + "description": "Location of the newly created resource", + "schema": { + "type": "string", + "description": "Location of the newly created resource", + "format": "uri" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, + "/umbraco/management/api/v1/document-type/{id}/move": { + "put": { + "tags": [ + "Document Type" + ], + "operationId": "PutDocumentTypeByIdMove", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/MoveDocumentTypeRequestModel" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/MoveDocumentTypeRequestModel" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/MoveDocumentTypeRequestModel" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/document-type/folder": { "post": { "tags": [ @@ -7908,6 +8124,222 @@ ] } }, + "/umbraco/management/api/v1/media-type/{id}/copy": { + "post": { + "tags": [ + "Media Type" + ], + "operationId": "PostMediaTypeByIdCopy", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/CopyMediaTypeRequestModel" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/CopyMediaTypeRequestModel" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/CopyMediaTypeRequestModel" + } + ] + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "headers": { + "Location": { + "description": "Location of the newly created resource", + "schema": { + "type": "string", + "description": "Location of the newly created resource", + "format": "uri" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, + "/umbraco/management/api/v1/media-type/{id}/move": { + "put": { + "tags": [ + "Media Type" + ], + "operationId": "PutMediaTypeByIdMove", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/MoveMediaTypeRequestModel" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/MoveMediaTypeRequestModel" + } + ] + } + }, + "application/*+json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/MoveMediaTypeRequestModel" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "Success" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/media-type/folder": { "post": { "tags": [ @@ -11301,6 +11733,46 @@ ] } }, + "/umbraco/management/api/v1/preview": { + "delete": { + "tags": [ + "Preview" + ], + "operationId": "DeletePreview", + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + }, + "post": { + "tags": [ + "Preview" + ], + "operationId": "PostPreview", + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/profiling/status": { "get": { "tags": [ @@ -13519,6 +13991,56 @@ ] } }, + "/umbraco/management/api/v1/server/configuration": { + "get": { + "tags": [ + "Server" + ], + "operationId": "GetServerConfiguration", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ServerConfigurationResponseModel" + } + ] + } + }, + "text/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ServerConfigurationResponseModel" + } + ] + } + }, + "text/plain": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/ServerConfigurationResponseModel" + } + ] + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/server/information": { "get": { "tags": [ @@ -16022,6 +16544,27 @@ ] } }, + "/umbraco/management/api/v1/temporaryfile/configuration": { + "get": { + "tags": [ + "Temporary File" + ], + "operationId": "GetTemporaryfileConfiguration", + "responses": { + "200": { + "description": "Success" + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/tour": { "get": { "tags": [ @@ -19415,6 +19958,28 @@ }, "additionalProperties": false }, + "CopyDocumentTypeRequestModel": { + "type": "object", + "properties": { + "targetId": { + "type": "string", + "format": "uuid", + "nullable": true + } + }, + "additionalProperties": false + }, + "CopyMediaTypeRequestModel": { + "type": "object", + "properties": { + "targetId": { + "type": "string", + "format": "uuid", + "nullable": true + } + }, + "additionalProperties": false + }, "CreateContentForDocumentRequestModel": { "required": [ "values", @@ -19981,6 +20546,13 @@ "$ref": "#/components/schemas/TemplateModelBaseModel" } ], + "properties": { + "key": { + "type": "string", + "format": "uuid", + "nullable": true + } + }, "additionalProperties": false }, "CreateTextFileViewModelBaseModel": { @@ -21933,6 +22505,17 @@ }, "additionalProperties": false }, + "MoveDocumentTypeRequestModel": { + "type": "object", + "properties": { + "targetId": { + "type": "string", + "format": "uuid", + "nullable": true + } + }, + "additionalProperties": false + }, "MoveMediaRequestModel": { "type": "object", "properties": { @@ -21944,6 +22527,17 @@ }, "additionalProperties": false }, + "MoveMediaTypeRequestModel": { + "type": "object", + "properties": { + "targetId": { + "type": "string", + "format": "uuid", + "nullable": true + } + }, + "additionalProperties": false + }, "ObjectTypeResponseModel": { "required": [ "id" @@ -23975,6 +24569,18 @@ }, "additionalProperties": false }, + "ServerConfigurationResponseModel": { + "required": [ + "allowPasswordReset" + ], + "type": "object", + "properties": { + "allowPasswordReset": { + "type": "boolean" + } + }, + "additionalProperties": false + }, "ServerInformationResponseModel": { "required": [ "assemblyVersion", diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/CopyDocumentTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/CopyDocumentTypeRequestModel.cs new file mode 100644 index 0000000000..89cf827f3a --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/CopyDocumentTypeRequestModel.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType; + +public class CopyDocumentTypeRequestModel +{ + public Guid? TargetId { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/MoveDocumentTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/MoveDocumentTypeRequestModel.cs new file mode 100644 index 0000000000..11eadd3cba --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/MoveDocumentTypeRequestModel.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType; + +public class MoveDocumentTypeRequestModel +{ + public Guid? TargetId { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CopyMediaTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CopyMediaTypeRequestModel.cs new file mode 100644 index 0000000000..4fc9615de5 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CopyMediaTypeRequestModel.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.MediaType; + +public class CopyMediaTypeRequestModel +{ + public Guid? TargetId { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MoveMediaTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MoveMediaTypeRequestModel.cs new file mode 100644 index 0000000000..cb26c27e79 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MoveMediaTypeRequestModel.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.MediaType; + +public class MoveMediaTypeRequestModel +{ + public Guid? TargetId { get; set; } +} diff --git a/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index a645e6222e..66beb38002 100644 --- a/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -754,6 +754,7 @@ public abstract class ContentTypeServiceBase : ContentTypeSe #region Copy + [Obsolete("Please use CopyAsync. Will be removed in V15.")] public TItem Copy(TItem original, string alias, string name, int parentId = -1) { TItem? parent = null; @@ -768,6 +769,7 @@ public abstract class ContentTypeServiceBase : ContentTypeSe return Copy(original, alias, name, parent); } + [Obsolete("Please use CopyAsync. Will be removed in V15.")] public TItem Copy(TItem original, string alias, string name, TItem? parent) { if (original == null) @@ -822,6 +824,7 @@ public abstract class ContentTypeServiceBase : ContentTypeSe return clone; } + [Obsolete("Please use CopyAsync. Will be removed in V16.")] public Attempt?> Copy(TItem copying, int containerId) { EventMessages eventMessages = EventMessagesFactory.Get(); @@ -894,10 +897,53 @@ public abstract class ContentTypeServiceBase : ContentTypeSe return OperationResult.Attempt.Succeed(MoveOperationStatusType.Success, eventMessages, copy); } + public async Task> CopyAsync(Guid key, Guid? containerKey) + { + TItem? toCopy = await GetAsync(key); + if (toCopy is null) + { + return Attempt.FailWithStatus(ContentTypeStructureOperationStatus.NotFound, toCopy); + } + + var containerId = GetContainerOrRootId(containerKey); + + if (containerId is null) + { + return Attempt.FailWithStatus(ContentTypeStructureOperationStatus.ContainerNotFound, toCopy); + } + + // using obsolete method for version control while it still exists + Attempt?> result = Copy(toCopy, containerId.Value); + + return MapStatusTypeToAttempt(result.Result?.Entity, result.Result?.Result); + } + + private int? GetContainerOrRootId(Guid? containerKey) + { + if (containerKey is null) + { + return Constants.System.Root; + } + + EntityContainer? container = GetContainer(containerKey.Value); + return container?.Id; + } + + private Attempt MapStatusTypeToAttempt(TItem? item, MoveOperationStatusType? resultStatus) => + resultStatus switch + { + MoveOperationStatusType.Success => Attempt.SucceedWithStatus(ContentTypeStructureOperationStatus.Success, item), + MoveOperationStatusType.FailedParentNotFound => Attempt.FailWithStatus(ContentTypeStructureOperationStatus.ContainerNotFound, item), + MoveOperationStatusType.FailedCancelledByEvent => Attempt.FailWithStatus(ContentTypeStructureOperationStatus.CancelledByNotification, item), + MoveOperationStatusType.FailedNotAllowedByPath => Attempt.FailWithStatus(ContentTypeStructureOperationStatus.NotAllowedByPath, item), + _ => throw new NotImplementedException($"{nameof(ContentTypeStructureOperationStatus)} does not map to a corresponding {nameof(MoveOperationStatusType)}") + }; + #endregion #region Move + [Obsolete("Please use MoveAsync. Will be removed in V16.")] public Attempt?> Move(TItem moving, int containerId) { EventMessages eventMessages = EventMessagesFactory.Get(); @@ -950,6 +996,27 @@ public abstract class ContentTypeServiceBase : ContentTypeSe return OperationResult.Attempt.Succeed(MoveOperationStatusType.Success, eventMessages); } + public async Task> MoveAsync(Guid key, Guid? containerKey) + { + TItem? toMove = await GetAsync(key); + if (toMove is null) + { + return Attempt.FailWithStatus(ContentTypeStructureOperationStatus.NotFound, toMove); + } + + var containerId = GetContainerOrRootId(containerKey); + + if (containerId is null) + { + return Attempt.FailWithStatus(ContentTypeStructureOperationStatus.ContainerNotFound, toMove); + } + + // using obsolete method for version control while it still exists + Attempt?> result = Move(toMove, containerId.Value); + + return MapStatusTypeToAttempt(toMove, result.Result?.Result); + } + #endregion #region Containers diff --git a/src/Umbraco.Core/Services/IContentTypeServiceBase.cs b/src/Umbraco.Core/Services/IContentTypeServiceBase.cs index 372ff5b15b..165dfa6e24 100644 --- a/src/Umbraco.Core/Services/IContentTypeServiceBase.cs +++ b/src/Umbraco.Core/Services/IContentTypeServiceBase.cs @@ -124,11 +124,19 @@ public interface IContentTypeBaseService : IContentTypeBaseService, IServ Attempt?> RenameContainer(int id, string name, int userId = Constants.Security.SuperUserId); + [Obsolete("Please use MoveAsync. Will be removed in V16.")] Attempt?> Move(TItem moving, int containerId); + [Obsolete("Please use CopyAsync. Will be removed in V16.")] Attempt?> Copy(TItem copying, int containerId); + [Obsolete("Please use CopyAsync. Will be removed in V15.")] TItem Copy(TItem original, string alias, string name, int parentId = -1); + [Obsolete("Please use CopyAsync. Will be removed in V15.")] TItem Copy(TItem original, string alias, string name, TItem parent); + + Task> CopyAsync(Guid key, Guid? containerKey); + + Task> MoveAsync(Guid key, Guid? containerKey); } diff --git a/src/Umbraco.Core/Services/OperationStatus/ContentTypeStructureOperationStatus.cs b/src/Umbraco.Core/Services/OperationStatus/ContentTypeStructureOperationStatus.cs new file mode 100644 index 0000000000..a4c7c5c9f2 --- /dev/null +++ b/src/Umbraco.Core/Services/OperationStatus/ContentTypeStructureOperationStatus.cs @@ -0,0 +1,10 @@ +namespace Umbraco.Cms.Core.Services.OperationStatus; + +public enum ContentTypeStructureOperationStatus +{ + Success, + CancelledByNotification, + ContainerNotFound, + NotAllowedByPath, + NotFound +}