diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/ChildrenDictionaryTreeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/ChildrenDictionaryTreeController.cs index bb3c08d8d9..afbac03537 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/ChildrenDictionaryTreeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/ChildrenDictionaryTreeController.cs @@ -19,8 +19,8 @@ public class ChildrenDictionaryTreeController : DictionaryTreeControllerBase [HttpGet("children")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Children(Guid parentId, int skip = 0, int take = 100) + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> Children(Guid parentId, int skip = 0, int take = 100) { if (PaginationService.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize, out ProblemDetails? error) == false) { diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/DictionaryTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/DictionaryTreeControllerBase.cs index b51506c8da..2113804361 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/DictionaryTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/DictionaryTreeControllerBase.cs @@ -6,6 +6,7 @@ using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.Controllers.Tree; using Umbraco.Cms.Api.Management.ViewModels.Tree; using Umbraco.Cms.Api.Management.Routing; +using Umbraco.Cms.Api.Management.ViewModels; using Umbraco.Cms.Web.Common.Authorization; namespace Umbraco.Cms.Api.Management.Controllers.Dictionary.Tree; @@ -16,7 +17,7 @@ namespace Umbraco.Cms.Api.Management.Controllers.Dictionary.Tree; [Authorize(Policy = "New" + AuthorizationPolicies.TreeAccessDictionaryOrTemplates)] // NOTE: at the moment dictionary items (renamed to dictionary tree) aren't supported by EntityService, so we have little use of the // tree controller base. We'll keep it though, in the hope that we can mend EntityService. -public class DictionaryTreeControllerBase : EntityTreeControllerBase +public class DictionaryTreeControllerBase : NamedEntityTreeControllerBase { public DictionaryTreeControllerBase(IEntityService entityService, IDictionaryItemService dictionaryItemService) : base(entityService) => @@ -27,19 +28,23 @@ public class DictionaryTreeControllerBase : EntityTreeControllerBase> MapTreeItemViewModels(Guid? parentKey, IEnumerable dictionaryItems) + protected async Task> MapTreeItemViewModels(Guid? parentKey, IEnumerable dictionaryItems) { - async Task CreateEntityTreeItemViewModelAsync(IDictionaryItem dictionaryItem) + async Task CreateEntityTreeItemViewModelAsync(IDictionaryItem dictionaryItem) { var hasChildren = await DictionaryItemService.CountChildrenAsync(dictionaryItem.Key) > 0; - return new EntityTreeItemResponseModel + return new NamedEntityTreeItemResponseModel { Name = dictionaryItem.ItemKey, Id = dictionaryItem.Key, Type = Constants.UdiEntityType.DictionaryItem, HasChildren = hasChildren, - IsContainer = false, - ParentId = parentKey + Parent = parentKey.HasValue + ? new ReferenceByIdModel + { + Id = parentKey.Value + } + : null }; } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/RootDictionaryTreeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/RootDictionaryTreeController.cs index b8cc96dbb1..8bd18aac63 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/RootDictionaryTreeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Dictionary/Tree/RootDictionaryTreeController.cs @@ -19,8 +19,8 @@ public class RootDictionaryTreeController : DictionaryTreeControllerBase [HttpGet("root")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Root(int skip = 0, int take = 100) + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> Root(int skip = 0, int take = 100) { if (PaginationService.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize, out ProblemDetails? error) == false) { diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/AllowedChildrenDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/AllowedChildrenDocumentController.cs deleted file mode 100644 index fae6bd0fdf..0000000000 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/AllowedChildrenDocumentController.cs +++ /dev/null @@ -1,64 +0,0 @@ -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.DocumentType; -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.Document; - -[ApiVersion("1.0")] -[Authorize(Policy = "New" + AuthorizationPolicies.TreeAccessDocumentsOrDocumentTypes)] -public class AllowedChildrenDocumentController : DocumentControllerBase -{ - private readonly IUmbracoMapper _umbracoMapper; - private readonly IContentCreatingService _contentCreatingService; - - public AllowedChildrenDocumentController(IUmbracoMapper umbracoMapper, IContentCreatingService contentCreatingService) - { - _umbracoMapper = umbracoMapper; - _contentCreatingService = contentCreatingService; - } - - [HttpGet("allowed-document-types")] - [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] - public async Task AllowedChildrenByKey(Guid? parentId, int skip = 0, int take = 100) - { - PagedModel allowedChildren; - - if (parentId.HasValue is false) - { - allowedChildren = await _contentCreatingService.GetAllowedChildrenContentTypesAtRootAsync(skip, take); - } - else - { - Attempt?, ContentCreatingOperationStatus> allowedChildrenAttempt = - await _contentCreatingService.GetAllowedChildrenContentTypesAsync(parentId.Value, skip, take); - - if (allowedChildrenAttempt.Success is false) - { - return ContentCreatingOperationStatusResult(allowedChildrenAttempt.Status); - } - - allowedChildren = allowedChildrenAttempt.Result!; - } - - List viewModels = _umbracoMapper.MapEnumerable(allowedChildren.Items); - - var pagedViewModel = new PagedViewModel - { - Total = allowedChildren.Total, - Items = viewModels, - }; - - return Ok(pagedViewModel); - } -} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/CopyDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/CopyDocumentController.cs index 00e3823cea..055c082d7e 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/CopyDocumentController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/CopyDocumentController.cs @@ -40,7 +40,7 @@ public class CopyDocumentController : DocumentControllerBase { AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync( User, - ContentPermissionResource.WithKeys(ActionCopy.ActionLetter, new[] { copyDocumentRequestModel.TargetId, id }), + ContentPermissionResource.WithKeys(ActionCopy.ActionLetter, new[] { copyDocumentRequestModel.Target?.Id, id }), AuthorizationPolicies.ContentPermissionByResource); if (!authorizationResult.Succeeded) @@ -50,7 +50,7 @@ public class CopyDocumentController : DocumentControllerBase Attempt result = await _contentEditingService.CopyAsync( id, - copyDocumentRequestModel.TargetId, + copyDocumentRequestModel.Target?.Id, copyDocumentRequestModel.RelateToOriginal, copyDocumentRequestModel.IncludeDescendants, CurrentUserKey(_backOfficeSecurityAccessor)); diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/CreateDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/CreateDocumentController.cs index c2302fba2c..b55befc3e5 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/CreateDocumentController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/CreateDocumentController.cs @@ -47,7 +47,7 @@ public class CreateDocumentController : DocumentControllerBase User, ContentPermissionResource.WithKeys( ActionNew.ActionLetter, - requestModel.ParentId, + requestModel.Parent?.Id, requestModel.Variants .Where(v => v.Culture is not null) .Select(v => v.Culture!)), diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/ItemDocumentItemController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/ItemDocumentItemController.cs index 66077769e6..04c057291d 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/ItemDocumentItemController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/Item/ItemDocumentItemController.cs @@ -2,12 +2,10 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Management.Factories; -using Umbraco.Cms.Api.Management.Services.Entities; using Umbraco.Cms.Api.Management.ViewModels.Document.Item; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Services; -using Umbraco.Extensions; namespace Umbraco.Cms.Api.Management.Controllers.Document.Item; @@ -15,41 +13,24 @@ namespace Umbraco.Cms.Api.Management.Controllers.Document.Item; public class ItemDocumentItemController : DocumentItemControllerBase { private readonly IEntityService _entityService; - private readonly IDataTypeService _dataTypeService; - private readonly IUserStartNodeEntitiesService _userStartNodeEntitiesService; private readonly IDocumentPresentationFactory _documentPresentationFactory; - public ItemDocumentItemController( - IEntityService entityService, - IDataTypeService dataTypeService, - IUserStartNodeEntitiesService userStartNodeEntitiesService, - IDocumentPresentationFactory documentPresentationFactory) + public ItemDocumentItemController(IEntityService entityService, IDocumentPresentationFactory documentPresentationFactory) { _entityService = entityService; - _dataTypeService = dataTypeService; - _userStartNodeEntitiesService = userStartNodeEntitiesService; _documentPresentationFactory = documentPresentationFactory; } [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public async Task Item([FromQuery(Name = "id")] HashSet ids, Guid? dataTypeId = null, string? culture = null) + public async Task Item([FromQuery(Name = "id")] HashSet ids) { - IEnumerable documents = _entityService.GetAll(UmbracoObjectTypes.Document, ids.ToArray()).Select(x => x as IDocumentEntitySlim).Where(x => x is not null)!; + IEnumerable documents = _entityService + .GetAll(UmbracoObjectTypes.Document, ids.ToArray()) + .OfType(); - // Filter start nodes - if (dataTypeId is not null) - { - if (_dataTypeService.IsDataTypeIgnoringUserStartNodes(dataTypeId.Value)) - { - // FIXME: right now we're faking user id by just passing "-1" - // We should use the backoffice security accessor once auth is in place. - documents = _userStartNodeEntitiesService.UserAccessEntities(documents, new[] {"-1"}).Select(x => x.Entity as IDocumentEntitySlim).WhereNotNull(); - } - } - - IEnumerable documentItemResponseModels = documents.Select(x => _documentPresentationFactory.CreateItemResponseModel(x, culture)); - return Ok(documentItemResponseModels); + IEnumerable documentItemResponseModels = documents.Select(_documentPresentationFactory.CreateItemResponseModel); + return await Task.FromResult(Ok(documentItemResponseModels)); } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/MoveDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/MoveDocumentController.cs index 7ec40f896f..c7b5ead51a 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/MoveDocumentController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/MoveDocumentController.cs @@ -40,7 +40,7 @@ public class MoveDocumentController : DocumentControllerBase { AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync( User, - ContentPermissionResource.WithKeys(ActionMove.ActionLetter, new[] { moveDocumentRequestModel.TargetId, id }), + ContentPermissionResource.WithKeys(ActionMove.ActionLetter, new[] { moveDocumentRequestModel.Target?.Id, id }), AuthorizationPolicies.ContentPermissionByResource); if (!authorizationResult.Succeeded) @@ -50,7 +50,7 @@ public class MoveDocumentController : DocumentControllerBase Attempt result = await _contentEditingService.MoveAsync( id, - moveDocumentRequestModel.TargetId, + moveDocumentRequestModel.Target?.Id, CurrentUserKey(_backOfficeSecurityAccessor)); return result.Success diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/ChildrenDocumentRecycleBinController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/ChildrenDocumentRecycleBinController.cs index 82f9e3ed8f..ce3cd9cd05 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/ChildrenDocumentRecycleBinController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/ChildrenDocumentRecycleBinController.cs @@ -3,21 +3,22 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Common.ViewModels.Pagination; -using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; +using Umbraco.Cms.Api.Management.Factories; +using Umbraco.Cms.Api.Management.ViewModels.Document.RecycleBin; namespace Umbraco.Cms.Api.Management.Controllers.Document.RecycleBin; [ApiVersion("1.0")] public class ChildrenDocumentRecycleBinController : DocumentRecycleBinControllerBase { - public ChildrenDocumentRecycleBinController(IEntityService entityService) - : base(entityService) + public ChildrenDocumentRecycleBinController(IEntityService entityService, IDocumentPresentationFactory documentPresentationFactory) + : base(entityService, documentPresentationFactory) { } [HttpGet("children")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Children(Guid parentId, int skip = 0, int take = 100) + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> Children(Guid parentId, int skip = 0, int take = 100) => await GetChildren(parentId, skip, take); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DeleteDocumentRecycleBinController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DeleteDocumentRecycleBinController.cs index d152ba4c95..17bfcd758f 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DeleteDocumentRecycleBinController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DeleteDocumentRecycleBinController.cs @@ -2,6 +2,7 @@ using Asp.Versioning; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.Factories; using Umbraco.Cms.Api.Management.Security.Authorization.Content; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Actions; @@ -23,10 +24,11 @@ public class DeleteDocumentRecycleBinController : DocumentRecycleBinControllerBa public DeleteDocumentRecycleBinController( IEntityService entityService, + IDocumentPresentationFactory documentPresentationFactory, IAuthorizationService authorizationService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IContentEditingService contentEditingService) - : base(entityService) + : base(entityService, documentPresentationFactory) { _authorizationService = authorizationService; _backOfficeSecurityAccessor = backOfficeSecurityAccessor; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs index 47dea7fcbc..5f73af8a99 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs @@ -1,16 +1,14 @@ using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Api.Common.Builders; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.Controllers.RecycleBin; +using Umbraco.Cms.Api.Management.Factories; using Umbraco.Cms.Api.Management.Filters; -using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; using Umbraco.Cms.Api.Management.Routing; -using Umbraco.Cms.Core.Services.OperationStatus; +using Umbraco.Cms.Api.Management.ViewModels.Document.RecycleBin; using Umbraco.Cms.Web.Common.Authorization; namespace Umbraco.Cms.Api.Management.Controllers.Document.RecycleBin; @@ -20,24 +18,26 @@ namespace Umbraco.Cms.Api.Management.Controllers.Document.RecycleBin; [RequireDocumentTreeRootAccess] [ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Document))] [Authorize(Policy = "New" + AuthorizationPolicies.TreeAccessDocuments)] -public class DocumentRecycleBinControllerBase : RecycleBinControllerBase +public class DocumentRecycleBinControllerBase : RecycleBinControllerBase { - public DocumentRecycleBinControllerBase(IEntityService entityService) + private readonly IDocumentPresentationFactory _documentPresentationFactory; + + public DocumentRecycleBinControllerBase(IEntityService entityService, IDocumentPresentationFactory documentPresentationFactory) : base(entityService) - { - } + => _documentPresentationFactory = documentPresentationFactory; protected override UmbracoObjectTypes ItemObjectType => UmbracoObjectTypes.Document; protected override int RecycleBinRootId => Constants.System.RecycleBinContent; - protected override RecycleBinItemResponseModel MapRecycleBinViewModel(Guid? parentId, IEntitySlim entity) + protected override DocumentRecycleBinItemResponseModel MapRecycleBinViewModel(Guid? parentId, IEntitySlim entity) { - RecycleBinItemResponseModel responseModel = base.MapRecycleBinViewModel(parentId, entity); + DocumentRecycleBinItemResponseModel responseModel = base.MapRecycleBinViewModel(parentId, entity); if (entity is IDocumentEntitySlim documentEntitySlim) { - responseModel.Icon = documentEntitySlim.ContentTypeIcon ?? responseModel.Icon; + responseModel.Variants = _documentPresentationFactory.CreateVariantsItemResponseModels(documentEntitySlim); + responseModel.DocumentType = _documentPresentationFactory.CreateDocumentTypeReferenceResponseModel(documentEntitySlim); } return responseModel; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/EmptyDocumentRecycleBinController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/EmptyDocumentRecycleBinController.cs index 6445c71c89..1ce408e8d4 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/EmptyDocumentRecycleBinController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/EmptyDocumentRecycleBinController.cs @@ -2,6 +2,7 @@ using Asp.Versioning; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.Factories; using Umbraco.Cms.Api.Management.Security.Authorization.Content; using Umbraco.Cms.Core.Actions; using Umbraco.Cms.Core.Security; @@ -22,8 +23,9 @@ public class EmptyDocumentRecycleBinController : DocumentRecycleBinControllerBas IEntityService entityService, IAuthorizationService authorizationService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, - IContentService contentService) - : base(entityService) + IContentService contentService, + IDocumentPresentationFactory documentPresentationFactory) + : base(entityService, documentPresentationFactory) { _authorizationService = authorizationService; _backOfficeSecurityAccessor = backOfficeSecurityAccessor; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/RootDocumentRecycleBinController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/RootDocumentRecycleBinController.cs index 5471adb291..45118a8e35 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/RootDocumentRecycleBinController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/RootDocumentRecycleBinController.cs @@ -3,21 +3,22 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Common.ViewModels.Pagination; -using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; +using Umbraco.Cms.Api.Management.Factories; +using Umbraco.Cms.Api.Management.ViewModels.Document.RecycleBin; namespace Umbraco.Cms.Api.Management.Controllers.Document.RecycleBin; [ApiVersion("1.0")] public class RootDocumentRecycleBinController : DocumentRecycleBinControllerBase { - public RootDocumentRecycleBinController(IEntityService entityService) - : base(entityService) + public RootDocumentRecycleBinController(IEntityService entityService, IDocumentPresentationFactory documentPresentationFactory) + : base(entityService, documentPresentationFactory) { } [HttpGet("root")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Root(int skip = 0, int take = 100) + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> Root(int skip = 0, int take = 100) => await GetRoot(skip, take); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/ChildrenDocumentTreeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/ChildrenDocumentTreeController.cs index 59bc23a838..841d9c286a 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/ChildrenDocumentTreeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/ChildrenDocumentTreeController.cs @@ -6,6 +6,7 @@ using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.Services.Entities; using Umbraco.Cms.Api.Common.ViewModels.Pagination; +using Umbraco.Cms.Api.Management.Factories; using Umbraco.Cms.Api.Management.ViewModels.Tree; namespace Umbraco.Cms.Api.Management.Controllers.Document.Tree; @@ -20,18 +21,24 @@ public class ChildrenDocumentTreeController : DocumentTreeControllerBase IPublicAccessService publicAccessService, AppCaches appCaches, IBackOfficeSecurityAccessor backofficeSecurityAccessor, - IContentTypeService contentTypeService) - : base(entityService, userStartNodeEntitiesService, dataTypeService, publicAccessService, appCaches, backofficeSecurityAccessor, contentTypeService) + IDocumentPresentationFactory documentPresentationFactory) + : base( + entityService, + userStartNodeEntitiesService, + dataTypeService, + publicAccessService, + appCaches, + backofficeSecurityAccessor, + documentPresentationFactory) { } [HttpGet("children")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Children(Guid parentId, int skip = 0, int take = 100, Guid? dataTypeId = null, string? culture = null) + public async Task>> Children(Guid parentId, int skip = 0, int take = 100, Guid? dataTypeId = null) { IgnoreUserStartNodesForDataType(dataTypeId); - RenderForClientCulture(culture); return await GetChildren(parentId, skip, take); } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/DocumentTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/DocumentTreeControllerBase.cs index 75acc6e731..9aa4bd48aa 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/DocumentTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/DocumentTreeControllerBase.cs @@ -7,9 +7,9 @@ using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.Controllers.Tree; +using Umbraco.Cms.Api.Management.Factories; using Umbraco.Cms.Api.Management.Services.Entities; using Umbraco.Cms.Api.Management.ViewModels.Tree; -using Umbraco.Extensions; using Umbraco.Cms.Api.Management.Routing; using Umbraco.Cms.Web.Common.Authorization; @@ -24,8 +24,7 @@ public abstract class DocumentTreeControllerBase : UserStartNodeTreeControllerBa private readonly IPublicAccessService _publicAccessService; private readonly AppCaches _appCaches; private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor; - private readonly IContentTypeService _contentTypeService; - private string? _culture; + private readonly IDocumentPresentationFactory _documentPresentationFactory; protected DocumentTreeControllerBase( IEntityService entityService, @@ -34,85 +33,36 @@ public abstract class DocumentTreeControllerBase : UserStartNodeTreeControllerBa IPublicAccessService publicAccessService, AppCaches appCaches, IBackOfficeSecurityAccessor backofficeSecurityAccessor, - IContentTypeService contentTypeService) + IDocumentPresentationFactory documentPresentationFactory) : base(entityService, userStartNodeEntitiesService, dataTypeService) { _publicAccessService = publicAccessService; _appCaches = appCaches; _backofficeSecurityAccessor = backofficeSecurityAccessor; - _contentTypeService = contentTypeService; + _documentPresentationFactory = documentPresentationFactory; } protected override UmbracoObjectTypes ItemObjectType => UmbracoObjectTypes.Document; protected override Ordering ItemOrdering => Ordering.By(nameof(Infrastructure.Persistence.Dtos.NodeDto.SortOrder)); - protected void RenderForClientCulture(string? culture) => _culture = culture; - protected override DocumentTreeItemResponseModel MapTreeItemViewModel(Guid? parentId, IEntitySlim entity) { DocumentTreeItemResponseModel responseModel = base.MapTreeItemViewModel(parentId, entity); if (entity is IDocumentEntitySlim documentEntitySlim) { - responseModel.IsPublished = documentEntitySlim.Published; - responseModel.IsEdited = documentEntitySlim.Edited; - responseModel.Icon = documentEntitySlim.ContentTypeIcon ?? responseModel.Icon; responseModel.IsProtected = _publicAccessService.IsProtected(entity.Path); responseModel.IsTrashed = entity.Trashed; responseModel.Id = entity.Key; - if (_culture != null && documentEntitySlim.Variations.VariesByCulture()) - { - responseModel.Name = documentEntitySlim.CultureNames.TryGetValue(_culture, out var cultureName) - ? cultureName - : $"({responseModel.Name})"; - - responseModel.IsPublished = documentEntitySlim.PublishedCultures.Contains(_culture); - responseModel.IsEdited = documentEntitySlim.EditedCultures.Contains(_culture); - } - - responseModel.IsEdited &= responseModel.IsPublished; - - responseModel.Variants = MapVariants(documentEntitySlim); - - // TODO: This make this either be part of the IDocumentEntitySlim, or at the very least be more performantly fetched. - // This sucks, since it'll cost an extra DB call - // but currently there's no really good way to get the content type key from an IDocumentEntitySlim - // We have the same issue in DocumentPresentationFactory - IContentType? contentType = _contentTypeService.Get(documentEntitySlim.ContentTypeAlias); - responseModel.ContentTypeId = contentType?.Key ?? Guid.Empty; + responseModel.Variants = _documentPresentationFactory.CreateVariantsItemResponseModels(documentEntitySlim); + responseModel.DocumentType = _documentPresentationFactory.CreateDocumentTypeReferenceResponseModel(documentEntitySlim); } return responseModel; } - private IEnumerable MapVariants(IDocumentEntitySlim entity) - { - if (entity.Variations.VariesByCulture() is false) - { - yield return new VariantTreeItemViewModel - { - Name = entity.Name ?? string.Empty, - State = entity.Published ? PublishedState.Published : PublishedState.Unpublished, - Culture = null, - }; - yield break; - } - - foreach (KeyValuePair cultureNamePair in entity.CultureNames) - { - yield return new VariantTreeItemViewModel - { - Name = cultureNamePair.Value, - Culture = cultureNamePair.Key, - State = entity.PublishedCultures.Contains(cultureNamePair.Key) - ? PublishedState.Published - : PublishedState.Unpublished, - }; - } - } - // TODO: delete these (faking start node setup for unlimited editor) protected override int[] GetUserStartNodeIds() => new[] { -1 }; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/RootDocumentTreeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/RootDocumentTreeController.cs index 6e52d6c3dd..965307829a 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/RootDocumentTreeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/RootDocumentTreeController.cs @@ -6,6 +6,7 @@ using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.Services.Entities; using Umbraco.Cms.Api.Common.ViewModels.Pagination; +using Umbraco.Cms.Api.Management.Factories; using Umbraco.Cms.Api.Management.ViewModels.Tree; namespace Umbraco.Cms.Api.Management.Controllers.Document.Tree; @@ -20,18 +21,24 @@ public class RootDocumentTreeController : DocumentTreeControllerBase IPublicAccessService publicAccessService, AppCaches appCaches, IBackOfficeSecurityAccessor backofficeSecurityAccessor, - IContentTypeService contentTypeService) - : base(entityService, userStartNodeEntitiesService, dataTypeService, publicAccessService, appCaches, backofficeSecurityAccessor, contentTypeService) + IDocumentPresentationFactory documentPresentationFactory) + : base( + entityService, + userStartNodeEntitiesService, + dataTypeService, + publicAccessService, + appCaches, + backofficeSecurityAccessor, + documentPresentationFactory) { } [HttpGet("root")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Root(int skip = 0, int take = 100, Guid? dataTypeId = null, string? culture = null) + public async Task>> Root(int skip = 0, int take = 100, Guid? dataTypeId = null) { IgnoreUserStartNodesForDataType(dataTypeId); - RenderForClientCulture(culture); return await GetRoot(skip, take); } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/DocumentBlueprint/Tree/DocumentBlueprintTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/DocumentBlueprint/Tree/DocumentBlueprintTreeControllerBase.cs index 7ada226ea7..4112fe3bd3 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/DocumentBlueprint/Tree/DocumentBlueprintTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/DocumentBlueprint/Tree/DocumentBlueprintTreeControllerBase.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Api.Management.Controllers.DocumentBlueprint.Tree; [VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.DocumentBlueprint}")] [ApiExplorerSettings(GroupName = "Document Blueprint")] [Authorize(Policy = "New" + AuthorizationPolicies.SectionAccessContent)] -public class DocumentBlueprintTreeControllerBase : EntityTreeControllerBase +public class DocumentBlueprintTreeControllerBase : NamedEntityTreeControllerBase { private readonly IContentTypeService _contentTypeService; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/AllowedAtRootDocumentTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/AllowedAtRootDocumentTypeController.cs new file mode 100644 index 0000000000..82c2d1a0c8 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/AllowedAtRootDocumentTypeController.cs @@ -0,0 +1,44 @@ +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.DocumentType; +using Umbraco.Cms.Core.Mapping; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Web.Common.Authorization; + +namespace Umbraco.Cms.Api.Management.Controllers.DocumentType; + +[ApiVersion("1.0")] +[Authorize(Policy = "New" + AuthorizationPolicies.TreeAccessDocumentsOrDocumentTypes)] +public class AllowedAtRootDocumentTypeController : DocumentTypeControllerBase +{ + private readonly IContentTypeService _contentTypeService; + private readonly IUmbracoMapper _umbracoMapper; + + public AllowedAtRootDocumentTypeController(IContentTypeService contentTypeService, IUmbracoMapper umbracoMapper) + { + _contentTypeService = contentTypeService; + _umbracoMapper = umbracoMapper; + } + + [HttpGet("allowed-at-root")] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task AllowedAtRoot(int skip = 0, int take = 100) + { + PagedModel result = await _contentTypeService.GetAllAllowedAsRootAsync(skip, take); + + List viewModels = _umbracoMapper.MapEnumerable(result.Items); + + var pagedViewModel = new PagedViewModel + { + Total = result.Total, + Items = viewModels, + }; + + return Ok(pagedViewModel); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/AllowedChildrenDocumentTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/AllowedChildrenDocumentTypeController.cs new file mode 100644 index 0000000000..ab59c55ff4 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/AllowedChildrenDocumentTypeController.cs @@ -0,0 +1,51 @@ +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.DocumentType; +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.DocumentType; + +[ApiVersion("1.0")] +[Authorize(Policy = "New" + AuthorizationPolicies.TreeAccessDocumentsOrDocumentTypes)] +public class AllowedChildrenDocumentTypeController : DocumentTypeControllerBase +{ + private readonly IContentTypeService _contentTypeService; + private readonly IUmbracoMapper _umbracoMapper; + + public AllowedChildrenDocumentTypeController(IContentTypeService contentTypeService, IUmbracoMapper umbracoMapper) + { + _contentTypeService = contentTypeService; + _umbracoMapper = umbracoMapper; + } + + [HttpGet("{id:guid}/allowed-children")] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] + public async Task AllowedChildrenByKey(Guid id, int skip = 0, int take = 100) + { + Attempt?, ContentTypeOperationStatus> attempt = await _contentTypeService.GetAllowedChildrenAsync(id, skip, take); + if (attempt.Success is false) + { + return OperationStatusResult(attempt.Status); + } + + List viewModels = _umbracoMapper.MapEnumerable(attempt.Result!.Items); + + var pagedViewModel = new PagedViewModel + { + Total = attempt.Result.Total, + Items = viewModels, + }; + + return Ok(pagedViewModel); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/CopyDocumentTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/CopyDocumentTypeController.cs index cea14961da..abccabdbe2 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/CopyDocumentTypeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/CopyDocumentTypeController.cs @@ -24,7 +24,7 @@ public class CopyDocumentTypeController : DocumentTypeControllerBase [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] public async Task Copy(Guid id, CopyDocumentTypeRequestModel copyDocumentTypeRequestModel) { - Attempt result = await _contentTypeService.CopyAsync(id, copyDocumentTypeRequestModel.TargetId); + Attempt result = await _contentTypeService.CopyAsync(id, copyDocumentTypeRequestModel.Target?.Id); return result.Success ? CreatedAtId(controller => nameof(controller.ByKey), result.Result!.Key) diff --git a/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/MoveDocumentTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/MoveDocumentTypeController.cs index 792f387973..80e488906a 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/MoveDocumentTypeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/DocumentType/MoveDocumentTypeController.cs @@ -24,7 +24,7 @@ public class MoveDocumentTypeController : DocumentTypeControllerBase [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] public async Task Move(Guid id, MoveDocumentTypeRequestModel moveDocumentTypeRequestModel) { - Attempt result = await _contentTypeService.MoveAsync(id, moveDocumentTypeRequestModel.TargetId); + Attempt result = await _contentTypeService.MoveAsync(id, moveDocumentTypeRequestModel.Target?.Id); return result.Success ? Ok() diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/ByKeyMediaController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/ByKeyMediaController.cs index 5f00a0f843..f778f0df42 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/ByKeyMediaController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/ByKeyMediaController.cs @@ -32,7 +32,7 @@ public class ByKeyMediaController : MediaControllerBase [HttpGet("{id:guid}")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(DocumentResponseModel), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(MediaResponseModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] public async Task ByKey(Guid id) { diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/CreateMediaController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/CreateMediaController.cs index 2eaef8a8e5..7ea38ded64 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/CreateMediaController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/CreateMediaController.cs @@ -44,9 +44,8 @@ public class CreateMediaController : MediaControllerBase { AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync( User, - MediaPermissionResource.WithKeys(createRequestModel.ParentId), + MediaPermissionResource.WithKeys(createRequestModel.Parent?.Id), AuthorizationPolicies.MediaPermissionByResource); - ; if (!authorizationResult.Succeeded) { diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/Item/ItemMediaItemController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/Item/ItemMediaItemController.cs index 82e96f6876..f13bb56799 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/Item/ItemMediaItemController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/Item/ItemMediaItemController.cs @@ -1,13 +1,12 @@ using Asp.Versioning; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Api.Management.Services.Entities; +using Umbraco.Cms.Api.Management.Factories; using Umbraco.Cms.Api.Management.ViewModels.Media.Item; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Services; -using Umbraco.Extensions; namespace Umbraco.Cms.Api.Management.Controllers.Media.Item; @@ -15,36 +14,24 @@ namespace Umbraco.Cms.Api.Management.Controllers.Media.Item; public class ItemMediaItemController : MediaItemControllerBase { private readonly IEntityService _entityService; - private readonly IDataTypeService _dataTypeService; - private readonly IUserStartNodeEntitiesService _userStartNodeEntitiesService; - private readonly IUmbracoMapper _mapper; + private readonly IMediaPresentationModelFactory _mediaPresentationModelFactory; - public ItemMediaItemController(IEntityService entityService, IDataTypeService dataTypeService, IUserStartNodeEntitiesService userStartNodeEntitiesService, IUmbracoMapper mapper) + public ItemMediaItemController(IEntityService entityService, IMediaPresentationModelFactory mediaPresentationModelFactory) { _entityService = entityService; - _dataTypeService = dataTypeService; - _userStartNodeEntitiesService = userStartNodeEntitiesService; - _mapper = mapper; + _mediaPresentationModelFactory = mediaPresentationModelFactory; } [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public async Task Item([FromQuery(Name = "id")] HashSet ids, Guid? dataTypeId = null) + public async Task Item([FromQuery(Name = "id")] HashSet ids) { - IEnumerable media = _entityService.GetAll(UmbracoObjectTypes.Media, ids.ToArray()).OfType(); - if (dataTypeId is not null) - { - if (_dataTypeService.IsDataTypeIgnoringUserStartNodes(dataTypeId.Value)) - { - // FIXME: right now we're faking user id by just passing "-1" - // We should use the backoffice security accessor once auth is in place. - media = _userStartNodeEntitiesService.UserAccessEntities(media, new[] {"-1"}).OfType(); - } - } + IEnumerable media = _entityService + .GetAll(UmbracoObjectTypes.Media, ids.ToArray()) + .OfType(); - List responseModels = _mapper.MapEnumerable(media); - - return Ok(responseModels); + IEnumerable responseModels = media.Select(_mediaPresentationModelFactory.CreateItemResponseModel); + return await Task.FromResult(Ok(responseModels)); } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/MoveMediaController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/MoveMediaController.cs index ace71c738e..29fb30a0db 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/MoveMediaController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/MoveMediaController.cs @@ -39,7 +39,7 @@ public class MoveMediaController : MediaControllerBase { AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync( User, - MediaPermissionResource.WithKeys(new[] { moveDocumentRequestModel.TargetId, id }), + MediaPermissionResource.WithKeys(new[] { moveDocumentRequestModel.Target?.Id, id }), AuthorizationPolicies.MediaPermissionByResource); if (!authorizationResult.Succeeded) @@ -49,7 +49,7 @@ public class MoveMediaController : MediaControllerBase Attempt result = await _mediaEditingService.MoveAsync( id, - moveDocumentRequestModel.TargetId, + moveDocumentRequestModel.Target?.Id, CurrentUserKey(_backOfficeSecurityAccessor)); return result.Success diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/ChildrenMediaRecycleBinController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/ChildrenMediaRecycleBinController.cs index f1d0dc4654..d7bb0a0fcb 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/ChildrenMediaRecycleBinController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/ChildrenMediaRecycleBinController.cs @@ -3,21 +3,22 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Common.ViewModels.Pagination; -using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; +using Umbraco.Cms.Api.Management.Factories; +using Umbraco.Cms.Api.Management.ViewModels.Media.RecycleBin; namespace Umbraco.Cms.Api.Management.Controllers.Media.RecycleBin; [ApiVersion("1.0")] public class ChildrenMediaRecycleBinController : MediaRecycleBinControllerBase { - public ChildrenMediaRecycleBinController(IEntityService entityService) - : base(entityService) + public ChildrenMediaRecycleBinController(IEntityService entityService, IMediaPresentationModelFactory mediaPresentationModelFactory) + : base(entityService, mediaPresentationModelFactory) { } [HttpGet("children")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Children(Guid parentId, int skip = 0, int take = 100) + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> Children(Guid parentId, int skip = 0, int take = 100) => await GetChildren(parentId, skip, take); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/EmptyMediaRecycleBinController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/EmptyMediaRecycleBinController.cs index c235c163b7..1f36cdb9fc 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/EmptyMediaRecycleBinController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/EmptyMediaRecycleBinController.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Management.Controllers.Media.RecycleBin; +using Umbraco.Cms.Api.Management.Factories; using Umbraco.Cms.Api.Management.Security.Authorization.Media; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; @@ -22,8 +23,9 @@ public class EmptyMediaRecycleBinController : MediaRecycleBinControllerBase IEntityService entityService, IAuthorizationService authorizationService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, - IMediaService mediaService) - : base(entityService) + IMediaService mediaService, + IMediaPresentationModelFactory mediaPresentationModelFactory) + : base(entityService, mediaPresentationModelFactory) { _authorizationService = authorizationService; _backOfficeSecurityAccessor = backOfficeSecurityAccessor; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs index 38ca053fc6..21f228a580 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs @@ -6,9 +6,11 @@ using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.Controllers.RecycleBin; +using Umbraco.Cms.Api.Management.Factories; using Umbraco.Cms.Api.Management.Filters; using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; using Umbraco.Cms.Api.Management.Routing; +using Umbraco.Cms.Api.Management.ViewModels.Media.RecycleBin; using Umbraco.Cms.Web.Common.Authorization; namespace Umbraco.Cms.Api.Management.Controllers.Media.RecycleBin; @@ -18,24 +20,26 @@ namespace Umbraco.Cms.Api.Management.Controllers.Media.RecycleBin; [RequireMediaTreeRootAccess] [ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Media))] [Authorize(Policy = "New" + AuthorizationPolicies.SectionAccessMedia)] -public class MediaRecycleBinControllerBase : RecycleBinControllerBase +public class MediaRecycleBinControllerBase : RecycleBinControllerBase { - public MediaRecycleBinControllerBase(IEntityService entityService) + private readonly IMediaPresentationModelFactory _mediaPresentationModelFactory; + + public MediaRecycleBinControllerBase(IEntityService entityService, IMediaPresentationModelFactory mediaPresentationModelFactory) : base(entityService) - { - } + => _mediaPresentationModelFactory = mediaPresentationModelFactory; protected override UmbracoObjectTypes ItemObjectType => UmbracoObjectTypes.Media; protected override int RecycleBinRootId => Constants.System.RecycleBinMedia; - protected override RecycleBinItemResponseModel MapRecycleBinViewModel(Guid? parentKey, IEntitySlim entity) + protected override MediaRecycleBinItemResponseModel MapRecycleBinViewModel(Guid? parentKey, IEntitySlim entity) { - RecycleBinItemResponseModel responseModel = base.MapRecycleBinViewModel(parentKey, entity); + MediaRecycleBinItemResponseModel responseModel = base.MapRecycleBinViewModel(parentKey, entity); if (entity is IMediaEntitySlim mediaEntitySlim) { - responseModel.Icon = mediaEntitySlim.ContentTypeIcon ?? responseModel.Icon; + responseModel.Variants = _mediaPresentationModelFactory.CreateVariantsItemResponseModels(mediaEntitySlim); + responseModel.MediaType = _mediaPresentationModelFactory.CreateMediaTypeReferenceResponseModel(mediaEntitySlim); } return responseModel; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/RootMediaRecycleBinController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/RootMediaRecycleBinController.cs index 1990493e02..01301d5db7 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/RootMediaRecycleBinController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/RootMediaRecycleBinController.cs @@ -3,21 +3,22 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Common.ViewModels.Pagination; -using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; +using Umbraco.Cms.Api.Management.Factories; +using Umbraco.Cms.Api.Management.ViewModels.Media.RecycleBin; namespace Umbraco.Cms.Api.Management.Controllers.Media.RecycleBin; [ApiVersion("1.0")] public class RootMediaRecycleBinController : MediaRecycleBinControllerBase { - public RootMediaRecycleBinController(IEntityService entityService) - : base(entityService) + public RootMediaRecycleBinController(IEntityService entityService, IMediaPresentationModelFactory mediaPresentationModelFactory) + : base(entityService, mediaPresentationModelFactory) { } [HttpGet("root")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Root(int skip = 0, int take = 100) + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> Root(int skip = 0, int take = 100) => await GetRoot(skip, take); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/ChildrenMediaTreeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/ChildrenMediaTreeController.cs index eefcbb9d40..bea5aab029 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/ChildrenMediaTreeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/ChildrenMediaTreeController.cs @@ -2,6 +2,7 @@ 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.Entities; using Umbraco.Cms.Api.Management.ViewModels.Media.Item; using Umbraco.Cms.Core.Cache; @@ -18,8 +19,9 @@ public class ChildrenMediaTreeController : MediaTreeControllerBase IUserStartNodeEntitiesService userStartNodeEntitiesService, IDataTypeService dataTypeService, AppCaches appCaches, - IBackOfficeSecurityAccessor backofficeSecurityAccessor) - : base(entityService, userStartNodeEntitiesService, dataTypeService, appCaches, backofficeSecurityAccessor) + IBackOfficeSecurityAccessor backofficeSecurityAccessor, + IMediaPresentationModelFactory mediaPresentationModelFactory) + : base(entityService, userStartNodeEntitiesService, dataTypeService, appCaches, backofficeSecurityAccessor, mediaPresentationModelFactory) { } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/ItemsMediaTreeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/ItemsMediaTreeController.cs deleted file mode 100644 index 00a23e8777..0000000000 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/ItemsMediaTreeController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Asp.Versioning; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Api.Management.Services.Entities; -using Umbraco.Cms.Api.Management.ViewModels.Media.Item; -using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Core.Services; - -namespace Umbraco.Cms.Api.Management.Controllers.Media.Tree; - -[ApiVersion("1.0")] -public class ItemsMediaTreeController : MediaTreeControllerBase -{ - public ItemsMediaTreeController( - IEntityService entityService, - IUserStartNodeEntitiesService userStartNodeEntitiesService, - IDataTypeService dataTypeService, - AppCaches appCaches, - IBackOfficeSecurityAccessor backofficeSecurityAccessor) - : base(entityService, userStartNodeEntitiesService, dataTypeService, appCaches, backofficeSecurityAccessor) - { - } - - [HttpGet("item")] - [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public async Task>> Items([FromQuery(Name = "id")] Guid[] ids, Guid? dataTypeId = null) - { - IgnoreUserStartNodesForDataType(dataTypeId); - return await GetItems(ids); - } -} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/MediaTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/MediaTreeControllerBase.cs index 4938aee7b8..b3c191f635 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/MediaTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/MediaTreeControllerBase.cs @@ -7,6 +7,7 @@ using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.Controllers.Tree; +using Umbraco.Cms.Api.Management.Factories; using Umbraco.Cms.Api.Management.Services.Entities; using Umbraco.Cms.Api.Management.Routing; using Umbraco.Cms.Api.Management.ViewModels.Media.Item; @@ -22,17 +23,20 @@ public class MediaTreeControllerBase : UserStartNodeTreeControllerBase UmbracoObjectTypes.Media; @@ -45,9 +49,11 @@ public class MediaTreeControllerBase : UserStartNodeTreeControllerBase), StatusCodes.Status200OK)] + public async Task AllowedAtRoot(int skip = 0, int take = 100) + { + PagedModel result = await _mediaTypeService.GetAllAllowedAsRootAsync(skip, take); + + List viewModels = _umbracoMapper.MapEnumerable(result.Items); + + var pagedViewModel = new PagedViewModel + { + Total = result.Total, + Items = viewModels, + }; + + return Ok(pagedViewModel); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/MediaType/AllowedChildrenMediaTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/AllowedChildrenMediaTypeController.cs new file mode 100644 index 0000000000..a3f217a2af --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/AllowedChildrenMediaTypeController.cs @@ -0,0 +1,52 @@ +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.DocumentType; +using Umbraco.Cms.Api.Management.ViewModels.MediaType; +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.MediaType; + +[ApiVersion("1.0")] +[Authorize(Policy = "New" + AuthorizationPolicies.TreeAccessMediaOrMediaTypes)] +public class AllowedChildrenMediaTypeController : MediaTypeControllerBase +{ + private readonly IMediaTypeService _mediaTypeService; + private readonly IUmbracoMapper _umbracoMapper; + + public AllowedChildrenMediaTypeController(IMediaTypeService mediaTypeService, IUmbracoMapper umbracoMapper) + { + _mediaTypeService = mediaTypeService; + _umbracoMapper = umbracoMapper; + } + + [HttpGet("{id:guid}/allowed-children")] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] + public async Task AllowedChildrenByKey(Guid id, int skip = 0, int take = 100) + { + Attempt?, ContentTypeOperationStatus> attempt = await _mediaTypeService.GetAllowedChildrenAsync(id, skip, take); + if (attempt.Success is false) + { + return OperationStatusResult(attempt.Status); + } + + List viewModels = _umbracoMapper.MapEnumerable(attempt.Result!.Items); + + var pagedViewModel = new PagedViewModel + { + Total = attempt.Result.Total, + Items = viewModels, + }; + + return Ok(pagedViewModel); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/MediaType/CopyMediaTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/CopyMediaTypeController.cs index 08d1587c88..1dcd06ff92 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/MediaType/CopyMediaTypeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/CopyMediaTypeController.cs @@ -24,7 +24,7 @@ public class CopyMediaTypeController : MediaTypeControllerBase [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] public async Task Copy(Guid id, CopyMediaTypeRequestModel copyMediaTypeRequestModel) { - Attempt result = await _mediaTypeService.CopyAsync(id, copyMediaTypeRequestModel.TargetId); + Attempt result = await _mediaTypeService.CopyAsync(id, copyMediaTypeRequestModel.Target?.Id); return result.Success ? CreatedAtId(controller => nameof(controller.ByKey), result.Result!.Key) diff --git a/src/Umbraco.Cms.Api.Management/Controllers/MediaType/MoveMediaTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/MoveMediaTypeController.cs index b6f608fd90..084ea89179 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/MediaType/MoveMediaTypeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/MediaType/MoveMediaTypeController.cs @@ -24,7 +24,7 @@ public class MoveMediaTypeController : MediaTypeControllerBase [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] public async Task Move(Guid id, MoveMediaTypeRequestModel moveMediaTypeRequestModel) { - Attempt result = await _mediaTypeService.MoveAsync(id, moveMediaTypeRequestModel.TargetId); + Attempt result = await _mediaTypeService.MoveAsync(id, moveMediaTypeRequestModel.Target?.Id); return result.Success ? Ok() diff --git a/src/Umbraco.Cms.Api.Management/Controllers/MemberGroup/Tree/MemberGroupTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/MemberGroup/Tree/MemberGroupTreeControllerBase.cs index 73aa5e19ac..29010e5a34 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/MemberGroup/Tree/MemberGroupTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/MemberGroup/Tree/MemberGroupTreeControllerBase.cs @@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.Controllers.Tree; using Umbraco.Cms.Api.Management.ViewModels.Tree; @@ -15,7 +14,7 @@ namespace Umbraco.Cms.Api.Management.Controllers.MemberGroup.Tree; [VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.MemberGroup}")] [ApiExplorerSettings(GroupName = "Member Group")] [Authorize(Policy = "New" + AuthorizationPolicies.TreeAccessMemberGroups)] -public class MemberGroupTreeControllerBase : EntityTreeControllerBase +public class MemberGroupTreeControllerBase : NamedEntityTreeControllerBase { public MemberGroupTreeControllerBase(IEntityService entityService) : base(entityService) @@ -23,10 +22,4 @@ public class MemberGroupTreeControllerBase : EntityTreeControllerBase UmbracoObjectTypes.MemberGroup; - - protected override EntityTreeItemResponseModel MapTreeItemViewModel(Guid? parentKey, IEntitySlim entity) - { - EntityTreeItemResponseModel responseModel = base.MapTreeItemViewModel(parentKey, entity); - return responseModel; - } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/MemberGroup/Tree/RootMemberGroupTreeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/MemberGroup/Tree/RootMemberGroupTreeController.cs index 0a29610c79..cc9698ea61 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/MemberGroup/Tree/RootMemberGroupTreeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/MemberGroup/Tree/RootMemberGroupTreeController.cs @@ -17,7 +17,7 @@ public class RootMemberGroupTreeController : MemberGroupTreeControllerBase [HttpGet("root")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Root(int skip = 0, int take = 100) + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> Root(int skip = 0, int take = 100) => await GetRoot(skip, take); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/MemberType/Tree/MemberTypeTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/MemberType/Tree/MemberTypeTreeControllerBase.cs index e1c2c4a65b..5e44e8dcf3 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/MemberType/Tree/MemberTypeTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/MemberType/Tree/MemberTypeTreeControllerBase.cs @@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.Controllers.Tree; using Umbraco.Cms.Api.Management.ViewModels.Tree; @@ -15,7 +14,7 @@ namespace Umbraco.Cms.Api.Management.Controllers.MemberType.Tree; [VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.MemberType}")] [ApiExplorerSettings(GroupName = "Member Type")] [Authorize(Policy = "New" + AuthorizationPolicies.TreeAccessMemberTypes)] -public class MemberTypeTreeControllerBase : EntityTreeControllerBase +public class MemberTypeTreeControllerBase : NamedEntityTreeControllerBase { public MemberTypeTreeControllerBase(IEntityService entityService) : base(entityService) @@ -23,10 +22,4 @@ public class MemberTypeTreeControllerBase : EntityTreeControllerBase UmbracoObjectTypes.MemberType; - - protected override EntityTreeItemResponseModel MapTreeItemViewModel(Guid? parentKey, IEntitySlim entity) - { - EntityTreeItemResponseModel responseModel = base.MapTreeItemViewModel(parentKey, entity); - return responseModel; - } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/MemberType/Tree/RootMemberTypeTreeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/MemberType/Tree/RootMemberTypeTreeController.cs index 9d7e6a130b..081a469ef6 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/MemberType/Tree/RootMemberTypeTreeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/MemberType/Tree/RootMemberTypeTreeController.cs @@ -17,7 +17,7 @@ public class RootMemberTypeTreeController : MemberTypeTreeControllerBase [HttpGet("root")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Root(int skip = 0, int take = 100) + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> Root(int skip = 0, int take = 100) => await GetRoot(skip, take); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs index 8bd452ab1e..f9c863d1bd 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs @@ -1,18 +1,19 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Common.Builders; +using Umbraco.Cms.Api.Common.ViewModels.Pagination; +using Umbraco.Cms.Api.Management.Content; +using Umbraco.Cms.Api.Management.Services.Paging; +using Umbraco.Cms.Api.Management.ViewModels.Item; +using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Api.Management.Services.Paging; -using Umbraco.Cms.Api.Common.ViewModels.Pagination; -using Umbraco.Cms.Api.Management.Content; -using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; namespace Umbraco.Cms.Api.Management.Controllers.RecycleBin; public abstract class RecycleBinControllerBase : ContentControllerBase - where TItem : RecycleBinItemResponseModel, new() + where TItem : RecycleBinItemResponseModelBase, new() { private readonly IEntityService _entityService; private readonly string _itemUdiType; @@ -68,13 +69,15 @@ public abstract class RecycleBinControllerBase : ContentControllerBase var viewModel = new TItem { - Icon = _itemUdiType, - Name = entity.Name!, Id = entity.Key, Type = _itemUdiType, HasChildren = entity.HasChildren, - IsContainer = entity.IsContainer, - ParentId = parentKey + Parent = parentKey.HasValue + ? new ItemReferenceByIdResponseModel + { + Id = parentKey.Value + } + : null }; return viewModel; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RelationType/Tree/RelationTypeTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/RelationType/Tree/RelationTypeTreeControllerBase.cs index 77c5f88285..8311ed6234 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/RelationType/Tree/RelationTypeTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/RelationType/Tree/RelationTypeTreeControllerBase.cs @@ -6,6 +6,7 @@ using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.Controllers.Tree; using Umbraco.Cms.Api.Management.ViewModels.Tree; using Umbraco.Cms.Api.Management.Routing; +using Umbraco.Cms.Api.Management.ViewModels; using Umbraco.Cms.Web.Common.Authorization; namespace Umbraco.Cms.Api.Management.Controllers.RelationType.Tree; @@ -16,7 +17,7 @@ namespace Umbraco.Cms.Api.Management.Controllers.RelationType.Tree; [Authorize(Policy = "New" + AuthorizationPolicies.TreeAccessRelationTypes)] // NOTE: at the moment relation types aren't supported by EntityService, so we have little use of the // tree controller base. We'll keep it though, in the hope that we can mend EntityService. -public class RelationTypeTreeControllerBase : EntityTreeControllerBase +public class RelationTypeTreeControllerBase : NamedEntityTreeControllerBase { public RelationTypeTreeControllerBase(IEntityService entityService) : base(entityService) @@ -25,14 +26,18 @@ public class RelationTypeTreeControllerBase : EntityTreeControllerBase UmbracoObjectTypes.RelationType; - protected IEnumerable MapTreeItemViewModels(Guid? parentKey, IEnumerable relationTypes) - => relationTypes.Select(relationType => new EntityTreeItemResponseModel + protected IEnumerable MapTreeItemViewModels(Guid? parentKey, IEnumerable relationTypes) + => relationTypes.Select(relationType => new NamedEntityTreeItemResponseModel { Name = relationType.Name!, Id = relationType.Key, Type = Constants.UdiEntityType.RelationType, HasChildren = false, - IsContainer = false, - ParentId = parentKey + Parent = parentKey.HasValue + ? new ReferenceByIdModel + { + Id = parentKey.Value + } + : null }); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RelationType/Tree/RootRelationTypeTreeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/RelationType/Tree/RootRelationTypeTreeController.cs index 0e5bd55203..0bf7e01316 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/RelationType/Tree/RootRelationTypeTreeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/RelationType/Tree/RootRelationTypeTreeController.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Api.Management.Services.Paging; using Umbraco.Cms.Api.Common.ViewModels.Pagination; using Umbraco.Cms.Api.Management.ViewModels.Tree; @@ -20,12 +19,12 @@ public class RootRelationTypeTreeController : RelationTypeTreeControllerBase [HttpGet("root")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Root(int skip = 0, int take = 100) + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> Root(int skip = 0, int take = 100) { PagedModel pagedRelationTypes = await _relationService.GetPagedRelationTypesAsync(skip, take); - PagedViewModel pagedResult = PagedViewModel( + PagedViewModel pagedResult = PagedViewModel( MapTreeItemViewModels(null, pagedRelationTypes.Items), pagedRelationTypes.Total); diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/ChildrenTemplateTreeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/ChildrenTemplateTreeController.cs index 01b4219f28..43fba919bb 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/ChildrenTemplateTreeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/ChildrenTemplateTreeController.cs @@ -17,7 +17,7 @@ public class ChildrenTemplateTreeController : TemplateTreeControllerBase [HttpGet("children")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Children(Guid parentId, int skip = 0, int take = 100) + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> Children(Guid parentId, int skip = 0, int take = 100) => await GetChildren(parentId, skip, take); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/RootTemplateTreeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/RootTemplateTreeController.cs index a33876c3da..5e109063db 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/RootTemplateTreeController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/RootTemplateTreeController.cs @@ -17,7 +17,7 @@ public class RootTemplateTreeController : TemplateTreeControllerBase [HttpGet("root")] [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> Root(int skip = 0, int take = 100) + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> Root(int skip = 0, int take = 100) => await GetRoot(skip, take); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/TemplateTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/TemplateTreeControllerBase.cs index f25fcaa439..95b69ca395 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/TemplateTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/TemplateTreeControllerBase.cs @@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Api.Management.Controllers.Tree; using Umbraco.Cms.Api.Management.ViewModels.Tree; @@ -15,7 +14,7 @@ namespace Umbraco.Cms.Api.Management.Controllers.Template.Tree; [VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.Template}")] [ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Template))] [Authorize(Policy = "New" + AuthorizationPolicies.TreeAccessTemplates)] -public class TemplateTreeControllerBase : EntityTreeControllerBase +public class TemplateTreeControllerBase : NamedEntityTreeControllerBase { public TemplateTreeControllerBase(IEntityService entityService) : base(entityService) @@ -23,10 +22,4 @@ public class TemplateTreeControllerBase : EntityTreeControllerBase UmbracoObjectTypes.Template; - - protected override EntityTreeItemResponseModel MapTreeItemViewModel(Guid? parentKey, IEntitySlim entity) - { - EntityTreeItemResponseModel responseModel = base.MapTreeItemViewModel(parentKey, entity); - return responseModel; - } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Tree/EntityTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Tree/EntityTreeControllerBase.cs index 87a46b8d51..d8d3d3ffdd 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Tree/EntityTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Tree/EntityTreeControllerBase.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Common.ViewModels.Pagination; using Umbraco.Cms.Api.Management.Services.Paging; +using Umbraco.Cms.Api.Management.ViewModels; using Umbraco.Cms.Api.Management.ViewModels.Tree; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; @@ -115,12 +116,15 @@ public abstract class EntityTreeControllerBase : ManagementApiControllerB { var viewModel = new TItem { - Name = entity.Name!, Id = entity.Key, Type = _itemUdiType, HasChildren = entity.HasChildren, - IsContainer = entity.IsContainer, - ParentId = parentKey + Parent = parentKey.HasValue + ? new ReferenceByIdModel + { + Id = parentKey.Value + } + : null }; return viewModel; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Tree/FolderTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Tree/FolderTreeControllerBase.cs index 6bd810dc1e..435f98088f 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Tree/FolderTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Tree/FolderTreeControllerBase.cs @@ -6,7 +6,7 @@ using Umbraco.Cms.Api.Management.ViewModels.Tree; namespace Umbraco.Cms.Api.Management.Controllers.Tree; -public abstract class FolderTreeControllerBase : EntityTreeControllerBase +public abstract class FolderTreeControllerBase : NamedEntityTreeControllerBase where TItem : FolderTreeItemResponseModel, new() { private readonly Guid _folderObjectTypeId; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Tree/NamedEntityTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Tree/NamedEntityTreeControllerBase.cs new file mode 100644 index 0000000000..a50c6b1cbe --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Tree/NamedEntityTreeControllerBase.cs @@ -0,0 +1,21 @@ +using Umbraco.Cms.Api.Management.ViewModels.Tree; +using Umbraco.Cms.Core.Models.Entities; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Controllers.Tree; + +public abstract class NamedEntityTreeControllerBase : EntityTreeControllerBase + where TItem : NamedEntityTreeItemResponseModel, new() +{ + protected NamedEntityTreeControllerBase(IEntityService entityService) + : base(entityService) + { + } + + protected override TItem MapTreeItemViewModel(Guid? parentKey, IEntitySlim entity) + { + TItem item = base.MapTreeItemViewModel(parentKey, entity); + item.Name = entity.Name ?? string.Empty; + return item; + } +} diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthPolicyBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthPolicyBuilderExtensions.cs index 3f678c1bc4..9b6653f11b 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthPolicyBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthPolicyBuilderExtensions.cs @@ -89,6 +89,7 @@ internal static class BackOfficeAuthPolicyBuilderExtensions AddPolicy(AuthorizationPolicies.TreeAccessDocumentTypes, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Settings); AddPolicy(AuthorizationPolicies.TreeAccessLanguages, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Settings); AddPolicy(AuthorizationPolicies.TreeAccessMediaTypes, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Settings); + AddPolicy(AuthorizationPolicies.TreeAccessMediaOrMediaTypes, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Media, Constants.Applications.Settings); AddPolicy(AuthorizationPolicies.TreeAccessMemberGroups, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Members); AddPolicy(AuthorizationPolicies.TreeAccessMemberTypes, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Settings); AddPolicy(AuthorizationPolicies.TreeAccessPartialViews, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Settings); diff --git a/src/Umbraco.Cms.Api.Management/Factories/ContentPresentationFactoryBase.cs b/src/Umbraco.Cms.Api.Management/Factories/ContentPresentationFactoryBase.cs new file mode 100644 index 0000000000..ba4885f2a3 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Factories/ContentPresentationFactoryBase.cs @@ -0,0 +1,33 @@ +using Umbraco.Cms.Api.Management.ViewModels.ContentType; +using Umbraco.Cms.Core.Mapping; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Entities; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Factories; + +internal abstract class ContentPresentationFactoryBase + where TContentTypeService : IContentTypeBaseService + where TContentType : IContentTypeComposition +{ + private readonly TContentTypeService _contentTypeService; + private readonly IUmbracoMapper _umbracoMapper; + + protected ContentPresentationFactoryBase(TContentTypeService contentTypeService, IUmbracoMapper umbracoMapper) + { + _contentTypeService = contentTypeService; + _umbracoMapper = umbracoMapper; + } + + protected TContentTypeReferenceResponseModel CreateContentTypeReferenceResponseModel(IContentEntitySlim entity) + where TContentTypeReferenceResponseModel : ContentTypeReferenceResponseModelBase, new() + { + // This sucks, since it'll cost an extra DB call. + // but currently there's no really good way to get the content type key from an IDocumentEntitySlim or IMediaEntitySlim. + // FIXME: to fix this, add content type key and "IsContainer" to IDocumentEntitySlim and IMediaEntitySlim, and use those here instead of fetching the entire content type. + TContentType? contentType = _contentTypeService.Get(entity.ContentTypeAlias); + return contentType is not null + ? _umbracoMapper.Map(contentType)! + : new TContentTypeReferenceResponseModel(); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Factories/ContentTypeEditingPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/ContentTypeEditingPresentationFactory.cs index a5a381ca0c..f979c17649 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/ContentTypeEditingPresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/ContentTypeEditingPresentationFactory.cs @@ -37,10 +37,8 @@ internal abstract class ContentTypeEditingPresentationFactory AllowedAsRoot = viewModel.AllowedAsRoot, VariesByCulture = viewModel.VariesByCulture, VariesBySegment = viewModel.VariesBySegment, - Compositions = MapCompositions(viewModel.Compositions), Containers = MapContainers(viewModel.Containers), - Properties = MapProperties(viewModel.Properties), - AllowedContentTypes = MapAllowedContentTypes(viewModel.AllowedContentTypes), + Properties = MapProperties(viewModel.Properties) }; return editingModel; @@ -70,26 +68,32 @@ internal abstract class ContentTypeEditingPresentationFactory return compositionModel; } - private ContentTypeSort[] MapAllowedContentTypes(IEnumerable allowedContentTypes) + protected ContentTypeSort[] MapAllowedContentTypes(IDictionary allowedContentTypesAndSortOrder) { // need to fetch the content type aliases to construct the corresponding ContentTypeSort entities - ContentTypeViewModels.ContentTypeSort[] allowedContentTypesArray = allowedContentTypes as ContentTypeViewModels.ContentTypeSort[] - ?? allowedContentTypes.ToArray(); - Guid[] contentTypeKeys = allowedContentTypesArray.Select(a => a.Id).ToArray(); IDictionary contentTypeAliasesByKey = _contentTypeService .GetAll() - .Where(c => contentTypeKeys.Contains(c.Key)) + .Where(c => allowedContentTypesAndSortOrder.Keys.Contains(c.Key)) .ToDictionary(c => c.Key, c => c.Alias); - return allowedContentTypesArray + return allowedContentTypesAndSortOrder .Select(a => - contentTypeAliasesByKey.TryGetValue(a.Id, out var alias) - ? new ContentTypeSort(a.Id, a.SortOrder, alias) + contentTypeAliasesByKey.TryGetValue(a.Key, out var alias) + ? new ContentTypeSort(a.Key, a.Value, alias) : null) .WhereNotNull() .ToArray(); } + protected ContentTypeEditingModels.Composition[] MapCompositions(IDictionary compositions) + => compositions.Select(composition => new ContentTypeEditingModels.Composition + { + Key = composition.Key, + CompositionType = composition.Value == ContentTypeViewModels.CompositionType.Inheritance + ? ContentTypeEditingModels.CompositionType.Inheritance + : ContentTypeEditingModels.CompositionType.Composition + }).ToArray(); + private TPropertyTypeEditingModel[] MapProperties( IEnumerable properties) where TPropertyTypeEditingModel : ContentTypeEditingModels.PropertyTypeModelBase, new() @@ -110,9 +114,9 @@ internal abstract class ContentTypeEditingPresentationFactory VariesBySegment = property.VariesBySegment, VariesByCulture = property.VariesByCulture, Key = property.Id, - ContainerKey = property.ContainerId, + ContainerKey = property.Container?.Id, SortOrder = property.SortOrder, - DataTypeKey = property.DataTypeId, + DataTypeKey = property.DataType.Id, }).ToArray(); private TPropertyTypeContainerEditingModel[] MapContainers( @@ -124,15 +128,6 @@ internal abstract class ContentTypeEditingPresentationFactory Key = container.Id, SortOrder = container.SortOrder, Name = container.Name, - ParentKey = container.ParentId, - }).ToArray(); - - private ContentTypeEditingModels.Composition[] MapCompositions(IEnumerable compositions) - => compositions.Select(composition => new ContentTypeEditingModels.Composition - { - Key = composition.Id, - CompositionType = composition.CompositionType == ContentTypeViewModels.ContentTypeCompositionType.Inheritance - ? ContentTypeEditingModels.CompositionType.Inheritance - : ContentTypeEditingModels.CompositionType.Composition + ParentKey = container.Parent?.Id, }).ToArray(); } diff --git a/src/Umbraco.Cms.Api.Management/Factories/DocumentEditingPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/DocumentEditingPresentationFactory.cs index a16f587a95..4f96cdb099 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/DocumentEditingPresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/DocumentEditingPresentationFactory.cs @@ -9,9 +9,9 @@ internal sealed class DocumentEditingPresentationFactory : ContentEditingPresent { ContentCreateModel model = MapContentEditingModel(requestModel); model.Key = requestModel.Id; - model.ContentTypeKey = requestModel.ContentTypeId; - model.TemplateKey = requestModel.TemplateId; - model.ParentKey = requestModel.ParentId; + model.ContentTypeKey = requestModel.DocumentType.Id; + model.TemplateKey = requestModel.Template?.Id; + model.ParentKey = requestModel.Parent?.Id; return model; } @@ -19,7 +19,7 @@ internal sealed class DocumentEditingPresentationFactory : ContentEditingPresent public ContentUpdateModel MapUpdateModel(UpdateDocumentRequestModel requestModel) { ContentUpdateModel model = MapContentEditingModel(requestModel); - model.TemplateKey = requestModel.TemplateId; + model.TemplateKey = requestModel.Template?.Id; return model; } diff --git a/src/Umbraco.Cms.Api.Management/Factories/DocumentPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/DocumentPresentationFactory.cs index be11fadaf5..d14fa8a74e 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/DocumentPresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/DocumentPresentationFactory.cs @@ -1,6 +1,10 @@ -using Umbraco.Cms.Api.Management.ViewModels.Document; +using Umbraco.Cms.Api.Management.Mapping.Content; +using Umbraco.Cms.Api.Management.ViewModels; +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Management.ViewModels.Document; using Umbraco.Cms.Api.Management.ViewModels.Document.Item; using Umbraco.Cms.Api.Management.ViewModels.DocumentBlueprint.Item; +using Umbraco.Cms.Api.Management.ViewModels.DocumentType; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -9,23 +13,28 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Api.Management.Factories; -public class DocumentPresentationFactory : IDocumentPresentationFactory +internal sealed class DocumentPresentationFactory + : ContentPresentationFactoryBase, IDocumentPresentationFactory { private readonly IUmbracoMapper _umbracoMapper; private readonly IContentUrlFactory _contentUrlFactory; private readonly IFileService _fileService; private readonly IContentTypeService _contentTypeService; + private readonly IPublicAccessService _publicAccessService; public DocumentPresentationFactory( IUmbracoMapper umbracoMapper, IContentUrlFactory contentUrlFactory, IFileService fileService, - IContentTypeService contentTypeService) + IContentTypeService contentTypeService, + IPublicAccessService publicAccessService) + : base(contentTypeService, umbracoMapper) { _umbracoMapper = umbracoMapper; _contentUrlFactory = contentUrlFactory; _fileService = fileService; _contentTypeService = contentTypeService; + _publicAccessService = publicAccessService; } public async Task CreateResponseModelAsync(IContent content) @@ -34,35 +43,34 @@ public class DocumentPresentationFactory : IDocumentPresentationFactory responseModel.Urls = await _contentUrlFactory.GetUrlsAsync(content); - responseModel.TemplateId = content.TemplateId.HasValue + Guid? templateKey = content.TemplateId.HasValue ? _fileService.GetTemplate(content.TemplateId.Value)?.Key : null; + responseModel.Template = templateKey.HasValue + ? new ReferenceByIdModel { Id = templateKey.Value } + : null; + return responseModel; } - public DocumentItemResponseModel CreateItemResponseModel(IDocumentEntitySlim entity, string? culture = null) + public DocumentItemResponseModel CreateItemResponseModel(IDocumentEntitySlim entity) { var responseModel = new DocumentItemResponseModel { - Name = entity.Name ?? string.Empty, Id = entity.Key, - Icon = entity.ContentTypeIcon, IsTrashed = entity.Trashed }; + responseModel.IsProtected = _publicAccessService.IsProtected(entity.Path); + IContentType? contentType = _contentTypeService.Get(entity.ContentTypeAlias); - responseModel.ContentTypeId = contentType?.Key ?? Guid.Empty; - - if (culture == null || !entity.Variations.VariesByCulture()) + if (contentType is not null) { - return responseModel; + responseModel.DocumentType = _umbracoMapper.Map(contentType)!; } - if (entity.CultureNames.TryGetValue(culture, out var cultureName)) - { - responseModel.Name = cultureName; - } + responseModel.Variants = CreateVariantsItemResponseModels(entity); return responseModel; } @@ -78,4 +86,31 @@ public class DocumentPresentationFactory : IDocumentPresentationFactory responseModel.Name = contentType?.Name ?? entity.Name ?? string.Empty; return responseModel; } + + public IEnumerable CreateVariantsItemResponseModels(IDocumentEntitySlim entity) + { + if (entity.Variations.VariesByCulture() is false) + { + yield return new() + { + Name = entity.Name ?? string.Empty, + State = ContentStateHelper.GetContentState(entity, null), + Culture = null, + }; + yield break; + } + + foreach (KeyValuePair cultureNamePair in entity.CultureNames) + { + yield return new() + { + Name = cultureNamePair.Value, + Culture = cultureNamePair.Key, + State = ContentStateHelper.GetContentState(entity, cultureNamePair.Key) + }; + } + } + + public DocumentTypeReferenceResponseModel CreateDocumentTypeReferenceResponseModel(IDocumentEntitySlim entity) + => CreateContentTypeReferenceResponseModel(entity); } diff --git a/src/Umbraco.Cms.Api.Management/Factories/DocumentTypeEditingPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/DocumentTypeEditingPresentationFactory.cs index aeff9e1c23..0aa3da8d27 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/DocumentTypeEditingPresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/DocumentTypeEditingPresentationFactory.cs @@ -1,5 +1,6 @@ using Umbraco.Cms.Api.Management.ViewModels.DocumentType; using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.ContentTypeEditing; using Umbraco.Cms.Core.Services; using ContentTypeCleanupViewModel = Umbraco.Cms.Api.Management.ViewModels.ContentType.ContentTypeCleanup; @@ -26,9 +27,11 @@ internal sealed class DocumentTypeEditingPresentationFactory : ContentTypeEditin MapCleanup(createModel, requestModel.Cleanup); createModel.Key = requestModel.Id; - createModel.ContainerKey = requestModel.ContainerId; - createModel.AllowedTemplateKeys = requestModel.AllowedTemplateIds; - createModel.DefaultTemplateKey = requestModel.DefaultTemplateId; + createModel.ContainerKey = requestModel.Folder?.Id; + createModel.AllowedTemplateKeys = requestModel.AllowedTemplates.Select(reference => reference.Id).ToArray(); + createModel.DefaultTemplateKey = requestModel.DefaultTemplate?.Id; + createModel.AllowedContentTypes = MapAllowedContentTypes(requestModel.AllowedDocumentTypes); + createModel.Compositions = MapCompositions(requestModel.Compositions); return createModel; } @@ -45,8 +48,10 @@ internal sealed class DocumentTypeEditingPresentationFactory : ContentTypeEditin MapCleanup(updateModel, requestModel.Cleanup); - updateModel.AllowedTemplateKeys = requestModel.AllowedTemplateIds; - updateModel.DefaultTemplateKey = requestModel.DefaultTemplateId; + updateModel.AllowedTemplateKeys = requestModel.AllowedTemplates.Select(reference => reference.Id).ToArray(); + updateModel.DefaultTemplateKey = requestModel.DefaultTemplate?.Id; + updateModel.AllowedContentTypes = MapAllowedContentTypes(requestModel.AllowedDocumentTypes); + updateModel.Compositions = MapCompositions(requestModel.Compositions); return updateModel; } @@ -61,4 +66,14 @@ internal sealed class DocumentTypeEditingPresentationFactory : ContentTypeEditin KeepAllVersionsNewerThanDays = cleanup.KeepAllVersionsNewerThanDays, KeepLatestVersionPerDayForDays = cleanup.KeepLatestVersionPerDayForDays }; + + private IEnumerable MapAllowedContentTypes(IEnumerable allowedDocumentTypes) + => MapAllowedContentTypes(allowedDocumentTypes + .DistinctBy(t => t.DocumentType.Id) + .ToDictionary(t => t.DocumentType.Id, t => t.SortOrder)); + + private IEnumerable MapCompositions(IEnumerable documentTypeCompositions) + => MapCompositions(documentTypeCompositions + .DistinctBy(c => c.DocumentType.Id) + .ToDictionary(c => c.DocumentType.Id, c => c.CompositionType)); } diff --git a/src/Umbraco.Cms.Api.Management/Factories/IDocumentPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/IDocumentPresentationFactory.cs index 03df51cd2e..eda78e2c0b 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/IDocumentPresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/IDocumentPresentationFactory.cs @@ -1,6 +1,8 @@ -using Umbraco.Cms.Api.Management.ViewModels.Document; +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Management.ViewModels.Document; using Umbraco.Cms.Api.Management.ViewModels.Document.Item; using Umbraco.Cms.Api.Management.ViewModels.DocumentBlueprint.Item; +using Umbraco.Cms.Api.Management.ViewModels.DocumentType; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -10,7 +12,11 @@ public interface IDocumentPresentationFactory { Task CreateResponseModelAsync(IContent content); - DocumentItemResponseModel CreateItemResponseModel(IDocumentEntitySlim entity, string? culture = null); + DocumentItemResponseModel CreateItemResponseModel(IDocumentEntitySlim entity); DocumentBlueprintResponseModel CreateBlueprintItemResponseModel(IDocumentEntitySlim entity); + + IEnumerable CreateVariantsItemResponseModels(IDocumentEntitySlim entity); + + DocumentTypeReferenceResponseModel CreateDocumentTypeReferenceResponseModel(IDocumentEntitySlim entity); } diff --git a/src/Umbraco.Cms.Api.Management/Factories/IMediaPresentationModelFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/IMediaPresentationModelFactory.cs index 1c189a867b..829e951e3b 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/IMediaPresentationModelFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/IMediaPresentationModelFactory.cs @@ -1,9 +1,19 @@ -using Umbraco.Cms.Api.Management.ViewModels.Media; +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Management.ViewModels.Media; +using Umbraco.Cms.Api.Management.ViewModels.Media.Item; +using Umbraco.Cms.Api.Management.ViewModels.MediaType; using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Entities; namespace Umbraco.Cms.Api.Management.Factories; public interface IMediaPresentationModelFactory { Task CreateResponseModelAsync(IMedia media); + + MediaItemResponseModel CreateItemResponseModel(IMediaEntitySlim entity); + + IEnumerable CreateVariantsItemResponseModels(IMediaEntitySlim entity); + + MediaTypeReferenceResponseModel CreateMediaTypeReferenceResponseModel(IMediaEntitySlim entity); } diff --git a/src/Umbraco.Cms.Api.Management/Factories/MediaEditingPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/MediaEditingPresentationFactory.cs index 337ab8bca1..2444d5fdcc 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/MediaEditingPresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/MediaEditingPresentationFactory.cs @@ -9,8 +9,8 @@ internal sealed class MediaEditingPresentationFactory : ContentEditingPresentati { MediaCreateModel model = MapContentEditingModel(createRequestModel); model.Key = createRequestModel.Id; - model.ContentTypeKey = createRequestModel.ContentTypeId; - model.ParentKey = createRequestModel.ParentId; + model.ContentTypeKey = createRequestModel.MediaType.Id; + model.ParentKey = createRequestModel.Parent?.Id; return model; } diff --git a/src/Umbraco.Cms.Api.Management/Factories/MediaPresentationModelFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/MediaPresentationModelFactory.cs index 0b8e077ffc..f2012a80e6 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/MediaPresentationModelFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/MediaPresentationModelFactory.cs @@ -2,31 +2,40 @@ using Umbraco.Cms.Api.Management.Routing; using Umbraco.Cms.Api.Management.ViewModels.Content; using Umbraco.Cms.Api.Management.ViewModels.Media; +using Umbraco.Cms.Api.Management.ViewModels.Media.Item; +using Umbraco.Cms.Api.Management.ViewModels.MediaType; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; using Umbraco.Extensions; namespace Umbraco.Cms.Api.Management.Factories; -public class MediaPresentationModelFactory : IMediaPresentationModelFactory +internal sealed class MediaPresentationModelFactory + : ContentPresentationFactoryBase, IMediaPresentationModelFactory { private readonly IUmbracoMapper _umbracoMapper; private readonly ContentSettings _contentSettings; private readonly MediaUrlGeneratorCollection _mediaUrlGenerators; private readonly IAbsoluteUrlBuilder _absoluteUrlBuilder; + private readonly IMediaTypeService _mediaTypeService; public MediaPresentationModelFactory( IUmbracoMapper umbracoMapper, IOptions contentSettings, MediaUrlGeneratorCollection mediaUrlGenerators, - IAbsoluteUrlBuilder absoluteUrlBuilder) + IAbsoluteUrlBuilder absoluteUrlBuilder, + IMediaTypeService mediaTypeService) + : base(mediaTypeService, umbracoMapper) { _umbracoMapper = umbracoMapper; _contentSettings = contentSettings.Value; _mediaUrlGenerators = mediaUrlGenerators; _absoluteUrlBuilder = absoluteUrlBuilder; + _mediaTypeService = mediaTypeService; } public Task CreateResponseModelAsync(IMedia media) @@ -45,4 +54,36 @@ public class MediaPresentationModelFactory : IMediaPresentationModelFactory return Task.FromResult(responseModel); } + + public MediaItemResponseModel CreateItemResponseModel(IMediaEntitySlim entity) + { + var responseModel = new MediaItemResponseModel + { + Id = entity.Key, + IsTrashed = entity.Trashed + }; + + IMediaType? mediaType = _mediaTypeService.Get(entity.ContentTypeAlias); + if (mediaType is not null) + { + responseModel.MediaType = _umbracoMapper.Map(mediaType)!; + } + + responseModel.Variants = CreateVariantsItemResponseModels(entity); + + return responseModel; + } + + public IEnumerable CreateVariantsItemResponseModels(IMediaEntitySlim entity) + => new[] + { + new VariantItemResponseModel + { + Name = entity.Name ?? string.Empty, + Culture = null + } + }; + + public MediaTypeReferenceResponseModel CreateMediaTypeReferenceResponseModel(IMediaEntitySlim entity) + => CreateContentTypeReferenceResponseModel(entity); } diff --git a/src/Umbraco.Cms.Api.Management/Factories/MediaTypeEditingPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/MediaTypeEditingPresentationFactory.cs index cfec97cc90..5344feead2 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/MediaTypeEditingPresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/MediaTypeEditingPresentationFactory.cs @@ -1,5 +1,6 @@ using Umbraco.Cms.Api.Management.ViewModels.MediaType; using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.ContentTypeEditing; using Umbraco.Cms.Core.Services; @@ -23,13 +24,16 @@ internal sealed class MediaTypeEditingPresentationFactory : ContentTypeEditingPr >(requestModel); createModel.Key = requestModel.Id; - createModel.ContainerKey = requestModel.ContainerId; + createModel.ContainerKey = requestModel.Folder?.Id; + createModel.AllowedContentTypes = MapAllowedContentTypes(requestModel.AllowedMediaTypes); + createModel.Compositions = MapCompositions(requestModel.Compositions); return createModel; } public MediaTypeUpdateModel MapUpdateModel(UpdateMediaTypeRequestModel requestModel) - => MapContentTypeEditingModel< + { + MediaTypeUpdateModel updateModel = MapContentTypeEditingModel< MediaTypeUpdateModel, MediaTypePropertyTypeModel, MediaTypePropertyContainerModel, @@ -37,6 +41,22 @@ internal sealed class MediaTypeEditingPresentationFactory : ContentTypeEditingPr UpdateMediaTypePropertyTypeContainerRequestModel >(requestModel); + updateModel.AllowedContentTypes = MapAllowedContentTypes(requestModel.AllowedMediaTypes); + updateModel.Compositions = MapCompositions(requestModel.Compositions); + + return updateModel; + } + public IEnumerable MapCompositionModels(IEnumerable compositionResults) => compositionResults.Select(MapCompositionModel); + + private IEnumerable MapAllowedContentTypes(IEnumerable allowedMediaTypes) + => MapAllowedContentTypes(allowedMediaTypes + .DistinctBy(t => t.MediaType.Id) + .ToDictionary(t => t.MediaType.Id, t => t.SortOrder)); + + private IEnumerable MapCompositions(IEnumerable documentTypeCompositions) + => MapCompositions(documentTypeCompositions + .DistinctBy(c => c.MediaType.Id) + .ToDictionary(c => c.MediaType.Id, c => c.CompositionType)); } diff --git a/src/Umbraco.Cms.Api.Management/Mapping/Content/ContentStateHelper.cs b/src/Umbraco.Cms.Api.Management/Mapping/Content/ContentStateHelper.cs new file mode 100644 index 0000000000..f47418fad3 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Mapping/Content/ContentStateHelper.cs @@ -0,0 +1,49 @@ +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Entities; + +namespace Umbraco.Cms.Api.Management.Mapping.Content; + +internal static class ContentStateHelper +{ + internal static ContentState GetContentState(IContent content, string? culture) + => GetContentState( + content, + culture, + content.Edited, + content.Published, + content.AvailableCultures, + content.EditedCultures ?? Enumerable.Empty(), + content.PublishedCultures); + + internal static ContentState GetContentState(IDocumentEntitySlim content, string? culture) + => GetContentState( + content, + culture, + content.Edited, + content.Published, + content.CultureNames.Keys, + content.EditedCultures, + content.PublishedCultures); + + private static ContentState GetContentState(IEntity entity, string? culture, bool edited, bool published, IEnumerable availableCultures, IEnumerable editedCultures, IEnumerable publishedCultures) + { + if (entity.Id <= 0 || (culture is not null && availableCultures.Contains(culture) is false)) + { + return ContentState.NotCreated; + } + + var isDraft = published is false || + (culture != null && publishedCultures.Contains(culture) is false); + if (isDraft) + { + return ContentState.Draft; + } + + var isEdited = culture != null + ? editedCultures.Contains(culture) + : edited; + + return isEdited ? ContentState.PublishedPendingChanges : ContentState.Published; + } +} diff --git a/src/Umbraco.Cms.Api.Management/Mapping/ContentType/ContentTypeMapDefinition.cs b/src/Umbraco.Cms.Api.Management/Mapping/ContentType/ContentTypeMapDefinition.cs index 0bb3edb8a8..4b46b8f94d 100644 --- a/src/Umbraco.Cms.Api.Management/Mapping/ContentType/ContentTypeMapDefinition.cs +++ b/src/Umbraco.Cms.Api.Management/Mapping/ContentType/ContentTypeMapDefinition.cs @@ -1,8 +1,8 @@ -using Umbraco.Cms.Api.Management.ViewModels.ContentType; +using Umbraco.Cms.Api.Management.ViewModels; +using Umbraco.Cms.Api.Management.ViewModels.ContentType; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Extensions; -using ContentTypeSort = Umbraco.Cms.Api.Management.ViewModels.ContentType.ContentTypeSort; namespace Umbraco.Cms.Api.Management.Mapping.ContentType; @@ -25,13 +25,13 @@ public abstract class ContentTypeMapDefinition propertyGroup.Alias, propertyGroup => propertyGroup.Key); - Guid? ParentGroupKey(PropertyGroup group) + ReferenceByIdModel? ParentGroup(PropertyGroup group) { var path = group.Alias.Split(Constants.CharArrays.ForwardSlash); return path.Length == 1 || groupKeysByGroupAliases.TryGetValue(path.First(), out Guid parentGroupKey) == false ? null - : parentGroupKey; + : new ReferenceByIdModel(parentGroupKey); } return source @@ -70,7 +70,7 @@ public abstract class ContentTypeMapDefinition MapAllowedContentTypes(TContentType source) - => source.AllowedContentTypes?.Select(contentTypeSort => new ContentTypeSort { Id = contentTypeSort.Key, SortOrder = contentTypeSort.SortOrder }).ToArray() - ?? Array.Empty(); - - protected IEnumerable MapCompositions(TContentType source, IEnumerable contentTypeComposition) - => contentTypeComposition.Select(contentType => new ContentTypeComposition - { - Id = contentType.Key, - CompositionType = contentType.Id == source.ParentId - ? ContentTypeCompositionType.Inheritance - : ContentTypeCompositionType.Composition - }).ToArray(); + protected static CompositionType CalculateCompositionType(TContentType source, IContentTypeComposition contentTypeComposition) + => contentTypeComposition.Id == source.ParentId + ? CompositionType.Inheritance + : CompositionType.Composition; } diff --git a/src/Umbraco.Cms.Api.Management/Mapping/Document/DocumentMapDefinition.cs b/src/Umbraco.Cms.Api.Management/Mapping/Document/DocumentMapDefinition.cs index 8f84060fb5..ad40095102 100644 --- a/src/Umbraco.Cms.Api.Management/Mapping/Document/DocumentMapDefinition.cs +++ b/src/Umbraco.Cms.Api.Management/Mapping/Document/DocumentMapDefinition.cs @@ -1,6 +1,6 @@ using Umbraco.Cms.Api.Management.Mapping.Content; -using Umbraco.Cms.Api.Management.ViewModels.Content; using Umbraco.Cms.Api.Management.ViewModels.Document; +using Umbraco.Cms.Api.Management.ViewModels.DocumentType; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PropertyEditors; @@ -17,42 +17,21 @@ public class DocumentMapDefinition : ContentMapDefinition mapper.Define((_, _) => new DocumentResponseModel(), Map); - // Umbraco.Code.MapAll -Urls -TemplateId + // Umbraco.Code.MapAll -Urls -Template private void Map(IContent source, DocumentResponseModel target, MapperContext context) { target.Id = source.Key; - target.ContentTypeId = source.ContentType.Key; + target.DocumentType = context.Map(source.ContentType)!; target.Values = MapValueViewModels(source); target.Variants = MapVariantViewModels( source, (culture, _, documentVariantViewModel) => { - documentVariantViewModel.State = GetSavedState(source, culture); + documentVariantViewModel.State = ContentStateHelper.GetContentState(source, culture); documentVariantViewModel.PublishDate = culture == null ? source.PublishDate : source.GetPublishDate(culture); }); target.IsTrashed = source.Trashed; } - - private ContentState GetSavedState(IContent content, string? culture) - { - if (content.Id <= 0 || (culture != null && content.IsCultureAvailable(culture) == false)) - { - return ContentState.NotCreated; - } - - var isDraft = content.PublishedState == PublishedState.Unpublished || - (culture != null && content.IsCulturePublished(culture) == false); - if (isDraft) - { - return ContentState.Draft; - } - - var isEdited = culture != null - ? content.IsCultureEdited(culture) - : content.Edited; - - return isEdited ? ContentState.PublishedPendingChanges : ContentState.Published; - } } diff --git a/src/Umbraco.Cms.Api.Management/Mapping/DocumentType/DocumentTypeMapDefinition.cs b/src/Umbraco.Cms.Api.Management/Mapping/DocumentType/DocumentTypeMapDefinition.cs index 0888d1bef5..4e4e3f09e9 100644 --- a/src/Umbraco.Cms.Api.Management/Mapping/DocumentType/DocumentTypeMapDefinition.cs +++ b/src/Umbraco.Cms.Api.Management/Mapping/DocumentType/DocumentTypeMapDefinition.cs @@ -1,4 +1,5 @@ using Umbraco.Cms.Api.Management.Mapping.ContentType; +using Umbraco.Cms.Api.Management.ViewModels; using Umbraco.Cms.Api.Management.ViewModels.ContentType; using Umbraco.Cms.Api.Management.ViewModels.DocumentType; using Umbraco.Cms.Core.Mapping; @@ -10,10 +11,14 @@ namespace Umbraco.Cms.Api.Management.Mapping.DocumentType; public class DocumentTypeMapDefinition : ContentTypeMapDefinition, IMapDefinition { public void DefineMaps(IUmbracoMapper mapper) - => mapper.Define((_, _) => new DocumentTypeResponseModel(), Map); + { + mapper.Define((_, _) => new DocumentTypeResponseModel(), Map); + mapper.Define((_, _) => new DocumentTypeReferenceResponseModel(), Map); + mapper.Define((_, _) => new DocumentTypeReferenceResponseModel(), Map); + mapper.Define((_, _) => new AllowedDocumentType(), Map); + } - // TODO: ParentId - // Umbraco.Code.MapAll -ParentId + // Umbraco.Code.MapAll private void Map(IContentType source, DocumentTypeResponseModel target, MapperContext context) { target.Id = source.Key; @@ -27,15 +32,23 @@ public class DocumentTypeMapDefinition : ContentTypeMapDefinition + new DocumentTypeSort { DocumentType = new ReferenceByIdModel(ct.Key), SortOrder = ct.SortOrder }) + .ToArray() ?? Enumerable.Empty(); + target.Compositions = source.ContentTypeComposition.Select(contentTypeComposition => new DocumentTypeComposition + { + DocumentType = new ReferenceByIdModel(contentTypeComposition.Key), + CompositionType = CalculateCompositionType(source, contentTypeComposition) + }).ToArray(); if (source.AllowedTemplates != null) { - target.AllowedTemplateIds = source.AllowedTemplates.Select(template => template.Key); + target.AllowedTemplates = source.AllowedTemplates.Select(template => new ReferenceByIdModel(template.Key)); } - target.DefaultTemplateId = source.DefaultTemplate?.Key; + target.DefaultTemplate = source.DefaultTemplate is not null + ? new ReferenceByIdModel(source.DefaultTemplate.Key) + : null; if (source.HistoryCleanup != null) { @@ -47,4 +60,29 @@ public class DocumentTypeMapDefinition : ContentTypeMapDefinition((_, _) => new TemplateItemResponseModel { Alias = string.Empty }, Map); mapper.Define((_, _) => new MemberTypeItemResponseModel(), Map); mapper.Define((_, _) => new RelationTypeItemResponseModel(), Map); - mapper.Define((_, _) => new MediaItemResponseModel(), Map); mapper.Define((_, _) => new MemberItemResponseModel(), Map); mapper.Define((_, _) => new UserItemResponseModel(), Map); mapper.Define((_, _) => new UserGroupItemResponseModel(), Map); @@ -106,15 +105,6 @@ public class ItemTypeMapDefinition : IMapDefinition target.Name = source.Name ?? string.Empty; } - // Umbraco.Code.MapAll - private static void Map(IMediaEntitySlim source, MediaItemResponseModel target, MapperContext context) - { - target.Icon = source.ContentTypeIcon; - target.Id = source.Key; - target.Name = source.Name ?? string.Empty; - target.IsTrashed = source.Trashed; - } - // Umbraco.Code.MapAll private static void Map(IMember source, MemberItemResponseModel target, MapperContext context) { diff --git a/src/Umbraco.Cms.Api.Management/Mapping/Media/MediaMapDefinition.cs b/src/Umbraco.Cms.Api.Management/Mapping/Media/MediaMapDefinition.cs index 2d0bf1d38f..d0f3407713 100644 --- a/src/Umbraco.Cms.Api.Management/Mapping/Media/MediaMapDefinition.cs +++ b/src/Umbraco.Cms.Api.Management/Mapping/Media/MediaMapDefinition.cs @@ -1,5 +1,6 @@ using Umbraco.Cms.Api.Management.Mapping.Content; using Umbraco.Cms.Api.Management.ViewModels.Media; +using Umbraco.Cms.Api.Management.ViewModels.MediaType; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PropertyEditors; @@ -20,7 +21,7 @@ public class MediaMapDefinition : ContentMapDefinition(source.ContentType)!; target.Values = MapValueViewModels(source); target.Variants = MapVariantViewModels(source); target.IsTrashed = source.Trashed; diff --git a/src/Umbraco.Cms.Api.Management/Mapping/MediaType/MediaTypeMapDefinition.cs b/src/Umbraco.Cms.Api.Management/Mapping/MediaType/MediaTypeMapDefinition.cs index 3c2cf95db2..bc67838abc 100644 --- a/src/Umbraco.Cms.Api.Management/Mapping/MediaType/MediaTypeMapDefinition.cs +++ b/src/Umbraco.Cms.Api.Management/Mapping/MediaType/MediaTypeMapDefinition.cs @@ -1,4 +1,5 @@ using Umbraco.Cms.Api.Management.Mapping.ContentType; +using Umbraco.Cms.Api.Management.ViewModels; using Umbraco.Cms.Api.Management.ViewModels.MediaType; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; @@ -9,10 +10,14 @@ namespace Umbraco.Cms.Api.Management.Mapping.MediaType; public class MediaTypeMapDefinition : ContentTypeMapDefinition, IMapDefinition { public void DefineMaps(IUmbracoMapper mapper) - => mapper.Define((_, _) => new MediaTypeResponseModel(), Map); + { + mapper.Define((_, _) => new MediaTypeResponseModel(), Map); + mapper.Define((_, _) => new MediaTypeReferenceResponseModel(), Map); + mapper.Define((_, _) => new MediaTypeReferenceResponseModel(), Map); + mapper.Define((_, _) => new AllowedMediaType(), Map); + } - // Todo: ParentId - // Umbraco.Code.MapAll -ParentId + // Umbraco.Code.MapAll private void Map(IMediaType source, MediaTypeResponseModel target, MapperContext context) { target.Id = source.Key; @@ -26,7 +31,38 @@ public class MediaTypeMapDefinition : ContentTypeMapDefinition + new MediaTypeSort { MediaType = new ReferenceByIdModel(ct.Key), SortOrder = ct.SortOrder }) + .ToArray() ?? Enumerable.Empty(); + target.Compositions = source.ContentTypeComposition.Select(contentTypeComposition => new MediaTypeComposition + { + MediaType = new ReferenceByIdModel(contentTypeComposition.Key), + CompositionType = CalculateCompositionType(source, contentTypeComposition) + }).ToArray(); + } + + // Umbraco.Code.MapAll + private void Map(IMediaType source, MediaTypeReferenceResponseModel target, MapperContext context) + { + target.Id = source.Key; + target.Icon = source.Icon ?? string.Empty; + target.HasListView = source.IsContainer; + } + + // Umbraco.Code.MapAll + private void Map(ISimpleContentType source, MediaTypeReferenceResponseModel target, MapperContext context) + { + target.Id = source.Key; + target.Icon = source.Icon ?? string.Empty; + target.HasListView = source.IsContainer; + } + + // Umbraco.Code.MapAll + private void Map(IMediaType source, AllowedMediaType target, MapperContext context) + { + target.Id = source.Key; + target.Name = source.Name ?? string.Empty; + target.Description = source.Description; + target.Icon = source.Icon ?? string.Empty; } } diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index 5db0c8652e..2a0078cbe5 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -1856,6 +1856,9 @@ }, "401": { "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user do not have access to this resource" } }, "security": [ @@ -2108,6 +2111,9 @@ }, "401": { "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user do not have access to this resource" } }, "security": [ @@ -2522,17 +2528,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/plain": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } } } @@ -2580,17 +2586,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/plain": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } } } @@ -3078,6 +3084,93 @@ ] } }, + "/umbraco/management/api/v1/document-type/{id}/allowed-children": { + "get": { + "tags": [ + "Document Type" + ], + "operationId": "GetDocumentTypeByIdAllowedChildren", + "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": { + "$ref": "#/components/schemas/PagedAllowedDocumentTypeModel" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PagedAllowedDocumentTypeModel" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PagedAllowedDocumentTypeModel" + } + } + } + }, + "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}/composition-references": { "get": { "tags": [ @@ -3411,6 +3504,64 @@ ] } }, + "/umbraco/management/api/v1/document-type/allowed-at-root": { + "get": { + "tags": [ + "Document Type" + ], + "operationId": "GetDocumentTypeAllowedAtRoot", + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedAllowedDocumentTypeModel" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PagedAllowedDocumentTypeModel" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PagedAllowedDocumentTypeModel" + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/document-type/available-compositions": { "post": { "tags": [ @@ -4300,6 +4451,79 @@ } ] }, + "delete": { + "tags": [ + "Document" + ], + "operationId": "DeleteDocumentById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "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" + }, + "403": { + "description": "The authenticated user do not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + }, "put": { "tags": [ "Document" @@ -5582,92 +5806,6 @@ ] } }, - "/umbraco/management/api/v1/document/allowed-document-types": { - "get": { - "tags": [ - "Document" - ], - "operationId": "GetDocumentAllowedDocumentTypes", - "parameters": [ - { - "name": "parentId", - "in": "query", - "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": { - "$ref": "#/components/schemas/PagedDocumentTypeResponseModel" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/PagedDocumentTypeResponseModel" - } - }, - "text/plain": { - "schema": { - "$ref": "#/components/schemas/PagedDocumentTypeResponseModel" - } - } - } - }, - "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/configuration": { "get": { "tags": [ @@ -5736,21 +5874,6 @@ "format": "uuid" } } - }, - { - "name": "dataTypeId", - "in": "query", - "schema": { - "type": "string", - "format": "uuid" - } - }, - { - "name": "culture", - "in": "query", - "schema": { - "type": "string" - } } ], "responses": { @@ -5945,6 +6068,81 @@ ] } }, + "/umbraco/management/api/v1/recycle-bin/document/{id}": { + "delete": { + "tags": [ + "Document" + ], + "operationId": "DeleteRecycleBinDocumentById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "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" + }, + "403": { + "description": "The authenticated user do not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/recycle-bin/document/children": { "get": { "tags": [ @@ -5985,17 +6183,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedDocumentRecycleBinItemResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedDocumentRecycleBinItemResponseModel" } }, "text/plain": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedDocumentRecycleBinItemResponseModel" } } } @@ -6043,17 +6241,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedDocumentRecycleBinItemResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedDocumentRecycleBinItemResponseModel" } }, "text/plain": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedDocumentRecycleBinItemResponseModel" } } } @@ -6109,13 +6307,6 @@ "type": "string", "format": "uuid" } - }, - { - "name": "culture", - "in": "query", - "schema": { - "type": "string" - } } ], "responses": { @@ -6182,13 +6373,6 @@ "type": "string", "format": "uuid" } - }, - { - "name": "culture", - "in": "query", - "schema": { - "type": "string" - } } ], "responses": { @@ -8744,6 +8928,93 @@ ] } }, + "/umbraco/management/api/v1/media-type/{id}/allowed-children": { + "get": { + "tags": [ + "Media Type" + ], + "operationId": "GetMediaTypeByIdAllowedChildren", + "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": { + "$ref": "#/components/schemas/PagedAllowedMediaTypeModel" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PagedAllowedMediaTypeModel" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PagedAllowedMediaTypeModel" + } + } + } + }, + "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}/composition-references": { "get": { "tags": [ @@ -9077,6 +9348,64 @@ ] } }, + "/umbraco/management/api/v1/media-type/allowed-at-root": { + "get": { + "tags": [ + "Media Type" + ], + "operationId": "GetMediaTypeAllowedAtRoot", + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedAllowedMediaTypeModel" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PagedAllowedMediaTypeModel" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PagedAllowedMediaTypeModel" + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/media-type/available-compositions": { "post": { "tags": [ @@ -9858,7 +10187,7 @@ "schema": { "oneOf": [ { - "$ref": "#/components/schemas/DocumentResponseModel" + "$ref": "#/components/schemas/MediaResponseModel" } ] } @@ -9867,7 +10196,7 @@ "schema": { "oneOf": [ { - "$ref": "#/components/schemas/DocumentResponseModel" + "$ref": "#/components/schemas/MediaResponseModel" } ] } @@ -9876,7 +10205,7 @@ "schema": { "oneOf": [ { - "$ref": "#/components/schemas/DocumentResponseModel" + "$ref": "#/components/schemas/MediaResponseModel" } ] } @@ -10230,14 +10559,6 @@ "format": "uuid" } } - }, - { - "name": "dataTypeId", - "in": "query", - "schema": { - "type": "string", - "format": "uuid" - } } ], "responses": { @@ -10472,17 +10793,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedMediaRecycleBinItemResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedMediaRecycleBinItemResponseModel" } }, "text/plain": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedMediaRecycleBinItemResponseModel" } } } @@ -10530,17 +10851,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedMediaRecycleBinItemResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedMediaRecycleBinItemResponseModel" } }, "text/plain": { "schema": { - "$ref": "#/components/schemas/PagedRecycleBinItemResponseModel" + "$ref": "#/components/schemas/PagedMediaRecycleBinItemResponseModel" } } } @@ -10630,86 +10951,6 @@ ] } }, - "/umbraco/management/api/v1/tree/media/item": { - "get": { - "tags": [ - "Media" - ], - "operationId": "GetTreeMediaItem", - "parameters": [ - { - "name": "id", - "in": "query", - "schema": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - } - } - }, - { - "name": "dataTypeId", - "in": "query", - "schema": { - "type": "string", - "format": "uuid" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/MediaTreeItemResponseModel" - } - ] - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/MediaTreeItemResponseModel" - } - ] - } - } - }, - "text/plain": { - "schema": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/MediaTreeItemResponseModel" - } - ] - } - } - } - } - }, - "401": { - "description": "The resource is protected and requires an authentication token" - } - }, - "security": [ - { - "Backoffice User": [ ] - } - ] - } - }, "/umbraco/management/api/v1/tree/media/root": { "get": { "tags": [ @@ -10881,17 +11122,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/plain": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } } } @@ -11012,17 +11253,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/plain": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } } } @@ -14096,17 +14337,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/plain": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } } } @@ -18049,17 +18290,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/plain": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } } } @@ -18107,17 +18348,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } }, "text/plain": { "schema": { - "$ref": "#/components/schemas/PagedEntityTreeItemResponseModel" + "$ref": "#/components/schemas/PagedNamedEntityTreeItemResponseModel" } } } @@ -20024,6 +20265,26 @@ } } }, + "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" }, @@ -20466,6 +20727,82 @@ } }, "/umbraco/management/api/v1/user/current/2fa/{providerName}": { + "delete": { + "tags": [ + "User" + ], + "operationId": "DeleteUserCurrent2faByProviderName", + "parameters": [ + { + "name": "providerName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "code", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "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" + } + } + } + }, + "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" + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + }, "post": { "tags": [ "User" @@ -20565,6 +20902,26 @@ } } }, + "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" } @@ -20672,82 +21029,6 @@ "Backoffice User": [ ] } ] - }, - "delete": { - "tags": [ - "User" - ], - "operationId": "DeleteUserCurrent2faByProviderName", - "parameters": [ - { - "name": "providerName", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "code", - "in": "query", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success" - }, - "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" - } - } - } - }, - "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" - } - } - } - }, - "401": { - "description": "The resource is protected and requires an authentication token" - } - }, - "security": [ - { - "Backoffice User": [ ] - } - ] } }, "/umbraco/management/api/v1/user/current/avatar": { @@ -21912,6 +22193,49 @@ }, "components": { "schemas": { + "AllowedContentTypeModel": { + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "icon": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "AllowedDocumentTypeModel": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/AllowedContentTypeModel" + } + ], + "additionalProperties": false + }, + "AllowedMediaTypeModel": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/AllowedContentTypeModel" + } + ], + "additionalProperties": false + }, "AuditLogBaseModel": { "required": [ "logType", @@ -22079,6 +22403,13 @@ }, "additionalProperties": false }, + "CompositionTypeModel": { + "enum": [ + "Composition", + "Inheritance" + ], + "type": "string" + }, "ConsentLevelPresentationModel": { "required": [ "description", @@ -22098,7 +22429,6 @@ }, "ContentForDocumentResponseModel": { "required": [ - "contentTypeId", "id", "values", "variants" @@ -22128,8 +22458,39 @@ "id": { "type": "string", "format": "uuid" + } + }, + "additionalProperties": false + }, + "ContentForMediaResponseModel": { + "required": [ + "id", + "values", + "variants" + ], + "type": "object", + "properties": { + "values": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaValueModel" + } + ] + } }, - "contentTypeId": { + "variants": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaVariantResponseModel" + } + ] + } + }, + "id": { "type": "string", "format": "uuid" } @@ -22193,23 +22554,6 @@ }, "additionalProperties": false }, - "ContentTypeCompositionModel": { - "required": [ - "compositionType", - "id" - ], - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "compositionType": { - "$ref": "#/components/schemas/ContentTypeCompositionTypeModel" - } - }, - "additionalProperties": false - }, "ContentTypeCompositionRequestModelBaseModel": { "required": [ "currentCompositeIds", @@ -22259,19 +22603,10 @@ }, "additionalProperties": false }, - "ContentTypeCompositionTypeModel": { - "enum": [ - "Composition", - "Inheritance" - ], - "type": "string" - }, "ContentTypeForDocumentTypeResponseModel": { "required": [ "alias", "allowedAsRoot", - "allowedContentTypes", - "compositions", "containers", "icon", "id", @@ -22331,26 +22666,6 @@ ] } }, - "allowedContentTypes": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeSortModel" - } - ] - } - }, - "compositions": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeCompositionModel" - } - ] - } - }, "id": { "type": "string", "format": "uuid" @@ -22362,8 +22677,6 @@ "required": [ "alias", "allowedAsRoot", - "allowedContentTypes", - "compositions", "containers", "icon", "id", @@ -22423,26 +22736,6 @@ ] } }, - "allowedContentTypes": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeSortModel" - } - ] - } - }, - "compositions": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeCompositionModel" - } - ] - } - }, "id": { "type": "string", "format": "uuid" @@ -22450,10 +22743,11 @@ }, "additionalProperties": false }, - "ContentTypeSortModel": { + "ContentTypeReferenceResponseModelBaseModel": { "required": [ - "id", - "sortOrder" + "hasListView", + "icon", + "id" ], "type": "object", "properties": { @@ -22461,9 +22755,11 @@ "type": "string", "format": "uuid" }, - "sortOrder": { - "type": "integer", - "format": "int32" + "icon": { + "type": "string" + }, + "hasListView": { + "type": "boolean" } }, "additionalProperties": false @@ -22502,9 +22798,12 @@ ], "type": "object", "properties": { - "targetId": { - "type": "string", - "format": "uuid", + "target": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true }, "relateToOriginal": { @@ -22519,9 +22818,12 @@ "CopyDocumentTypeRequestModel": { "type": "object", "properties": { - "targetId": { - "type": "string", - "format": "uuid", + "target": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -22530,9 +22832,12 @@ "CopyMediaTypeRequestModel": { "type": "object", "properties": { - "targetId": { - "type": "string", - "format": "uuid", + "target": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -22570,9 +22875,12 @@ "format": "uuid", "nullable": true }, - "parentId": { - "type": "string", - "format": "uuid", + "parent": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -22610,9 +22918,12 @@ "format": "uuid", "nullable": true }, - "parentId": { - "type": "string", - "format": "uuid", + "parent": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -22622,8 +22933,6 @@ "required": [ "alias", "allowedAsRoot", - "allowedContentTypes", - "compositions", "containers", "icon", "isElement", @@ -22682,34 +22991,17 @@ ] } }, - "allowedContentTypes": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeSortModel" - } - ] - } - }, - "compositions": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeCompositionModel" - } - ] - } - }, "id": { "type": "string", "format": "uuid", "nullable": true }, - "containerId": { - "type": "string", - "format": "uuid", + "folder": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -22719,8 +23011,6 @@ "required": [ "alias", "allowedAsRoot", - "allowedContentTypes", - "compositions", "containers", "icon", "isElement", @@ -22779,34 +23069,17 @@ ] } }, - "allowedContentTypes": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeSortModel" - } - ] - } - }, - "compositions": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeCompositionModel" - } - ] - } - }, "id": { "type": "string", "format": "uuid", "nullable": true }, - "containerId": { - "type": "string", - "format": "uuid", + "folder": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -22856,7 +23129,7 @@ }, "CreateDocumentRequestModel": { "required": [ - "contentTypeId" + "documentType" ], "type": "object", "allOf": [ @@ -22865,13 +23138,19 @@ } ], "properties": { - "contentTypeId": { - "type": "string", - "format": "uuid" + "documentType": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ] }, - "templateId": { - "type": "string", - "format": "uuid", + "template": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -22897,8 +23176,10 @@ }, "CreateDocumentTypeRequestModel": { "required": [ - "allowedTemplateIds", - "cleanup" + "allowedDocumentTypes", + "allowedTemplates", + "cleanup", + "compositions" ], "type": "object", "allOf": [ @@ -22907,16 +23188,22 @@ } ], "properties": { - "allowedTemplateIds": { + "allowedTemplates": { "type": "array", "items": { - "type": "string", - "format": "uuid" + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ] } }, - "defaultTemplateId": { - "type": "string", - "format": "uuid", + "defaultTemplate": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true }, "cleanup": { @@ -22925,6 +23212,26 @@ "$ref": "#/components/schemas/ContentTypeCleanupModel" } ] + }, + "allowedDocumentTypes": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeSortModel" + } + ] + } + }, + "compositions": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeCompositionModel" + } + ] + } } }, "additionalProperties": false @@ -22987,7 +23294,7 @@ }, "CreateMediaRequestModel": { "required": [ - "contentTypeId" + "mediaType" ], "type": "object", "allOf": [ @@ -22996,9 +23303,12 @@ } ], "properties": { - "contentTypeId": { - "type": "string", - "format": "uuid" + "mediaType": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ] } }, "additionalProperties": false @@ -23022,12 +23332,38 @@ "additionalProperties": false }, "CreateMediaTypeRequestModel": { + "required": [ + "allowedMediaTypes", + "compositions" + ], "type": "object", "allOf": [ { "$ref": "#/components/schemas/CreateContentTypeForMediaTypeRequestModel" } ], + "properties": { + "allowedMediaTypes": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTypeSortModel" + } + ] + } + }, + "compositions": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTypeCompositionModel" + } + ] + } + } + }, "additionalProperties": false }, "CreatePackageRequestModel": { @@ -23287,7 +23623,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "properties": { @@ -23582,7 +23918,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "additionalProperties": false @@ -23704,7 +24040,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "additionalProperties": false @@ -23717,7 +24053,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/EntityTreeItemResponseModel" + "$ref": "#/components/schemas/NamedEntityTreeItemResponseModel" } ], "properties": { @@ -23761,8 +24097,10 @@ }, "DocumentItemResponseModel": { "required": [ - "contentTypeId", - "isTrashed" + "documentType", + "isProtected", + "isTrashed", + "variants" ], "type": "object", "allOf": [ @@ -23771,16 +24109,28 @@ } ], "properties": { - "icon": { - "type": "string", - "nullable": true - }, - "contentTypeId": { - "type": "string", - "format": "uuid" - }, "isTrashed": { "type": "boolean" + }, + "isProtected": { + "type": "boolean" + }, + "documentType": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeReferenceResponseModel" + } + ] + }, + "variants": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentVariantItemResponseModel" + } + ] + } } }, "additionalProperties": false @@ -23801,8 +24151,41 @@ }, "additionalProperties": false }, + "DocumentRecycleBinItemResponseModel": { + "required": [ + "documentType", + "variants" + ], + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/RecycleBinItemResponseModelBaseModel" + } + ], + "properties": { + "documentType": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeReferenceResponseModel" + } + ] + }, + "variants": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentVariantItemResponseModel" + } + ] + } + } + }, + "additionalProperties": false + }, "DocumentResponseModel": { "required": [ + "documentType", "isTrashed", "urls" ], @@ -23823,24 +24206,31 @@ ] } }, - "templateId": { - "type": "string", - "format": "uuid", + "template": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true }, "isTrashed": { "type": "boolean" + }, + "documentType": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeReferenceResponseModel" + } + ] } }, "additionalProperties": false }, "DocumentTreeItemResponseModel": { "required": [ - "contentTypeId", - "icon", - "isEdited", + "documentType", "isProtected", - "isPublished", "variants" ], "type": "object", @@ -23853,28 +24243,42 @@ "isProtected": { "type": "boolean" }, - "isPublished": { - "type": "boolean" - }, - "isEdited": { - "type": "boolean" - }, - "contentTypeId": { - "type": "string", - "format": "uuid" + "documentType": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeReferenceResponseModel" + } + ] }, "variants": { "type": "array", "items": { "oneOf": [ { - "$ref": "#/components/schemas/VariantTreeItemModel" + "$ref": "#/components/schemas/DocumentVariantItemResponseModel" } ] } + } + }, + "additionalProperties": false + }, + "DocumentTypeCompositionModel": { + "required": [ + "compositionType", + "documentType" + ], + "type": "object", + "properties": { + "documentType": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ] }, - "icon": { - "type": "string" + "compositionType": { + "$ref": "#/components/schemas/CompositionTypeModel" } }, "additionalProperties": false @@ -23928,7 +24332,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "properties": { @@ -23960,10 +24364,21 @@ ], "additionalProperties": false }, + "DocumentTypeReferenceResponseModel": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/ContentTypeReferenceResponseModelBaseModel" + } + ], + "additionalProperties": false + }, "DocumentTypeResponseModel": { "required": [ - "allowedTemplateIds", - "cleanup" + "allowedDocumentTypes", + "allowedTemplates", + "cleanup", + "compositions" ], "type": "object", "allOf": [ @@ -23972,16 +24387,22 @@ } ], "properties": { - "allowedTemplateIds": { + "allowedTemplates": { "type": "array", "items": { - "type": "string", - "format": "uuid" + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ] } }, - "defaultTemplateId": { - "type": "string", - "format": "uuid", + "defaultTemplate": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true }, "cleanup": { @@ -23990,6 +24411,47 @@ "$ref": "#/components/schemas/ContentTypeCleanupModel" } ] + }, + "allowedDocumentTypes": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeSortModel" + } + ] + } + }, + "compositions": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeCompositionModel" + } + ] + } + } + }, + "additionalProperties": false + }, + "DocumentTypeSortModel": { + "required": [ + "documentType", + "sortOrder" + ], + "type": "object", + "properties": { + "documentType": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ] + }, + "sortOrder": { + "type": "integer", + "format": "int32" } }, "additionalProperties": false @@ -24024,6 +24486,23 @@ ], "additionalProperties": false }, + "DocumentVariantItemResponseModel": { + "required": [ + "state" + ], + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/VariantItemResponseModelBaseModel" + } + ], + "properties": { + "state": { + "$ref": "#/components/schemas/ContentStateModel" + } + }, + "additionalProperties": false + }, "DocumentVariantRequestModel": { "type": "object", "allOf": [ @@ -24268,8 +24747,7 @@ }, "EntityTreeItemResponseModel": { "required": [ - "id", - "isContainer" + "id" ], "type": "object", "allOf": [ @@ -24282,12 +24760,12 @@ "type": "string", "format": "uuid" }, - "isContainer": { - "type": "boolean" - }, - "parentId": { - "type": "string", - "format": "uuid", + "parent": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -24484,6 +24962,7 @@ "FileSystemTreeItemPresentationModel": { "required": [ "isFolder", + "name", "path" ], "type": "object", @@ -24493,6 +24972,9 @@ } ], "properties": { + "name": { + "type": "string" + }, "path": { "type": "string" }, @@ -24553,7 +25035,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/EntityTreeItemResponseModel" + "$ref": "#/components/schemas/NamedEntityTreeItemResponseModel" } ], "properties": { @@ -24913,16 +25395,25 @@ }, "additionalProperties": false }, - "ItemResponseModelBaseModel": { + "ItemReferenceByIdResponseModel": { "required": [ - "id", - "name" + "id" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + }, + "ItemResponseModelBaseModel": { + "required": [ + "id" ], "type": "object", "properties": { - "name": { - "type": "string" - }, "id": { "type": "string", "format": "uuid" @@ -25199,7 +25690,9 @@ }, "MediaItemResponseModel": { "required": [ - "isTrashed" + "isTrashed", + "mediaType", + "variants" ], "type": "object", "allOf": [ @@ -25208,19 +25701,101 @@ } ], "properties": { - "icon": { - "type": "string", - "nullable": true + "isTrashed": { + "type": "boolean" + }, + "mediaType": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTypeReferenceResponseModel" + } + ] + }, + "variants": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/VariantItemResponseModel" + } + ] + } + } + }, + "additionalProperties": false + }, + "MediaRecycleBinItemResponseModel": { + "required": [ + "mediaType", + "variants" + ], + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/RecycleBinItemResponseModelBaseModel" + } + ], + "properties": { + "mediaType": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTypeReferenceResponseModel" + } + ] + }, + "variants": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/VariantItemResponseModel" + } + ] + } + } + }, + "additionalProperties": false + }, + "MediaResponseModel": { + "required": [ + "isTrashed", + "mediaType", + "urls" + ], + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/ContentForMediaResponseModel" + } + ], + "properties": { + "urls": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/ContentUrlInfoModel" + } + ] + } }, "isTrashed": { "type": "boolean" + }, + "mediaType": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTypeReferenceResponseModel" + } + ] } }, "additionalProperties": false }, "MediaTreeItemResponseModel": { "required": [ - "icon" + "mediaType", + "variants" ], "type": "object", "allOf": [ @@ -25229,9 +25804,42 @@ } ], "properties": { - "icon": { - "minLength": 1, - "type": "string" + "mediaType": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTypeReferenceResponseModel" + } + ] + }, + "variants": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/VariantItemResponseModel" + } + ] + } + } + }, + "additionalProperties": false + }, + "MediaTypeCompositionModel": { + "required": [ + "compositionType", + "mediaType" + ], + "type": "object", + "properties": { + "mediaType": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ] + }, + "compositionType": { + "$ref": "#/components/schemas/CompositionTypeModel" } }, "additionalProperties": false @@ -25258,7 +25866,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "properties": { @@ -25287,13 +25895,69 @@ ], "additionalProperties": false }, + "MediaTypeReferenceResponseModel": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/ContentTypeReferenceResponseModelBaseModel" + } + ], + "additionalProperties": false + }, "MediaTypeResponseModel": { + "required": [ + "allowedMediaTypes", + "compositions" + ], "type": "object", "allOf": [ { "$ref": "#/components/schemas/ContentTypeForMediaTypeResponseModel" } ], + "properties": { + "allowedMediaTypes": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTypeSortModel" + } + ] + } + }, + "compositions": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTypeCompositionModel" + } + ] + } + } + }, + "additionalProperties": false + }, + "MediaTypeSortModel": { + "required": [ + "mediaType", + "sortOrder" + ], + "type": "object", + "properties": { + "mediaType": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ] + }, + "sortOrder": { + "type": "integer", + "format": "int32" + } + }, "additionalProperties": false }, "MediaTypeTreeItemResponseModel": { @@ -25344,7 +26008,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "additionalProperties": false @@ -25353,7 +26017,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "properties": { @@ -25368,7 +26032,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "properties": { @@ -25449,9 +26113,12 @@ "MoveDocumentRequestModel": { "type": "object", "properties": { - "targetId": { - "type": "string", - "format": "uuid", + "target": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -25460,9 +26127,12 @@ "MoveDocumentTypeRequestModel": { "type": "object", "properties": { - "targetId": { - "type": "string", - "format": "uuid", + "target": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -25471,9 +26141,12 @@ "MoveMediaRequestModel": { "type": "object", "properties": { - "targetId": { - "type": "string", - "format": "uuid", + "target": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -25482,14 +26155,51 @@ "MoveMediaTypeRequestModel": { "type": "object", "properties": { - "targetId": { - "type": "string", - "format": "uuid", + "target": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, "additionalProperties": false }, + "NamedEntityTreeItemResponseModel": { + "required": [ + "name" + ], + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/EntityTreeItemResponseModel" + } + ], + "properties": { + "name": { + "type": "string" + } + }, + "additionalProperties": false + }, + "NamedItemResponseModelBaseModel": { + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + }, + "additionalProperties": false + }, "NoopSetupTwoFactorModel": { "type": "object", "additionalProperties": false @@ -25724,6 +26434,54 @@ }, "additionalProperties": false }, + "PagedAllowedDocumentTypeModel": { + "required": [ + "items", + "total" + ], + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/AllowedDocumentTypeModel" + } + ] + } + } + }, + "additionalProperties": false + }, + "PagedAllowedMediaTypeModel": { + "required": [ + "items", + "total" + ], + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/AllowedMediaTypeModel" + } + ] + } + } + }, + "additionalProperties": false + }, "PagedAuditLogResponseModel": { "required": [ "items", @@ -25868,6 +26626,30 @@ }, "additionalProperties": false }, + "PagedDocumentRecycleBinItemResponseModel": { + "required": [ + "items", + "total" + ], + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentRecycleBinItemResponseModel" + } + ] + } + } + }, + "additionalProperties": false + }, "PagedDocumentTreeItemResponseModel": { "required": [ "items", @@ -25892,30 +26674,6 @@ }, "additionalProperties": false }, - "PagedDocumentTypeResponseModel": { - "required": [ - "items", - "total" - ], - "type": "object", - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/DocumentTypeResponseModel" - } - ] - } - } - }, - "additionalProperties": false - }, "PagedDocumentTypeTreeItemResponseModel": { "required": [ "items", @@ -25940,54 +26698,6 @@ }, "additionalProperties": false }, - "PagedEntityTreeItemResponseModel": { - "required": [ - "items", - "total" - ], - "type": "object", - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/EntityTreeItemResponseModel" - }, - { - "$ref": "#/components/schemas/ContentTreeItemResponseModel" - }, - { - "$ref": "#/components/schemas/DataTypeTreeItemResponseModel" - }, - { - "$ref": "#/components/schemas/DocumentBlueprintTreeItemResponseModel" - }, - { - "$ref": "#/components/schemas/DocumentTreeItemResponseModel" - }, - { - "$ref": "#/components/schemas/DocumentTypeTreeItemResponseModel" - }, - { - "$ref": "#/components/schemas/FolderTreeItemResponseModel" - }, - { - "$ref": "#/components/schemas/MediaTreeItemResponseModel" - }, - { - "$ref": "#/components/schemas/MediaTypeTreeItemResponseModel" - } - ] - } - } - }, - "additionalProperties": false - }, "PagedFileSystemTreeItemPresentationModel": { "required": [ "items", @@ -26180,6 +26890,30 @@ }, "additionalProperties": false }, + "PagedMediaRecycleBinItemResponseModel": { + "required": [ + "items", + "total" + ], + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaRecycleBinItemResponseModel" + } + ] + } + } + }, + "additionalProperties": false + }, "PagedMediaTreeItemResponseModel": { "required": [ "items", @@ -26228,6 +26962,45 @@ }, "additionalProperties": false }, + "PagedNamedEntityTreeItemResponseModel": { + "required": [ + "items", + "total" + ], + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/NamedEntityTreeItemResponseModel" + }, + { + "$ref": "#/components/schemas/DataTypeTreeItemResponseModel" + }, + { + "$ref": "#/components/schemas/DocumentBlueprintTreeItemResponseModel" + }, + { + "$ref": "#/components/schemas/DocumentTypeTreeItemResponseModel" + }, + { + "$ref": "#/components/schemas/FolderTreeItemResponseModel" + }, + { + "$ref": "#/components/schemas/MediaTypeTreeItemResponseModel" + } + ] + } + } + }, + "additionalProperties": false + }, "PagedObjectTypeResponseModel": { "required": [ "items", @@ -26347,30 +27120,6 @@ }, "additionalProperties": false }, - "PagedRecycleBinItemResponseModel": { - "required": [ - "items", - "total" - ], - "type": "object", - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/RecycleBinItemResponseModel" - } - ] - } - } - }, - "additionalProperties": false - }, "PagedRedirectUrlResponseModel": { "required": [ "items", @@ -26779,9 +27528,12 @@ "type": "string", "format": "uuid" }, - "parentId": { - "type": "string", - "format": "uuid", + "parent": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true }, "name": { @@ -26803,7 +27555,7 @@ "required": [ "alias", "appearance", - "dataTypeId", + "dataType", "id", "name", "sortOrder", @@ -26817,9 +27569,12 @@ "type": "string", "format": "uuid" }, - "containerId": { - "type": "string", - "format": "uuid", + "container": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true }, "sortOrder": { @@ -26838,9 +27593,12 @@ "type": "string", "nullable": true }, - "dataTypeId": { - "type": "string", - "format": "uuid" + "dataType": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ] }, "variesByCulture": { "type": "boolean" @@ -27001,22 +27759,10 @@ }, "additionalProperties": false }, - "PublishedStateModel": { - "enum": [ - "Published", - "Unpublished", - "Publishing", - "Unpublishing" - ], - "type": "string" - }, - "RecycleBinItemResponseModel": { + "RecycleBinItemResponseModelBaseModel": { "required": [ "hasChildren", - "icon", "id", - "isContainer", - "name", "type" ], "type": "object", @@ -27025,27 +27771,19 @@ "type": "string", "format": "uuid" }, - "name": { - "minLength": 1, - "type": "string" - }, "type": { "minLength": 1, "type": "string" }, - "icon": { - "minLength": 1, - "type": "string" - }, "hasChildren": { "type": "boolean" }, - "isContainer": { - "type": "boolean" - }, - "parentId": { - "type": "string", - "format": "uuid", + "parent": { + "oneOf": [ + { + "$ref": "#/components/schemas/ItemReferenceByIdResponseModel" + } + ], "nullable": true } }, @@ -27109,6 +27847,19 @@ }, "additionalProperties": false }, + "ReferenceByIdModel": { + "required": [ + "id" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + }, "RelationItemResponseModel": { "required": [ "nodeId", @@ -27228,7 +27979,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "additionalProperties": false @@ -27757,7 +28508,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "properties": { @@ -28079,14 +28830,10 @@ "TreeItemPresentationModel": { "required": [ "hasChildren", - "name", "type" ], "type": "object", "properties": { - "name": { - "type": "string" - }, "type": { "type": "string" }, @@ -28187,8 +28934,6 @@ "required": [ "alias", "allowedAsRoot", - "allowedContentTypes", - "compositions", "containers", "icon", "isElement", @@ -28246,26 +28991,6 @@ } ] } - }, - "allowedContentTypes": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeSortModel" - } - ] - } - }, - "compositions": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeCompositionModel" - } - ] - } } }, "additionalProperties": false @@ -28274,8 +28999,6 @@ "required": [ "alias", "allowedAsRoot", - "allowedContentTypes", - "compositions", "containers", "icon", "isElement", @@ -28333,26 +29056,6 @@ } ] } - }, - "allowedContentTypes": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeSortModel" - } - ] - } - }, - "compositions": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/components/schemas/ContentTypeCompositionModel" - } - ] - } } }, "additionalProperties": false @@ -28398,9 +29101,12 @@ } ], "properties": { - "templateId": { - "type": "string", - "format": "uuid", + "template": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true } }, @@ -28426,8 +29132,10 @@ }, "UpdateDocumentTypeRequestModel": { "required": [ - "allowedTemplateIds", - "cleanup" + "allowedDocumentTypes", + "allowedTemplates", + "cleanup", + "compositions" ], "type": "object", "allOf": [ @@ -28436,16 +29144,22 @@ } ], "properties": { - "allowedTemplateIds": { + "allowedTemplates": { "type": "array", "items": { - "type": "string", - "format": "uuid" + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ] } }, - "defaultTemplateId": { - "type": "string", - "format": "uuid", + "defaultTemplate": { + "oneOf": [ + { + "$ref": "#/components/schemas/ReferenceByIdModel" + } + ], "nullable": true }, "cleanup": { @@ -28454,6 +29168,26 @@ "$ref": "#/components/schemas/ContentTypeCleanupModel" } ] + }, + "allowedDocumentTypes": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeSortModel" + } + ] + } + }, + "compositions": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeCompositionModel" + } + ] + } } }, "additionalProperties": false @@ -28513,12 +29247,38 @@ "additionalProperties": false }, "UpdateMediaTypeRequestModel": { + "required": [ + "allowedMediaTypes", + "compositions" + ], "type": "object", "allOf": [ { "$ref": "#/components/schemas/UpdateContentTypeForMediaTypeRequestModel" } ], + "properties": { + "allowedMediaTypes": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTypeSortModel" + } + ] + } + }, + "compositions": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTypeCompositionModel" + } + ] + } + } + }, "additionalProperties": false }, "UpdatePackageRequestModel": { @@ -28770,7 +29530,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "properties": { @@ -28837,7 +29597,7 @@ "type": "object", "allOf": [ { - "$ref": "#/components/schemas/ItemResponseModelBaseModel" + "$ref": "#/components/schemas/NamedItemResponseModelBaseModel" } ], "additionalProperties": false @@ -29108,6 +29868,31 @@ }, "additionalProperties": false }, + "VariantItemResponseModel": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/VariantItemResponseModelBaseModel" + } + ], + "additionalProperties": false + }, + "VariantItemResponseModelBaseModel": { + "required": [ + "name" + ], + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "culture": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, "VariantModelBaseModel": { "required": [ "name" @@ -29160,26 +29945,6 @@ }, "additionalProperties": false }, - "VariantTreeItemModel": { - "required": [ - "name", - "state" - ], - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "culture": { - "type": "string", - "nullable": true - }, - "state": { - "$ref": "#/components/schemas/PublishedStateModel" - } - }, - "additionalProperties": false - }, "VerifyInviteUserRequestModel": { "required": [ "token", diff --git a/src/Umbraco.Cms.Api.Management/Umbraco.Cms.Api.Management.csproj b/src/Umbraco.Cms.Api.Management/Umbraco.Cms.Api.Management.csproj index bb9874e5df..9ab9a839d3 100644 --- a/src/Umbraco.Cms.Api.Management/Umbraco.Cms.Api.Management.csproj +++ b/src/Umbraco.Cms.Api.Management/Umbraco.Cms.Api.Management.csproj @@ -18,6 +18,15 @@ + + + <_Parameter1>Umbraco.Tests.UnitTests + + + <_Parameter1>DynamicProxyGenAssembly2 + + + diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Content/ContentResponseModelBase.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Content/ContentResponseModelBase.cs index 69efd38971..368f2c46dd 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Content/ContentResponseModelBase.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Content/ContentResponseModelBase.cs @@ -6,6 +6,4 @@ public abstract class ContentResponseModelBase { public Guid? Id { get; set; } - public Guid? ParentId { get; set; } + public ReferenceByIdModel? Parent { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Content/DocumentVariantItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Content/DocumentVariantItemResponseModel.cs new file mode 100644 index 0000000000..9023d13f60 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Content/DocumentVariantItemResponseModel.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.Content; + +public class DocumentVariantItemResponseModel : VariantItemResponseModelBase +{ + public required ContentState State { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Content/VariantItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Content/VariantItemResponseModel.cs new file mode 100644 index 0000000000..c37d1f883d --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Content/VariantItemResponseModel.cs @@ -0,0 +1,5 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.Content; + +public class VariantItemResponseModel : VariantItemResponseModelBase +{ +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Content/VariantItemResponseModelBase.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Content/VariantItemResponseModelBase.cs new file mode 100644 index 0000000000..76a9210369 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Content/VariantItemResponseModelBase.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.Content; + +public abstract class VariantItemResponseModelBase +{ + public required string Name { get; set; } + + public string? Culture { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/AllowedDocumentTypeChild.cs b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/AllowedDocumentTypeChild.cs new file mode 100644 index 0000000000..846073e0b5 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/AllowedDocumentTypeChild.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.ContentType; + +public abstract class AllowedContentType +{ + public Guid Id { get; set; } + + public string Name { get; set; } = string.Empty; + + public string? Description { get; set; } = string.Empty; + + public string? Icon { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeCompositionType.cs b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/CompositionType.cs similarity index 72% rename from src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeCompositionType.cs rename to src/Umbraco.Cms.Api.Management/ViewModels/ContentType/CompositionType.cs index ad8479e05b..8f6133e8cc 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeCompositionType.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/CompositionType.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Api.Management.ViewModels.ContentType; -public enum ContentTypeCompositionType +public enum CompositionType { Composition, Inheritance diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeComposition.cs b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeComposition.cs deleted file mode 100644 index a4563aa5f9..0000000000 --- a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeComposition.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Umbraco.Cms.Api.Management.ViewModels.ContentType; - -public class ContentTypeComposition -{ - public required Guid Id { get; init; } - - public required ContentTypeCompositionType CompositionType { get; init; } -} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeModelBase.cs b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeModelBase.cs index 53f5d66564..48add2eaf2 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeModelBase.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeModelBase.cs @@ -29,8 +29,4 @@ public abstract class ContentTypeModelBase Properties { get; set; } = Enumerable.Empty(); public IEnumerable Containers { get; set; } = Enumerable.Empty(); - - public IEnumerable AllowedContentTypes { get; set; } = Enumerable.Empty(); - - public IEnumerable Compositions { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeReferenceResponseModelBase.cs b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeReferenceResponseModelBase.cs new file mode 100644 index 0000000000..82071deb2f --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeReferenceResponseModelBase.cs @@ -0,0 +1,11 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.ContentType; + +public abstract class ContentTypeReferenceResponseModelBase +{ + public Guid Id { get; set; } + + public string Icon { get; set; } = string.Empty; + + // FIXME: ensure that this naming is consistent with the "full" content type model representation for listviews (pending listview implementation) + public bool HasListView { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeSort.cs b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeSort.cs deleted file mode 100644 index fee58d9d01..0000000000 --- a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/ContentTypeSort.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Umbraco.Cms.Api.Management.ViewModels.ContentType; - -public class ContentTypeSort -{ - public required Guid Id { get; init; } - - public required int SortOrder { get; init; } -} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/CreateContentTypeRequestModelBase.cs b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/CreateContentTypeRequestModelBase.cs index 90ca19cb29..000f78190c 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/CreateContentTypeRequestModelBase.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/ContentType/CreateContentTypeRequestModelBase.cs @@ -7,5 +7,5 @@ public abstract class CreateContentTypeRequestModelBase("CreateContentForDocumentRequestModel")] public class CreateDocumentRequestModel : CreateContentRequestModelBase { - public Guid ContentTypeId { get; set; } + public required ReferenceByIdModel DocumentType { get; set; } - public Guid? TemplateId { get; set; } + public required ReferenceByIdModel? Template { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Document/DocumentResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Document/DocumentResponseModel.cs index 3443095455..57e5f7c640 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Document/DocumentResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Document/DocumentResponseModel.cs @@ -1,5 +1,6 @@ using Umbraco.Cms.Api.Common.Attributes; using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Management.ViewModels.DocumentType; namespace Umbraco.Cms.Api.Management.ViewModels.Document; @@ -8,7 +9,9 @@ public class DocumentResponseModel : ContentResponseModelBase Urls { get; set; } = Enumerable.Empty(); - public Guid? TemplateId { get; set; } + public ReferenceByIdModel? Template { get; set; } public bool IsTrashed { get; set; } + + public DocumentTypeReferenceResponseModel DocumentType { get; set; } = new(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Document/Item/DocumentItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Document/Item/DocumentItemResponseModel.cs index 10dab656be..6dc8aa4d59 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Document/Item/DocumentItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Document/Item/DocumentItemResponseModel.cs @@ -1,12 +1,16 @@ -using Umbraco.Cms.Api.Management.ViewModels.Item; +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Management.ViewModels.DocumentType; +using Umbraco.Cms.Api.Management.ViewModels.Item; namespace Umbraco.Cms.Api.Management.ViewModels.Document.Item; public class DocumentItemResponseModel : ItemResponseModelBase { - public string? Icon { get; set; } - - public Guid ContentTypeId { get; set; } - public bool IsTrashed { get; set; } + + public bool IsProtected { get; set; } + + public DocumentTypeReferenceResponseModel DocumentType { get; set; } = new(); + + public IEnumerable Variants { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Document/MoveDocumentRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Document/MoveDocumentRequestModel.cs index ad3b2d02be..c5b87e484c 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Document/MoveDocumentRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Document/MoveDocumentRequestModel.cs @@ -2,5 +2,5 @@ public class MoveDocumentRequestModel { - public Guid? TargetId { get; set; } + public ReferenceByIdModel? Target { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Document/RecycleBin/DocumentRecycleBinItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Document/RecycleBin/DocumentRecycleBinItemResponseModel.cs new file mode 100644 index 0000000000..a6a18abe49 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Document/RecycleBin/DocumentRecycleBinItemResponseModel.cs @@ -0,0 +1,12 @@ +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Management.ViewModels.DocumentType; +using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; + +namespace Umbraco.Cms.Api.Management.ViewModels.Document.RecycleBin; + +public class DocumentRecycleBinItemResponseModel : RecycleBinItemResponseModelBase +{ + public DocumentTypeReferenceResponseModel DocumentType { get; set; } = new(); + + public IEnumerable Variants { get; set; } = Enumerable.Empty(); +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Document/UpdateDocumentRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Document/UpdateDocumentRequestModel.cs index cc1f0af1b2..0ab4b77c0a 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Document/UpdateDocumentRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Document/UpdateDocumentRequestModel.cs @@ -6,5 +6,5 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Document; [ShortGenericSchemaName("UpdateContentForDocumentRequestModel")] public class UpdateDocumentRequestModel : UpdateContentRequestModelBase { - public Guid? TemplateId { get; set; } + public ReferenceByIdModel? Template { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentBlueprint/Item/DocumentBlueprintResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentBlueprint/Item/DocumentBlueprintResponseModel.cs index 1110747b5a..36c1e1ca28 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentBlueprint/Item/DocumentBlueprintResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentBlueprint/Item/DocumentBlueprintResponseModel.cs @@ -2,6 +2,6 @@ namespace Umbraco.Cms.Api.Management.ViewModels.DocumentBlueprint.Item; -public class DocumentBlueprintResponseModel : ItemResponseModelBase +public class DocumentBlueprintResponseModel : NamedItemResponseModelBase { } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/AllowedDocumentTypeChild.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/AllowedDocumentTypeChild.cs new file mode 100644 index 0000000000..7ff3169bf6 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/AllowedDocumentTypeChild.cs @@ -0,0 +1,7 @@ +using Umbraco.Cms.Api.Management.ViewModels.ContentType; + +namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType; + +public sealed class AllowedDocumentType : AllowedContentType +{ +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/CopyDocumentTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/CopyDocumentTypeRequestModel.cs index 89cf827f3a..b8684cec3b 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/CopyDocumentTypeRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/CopyDocumentTypeRequestModel.cs @@ -2,5 +2,5 @@ namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType; public class CopyDocumentTypeRequestModel { - public Guid? TargetId { get; set; } + public ReferenceByIdModel? Target { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/CreateDocumentTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/CreateDocumentTypeRequestModel.cs index feffd076cd..0490e0fbb9 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/CreateDocumentTypeRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/CreateDocumentTypeRequestModel.cs @@ -7,9 +7,13 @@ namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType; public class CreateDocumentTypeRequestModel : CreateContentTypeRequestModelBase { - public IEnumerable AllowedTemplateIds { get; set; } = Enumerable.Empty(); + public IEnumerable AllowedTemplates { get; set; } = Enumerable.Empty(); - public Guid? DefaultTemplateId { get; set; } + public ReferenceByIdModel? DefaultTemplate { get; set; } public ContentTypeCleanup Cleanup { get; set; } = new(); + + public IEnumerable AllowedDocumentTypes { get; set; } = Enumerable.Empty(); + + public IEnumerable Compositions { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeComposition.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeComposition.cs new file mode 100644 index 0000000000..e8cc302a0a --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeComposition.cs @@ -0,0 +1,10 @@ +using Umbraco.Cms.Api.Management.ViewModels.ContentType; + +namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType; + +public class DocumentTypeComposition +{ + public required ReferenceByIdModel DocumentType { get; init; } + + public required CompositionType CompositionType { get; init; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeReferenceModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeReferenceModel.cs new file mode 100644 index 0000000000..f734fc142f --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeReferenceModel.cs @@ -0,0 +1,7 @@ +using Umbraco.Cms.Api.Management.ViewModels.ContentType; + +namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType; + +public class DocumentTypeReferenceResponseModel : ContentTypeReferenceResponseModelBase +{ +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeResponseModel.cs index 18031352d6..cb2f28f0a0 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeResponseModel.cs @@ -6,9 +6,13 @@ namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType; [ShortGenericSchemaName("ContentTypeForDocumentTypeResponseModel")] public class DocumentTypeResponseModel : ContentTypeResponseModelBase { - public IEnumerable AllowedTemplateIds { get; set; } = Enumerable.Empty(); + public IEnumerable AllowedTemplates { get; set; } = Enumerable.Empty(); - public Guid? DefaultTemplateId { get; set; } + public ReferenceByIdModel? DefaultTemplate { get; set; } public ContentTypeCleanup Cleanup { get; set; } = new(); + + public IEnumerable AllowedDocumentTypes { get; set; } = Enumerable.Empty(); + + public IEnumerable Compositions { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeSort.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeSort.cs new file mode 100644 index 0000000000..60a5d2555a --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/DocumentTypeSort.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType; + +public class DocumentTypeSort +{ + public required ReferenceByIdModel DocumentType { get; init; } + + public int SortOrder { get; init; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/Item/DocumentTypeItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/Item/DocumentTypeItemResponseModel.cs index 263b9d1910..0833ee5036 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/Item/DocumentTypeItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/Item/DocumentTypeItemResponseModel.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType.Item; -public class DocumentTypeItemResponseModel : ItemResponseModelBase +public class DocumentTypeItemResponseModel : NamedItemResponseModelBase { public bool IsElement { get; set; } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/MoveDocumentTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/MoveDocumentTypeRequestModel.cs index 11eadd3cba..b2f8b7ace7 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/MoveDocumentTypeRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/MoveDocumentTypeRequestModel.cs @@ -2,5 +2,5 @@ namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType; public class MoveDocumentTypeRequestModel { - public Guid? TargetId { get; set; } + public ReferenceByIdModel? Target { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/UpdateDocumentTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/UpdateDocumentTypeRequestModel.cs index 54920561d8..90ed1f900c 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/UpdateDocumentTypeRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/DocumentType/UpdateDocumentTypeRequestModel.cs @@ -7,9 +7,13 @@ namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType; public class UpdateDocumentTypeRequestModel : UpdateContentTypeRequestModelBase { - public IEnumerable AllowedTemplateIds { get; set; } = Enumerable.Empty(); + public IEnumerable AllowedTemplates { get; set; } = Enumerable.Empty(); - public Guid? DefaultTemplateId { get; set; } + public ReferenceByIdModel? DefaultTemplate { get; set; } public ContentTypeCleanup Cleanup { get; set; } = new(); + + public IEnumerable AllowedDocumentTypes { get; set; } = Enumerable.Empty(); + + public IEnumerable Compositions { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Folder/FolderResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Folder/FolderResponseModel.cs index dcfdb4a623..7babf1b5eb 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Folder/FolderResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Folder/FolderResponseModel.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Folder; -public class FolderResponseModel : FolderModelBase, INamedEntityPresentationModel +public class FolderResponseModel : FolderModelBase { public Guid Id { get; set; } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/INamedEntityPresentationModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/INamedEntityPresentationModel.cs deleted file mode 100644 index 6d2de35c6e..0000000000 --- a/src/Umbraco.Cms.Api.Management/ViewModels/INamedEntityPresentationModel.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Umbraco.Cms.Api.Management.ViewModels; - -public interface INamedEntityPresentationModel -{ - Guid Id { get; } - - string Name { get;} -} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Item/ItemReferenceByIdResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Item/ItemReferenceByIdResponseModel.cs new file mode 100644 index 0000000000..407843310e --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Item/ItemReferenceByIdResponseModel.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.Item; + +// IMPORTANT: do NOT unseal this class as long as we have polymorphism support in OpenAPI; it will make a mess of all models. +public sealed class ItemReferenceByIdResponseModel +{ + public Guid Id { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Item/ItemResponseModelBase.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Item/ItemResponseModelBase.cs index 5f662f7b77..f39ee8c578 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Item/ItemResponseModelBase.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Item/ItemResponseModelBase.cs @@ -2,7 +2,5 @@ public abstract class ItemResponseModelBase { - public string Name { get; set; } = string.Empty; - public Guid Id { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Item/NamedItemResponseModelBase.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Item/NamedItemResponseModelBase.cs new file mode 100644 index 0000000000..2d14ed0b88 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Item/NamedItemResponseModelBase.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.Item; + +public abstract class NamedItemResponseModelBase : ItemResponseModelBase +{ + public string Name { get; set; } = string.Empty; +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Media/CreateMediaRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Media/CreateMediaRequestModel.cs index 6fafa870cc..1d55a79077 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Media/CreateMediaRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Media/CreateMediaRequestModel.cs @@ -6,5 +6,5 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Media; [ShortGenericSchemaName("CreateContentForMediaRequestModel")] public class CreateMediaRequestModel : CreateContentRequestModelBase { - public Guid ContentTypeId { get; set; } + public required ReferenceByIdModel MediaType { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Media/MediaResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Media/MediaResponseModel.cs index 56de794a4f..964351f07e 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Media/MediaResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Media/MediaResponseModel.cs @@ -1,10 +1,15 @@ -using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Common.Attributes; +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Management.ViewModels.MediaType; namespace Umbraco.Cms.Api.Management.ViewModels.Media; +[ShortGenericSchemaName("ContentForMediaResponseModel")] public class MediaResponseModel : ContentResponseModelBase { public IEnumerable Urls { get; set; } = Enumerable.Empty(); public bool IsTrashed { get; set; } + + public MediaTypeReferenceResponseModel MediaType { get; set; } = new(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Media/MoveMediaRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Media/MoveMediaRequestModel.cs index 137a745c76..7db04c793a 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Media/MoveMediaRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Media/MoveMediaRequestModel.cs @@ -2,5 +2,5 @@ public class MoveMediaRequestModel { - public Guid? TargetId { get; set; } + public ReferenceByIdModel? Target { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Media/RecycleBin/MediaRecycleBinItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Media/RecycleBin/MediaRecycleBinItemResponseModel.cs new file mode 100644 index 0000000000..07698ce61c --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Media/RecycleBin/MediaRecycleBinItemResponseModel.cs @@ -0,0 +1,12 @@ +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Management.ViewModels.MediaType; +using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; + +namespace Umbraco.Cms.Api.Management.ViewModels.Media.RecycleBin; + +public class MediaRecycleBinItemResponseModel : RecycleBinItemResponseModelBase +{ + public MediaTypeReferenceResponseModel MediaType { get; set; } = new(); + + public IEnumerable Variants { get; set; } = Enumerable.Empty(); +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Media/item/MediaItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Media/item/MediaItemResponseModel.cs index 6775bc1a91..2eb4270600 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Media/item/MediaItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Media/item/MediaItemResponseModel.cs @@ -1,10 +1,14 @@ -using Umbraco.Cms.Api.Management.ViewModels.Item; +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Management.ViewModels.Item; +using Umbraco.Cms.Api.Management.ViewModels.MediaType; namespace Umbraco.Cms.Api.Management.ViewModels.Media.Item; public class MediaItemResponseModel : ItemResponseModelBase { - public string? Icon { get; set; } - public bool IsTrashed { get; set; } + + public MediaTypeReferenceResponseModel MediaType { get; set; } = new(); + + public IEnumerable Variants { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Media/item/MediaTreeItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Media/item/MediaTreeItemResponseModel.cs index 12645b5c6b..1f79207022 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Media/item/MediaTreeItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Media/item/MediaTreeItemResponseModel.cs @@ -1,10 +1,12 @@ -using System.ComponentModel.DataAnnotations; +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Management.ViewModels.MediaType; using Umbraco.Cms.Api.Management.ViewModels.Tree; namespace Umbraco.Cms.Api.Management.ViewModels.Media.Item; public class MediaTreeItemResponseModel : ContentTreeItemResponseModel { - [Required] - public string Icon { get; set; } = string.Empty; + public MediaTypeReferenceResponseModel MediaType { get; set; } = new(); + + public IEnumerable Variants { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/AllowedDocumentTypeChild.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/AllowedDocumentTypeChild.cs new file mode 100644 index 0000000000..e781860058 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/AllowedDocumentTypeChild.cs @@ -0,0 +1,7 @@ +using Umbraco.Cms.Api.Management.ViewModels.ContentType; + +namespace Umbraco.Cms.Api.Management.ViewModels.MediaType; + +public sealed class AllowedMediaType : AllowedContentType +{ +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CopyMediaTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CopyMediaTypeRequestModel.cs index 4fc9615de5..bb30928db3 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CopyMediaTypeRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CopyMediaTypeRequestModel.cs @@ -2,5 +2,5 @@ namespace Umbraco.Cms.Api.Management.ViewModels.MediaType; public class CopyMediaTypeRequestModel { - public Guid? TargetId { get; set; } + public ReferenceByIdModel? Target { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CreateMediaTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CreateMediaTypeRequestModel.cs index 1862340e59..edb7b7cf03 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CreateMediaTypeRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/CreateMediaTypeRequestModel.cs @@ -7,4 +7,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.MediaType; public class CreateMediaTypeRequestModel : CreateContentTypeRequestModelBase { + public IEnumerable AllowedMediaTypes { get; set; } = Enumerable.Empty(); + + public IEnumerable Compositions { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/Item/MediaTypeItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/Item/MediaTypeItemResponseModel.cs index dfb0eb2805..90b9427587 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/Item/MediaTypeItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/Item/MediaTypeItemResponseModel.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.MediaType.Item; -public class MediaTypeItemResponseModel : ItemResponseModelBase +public class MediaTypeItemResponseModel : NamedItemResponseModelBase { public string? Icon { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeComposition.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeComposition.cs new file mode 100644 index 0000000000..c008d321f4 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeComposition.cs @@ -0,0 +1,10 @@ +using Umbraco.Cms.Api.Management.ViewModels.ContentType; + +namespace Umbraco.Cms.Api.Management.ViewModels.MediaType; + +public class MediaTypeComposition +{ + public required ReferenceByIdModel MediaType { get; init; } + + public required CompositionType CompositionType { get; init; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeReferenceModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeReferenceModel.cs new file mode 100644 index 0000000000..b91aa074c1 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeReferenceModel.cs @@ -0,0 +1,7 @@ +using Umbraco.Cms.Api.Management.ViewModels.ContentType; + +namespace Umbraco.Cms.Api.Management.ViewModels.MediaType; + +public class MediaTypeReferenceResponseModel : ContentTypeReferenceResponseModelBase +{ +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeResponseModel.cs index 748c73ac7f..09d719a08c 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeResponseModel.cs @@ -6,4 +6,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.MediaType; [ShortGenericSchemaName("ContentTypeForMediaTypeResponseModel")] public class MediaTypeResponseModel : ContentTypeResponseModelBase { + public IEnumerable AllowedMediaTypes { get; set; } = Enumerable.Empty(); + + public IEnumerable Compositions { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeSort.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeSort.cs new file mode 100644 index 0000000000..83172ab424 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MediaTypeSort.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.MediaType; + +public class MediaTypeSort +{ + public required ReferenceByIdModel MediaType { get; init; } + + public int SortOrder { get; init; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MoveMediaTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MoveMediaTypeRequestModel.cs index cb26c27e79..c7b39981e3 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MoveMediaTypeRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/MoveMediaTypeRequestModel.cs @@ -2,5 +2,5 @@ namespace Umbraco.Cms.Api.Management.ViewModels.MediaType; public class MoveMediaTypeRequestModel { - public Guid? TargetId { get; set; } + public ReferenceByIdModel? Target { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/UpdateMediaTypeRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/UpdateMediaTypeRequestModel.cs index 47292b8711..07e080a3f6 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/UpdateMediaTypeRequestModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MediaType/UpdateMediaTypeRequestModel.cs @@ -7,4 +7,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.MediaType; public class UpdateMediaTypeRequestModel : UpdateContentTypeRequestModelBase { + public IEnumerable AllowedMediaTypes { get; set; } = Enumerable.Empty(); + + public IEnumerable Compositions { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Member/Item/MemberItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Member/Item/MemberItemResponseModel.cs index 24e7b55166..fe7cfb9fff 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Member/Item/MemberItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Member/Item/MemberItemResponseModel.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Member.Item; -public class MemberItemResponseModel : ItemResponseModelBase +public class MemberItemResponseModel : NamedItemResponseModelBase { public string? Icon { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MemberGroup/Item/MemberGroupItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MemberGroup/Item/MemberGroupItemResponseModel.cs index 118baf082b..229a42bec7 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/MemberGroup/Item/MemberGroupItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MemberGroup/Item/MemberGroupItemResponseModel.cs @@ -2,6 +2,6 @@ namespace Umbraco.Cms.Api.Management.ViewModels.MemberGroup.Item; -public class MemberGroupItemResponseModel : ItemResponseModelBase +public class MemberGroupItemResponseModel : NamedItemResponseModelBase { } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/MemberType/Items/MemberTypeItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/MemberType/Items/MemberTypeItemResponseModel.cs index 56da2d6114..b9dbcea538 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/MemberType/Items/MemberTypeItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/MemberType/Items/MemberTypeItemResponseModel.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.MemberType.Items; -public class MemberTypeItemResponseModel : ItemResponseModelBase +public class MemberTypeItemResponseModel : NamedItemResponseModelBase { public string? Icon { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Move/MoveViewModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Move/MoveViewModel.cs deleted file mode 100644 index 88942df570..0000000000 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Move/MoveViewModel.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Umbraco.Cms.Api.Management.ViewModels.Move; - -/// -/// A model representing a model for moving or copying -/// -public class MoveViewModel -{ - /// - /// The Id of the node to move or copy to - /// - [Required] - public int ParentId { get; set; } - - /// - /// The id of the node to move or copy - /// - [Required] - public int Id { get; set; } -} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/RecycleBin/RecycleBinItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/RecycleBin/RecycleBinItemResponseModel.cs deleted file mode 100644 index de9f925a21..0000000000 --- a/src/Umbraco.Cms.Api.Management/ViewModels/RecycleBin/RecycleBinItemResponseModel.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Umbraco.Cms.Api.Management.ViewModels.RecycleBin; - -public class RecycleBinItemResponseModel : INamedEntityPresentationModel -{ - [Required] - public Guid Id { get; set; } - - [Required] - public string Name { get; set; } = string.Empty; - - [Required] - public string Type { get; set; } = string.Empty; - - [Required] - public string Icon { get; set; } = string.Empty; - - [Required] - public bool HasChildren { get; set; } - - [Required] - public bool IsContainer { get; set; } - - public Guid? ParentId { get; set; } -} - diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/RecycleBin/RecycleBinItemResponseModelBase.cs b/src/Umbraco.Cms.Api.Management/ViewModels/RecycleBin/RecycleBinItemResponseModelBase.cs new file mode 100644 index 0000000000..2e77b259bd --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/RecycleBin/RecycleBinItemResponseModelBase.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; +using Umbraco.Cms.Api.Management.ViewModels.Item; + +namespace Umbraco.Cms.Api.Management.ViewModels.RecycleBin; + +public abstract class RecycleBinItemResponseModelBase +{ + [Required] + public Guid Id { get; set; } + + [Required] + public string Type { get; set; } = string.Empty; + + [Required] + public bool HasChildren { get; set; } + + public ItemReferenceByIdResponseModel? Parent { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/ReferenceByIdModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/ReferenceByIdModel.cs new file mode 100644 index 0000000000..591e77e575 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/ReferenceByIdModel.cs @@ -0,0 +1,15 @@ +namespace Umbraco.Cms.Api.Management.ViewModels; + +// IMPORTANT: do NOT unseal this class as long as we have polymorphism support in OpenAPI; it will make a mess of all models. +public sealed class ReferenceByIdModel +{ + public ReferenceByIdModel() + : this(Guid.Empty) + { + } + + public ReferenceByIdModel(Guid id) + => Id = id; + + public Guid Id { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/RelationType/Item/RelationTypeItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/RelationType/Item/RelationTypeItemResponseModel.cs index ae63252354..17c6991428 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/RelationType/Item/RelationTypeItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/RelationType/Item/RelationTypeItemResponseModel.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.RelationType.Item; -public class RelationTypeItemResponseModel : ItemResponseModelBase +public class RelationTypeItemResponseModel : NamedItemResponseModelBase { } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Template/Item/TemplateItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Template/Item/TemplateItemResponseModel.cs index 0d75a20c1a..4f50b6d631 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Template/Item/TemplateItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Template/Item/TemplateItemResponseModel.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Template.Item; -public class TemplateItemResponseModel : ItemResponseModelBase +public class TemplateItemResponseModel : NamedItemResponseModelBase { public required string Alias { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Template/TemplateResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Template/TemplateResponseModel.cs index b192df5551..9a9a4b0496 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Template/TemplateResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Template/TemplateResponseModel.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Template; -public class TemplateResponseModel : TemplateModelBase, INamedEntityPresentationModel +public class TemplateResponseModel : TemplateModelBase { public Guid Id { get; set; } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/DocumentBlueprintTreeItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/DocumentBlueprintTreeItemResponseModel.cs index b5ab2ff611..60aa9ab8b0 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/DocumentBlueprintTreeItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/DocumentBlueprintTreeItemResponseModel.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Tree; -public class DocumentBlueprintTreeItemResponseModel : EntityTreeItemResponseModel +public class DocumentBlueprintTreeItemResponseModel : NamedEntityTreeItemResponseModel { public Guid DocumentTypeId { get; set; } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/DocumentTreeItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/DocumentTreeItemResponseModel.cs index 19fb60c6ec..8aa8b9c281 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/DocumentTreeItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/DocumentTreeItemResponseModel.cs @@ -1,16 +1,13 @@ -namespace Umbraco.Cms.Api.Management.ViewModels.Tree; +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Api.Management.ViewModels.DocumentType; + +namespace Umbraco.Cms.Api.Management.ViewModels.Tree; public class DocumentTreeItemResponseModel : ContentTreeItemResponseModel { public bool IsProtected { get; set; } - public bool IsPublished { get; set; } + public DocumentTypeReferenceResponseModel DocumentType { get; set; } = new(); - public bool IsEdited { get; set; } - - public Guid ContentTypeId { get; set; } - - public IEnumerable Variants { get; set; } = Enumerable.Empty(); - - public string Icon { get; set; } = string.Empty; + public IEnumerable Variants { get; set; } = Enumerable.Empty(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/EntityTreeItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/EntityTreeItemResponseModel.cs index 438ba2b332..3373daf20d 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/EntityTreeItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/EntityTreeItemResponseModel.cs @@ -1,10 +1,8 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Tree; -public class EntityTreeItemResponseModel : TreeItemPresentationModel, INamedEntityPresentationModel +public class EntityTreeItemResponseModel : TreeItemPresentationModel { public Guid Id { get; set; } - public bool IsContainer { get; set; } - - public Guid? ParentId { get; set; } + public ReferenceByIdModel? Parent { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/FileSystemTreeItemPresentationModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/FileSystemTreeItemPresentationModel.cs index b6cc6519ce..d3a83c5f12 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/FileSystemTreeItemPresentationModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/FileSystemTreeItemPresentationModel.cs @@ -4,6 +4,8 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Tree; public class FileSystemTreeItemPresentationModel : TreeItemPresentationModel { + public string Name { get; set; } = string.Empty; + public string Path { get; set; } = string.Empty; public FileSystemFolderModel? Parent { get; set; } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/FolderTreeItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/FolderTreeItemResponseModel.cs index 89f0f39f87..c92da67ce4 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/FolderTreeItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/FolderTreeItemResponseModel.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Api.Management.ViewModels.Tree; -public class FolderTreeItemResponseModel : EntityTreeItemResponseModel +public class FolderTreeItemResponseModel : NamedEntityTreeItemResponseModel { public bool IsFolder { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/NamedEntityTreeItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/NamedEntityTreeItemResponseModel.cs new file mode 100644 index 0000000000..107eb49e8f --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/NamedEntityTreeItemResponseModel.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.Tree; + +public class NamedEntityTreeItemResponseModel : EntityTreeItemResponseModel +{ + public string Name { get; set; } = string.Empty; +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/TreeItemPresentationModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/TreeItemPresentationModel.cs index f6d02c107f..b8bc592af3 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/TreeItemPresentationModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/TreeItemPresentationModel.cs @@ -2,8 +2,6 @@ public class TreeItemPresentationModel { - public string Name { get; set; } = string.Empty; - public string Type { get; set; } = string.Empty; public bool HasChildren { get; set; } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/VariantTreeItemViewModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Tree/VariantTreeItemViewModel.cs deleted file mode 100644 index ae56418393..0000000000 --- a/src/Umbraco.Cms.Api.Management/ViewModels/Tree/VariantTreeItemViewModel.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Umbraco.Cms.Core.Models; - -namespace Umbraco.Cms.Api.Management.ViewModels.Tree; - -public class VariantTreeItemViewModel -{ - public required string Name { get; set; } - - public string? Culture { get; set; } - - public required PublishedState State { get; set; } -} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/User/Current/CurrentUserResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/User/Current/CurrentUserResponseModel.cs index dcabba86fe..c7860ec78b 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/User/Current/CurrentUserResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/User/Current/CurrentUserResponseModel.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Api.Management.ViewModels.User.Current; -public class CurrentUserResponseModel : INamedEntityPresentationModel +public class CurrentUserResponseModel { public required Guid Id { get; init; } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/User/Item/UserItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/User/Item/UserItemResponseModel.cs index 6c9c3884a6..33024acc37 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/User/Item/UserItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/User/Item/UserItemResponseModel.cs @@ -2,6 +2,6 @@ namespace Umbraco.Cms.Api.Management.ViewModels.User.Item; -public class UserItemResponseModel : ItemResponseModelBase +public class UserItemResponseModel : NamedItemResponseModelBase { } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/User/UserResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/User/UserResponseModel.cs index 1a5251227a..f601f8afa8 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/User/UserResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/User/UserResponseModel.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.User; -public class UserResponseModel : UserPresentationBase, INamedEntityPresentationModel +public class UserResponseModel : UserPresentationBase { public Guid Id { get; set; } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/UserGroup/Item/UserGroupItemResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/UserGroup/Item/UserGroupItemResponseModel.cs index 78675a0340..54730f1141 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/UserGroup/Item/UserGroupItemResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/UserGroup/Item/UserGroupItemResponseModel.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Api.Management.ViewModels.UserGroup.Item; -public class UserGroupItemResponseModel : ItemResponseModelBase +public class UserGroupItemResponseModel : NamedItemResponseModelBase { public string? Icon { get; set; } } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/UserGroup/UserGroupResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/UserGroup/UserGroupResponseModel.cs index ee5c6437df..dc555484fe 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/UserGroup/UserGroupResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/UserGroup/UserGroupResponseModel.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Api.Management.ViewModels.UserGroup; -public class UserGroupResponseModel : UserGroupBase, INamedEntityPresentationModel +public class UserGroupResponseModel : UserGroupBase { /// /// The key identifier for the user group. diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index 33770fec67..0eee44c4fb 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -306,7 +306,6 @@ namespace Umbraco.Cms.Core.DependencyInjection Services.AddUnique(); Services.AddUnique(); Services.AddUnique(); - Services.AddUnique(); Services.AddUnique(); Services.AddUnique(); Services.AddUnique(); diff --git a/src/Umbraco.Core/Services/ContentCreatingService.cs b/src/Umbraco.Core/Services/ContentCreatingService.cs deleted file mode 100644 index 1acd7c6651..0000000000 --- a/src/Umbraco.Core/Services/ContentCreatingService.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services.OperationStatus; - -namespace Umbraco.Cms.Core.Services; - -public class ContentCreatingService : IContentCreatingService -{ - private readonly IContentTypeService _contentTypeService; - private readonly IContentService _contentService; - private readonly IEntityService _entityService; - private readonly ICoreScopeProvider _coreScopeProvider; - - public ContentCreatingService(IContentTypeService contentTypeService, IContentService contentService, IEntityService entityService, ICoreScopeProvider coreScopeProvider) - { - _contentTypeService = contentTypeService; - _contentService = contentService; - _entityService = entityService; - _coreScopeProvider = coreScopeProvider; - } - - public async Task?, ContentCreatingOperationStatus>> GetAllowedChildrenContentTypesAsync(Guid key, int skip, int take) - { - using ICoreScope scope = _coreScopeProvider.CreateCoreScope(); - IContent? content = _contentService.GetById(key); - - if (content is null) - { - return Attempt.FailWithStatus?, ContentCreatingOperationStatus>(ContentCreatingOperationStatus.NotFound, null); - } - - // FIXME: When content gets a ContentTypeKey property, we no longer have to get the key from the entityService - Attempt contentTypeKeyAttempt = _entityService.GetKey(content.ContentTypeId, UmbracoObjectTypes.DocumentType); - - if (contentTypeKeyAttempt.Success is false) - { - // This should never happen, content shouldn't be able to exists without a document type - throw new InvalidOperationException("The document type could not be found."); - } - - Attempt?, ContentTypeOperationStatus> contentTypeAttempt = await _contentTypeService.GetAllowedChildrenAsync(contentTypeKeyAttempt.Result, skip, take); - - if (contentTypeAttempt.Success is false) - { - throw new InvalidOperationException("The document type could not be found."); - } - - scope.Complete(); - - return Attempt.SucceedWithStatus(ContentCreatingOperationStatus.Success, contentTypeAttempt.Result); - } - - // this is just a convenience, so consumers do not need dependencies on IContentTypeService - public async Task> GetAllowedChildrenContentTypesAtRootAsync(int skip, int take) - => await _contentTypeService.GetAllAllowedAsRootAsync(skip, take); -} diff --git a/src/Umbraco.Core/Services/ContentTypeService.cs b/src/Umbraco.Core/Services/ContentTypeService.cs index 4353e45f85..6a5570d632 100644 --- a/src/Umbraco.Core/Services/ContentTypeService.cs +++ b/src/Umbraco.Core/Services/ContentTypeService.cs @@ -120,59 +120,6 @@ public class ContentTypeService : ContentTypeServiceBase - public Task> GetAllAllowedAsRootAsync(int skip, int take) - { - using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true); - - // that one is special because it works across content, media and member types - scope.ReadLock(Constants.Locks.ContentTypes, Constants.Locks.MediaTypes, Constants.Locks.MemberTypes); - - IQuery query = ScopeProvider.CreateQuery().Where(x => x.AllowedAsRoot); - IEnumerable contentTypes = Repository.Get(query).ToArray(); - - var pagedModel = new PagedModel - { - Total = contentTypes.Count(), - Items = contentTypes.Skip(skip).Take(take) - }; - - return Task.FromResult(pagedModel); - } - - public Task?, ContentTypeOperationStatus>> GetAllowedChildrenAsync(Guid key, int skip, int take) - { - using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true); - IContentType? parent = Get(key); - - if (parent?.AllowedContentTypes is null) - { - return Task.FromResult(Attempt.FailWithStatus?, ContentTypeOperationStatus>(ContentTypeOperationStatus.NotFound, null)); - } - - PagedModel result; - if (parent.AllowedContentTypes.Any() is false) - { - // no content types allowed under parent - result = new PagedModel - { - Items = Array.Empty(), - Total = 0, - }; - } - else - { - IContentType[] allowedChildren = GetAll(parent.AllowedContentTypes.Select(x => x.Key)).ToArray(); - result = new PagedModel - { - Items = allowedChildren.Take(take).Skip(skip), - Total = allowedChildren.Length, - }; - } - - return Task.FromResult(Attempt.SucceedWithStatus?, ContentTypeOperationStatus>(ContentTypeOperationStatus.Success, result)); - } - protected override void DeleteItemsOfTypes(IEnumerable typeIds) { using (ICoreScope scope = ScopeProvider.CreateCoreScope()) diff --git a/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index 66beb38002..f44ebb3a28 100644 --- a/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -1019,6 +1019,64 @@ public abstract class ContentTypeServiceBase : ContentTypeSe #endregion + #region Allowed types + + /// + public Task> GetAllAllowedAsRootAsync(int skip, int take) + { + using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true); + + // that one is special because it works across content, media and member types + scope.ReadLock(Constants.Locks.ContentTypes, Constants.Locks.MediaTypes, Constants.Locks.MemberTypes); + + IQuery query = ScopeProvider.CreateQuery().Where(x => x.AllowedAsRoot); + IEnumerable contentTypes = Repository.Get(query).ToArray(); + + var pagedModel = new PagedModel + { + Total = contentTypes.Count(), + Items = contentTypes.Skip(skip).Take(take) + }; + + return Task.FromResult(pagedModel); + } + + /// + public Task?, ContentTypeOperationStatus>> GetAllowedChildrenAsync(Guid key, int skip, int take) + { + using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true); + TItem? parent = Get(key); + + if (parent?.AllowedContentTypes is null) + { + return Task.FromResult(Attempt.FailWithStatus?, ContentTypeOperationStatus>(ContentTypeOperationStatus.NotFound, null)); + } + + PagedModel result; + if (parent.AllowedContentTypes.Any() is false) + { + // no content types allowed under parent + result = new PagedModel + { + Items = Array.Empty(), + Total = 0, + }; + } + else + { + TItem[] allowedChildren = GetAll(parent.AllowedContentTypes.Select(x => x.Key)).ToArray(); + result = new PagedModel + { + Items = allowedChildren.Take(take).Skip(skip), + Total = allowedChildren.Length, + }; + } + + return Task.FromResult(Attempt.SucceedWithStatus?, ContentTypeOperationStatus>(ContentTypeOperationStatus.Success, result)); + } + + #endregion + #region Containers protected abstract Guid ContainedObjectType { get; } @@ -1248,6 +1306,4 @@ public abstract class ContentTypeServiceBase : ContentTypeSe } #endregion - - } diff --git a/src/Umbraco.Core/Services/IContentCreatingService.cs b/src/Umbraco.Core/Services/IContentCreatingService.cs deleted file mode 100644 index 003f162b89..0000000000 --- a/src/Umbraco.Core/Services/IContentCreatingService.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services.OperationStatus; - -namespace Umbraco.Cms.Core.Services; - -public interface IContentCreatingService -{ - Task?, ContentCreatingOperationStatus>> GetAllowedChildrenContentTypesAsync(Guid key, int skip, int take); - - Task> GetAllowedChildrenContentTypesAtRootAsync(int skip, int take); -} diff --git a/src/Umbraco.Core/Services/IContentTypeService.cs b/src/Umbraco.Core/Services/IContentTypeService.cs index b534c836d3..7dbd0834ec 100644 --- a/src/Umbraco.Core/Services/IContentTypeService.cs +++ b/src/Umbraco.Core/Services/IContentTypeService.cs @@ -30,16 +30,4 @@ public interface IContentTypeService : IContentTypeBaseService /// /// IEnumerable GetAllContentTypeIds(string[] aliases); - - /// - /// Returns all the content type allowed as root. - /// - /// - Task> GetAllAllowedAsRootAsync(int skip, int take); - - /// - /// Returns all content types allowed as children for a given content type key. - /// - /// - Task?, ContentTypeOperationStatus>> GetAllowedChildrenAsync(Guid key, int skip, int take); } diff --git a/src/Umbraco.Core/Services/IContentTypeServiceBase.cs b/src/Umbraco.Core/Services/IContentTypeServiceBase.cs index 165dfa6e24..f3707a5059 100644 --- a/src/Umbraco.Core/Services/IContentTypeServiceBase.cs +++ b/src/Umbraco.Core/Services/IContentTypeServiceBase.cs @@ -139,4 +139,16 @@ public interface IContentTypeBaseService : IContentTypeBaseService, IServ Task> CopyAsync(Guid key, Guid? containerKey); Task> MoveAsync(Guid key, Guid? containerKey); + + /// + /// Returns all the content type allowed as root. + /// + /// + Task> GetAllAllowedAsRootAsync(int skip, int take); + + /// + /// Returns all content types allowed as children for a given content type key. + /// + /// + Task?, ContentTypeOperationStatus>> GetAllowedChildrenAsync(Guid key, int skip, int take); } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Api.Management/Mapping/Content/ContentStateHelperTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Api.Management/Mapping/Content/ContentStateHelperTests.cs new file mode 100644 index 0000000000..ba6609a0dc --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Api.Management/Mapping/Content/ContentStateHelperTests.cs @@ -0,0 +1,116 @@ +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Api.Management.Mapping.Content; +using Umbraco.Cms.Api.Management.ViewModels.Content; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Entities; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.Mapping.Content; + +[TestFixture] +public class ContentStateHelperTests +{ + [TestCase(false, false, ContentState.Draft)] + [TestCase(false, true, ContentState.Published)] + [TestCase(true, false, ContentState.Draft)] + [TestCase(true, true, ContentState.PublishedPendingChanges)] + public void Culture_Invariant_Content_State(bool edited, bool published, ContentState expectedResult) + { + var content = Mock.Of(c => c.Id == 1 && c.Published == published && c.Edited == edited); + Assert.AreEqual(expectedResult, ContentStateHelper.GetContentState(content, culture: null)); + } + + [TestCase(false, false)] + [TestCase(false, true)] + [TestCase(true, false)] + [TestCase(true, true)] + public void Culture_Invariant_Content_Not_Created_State(bool edited, bool published) + { + var content = Mock.Of(c => c.Id == 0 && c.Published == published && c.Edited == edited); + Assert.AreEqual(ContentState.NotCreated, ContentStateHelper.GetContentState(content, culture: null)); + } + + [TestCase(false, false, ContentState.Draft)] + [TestCase(false, true, ContentState.Published)] + [TestCase(true, false, ContentState.Draft)] + [TestCase(true, true, ContentState.PublishedPendingChanges)] + public void Culture_Variant_Content_Existing_Culture_State(bool edited, bool published, ContentState expectedResult) + { + const string culture = "en"; + var content = Mock.Of(c => + c.Id == 1 + && c.AvailableCultures == new[] { culture } + && c.EditedCultures == (edited ? new[] { culture } : Enumerable.Empty()) + && c.Published == published + && c.PublishedCultures == (published ? new[] { culture } : Enumerable.Empty())); + Assert.AreEqual(expectedResult, ContentStateHelper.GetContentState(content, culture)); + } + + [TestCase(false, false)] + [TestCase(false, true)] + [TestCase(true, false)] + [TestCase(true, true)] + public void Culture_Variant_Content_Missing_Culture_State(bool edited, bool published) + { + const string culture = "en"; + var content = Mock.Of(c => + c.Id == 1 + && c.AvailableCultures == new[] { culture } + && c.EditedCultures == (edited ? new[] { culture } : Enumerable.Empty()) + && c.Published == published + && c.PublishedCultures == (published ? new[] { culture } : Enumerable.Empty())); + Assert.AreEqual(ContentState.NotCreated, ContentStateHelper.GetContentState(content, "dk")); + } + + [TestCase(false, false, ContentState.Draft)] + [TestCase(false, true, ContentState.Published)] + [TestCase(true, false, ContentState.Draft)] + [TestCase(true, true, ContentState.PublishedPendingChanges)] + public void Culture_Invariant_DocumentEntitySlim_State(bool edited, bool published, ContentState expectedResult) + { + var entity = Mock.Of(c => c.Id == 1 && c.Published == published && c.Edited == edited && c.CultureNames == new Dictionary()); + Assert.AreEqual(expectedResult, ContentStateHelper.GetContentState(entity, culture: null)); + } + + [TestCase(false, false)] + [TestCase(false, true)] + [TestCase(true, false)] + [TestCase(true, true)] + public void Culture_Invariant_DocumentEntitySlim_Not_Created_State(bool edited, bool published) + { + var entity = Mock.Of(c => c.Id == 0 && c.Published == published && c.Edited == edited && c.CultureNames == new Dictionary()); + Assert.AreEqual(ContentState.NotCreated, ContentStateHelper.GetContentState(entity, culture: null)); + } + + [TestCase(false, false, ContentState.Draft)] + [TestCase(false, true, ContentState.Published)] + [TestCase(true, false, ContentState.Draft)] + [TestCase(true, true, ContentState.PublishedPendingChanges)] + public void Culture_Variant_DocumentEntitySlim_Existing_Culture_State(bool edited, bool published, ContentState expectedResult) + { + const string culture = "en"; + var entity = Mock.Of(c => + c.Id == 1 + && c.CultureNames == new Dictionary { { culture, "value does not matter" } } + && c.EditedCultures == (edited ? new[] { culture } : Enumerable.Empty()) + && c.Published == published + && c.PublishedCultures == (published ? new[] { culture } : Enumerable.Empty())); + Assert.AreEqual(expectedResult, ContentStateHelper.GetContentState(entity, culture)); + } + + [TestCase(false, false)] + [TestCase(false, true)] + [TestCase(true, false)] + [TestCase(true, true)] + public void Culture_Variant_DocumentEntitySlim_Missing_Culture_State(bool edited, bool published) + { + const string culture = "en"; + var entity = Mock.Of(c => + c.Id == 1 + && c.CultureNames == new Dictionary { { culture, "value does not matter" } } + && c.EditedCultures == (edited ? new[] { culture } : Enumerable.Empty()) + && c.Published == published + && c.PublishedCultures == (published ? new[] { culture } : Enumerable.Empty())); + Assert.AreEqual(ContentState.NotCreated, ContentStateHelper.GetContentState(entity, "dk")); + } +}