From 468ca9ae94fbd329440b9bb7288328603e79a8a0 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Fri, 28 Mar 2025 16:34:25 +0100 Subject: [PATCH] Member relation tracking (#18852) * Added member reference type model. * Updated client-side types and sdk. * Render member relations on the member info view. * Add relation type for related member with migration. * Extend tests for track relations to include member relations. * Extend tests for relation repository. * Extend tests for relation service. * Addressed comments from Copilot review. * Add relation notification to member deletion. * Removed unused import. * Updates from code review. * export const * Fixed failing integration tests. * deprecate interface with wrong name * fix import --------- Co-authored-by: Mads Rasmussen --- .../AreReferencedDocumentController.cs | 4 +- .../ReferencedByDocumentController.cs | 2 +- ...ReferencedDescendantsDocumentController.cs | 4 +- .../AreReferencedMediaController.cs | 4 +- .../References/ReferencedByMediaController.cs | 2 +- .../ReferencedDescendantsMediaController.cs | 4 +- .../AreReferencedMemberController.cs | 51 ++++ .../ReferencedByMemberController.cs | 50 ++++ .../ReferencedDescendantsMemberController.cs | 50 ++++ .../RelationTypePresentationFactory.cs | 3 +- ...TrackedReferenceViewModelsMapDefinition.cs | 16 +- src/Umbraco.Cms.Api.Management/OpenApi.json | 274 +++++++++++++++++- .../DefaultReferenceResponseModel.cs | 8 +- .../DocumentReferenceResponseModel.cs | 8 +- .../MediaReferenceResponseModel.cs | 8 +- .../MemberReferenceResponseModel.cs | 6 + .../ReferenceResponseModel.cs | 8 + .../TrackedReferenceMemberType.cs | 5 + src/Umbraco.Core/Constants-Conventions.cs | 16 +- .../Models/Editors/UmbracoEntityReference.cs | 3 + .../Models/RelationTypeExtensions.cs | 1 + .../DataValueReferenceFactoryCollection.cs | 2 +- .../MemberPickerPropertyEditor.cs | 17 +- .../Migrations/Install/DatabaseDataCreator.cs | 3 + .../Migrations/Upgrade/UmbracoPlan.cs | 1 + .../V_15_4_0/AddRelationTypeForMembers.cs | 46 +++ .../src/external/backend-api/src/sdk.gen.ts | 84 +++++- .../src/external/backend-api/src/types.gen.ts | 43 ++- .../src/mocks/data/tracked-reference.data.ts | 5 +- .../workspace-info-app-layout.element.ts | 8 +- .../document-reference-table.element.ts | 4 + .../media/media/entity-actions/manifests.ts | 2 +- ...a-references-workspace-info-app.element.ts | 4 - .../src/packages/members/member/constants.ts | 1 + .../member/entity-actions/manifests.ts | 8 +- .../members/member/item/repository/types.ts | 11 +- .../src/packages/members/member/manifests.ts | 2 + .../members/member/reference/constants.ts | 1 + .../members/member/reference/index.ts | 1 + .../member/reference/info-app/manifests.ts | 18 ++ ...r-references-workspace-info-app.element.ts | 161 ++++++++++ .../members/member/reference/manifests.ts | 4 + .../member/reference/repository/constants.ts | 1 + .../member/reference/repository/index.ts | 1 + .../member/reference/repository/manifests.ts | 19 ++ ...ference-response.management-api.mapping.ts | 32 ++ .../repository/member-reference.repository.ts | 36 +++ .../member-reference.server.data.ts | 121 ++++++++ .../member/reference/repository/types.ts | 14 + ...mber-workspace-view-member-info.element.ts | 4 +- .../member-workspace-view-member.element.ts | 7 + .../relations/relations/reference/types.ts | 4 +- .../src/packages/relations/relations/utils.ts | 9 + .../Repositories/RelationRepositoryTest.cs | 49 ++-- .../RelationTypeRepositoryTest.cs | 6 +- .../Services/RelationServiceTests.cs | 37 +++ .../Services/TrackRelationsTests.cs | 18 +- 57 files changed, 1238 insertions(+), 73 deletions(-) create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/Member/References/AreReferencedMemberController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/Member/References/ReferencedByMemberController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/Member/References/ReferencedDescendantsMemberController.cs create mode 100644 src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/MemberReferenceResponseModel.cs create mode 100644 src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/ReferenceResponseModel.cs create mode 100644 src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/TrackedReferenceMemberType.cs create mode 100644 src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_4_0/AddRelationTypeForMembers.cs create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/constants.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/info-app/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/info-app/member-references-workspace-info-app.element.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/constants.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/manifests.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference-response.management-api.mapping.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference.repository.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference.server.data.ts create mode 100644 src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/types.ts diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/AreReferencedDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/AreReferencedDocumentController.cs index ed593e9c9e..bc2353dc55 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/AreReferencedDocumentController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/AreReferencedDocumentController.cs @@ -1,4 +1,4 @@ -using Asp.Versioning; +using Asp.Versioning; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Common.ViewModels.Pagination; @@ -45,6 +45,6 @@ public class AreReferencedDocumentController : DocumentControllerBase Items = _umbracoMapper.MapEnumerable(distinctByKeyItemsWithReferencedRelations.Items), }; - return await Task.FromResult(pagedViewModel); + return pagedViewModel; } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedByDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedByDocumentController.cs index 47df66fd6d..6a1d9b2824 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedByDocumentController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedByDocumentController.cs @@ -45,6 +45,6 @@ public class ReferencedByDocumentController : DocumentControllerBase Items = await _relationTypePresentationFactory.CreateReferenceResponseModelsAsync(relationItems.Items), }; - return await Task.FromResult(pagedViewModel); + return pagedViewModel; } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedDescendantsDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedDescendantsDocumentController.cs index 4b931632e1..138b919628 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedDescendantsDocumentController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/References/ReferencedDescendantsDocumentController.cs @@ -1,4 +1,4 @@ -using Asp.Versioning; +using Asp.Versioning; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Common.ViewModels.Pagination; @@ -45,6 +45,6 @@ public class ReferencedDescendantsDocumentController : DocumentControllerBase Items = _umbracoMapper.MapEnumerable(relationItems.Items), }; - return await Task.FromResult(pagedViewModel); + return pagedViewModel; } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/References/AreReferencedMediaController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/References/AreReferencedMediaController.cs index 89e0c2d1ba..d10bdb9627 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/References/AreReferencedMediaController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/References/AreReferencedMediaController.cs @@ -1,4 +1,4 @@ -using Asp.Versioning; +using Asp.Versioning; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Common.ViewModels.Pagination; @@ -46,6 +46,6 @@ public class AreReferencedMediaController : MediaControllerBase Items = _umbracoMapper.MapEnumerable(distinctByKeyItemsWithReferencedRelations.Items), }; - return await Task.FromResult(pagedViewModel); + return pagedViewModel; } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/References/ReferencedByMediaController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/References/ReferencedByMediaController.cs index 63748741b1..e9e62504ed 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/References/ReferencedByMediaController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/References/ReferencedByMediaController.cs @@ -45,6 +45,6 @@ public class ReferencedByMediaController : MediaControllerBase Items = await _relationTypePresentationFactory.CreateReferenceResponseModelsAsync(relationItems.Items), }; - return await Task.FromResult(pagedViewModel); + return pagedViewModel; } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/References/ReferencedDescendantsMediaController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/References/ReferencedDescendantsMediaController.cs index 2990602e02..c6c16cb222 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/References/ReferencedDescendantsMediaController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/References/ReferencedDescendantsMediaController.cs @@ -1,4 +1,4 @@ -using Asp.Versioning; +using Asp.Versioning; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Common.ViewModels.Pagination; @@ -45,6 +45,6 @@ public class ReferencedDescendantsMediaController : MediaControllerBase Items = _umbracoMapper.MapEnumerable(relationItems.Items), }; - return await Task.FromResult(pagedViewModel); + return pagedViewModel; } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Member/References/AreReferencedMemberController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Member/References/AreReferencedMemberController.cs new file mode 100644 index 0000000000..1b46a981ce --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Member/References/AreReferencedMemberController.cs @@ -0,0 +1,51 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Common.ViewModels.Pagination; +using Umbraco.Cms.Api.Management.ViewModels; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Mapping; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Controllers.Member.References; + +[ApiVersion("1.0")] +public class AreReferencedMemberController : MemberControllerBase +{ + private readonly ITrackedReferencesService _trackedReferencesSkipTakeService; + private readonly IUmbracoMapper _umbracoMapper; + + public AreReferencedMemberController(ITrackedReferencesService trackedReferencesSkipTakeService, IUmbracoMapper umbracoMapper) + { + _trackedReferencesSkipTakeService = trackedReferencesSkipTakeService; + _umbracoMapper = umbracoMapper; + } + + /// + /// Gets a page list of the items used in any kind of relation from selected keys. + /// + /// + /// Used when bulk deleting content/media and bulk unpublishing content (delete and unpublish on List view). + /// This is basically finding children of relations. + /// + // [HttpGet("item")] + [HttpGet("are-referenced")] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> GetPagedReferencedItems( + CancellationToken cancellationToken, + [FromQuery(Name="id")] HashSet ids, + int skip = 0, + int take = 20) + { + PagedModel distinctByKeyItemsWithReferencedRelations = await _trackedReferencesSkipTakeService.GetPagedKeysWithDependentReferencesAsync(ids, Constants.ObjectTypes.Member, skip, take); + var pagedViewModel = new PagedViewModel + { + Total = distinctByKeyItemsWithReferencedRelations.Total, + Items = _umbracoMapper.MapEnumerable(distinctByKeyItemsWithReferencedRelations.Items), + }; + + return pagedViewModel; + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Member/References/ReferencedByMemberController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Member/References/ReferencedByMemberController.cs new file mode 100644 index 0000000000..69237278a5 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Member/References/ReferencedByMemberController.cs @@ -0,0 +1,50 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Common.ViewModels.Pagination; +using Umbraco.Cms.Api.Management.Factories; +using Umbraco.Cms.Api.Management.ViewModels.TrackedReferences; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Controllers.Member.References; + +[ApiVersion("1.0")] +public class ReferencedByMemberController : MemberControllerBase +{ + private readonly ITrackedReferencesService _trackedReferencesService; + private readonly IRelationTypePresentationFactory _relationTypePresentationFactory; + + public ReferencedByMemberController(ITrackedReferencesService trackedReferencesService, IRelationTypePresentationFactory relationTypePresentationFactory) + { + _trackedReferencesService = trackedReferencesService; + _relationTypePresentationFactory = relationTypePresentationFactory; + } + + /// + /// Gets a page list of tracked references for the current item, so you can see where an item is being used. + /// + /// + /// Used by info tabs on content, media etc. and for the delete and unpublish of single items. + /// This is basically finding parents of relations. + /// + [HttpGet("{id:guid}/referenced-by")] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> ReferencedBy( + CancellationToken cancellationToken, + Guid id, + int skip = 0, + int take = 20) + { + PagedModel relationItems = await _trackedReferencesService.GetPagedRelationsForItemAsync(id, skip, take, true); + + var pagedViewModel = new PagedViewModel + { + Total = relationItems.Total, + Items = await _relationTypePresentationFactory.CreateReferenceResponseModelsAsync(relationItems.Items), + }; + + return pagedViewModel; + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Member/References/ReferencedDescendantsMemberController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Member/References/ReferencedDescendantsMemberController.cs new file mode 100644 index 0000000000..aa86950e6e --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Member/References/ReferencedDescendantsMemberController.cs @@ -0,0 +1,50 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Common.ViewModels.Pagination; +using Umbraco.Cms.Api.Management.ViewModels; +using Umbraco.Cms.Core.Mapping; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Controllers.Member.References; + +[ApiVersion("1.0")] +public class ReferencedDescendantsMemberController : MemberControllerBase +{ + private readonly ITrackedReferencesService _trackedReferencesSkipTakeService; + private readonly IUmbracoMapper _umbracoMapper; + + public ReferencedDescendantsMemberController(ITrackedReferencesService trackedReferencesSkipTakeService, IUmbracoMapper umbracoMapper) + { + _trackedReferencesSkipTakeService = trackedReferencesSkipTakeService; + _umbracoMapper = umbracoMapper; + } + + /// + /// Gets a page list of the child nodes of the current item used in any kind of relation. + /// + /// + /// Used when deleting and unpublishing a single item to check if this item has any descending items that are in any + /// kind of relation. + /// This is basically finding the descending items which are children in relations. + /// + [HttpGet("{id:guid}/referenced-descendants")] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task>> ReferencedDescendants( + CancellationToken cancellationToken, + Guid id, + int skip = 0, + int take = 20) + { + PagedModel relationItems = await _trackedReferencesSkipTakeService.GetPagedDescendantsInReferencesAsync(id, skip, take, true); + var pagedViewModel = new PagedViewModel + { + Total = relationItems.Total, + Items = _umbracoMapper.MapEnumerable(relationItems.Items), + }; + + return pagedViewModel; + } +} diff --git a/src/Umbraco.Cms.Api.Management/Factories/RelationTypePresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/RelationTypePresentationFactory.cs index 0c718bf663..a6fb1cbae8 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/RelationTypePresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/RelationTypePresentationFactory.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Api.Management.ViewModels.TrackedReferences; using Umbraco.Cms.Core; using Umbraco.Cms.Core.DependencyInjection; @@ -58,6 +58,7 @@ public class RelationTypePresentationFactory : IRelationTypePresentationFactory { Constants.UdiEntityType.Document => MapDocumentReference(relationItemModel, slimEntities), Constants.UdiEntityType.Media => _umbracoMapper.Map(relationItemModel), + Constants.UdiEntityType.Member => _umbracoMapper.Map(relationItemModel), _ => _umbracoMapper.Map(relationItemModel), }).WhereNotNull().ToArray(); diff --git a/src/Umbraco.Cms.Api.Management/Mapping/TrackedReferences/TrackedReferenceViewModelsMapDefinition.cs b/src/Umbraco.Cms.Api.Management/Mapping/TrackedReferences/TrackedReferenceViewModelsMapDefinition.cs index 7a3874271c..e9f2700f5a 100644 --- a/src/Umbraco.Cms.Api.Management/Mapping/TrackedReferences/TrackedReferenceViewModelsMapDefinition.cs +++ b/src/Umbraco.Cms.Api.Management/Mapping/TrackedReferences/TrackedReferenceViewModelsMapDefinition.cs @@ -1,4 +1,4 @@ -using Umbraco.Cms.Api.Management.ViewModels; +using Umbraco.Cms.Api.Management.ViewModels; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Api.Management.ViewModels.TrackedReferences; @@ -11,6 +11,7 @@ public class TrackedReferenceViewModelsMapDefinition : IMapDefinition { mapper.Define((source, context) => new DocumentReferenceResponseModel(), Map); mapper.Define((source, context) => new MediaReferenceResponseModel(), Map); + mapper.Define((source, context) => new MemberReferenceResponseModel(), Map); mapper.Define((source, context) => new DefaultReferenceResponseModel(), Map); mapper.Define((source, context) => new ReferenceByIdModel(), Map); mapper.Define((source, context) => new ReferenceByIdModel(), Map); @@ -43,6 +44,19 @@ public class TrackedReferenceViewModelsMapDefinition : IMapDefinition }; } + // Umbraco.Code.MapAll + private void Map(RelationItemModel source, MemberReferenceResponseModel target, MapperContext context) + { + target.Id = source.NodeKey; + target.Name = source.NodeName; + target.MemberType = new TrackedReferenceMemberType + { + Alias = source.ContentTypeAlias, + Icon = source.ContentTypeIcon, + Name = source.ContentTypeName, + }; + } + // Umbraco.Code.MapAll private void Map(RelationItemModel source, DefaultReferenceResponseModel target, MapperContext context) { diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index ebecf3e9cb..44a69ccc95 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -6245,6 +6245,13 @@ "type": "string" } }, + { + "name": "isElement", + "in": "query", + "schema": { + "type": "boolean" + } + }, { "name": "skip", "in": "query", @@ -10069,6 +10076,13 @@ "type": "string" } }, + { + "name": "trashed", + "in": "query", + "schema": { + "type": "boolean" + } + }, { "name": "skip", "in": "query", @@ -15766,6 +15780,13 @@ "type": "string" } }, + { + "name": "trashed", + "in": "query", + "schema": { + "type": "boolean" + } + }, { "name": "skip", "in": "query", @@ -20170,6 +20191,134 @@ ] } }, + "/umbraco/management/api/v1/member/{id}/referenced-by": { + "get": { + "tags": [ + "Member" + ], + "operationId": "GetMemberByIdReferencedBy", + "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": 20 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/PagedIReferenceResponseModel" + } + ] + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, + "/umbraco/management/api/v1/member/{id}/referenced-descendants": { + "get": { + "tags": [ + "Member" + ], + "operationId": "GetMemberByIdReferencedDescendants", + "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": 20 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/PagedReferenceByIdModel" + } + ] + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/member/{id}/validate": { "put": { "tags": [ @@ -20312,6 +20461,73 @@ ] } }, + "/umbraco/management/api/v1/member/are-referenced": { + "get": { + "tags": [ + "Member" + ], + "operationId": "GetMemberAreReferenced", + "parameters": [ + { + "name": "id", + "in": "query", + "schema": { + "uniqueItems": true, + "type": "array", + "items": { + "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": 20 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/PagedReferenceByIdModel" + } + ] + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/member/configuration": { "get": { "tags": [ @@ -40095,6 +40311,41 @@ ], "type": "string" }, + "MemberReferenceResponseModel": { + "required": [ + "$type", + "id", + "memberType" + ], + "type": "object", + "properties": { + "$type": { + "type": "string" + }, + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string", + "nullable": true + }, + "memberType": { + "oneOf": [ + { + "$ref": "#/components/schemas/TrackedReferenceMemberTypeModel" + } + ] + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "$type", + "mapping": { + "MemberReferenceResponseModel": "#/components/schemas/MemberReferenceResponseModel" + } + } + }, "MemberResponseModel": { "required": [ "email", @@ -41505,6 +41756,9 @@ }, { "$ref": "#/components/schemas/MediaReferenceResponseModel" + }, + { + "$ref": "#/components/schemas/MemberReferenceResponseModel" } ] } @@ -44177,6 +44431,24 @@ }, "additionalProperties": false }, + "TrackedReferenceMemberTypeModel": { + "type": "object", + "properties": { + "icon": { + "type": "string", + "nullable": true + }, + "alias": { + "type": "string", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, "UnknownTypePermissionPresentationModel": { "required": [ "$type", @@ -46521,4 +46793,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/DefaultReferenceResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/DefaultReferenceResponseModel.cs index 66780c9b47..f74b0d2840 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/DefaultReferenceResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/DefaultReferenceResponseModel.cs @@ -1,11 +1,7 @@ -namespace Umbraco.Cms.Api.Management.ViewModels.TrackedReferences; +namespace Umbraco.Cms.Api.Management.ViewModels.TrackedReferences; -public class DefaultReferenceResponseModel : IReferenceResponseModel +public class DefaultReferenceResponseModel : ReferenceResponseModel { - public Guid Id { get; set; } - - public string? Name { get; set; } - public string? Type { get; set; } public string? Icon { get; set; } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/DocumentReferenceResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/DocumentReferenceResponseModel.cs index e2bb767f99..a24ab23990 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/DocumentReferenceResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/DocumentReferenceResponseModel.cs @@ -1,13 +1,9 @@ -using Umbraco.Cms.Api.Management.ViewModels.Document; +using Umbraco.Cms.Api.Management.ViewModels.Document; namespace Umbraco.Cms.Api.Management.ViewModels.TrackedReferences; -public class DocumentReferenceResponseModel : IReferenceResponseModel +public class DocumentReferenceResponseModel : ReferenceResponseModel { - public Guid Id { get; set; } - - public string? Name { get; set; } - public bool? Published { get; set; } public TrackedReferenceDocumentType DocumentType { get; set; } = new(); diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/MediaReferenceResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/MediaReferenceResponseModel.cs index c9b910d0b1..5358088bb3 100644 --- a/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/MediaReferenceResponseModel.cs +++ b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/MediaReferenceResponseModel.cs @@ -1,10 +1,6 @@ -namespace Umbraco.Cms.Api.Management.ViewModels.TrackedReferences; +namespace Umbraco.Cms.Api.Management.ViewModels.TrackedReferences; -public class MediaReferenceResponseModel : IReferenceResponseModel +public class MediaReferenceResponseModel : ReferenceResponseModel { - public Guid Id { get; set; } - - public string? Name { get; set; } - public TrackedReferenceMediaType MediaType { get; set; } = new(); } diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/MemberReferenceResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/MemberReferenceResponseModel.cs new file mode 100644 index 0000000000..8e33a2a175 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/MemberReferenceResponseModel.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.TrackedReferences; + +public class MemberReferenceResponseModel : ReferenceResponseModel +{ + public TrackedReferenceMemberType MemberType { get; set; } = new(); +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/ReferenceResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/ReferenceResponseModel.cs new file mode 100644 index 0000000000..dae755fd33 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/ReferenceResponseModel.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.TrackedReferences; + +public abstract class ReferenceResponseModel : IReferenceResponseModel +{ + public Guid Id { get; set; } + + public string? Name { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/TrackedReferenceMemberType.cs b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/TrackedReferenceMemberType.cs new file mode 100644 index 0000000000..501ababd1f --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/TrackedReferences/TrackedReferenceMemberType.cs @@ -0,0 +1,5 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.TrackedReferences; + +public class TrackedReferenceMemberType : TrackedReferenceContentType +{ +} diff --git a/src/Umbraco.Core/Constants-Conventions.cs b/src/Umbraco.Core/Constants-Conventions.cs index 647226b6d7..989b947adc 100644 --- a/src/Umbraco.Core/Constants-Conventions.cs +++ b/src/Umbraco.Core/Constants-Conventions.cs @@ -233,17 +233,27 @@ public static partial class Constants public const string RelatedMediaName = "Related Media"; /// - /// Alias for default relation type "Related Media" + /// Alias for default relation type "Related Media". /// public const string RelatedMediaAlias = "umbMedia"; + /// + /// Name for default relation type "Related Member". + /// + public const string RelatedMemberName = "Related Member"; + + /// + /// Alias for default relation type "Related Member". + /// + public const string RelatedMemberAlias = "umbMember"; + /// /// Name for default relation type "Related Document". /// public const string RelatedDocumentName = "Related Document"; /// - /// Alias for default relation type "Related Document" + /// Alias for default relation type "Related Document". /// public const string RelatedDocumentAlias = "umbDocument"; @@ -284,7 +294,7 @@ public static partial class Constants /// Developers should not manually use these relation types since they will all be cleared whenever an entity /// (content, media or member) is saved since they are auto-populated based on property values. /// - public static string[] AutomaticRelationTypes { get; } = { RelatedMediaAlias, RelatedDocumentAlias }; + public static string[] AutomaticRelationTypes { get; } = { RelatedMediaAlias, RelatedMemberAlias, RelatedDocumentAlias }; // TODO: return a list of built in types so we can use that to prevent deletion in the UI } diff --git a/src/Umbraco.Core/Models/Editors/UmbracoEntityReference.cs b/src/Umbraco.Core/Models/Editors/UmbracoEntityReference.cs index 3f02be10b1..3c22042b99 100644 --- a/src/Umbraco.Core/Models/Editors/UmbracoEntityReference.cs +++ b/src/Umbraco.Core/Models/Editors/UmbracoEntityReference.cs @@ -34,6 +34,9 @@ public struct UmbracoEntityReference : IEquatable case Constants.UdiEntityType.Media: RelationTypeAlias = Constants.Conventions.RelationTypes.RelatedMediaAlias; break; + case Constants.UdiEntityType.Member: + RelationTypeAlias = Constants.Conventions.RelationTypes.RelatedMemberAlias; + break; default: // No relation type alias convention for this entity type, so leave it empty RelationTypeAlias = string.Empty; diff --git a/src/Umbraco.Core/Models/RelationTypeExtensions.cs b/src/Umbraco.Core/Models/RelationTypeExtensions.cs index 6a22f607be..81d6801330 100644 --- a/src/Umbraco.Core/Models/RelationTypeExtensions.cs +++ b/src/Umbraco.Core/Models/RelationTypeExtensions.cs @@ -11,6 +11,7 @@ public static class RelationTypeExtensions public static bool IsSystemRelationType(this IRelationType relationType) => relationType.Alias == Constants.Conventions.RelationTypes.RelatedDocumentAlias || relationType.Alias == Constants.Conventions.RelationTypes.RelatedMediaAlias + || relationType.Alias == Constants.Conventions.RelationTypes.RelatedMemberAlias || relationType.Alias == Constants.Conventions.RelationTypes.RelateDocumentOnCopyAlias || relationType.Alias == Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias || relationType.Alias == Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias; diff --git a/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs b/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs index 86c9c48fc0..c35ae6d2ae 100644 --- a/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs +++ b/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs @@ -91,7 +91,7 @@ public class DataValueReferenceFactoryCollection : BuilderCollectionBase DataValueEditorFactory.Create(Attribute!); - private class MemberPickerPropertyValueEditor : DataValueEditor + private class MemberPickerPropertyValueEditor : DataValueEditor, IDataValueReference { private readonly IMemberService _memberService; @@ -61,5 +61,20 @@ public class MemberPickerPropertyEditor : DataEditor => editorValue.Value is string stringValue && Guid.TryParse(stringValue, out Guid memberKey) ? new GuidUdi(Constants.UdiEntityType.Member, memberKey) : null; + + public IEnumerable GetReferences(object? value) + { + var asString = value is string str ? str : value?.ToString(); + + if (string.IsNullOrEmpty(asString)) + { + yield break; + } + + if (UdiParser.TryParse(asString, out Udi? udi)) + { + yield return new UmbracoEntityReference(udi); + } + } } } diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs index 379a3a91da..68209ee155 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs @@ -2299,6 +2299,9 @@ internal class DatabaseDataCreator Constants.Conventions.RelationTypes.RelatedMediaName, null, null, false, true); CreateRelationTypeData(5, Constants.Conventions.RelationTypes.RelatedDocumentAlias, Constants.Conventions.RelationTypes.RelatedDocumentName, null, null, false, true); + CreateRelationTypeData(6, Constants.Conventions.RelationTypes.RelatedMemberAlias, + Constants.Conventions.RelationTypes.RelatedMemberName, null, null, false, true); + } private void CreateRelationTypeData(int id, string alias, string name, Guid? parentObjectType, diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs index fe14f785d8..395504cfdc 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs @@ -114,5 +114,6 @@ public class UmbracoPlan : MigrationPlan // To 15.4.0 To("{A9E72794-4036-4563-B543-1717C73B8879}"); + To("{33D62294-D0DE-4A86-A830-991EB36B96DA}"); } } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_4_0/AddRelationTypeForMembers.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_4_0/AddRelationTypeForMembers.cs new file mode 100644 index 0000000000..bcc3422946 --- /dev/null +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_4_0/AddRelationTypeForMembers.cs @@ -0,0 +1,46 @@ +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.Migrations.Install; + +namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_15_4_0; + +/// +/// Migration to add an automatic relation type for members if it doesn't already exist. +/// +public class AddRelationTypeForMembers : MigrationBase +{ + private readonly IRelationService _relationService; + + /// + /// Initializes a new instance of the class. + /// + public AddRelationTypeForMembers(IMigrationContext context, IRelationService relationService) + : base(context) => _relationService = relationService; + + /// + protected override void Migrate() + { + Logger.LogDebug("Adding automatic relation type for members if it doesn't already exist"); + + IRelationType? relationType = _relationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMemberAlias); + if (relationType != null) + { + Logger.LogDebug("Automatic relation type for members already exists."); + return; + } + + // Generate a new unique relation type key that is the same as would have come from a new install. + Guid key = DatabaseDataCreator.CreateUniqueRelationTypeId( + Constants.Conventions.RelationTypes.RelatedMemberAlias, + Constants.Conventions.RelationTypes.RelatedMemberName); + + // Create new relation type using service, so the repository cache gets updated as well. + relationType = new RelationType(Constants.Conventions.RelationTypes.RelatedMemberName, Constants.Conventions.RelationTypes.RelatedMemberAlias, false, null, null, true) + { + Key = key + }; + _relationService.Save(relationType); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts index 9b36b8ffd2..ae4012fb62 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/sdk.gen.ts @@ -3,7 +3,7 @@ import type { CancelablePromise } from './core/CancelablePromise'; import { OpenAPI } from './core/OpenAPI'; import { request as __request } from './core/request'; -import type { GetCultureData, GetCultureResponse, PostDataTypeData, PostDataTypeResponse, GetDataTypeByIdData, GetDataTypeByIdResponse, DeleteDataTypeByIdData, DeleteDataTypeByIdResponse, PutDataTypeByIdData, PutDataTypeByIdResponse, PostDataTypeByIdCopyData, PostDataTypeByIdCopyResponse, GetDataTypeByIdIsUsedData, GetDataTypeByIdIsUsedResponse, PutDataTypeByIdMoveData, PutDataTypeByIdMoveResponse, GetDataTypeByIdReferencesData, GetDataTypeByIdReferencesResponse, GetDataTypeConfigurationResponse, PostDataTypeFolderData, PostDataTypeFolderResponse, GetDataTypeFolderByIdData, GetDataTypeFolderByIdResponse, DeleteDataTypeFolderByIdData, DeleteDataTypeFolderByIdResponse, PutDataTypeFolderByIdData, PutDataTypeFolderByIdResponse, GetFilterDataTypeData, GetFilterDataTypeResponse, GetItemDataTypeData, GetItemDataTypeResponse, GetItemDataTypeSearchData, GetItemDataTypeSearchResponse, GetTreeDataTypeAncestorsData, GetTreeDataTypeAncestorsResponse, GetTreeDataTypeChildrenData, GetTreeDataTypeChildrenResponse, GetTreeDataTypeRootData, GetTreeDataTypeRootResponse, GetDictionaryData, GetDictionaryResponse, PostDictionaryData, PostDictionaryResponse, GetDictionaryByIdData, GetDictionaryByIdResponse, DeleteDictionaryByIdData, DeleteDictionaryByIdResponse, PutDictionaryByIdData, PutDictionaryByIdResponse, GetDictionaryByIdExportData, GetDictionaryByIdExportResponse, PutDictionaryByIdMoveData, PutDictionaryByIdMoveResponse, PostDictionaryImportData, PostDictionaryImportResponse, GetItemDictionaryData, GetItemDictionaryResponse, GetTreeDictionaryAncestorsData, GetTreeDictionaryAncestorsResponse, GetTreeDictionaryChildrenData, GetTreeDictionaryChildrenResponse, GetTreeDictionaryRootData, GetTreeDictionaryRootResponse, GetCollectionDocumentByIdData, GetCollectionDocumentByIdResponse, PostDocumentData, PostDocumentResponse, GetDocumentByIdData, GetDocumentByIdResponse, DeleteDocumentByIdData, DeleteDocumentByIdResponse, PutDocumentByIdData, PutDocumentByIdResponse, GetDocumentByIdAuditLogData, GetDocumentByIdAuditLogResponse, PostDocumentByIdCopyData, PostDocumentByIdCopyResponse, GetDocumentByIdDomainsData, GetDocumentByIdDomainsResponse, PutDocumentByIdDomainsData, PutDocumentByIdDomainsResponse, PutDocumentByIdMoveData, PutDocumentByIdMoveResponse, PutDocumentByIdMoveToRecycleBinData, PutDocumentByIdMoveToRecycleBinResponse, GetDocumentByIdNotificationsData, GetDocumentByIdNotificationsResponse, PutDocumentByIdNotificationsData, PutDocumentByIdNotificationsResponse, PostDocumentByIdPublicAccessData, PostDocumentByIdPublicAccessResponse, DeleteDocumentByIdPublicAccessData, DeleteDocumentByIdPublicAccessResponse, GetDocumentByIdPublicAccessData, GetDocumentByIdPublicAccessResponse, PutDocumentByIdPublicAccessData, PutDocumentByIdPublicAccessResponse, PutDocumentByIdPublishData, PutDocumentByIdPublishResponse, PutDocumentByIdPublishWithDescendantsData, PutDocumentByIdPublishWithDescendantsResponse, GetDocumentByIdPublishedData, GetDocumentByIdPublishedResponse, GetDocumentByIdReferencedByData, GetDocumentByIdReferencedByResponse, GetDocumentByIdReferencedDescendantsData, GetDocumentByIdReferencedDescendantsResponse, PutDocumentByIdUnpublishData, PutDocumentByIdUnpublishResponse, PutDocumentByIdValidateData, PutDocumentByIdValidateResponse, PutUmbracoManagementApiV11DocumentByIdValidate11Data, PutUmbracoManagementApiV11DocumentByIdValidate11Response, GetDocumentAreReferencedData, GetDocumentAreReferencedResponse, GetDocumentConfigurationResponse, PutDocumentSortData, PutDocumentSortResponse, GetDocumentUrlsData, GetDocumentUrlsResponse, PostDocumentValidateData, PostDocumentValidateResponse, GetItemDocumentData, GetItemDocumentResponse, GetItemDocumentSearchData, GetItemDocumentSearchResponse, DeleteRecycleBinDocumentResponse, DeleteRecycleBinDocumentByIdData, DeleteRecycleBinDocumentByIdResponse, GetRecycleBinDocumentByIdOriginalParentData, GetRecycleBinDocumentByIdOriginalParentResponse, PutRecycleBinDocumentByIdRestoreData, PutRecycleBinDocumentByIdRestoreResponse, GetRecycleBinDocumentChildrenData, GetRecycleBinDocumentChildrenResponse, GetRecycleBinDocumentRootData, GetRecycleBinDocumentRootResponse, GetTreeDocumentAncestorsData, GetTreeDocumentAncestorsResponse, GetTreeDocumentChildrenData, GetTreeDocumentChildrenResponse, GetTreeDocumentRootData, GetTreeDocumentRootResponse, PostDocumentBlueprintData, PostDocumentBlueprintResponse, GetDocumentBlueprintByIdData, GetDocumentBlueprintByIdResponse, DeleteDocumentBlueprintByIdData, DeleteDocumentBlueprintByIdResponse, PutDocumentBlueprintByIdData, PutDocumentBlueprintByIdResponse, PutDocumentBlueprintByIdMoveData, PutDocumentBlueprintByIdMoveResponse, PostDocumentBlueprintFolderData, PostDocumentBlueprintFolderResponse, GetDocumentBlueprintFolderByIdData, GetDocumentBlueprintFolderByIdResponse, DeleteDocumentBlueprintFolderByIdData, DeleteDocumentBlueprintFolderByIdResponse, PutDocumentBlueprintFolderByIdData, PutDocumentBlueprintFolderByIdResponse, PostDocumentBlueprintFromDocumentData, PostDocumentBlueprintFromDocumentResponse, GetItemDocumentBlueprintData, GetItemDocumentBlueprintResponse, GetTreeDocumentBlueprintAncestorsData, GetTreeDocumentBlueprintAncestorsResponse, GetTreeDocumentBlueprintChildrenData, GetTreeDocumentBlueprintChildrenResponse, GetTreeDocumentBlueprintRootData, GetTreeDocumentBlueprintRootResponse, PostDocumentTypeData, PostDocumentTypeResponse, GetDocumentTypeByIdData, GetDocumentTypeByIdResponse, DeleteDocumentTypeByIdData, DeleteDocumentTypeByIdResponse, PutDocumentTypeByIdData, PutDocumentTypeByIdResponse, GetDocumentTypeByIdAllowedChildrenData, GetDocumentTypeByIdAllowedChildrenResponse, GetDocumentTypeByIdBlueprintData, GetDocumentTypeByIdBlueprintResponse, GetDocumentTypeByIdCompositionReferencesData, GetDocumentTypeByIdCompositionReferencesResponse, PostDocumentTypeByIdCopyData, PostDocumentTypeByIdCopyResponse, GetDocumentTypeByIdExportData, GetDocumentTypeByIdExportResponse, PutDocumentTypeByIdImportData, PutDocumentTypeByIdImportResponse, PutDocumentTypeByIdMoveData, PutDocumentTypeByIdMoveResponse, GetDocumentTypeAllowedAtRootData, GetDocumentTypeAllowedAtRootResponse, PostDocumentTypeAvailableCompositionsData, PostDocumentTypeAvailableCompositionsResponse, GetDocumentTypeConfigurationResponse, PostDocumentTypeFolderData, PostDocumentTypeFolderResponse, GetDocumentTypeFolderByIdData, GetDocumentTypeFolderByIdResponse, DeleteDocumentTypeFolderByIdData, DeleteDocumentTypeFolderByIdResponse, PutDocumentTypeFolderByIdData, PutDocumentTypeFolderByIdResponse, PostDocumentTypeImportData, PostDocumentTypeImportResponse, GetItemDocumentTypeData, GetItemDocumentTypeResponse, GetItemDocumentTypeSearchData, GetItemDocumentTypeSearchResponse, GetTreeDocumentTypeAncestorsData, GetTreeDocumentTypeAncestorsResponse, GetTreeDocumentTypeChildrenData, GetTreeDocumentTypeChildrenResponse, GetTreeDocumentTypeRootData, GetTreeDocumentTypeRootResponse, GetDocumentVersionData, GetDocumentVersionResponse, GetDocumentVersionByIdData, GetDocumentVersionByIdResponse, PutDocumentVersionByIdPreventCleanupData, PutDocumentVersionByIdPreventCleanupResponse, PostDocumentVersionByIdRollbackData, PostDocumentVersionByIdRollbackResponse, PostDynamicRootQueryData, PostDynamicRootQueryResponse, GetDynamicRootStepsResponse, GetHealthCheckGroupData, GetHealthCheckGroupResponse, GetHealthCheckGroupByNameData, GetHealthCheckGroupByNameResponse, PostHealthCheckGroupByNameCheckData, PostHealthCheckGroupByNameCheckResponse, PostHealthCheckExecuteActionData, PostHealthCheckExecuteActionResponse, GetHelpData, GetHelpResponse, GetImagingResizeUrlsData, GetImagingResizeUrlsResponse, GetImportAnalyzeData, GetImportAnalyzeResponse, GetIndexerData, GetIndexerResponse, GetIndexerByIndexNameData, GetIndexerByIndexNameResponse, PostIndexerByIndexNameRebuildData, PostIndexerByIndexNameRebuildResponse, GetInstallSettingsResponse, PostInstallSetupData, PostInstallSetupResponse, PostInstallValidateDatabaseData, PostInstallValidateDatabaseResponse, GetItemLanguageData, GetItemLanguageResponse, GetItemLanguageDefaultResponse, GetLanguageData, GetLanguageResponse, PostLanguageData, PostLanguageResponse, GetLanguageByIsoCodeData, GetLanguageByIsoCodeResponse, DeleteLanguageByIsoCodeData, DeleteLanguageByIsoCodeResponse, PutLanguageByIsoCodeData, PutLanguageByIsoCodeResponse, GetLogViewerLevelData, GetLogViewerLevelResponse, GetLogViewerLevelCountData, GetLogViewerLevelCountResponse, GetLogViewerLogData, GetLogViewerLogResponse, GetLogViewerMessageTemplateData, GetLogViewerMessageTemplateResponse, GetLogViewerSavedSearchData, GetLogViewerSavedSearchResponse, PostLogViewerSavedSearchData, PostLogViewerSavedSearchResponse, GetLogViewerSavedSearchByNameData, GetLogViewerSavedSearchByNameResponse, DeleteLogViewerSavedSearchByNameData, DeleteLogViewerSavedSearchByNameResponse, GetLogViewerValidateLogsSizeData, GetLogViewerValidateLogsSizeResponse, GetManifestManifestResponse, GetManifestManifestPrivateResponse, GetManifestManifestPublicResponse, GetCollectionMediaData, GetCollectionMediaResponse, GetItemMediaData, GetItemMediaResponse, GetItemMediaSearchData, GetItemMediaSearchResponse, PostMediaData, PostMediaResponse, GetMediaByIdData, GetMediaByIdResponse, DeleteMediaByIdData, DeleteMediaByIdResponse, PutMediaByIdData, PutMediaByIdResponse, GetMediaByIdAuditLogData, GetMediaByIdAuditLogResponse, PutMediaByIdMoveData, PutMediaByIdMoveResponse, PutMediaByIdMoveToRecycleBinData, PutMediaByIdMoveToRecycleBinResponse, GetMediaByIdReferencedByData, GetMediaByIdReferencedByResponse, GetMediaByIdReferencedDescendantsData, GetMediaByIdReferencedDescendantsResponse, PutMediaByIdValidateData, PutMediaByIdValidateResponse, GetMediaAreReferencedData, GetMediaAreReferencedResponse, GetMediaConfigurationResponse, PutMediaSortData, PutMediaSortResponse, GetMediaUrlsData, GetMediaUrlsResponse, PostMediaValidateData, PostMediaValidateResponse, DeleteRecycleBinMediaResponse, DeleteRecycleBinMediaByIdData, DeleteRecycleBinMediaByIdResponse, GetRecycleBinMediaByIdOriginalParentData, GetRecycleBinMediaByIdOriginalParentResponse, PutRecycleBinMediaByIdRestoreData, PutRecycleBinMediaByIdRestoreResponse, GetRecycleBinMediaChildrenData, GetRecycleBinMediaChildrenResponse, GetRecycleBinMediaRootData, GetRecycleBinMediaRootResponse, GetTreeMediaAncestorsData, GetTreeMediaAncestorsResponse, GetTreeMediaChildrenData, GetTreeMediaChildrenResponse, GetTreeMediaRootData, GetTreeMediaRootResponse, GetItemMediaTypeData, GetItemMediaTypeResponse, GetItemMediaTypeAllowedData, GetItemMediaTypeAllowedResponse, GetItemMediaTypeFoldersData, GetItemMediaTypeFoldersResponse, GetItemMediaTypeSearchData, GetItemMediaTypeSearchResponse, PostMediaTypeData, PostMediaTypeResponse, GetMediaTypeByIdData, GetMediaTypeByIdResponse, DeleteMediaTypeByIdData, DeleteMediaTypeByIdResponse, PutMediaTypeByIdData, PutMediaTypeByIdResponse, GetMediaTypeByIdAllowedChildrenData, GetMediaTypeByIdAllowedChildrenResponse, GetMediaTypeByIdCompositionReferencesData, GetMediaTypeByIdCompositionReferencesResponse, PostMediaTypeByIdCopyData, PostMediaTypeByIdCopyResponse, GetMediaTypeByIdExportData, GetMediaTypeByIdExportResponse, PutMediaTypeByIdImportData, PutMediaTypeByIdImportResponse, PutMediaTypeByIdMoveData, PutMediaTypeByIdMoveResponse, GetMediaTypeAllowedAtRootData, GetMediaTypeAllowedAtRootResponse, PostMediaTypeAvailableCompositionsData, PostMediaTypeAvailableCompositionsResponse, GetMediaTypeConfigurationResponse, PostMediaTypeFolderData, PostMediaTypeFolderResponse, GetMediaTypeFolderByIdData, GetMediaTypeFolderByIdResponse, DeleteMediaTypeFolderByIdData, DeleteMediaTypeFolderByIdResponse, PutMediaTypeFolderByIdData, PutMediaTypeFolderByIdResponse, PostMediaTypeImportData, PostMediaTypeImportResponse, GetTreeMediaTypeAncestorsData, GetTreeMediaTypeAncestorsResponse, GetTreeMediaTypeChildrenData, GetTreeMediaTypeChildrenResponse, GetTreeMediaTypeRootData, GetTreeMediaTypeRootResponse, GetFilterMemberData, GetFilterMemberResponse, GetItemMemberData, GetItemMemberResponse, GetItemMemberSearchData, GetItemMemberSearchResponse, PostMemberData, PostMemberResponse, GetMemberByIdData, GetMemberByIdResponse, DeleteMemberByIdData, DeleteMemberByIdResponse, PutMemberByIdData, PutMemberByIdResponse, PutMemberByIdValidateData, PutMemberByIdValidateResponse, GetMemberConfigurationResponse, PostMemberValidateData, PostMemberValidateResponse, GetItemMemberGroupData, GetItemMemberGroupResponse, GetMemberGroupData, GetMemberGroupResponse, PostMemberGroupData, PostMemberGroupResponse, GetMemberGroupByIdData, GetMemberGroupByIdResponse, DeleteMemberGroupByIdData, DeleteMemberGroupByIdResponse, PutMemberGroupByIdData, PutMemberGroupByIdResponse, GetTreeMemberGroupRootData, GetTreeMemberGroupRootResponse, GetItemMemberTypeData, GetItemMemberTypeResponse, GetItemMemberTypeSearchData, GetItemMemberTypeSearchResponse, PostMemberTypeData, PostMemberTypeResponse, GetMemberTypeByIdData, GetMemberTypeByIdResponse, DeleteMemberTypeByIdData, DeleteMemberTypeByIdResponse, PutMemberTypeByIdData, PutMemberTypeByIdResponse, GetMemberTypeByIdCompositionReferencesData, GetMemberTypeByIdCompositionReferencesResponse, PostMemberTypeByIdCopyData, PostMemberTypeByIdCopyResponse, PostMemberTypeAvailableCompositionsData, PostMemberTypeAvailableCompositionsResponse, GetMemberTypeConfigurationResponse, GetTreeMemberTypeRootData, GetTreeMemberTypeRootResponse, PostModelsBuilderBuildResponse, GetModelsBuilderDashboardResponse, GetModelsBuilderStatusResponse, GetObjectTypesData, GetObjectTypesResponse, GetOembedQueryData, GetOembedQueryResponse, PostPackageByNameRunMigrationData, PostPackageByNameRunMigrationResponse, GetPackageConfigurationResponse, GetPackageCreatedData, GetPackageCreatedResponse, PostPackageCreatedData, PostPackageCreatedResponse, GetPackageCreatedByIdData, GetPackageCreatedByIdResponse, DeletePackageCreatedByIdData, DeletePackageCreatedByIdResponse, PutPackageCreatedByIdData, PutPackageCreatedByIdResponse, GetPackageCreatedByIdDownloadData, GetPackageCreatedByIdDownloadResponse, GetPackageMigrationStatusData, GetPackageMigrationStatusResponse, GetItemPartialViewData, GetItemPartialViewResponse, PostPartialViewData, PostPartialViewResponse, GetPartialViewByPathData, GetPartialViewByPathResponse, DeletePartialViewByPathData, DeletePartialViewByPathResponse, PutPartialViewByPathData, PutPartialViewByPathResponse, PutPartialViewByPathRenameData, PutPartialViewByPathRenameResponse, PostPartialViewFolderData, PostPartialViewFolderResponse, GetPartialViewFolderByPathData, GetPartialViewFolderByPathResponse, DeletePartialViewFolderByPathData, DeletePartialViewFolderByPathResponse, GetPartialViewSnippetData, GetPartialViewSnippetResponse, GetPartialViewSnippetByIdData, GetPartialViewSnippetByIdResponse, GetTreePartialViewAncestorsData, GetTreePartialViewAncestorsResponse, GetTreePartialViewChildrenData, GetTreePartialViewChildrenResponse, GetTreePartialViewRootData, GetTreePartialViewRootResponse, DeletePreviewResponse, PostPreviewResponse, GetProfilingStatusResponse, PutProfilingStatusData, PutProfilingStatusResponse, GetPropertyTypeIsUsedData, GetPropertyTypeIsUsedResponse, PostPublishedCacheRebuildResponse, GetPublishedCacheRebuildStatusResponse, PostPublishedCacheReloadResponse, GetRedirectManagementData, GetRedirectManagementResponse, GetRedirectManagementByIdData, GetRedirectManagementByIdResponse, DeleteRedirectManagementByIdData, DeleteRedirectManagementByIdResponse, GetRedirectManagementStatusResponse, PostRedirectManagementStatusData, PostRedirectManagementStatusResponse, GetRelationByRelationTypeIdData, GetRelationByRelationTypeIdResponse, GetItemRelationTypeData, GetItemRelationTypeResponse, GetRelationTypeData, GetRelationTypeResponse, GetRelationTypeByIdData, GetRelationTypeByIdResponse, GetItemScriptData, GetItemScriptResponse, PostScriptData, PostScriptResponse, GetScriptByPathData, GetScriptByPathResponse, DeleteScriptByPathData, DeleteScriptByPathResponse, PutScriptByPathData, PutScriptByPathResponse, PutScriptByPathRenameData, PutScriptByPathRenameResponse, PostScriptFolderData, PostScriptFolderResponse, GetScriptFolderByPathData, GetScriptFolderByPathResponse, DeleteScriptFolderByPathData, DeleteScriptFolderByPathResponse, GetTreeScriptAncestorsData, GetTreeScriptAncestorsResponse, GetTreeScriptChildrenData, GetTreeScriptChildrenResponse, GetTreeScriptRootData, GetTreeScriptRootResponse, GetSearcherData, GetSearcherResponse, GetSearcherBySearcherNameQueryData, GetSearcherBySearcherNameQueryResponse, GetSecurityConfigurationResponse, PostSecurityForgotPasswordData, PostSecurityForgotPasswordResponse, PostSecurityForgotPasswordResetData, PostSecurityForgotPasswordResetResponse, PostSecurityForgotPasswordVerifyData, PostSecurityForgotPasswordVerifyResponse, GetSegmentData, GetSegmentResponse, GetServerConfigurationResponse, GetServerInformationResponse, GetServerStatusResponse, GetServerTroubleshootingResponse, GetServerUpgradeCheckResponse, GetItemStaticFileData, GetItemStaticFileResponse, GetTreeStaticFileAncestorsData, GetTreeStaticFileAncestorsResponse, GetTreeStaticFileChildrenData, GetTreeStaticFileChildrenResponse, GetTreeStaticFileRootData, GetTreeStaticFileRootResponse, GetItemStylesheetData, GetItemStylesheetResponse, PostStylesheetData, PostStylesheetResponse, GetStylesheetByPathData, GetStylesheetByPathResponse, DeleteStylesheetByPathData, DeleteStylesheetByPathResponse, PutStylesheetByPathData, PutStylesheetByPathResponse, PutStylesheetByPathRenameData, PutStylesheetByPathRenameResponse, PostStylesheetFolderData, PostStylesheetFolderResponse, GetStylesheetFolderByPathData, GetStylesheetFolderByPathResponse, DeleteStylesheetFolderByPathData, DeleteStylesheetFolderByPathResponse, GetTreeStylesheetAncestorsData, GetTreeStylesheetAncestorsResponse, GetTreeStylesheetChildrenData, GetTreeStylesheetChildrenResponse, GetTreeStylesheetRootData, GetTreeStylesheetRootResponse, GetTagData, GetTagResponse, GetTelemetryData, GetTelemetryResponse, GetTelemetryLevelResponse, PostTelemetryLevelData, PostTelemetryLevelResponse, GetItemTemplateData, GetItemTemplateResponse, GetItemTemplateSearchData, GetItemTemplateSearchResponse, PostTemplateData, PostTemplateResponse, GetTemplateByIdData, GetTemplateByIdResponse, DeleteTemplateByIdData, DeleteTemplateByIdResponse, PutTemplateByIdData, PutTemplateByIdResponse, GetTemplateConfigurationResponse, PostTemplateQueryExecuteData, PostTemplateQueryExecuteResponse, GetTemplateQuerySettingsResponse, GetTreeTemplateAncestorsData, GetTreeTemplateAncestorsResponse, GetTreeTemplateChildrenData, GetTreeTemplateChildrenResponse, GetTreeTemplateRootData, GetTreeTemplateRootResponse, PostTemporaryFileData, PostTemporaryFileResponse, GetTemporaryFileByIdData, GetTemporaryFileByIdResponse, DeleteTemporaryFileByIdData, DeleteTemporaryFileByIdResponse, GetTemporaryFileConfigurationResponse, PostUpgradeAuthorizeResponse, GetUpgradeSettingsResponse, GetFilterUserData, GetFilterUserResponse, GetItemUserData, GetItemUserResponse, PostUserData, PostUserResponse, DeleteUserData, DeleteUserResponse, GetUserData, GetUserResponse, GetUserByIdData, GetUserByIdResponse, DeleteUserByIdData, DeleteUserByIdResponse, PutUserByIdData, PutUserByIdResponse, GetUserById2FaData, GetUserById2FaResponse, DeleteUserById2FaByProviderNameData, DeleteUserById2FaByProviderNameResponse, GetUserByIdCalculateStartNodesData, GetUserByIdCalculateStartNodesResponse, PostUserByIdChangePasswordData, PostUserByIdChangePasswordResponse, PostUserByIdClientCredentialsData, PostUserByIdClientCredentialsResponse, GetUserByIdClientCredentialsData, GetUserByIdClientCredentialsResponse, DeleteUserByIdClientCredentialsByClientIdData, DeleteUserByIdClientCredentialsByClientIdResponse, PostUserByIdResetPasswordData, PostUserByIdResetPasswordResponse, DeleteUserAvatarByIdData, DeleteUserAvatarByIdResponse, PostUserAvatarByIdData, PostUserAvatarByIdResponse, GetUserConfigurationResponse, GetUserCurrentResponse, GetUserCurrent2FaResponse, DeleteUserCurrent2FaByProviderNameData, DeleteUserCurrent2FaByProviderNameResponse, PostUserCurrent2FaByProviderNameData, PostUserCurrent2FaByProviderNameResponse, GetUserCurrent2FaByProviderNameData, GetUserCurrent2FaByProviderNameResponse, PostUserCurrentAvatarData, PostUserCurrentAvatarResponse, PostUserCurrentChangePasswordData, PostUserCurrentChangePasswordResponse, GetUserCurrentConfigurationResponse, GetUserCurrentLoginProvidersResponse, GetUserCurrentPermissionsData, GetUserCurrentPermissionsResponse, GetUserCurrentPermissionsDocumentData, GetUserCurrentPermissionsDocumentResponse, GetUserCurrentPermissionsMediaData, GetUserCurrentPermissionsMediaResponse, PostUserDisableData, PostUserDisableResponse, PostUserEnableData, PostUserEnableResponse, PostUserInviteData, PostUserInviteResponse, PostUserInviteCreatePasswordData, PostUserInviteCreatePasswordResponse, PostUserInviteResendData, PostUserInviteResendResponse, PostUserInviteVerifyData, PostUserInviteVerifyResponse, PostUserSetUserGroupsData, PostUserSetUserGroupsResponse, PostUserUnlockData, PostUserUnlockResponse, PostUserDataData, PostUserDataResponse, GetUserDataData, GetUserDataResponse, PutUserDataData, PutUserDataResponse, GetUserDataByIdData, GetUserDataByIdResponse, GetFilterUserGroupData, GetFilterUserGroupResponse, GetItemUserGroupData, GetItemUserGroupResponse, DeleteUserGroupData, DeleteUserGroupResponse, PostUserGroupData, PostUserGroupResponse, GetUserGroupData, GetUserGroupResponse, GetUserGroupByIdData, GetUserGroupByIdResponse, DeleteUserGroupByIdData, DeleteUserGroupByIdResponse, PutUserGroupByIdData, PutUserGroupByIdResponse, DeleteUserGroupByIdUsersData, DeleteUserGroupByIdUsersResponse, PostUserGroupByIdUsersData, PostUserGroupByIdUsersResponse, GetItemWebhookData, GetItemWebhookResponse, GetWebhookData, GetWebhookResponse, PostWebhookData, PostWebhookResponse, GetWebhookByIdData, GetWebhookByIdResponse, DeleteWebhookByIdData, DeleteWebhookByIdResponse, PutWebhookByIdData, PutWebhookByIdResponse, GetWebhookByIdLogsData, GetWebhookByIdLogsResponse, GetWebhookEventsData, GetWebhookEventsResponse, GetWebhookLogsData, GetWebhookLogsResponse } from './types.gen'; +import type { GetCultureData, GetCultureResponse, PostDataTypeData, PostDataTypeResponse, GetDataTypeByIdData, GetDataTypeByIdResponse, DeleteDataTypeByIdData, DeleteDataTypeByIdResponse, PutDataTypeByIdData, PutDataTypeByIdResponse, PostDataTypeByIdCopyData, PostDataTypeByIdCopyResponse, GetDataTypeByIdIsUsedData, GetDataTypeByIdIsUsedResponse, PutDataTypeByIdMoveData, PutDataTypeByIdMoveResponse, GetDataTypeByIdReferencesData, GetDataTypeByIdReferencesResponse, GetDataTypeConfigurationResponse, PostDataTypeFolderData, PostDataTypeFolderResponse, GetDataTypeFolderByIdData, GetDataTypeFolderByIdResponse, DeleteDataTypeFolderByIdData, DeleteDataTypeFolderByIdResponse, PutDataTypeFolderByIdData, PutDataTypeFolderByIdResponse, GetFilterDataTypeData, GetFilterDataTypeResponse, GetItemDataTypeData, GetItemDataTypeResponse, GetItemDataTypeSearchData, GetItemDataTypeSearchResponse, GetTreeDataTypeAncestorsData, GetTreeDataTypeAncestorsResponse, GetTreeDataTypeChildrenData, GetTreeDataTypeChildrenResponse, GetTreeDataTypeRootData, GetTreeDataTypeRootResponse, GetDictionaryData, GetDictionaryResponse, PostDictionaryData, PostDictionaryResponse, GetDictionaryByIdData, GetDictionaryByIdResponse, DeleteDictionaryByIdData, DeleteDictionaryByIdResponse, PutDictionaryByIdData, PutDictionaryByIdResponse, GetDictionaryByIdExportData, GetDictionaryByIdExportResponse, PutDictionaryByIdMoveData, PutDictionaryByIdMoveResponse, PostDictionaryImportData, PostDictionaryImportResponse, GetItemDictionaryData, GetItemDictionaryResponse, GetTreeDictionaryAncestorsData, GetTreeDictionaryAncestorsResponse, GetTreeDictionaryChildrenData, GetTreeDictionaryChildrenResponse, GetTreeDictionaryRootData, GetTreeDictionaryRootResponse, GetCollectionDocumentByIdData, GetCollectionDocumentByIdResponse, PostDocumentData, PostDocumentResponse, GetDocumentByIdData, GetDocumentByIdResponse, DeleteDocumentByIdData, DeleteDocumentByIdResponse, PutDocumentByIdData, PutDocumentByIdResponse, GetDocumentByIdAuditLogData, GetDocumentByIdAuditLogResponse, PostDocumentByIdCopyData, PostDocumentByIdCopyResponse, GetDocumentByIdDomainsData, GetDocumentByIdDomainsResponse, PutDocumentByIdDomainsData, PutDocumentByIdDomainsResponse, PutDocumentByIdMoveData, PutDocumentByIdMoveResponse, PutDocumentByIdMoveToRecycleBinData, PutDocumentByIdMoveToRecycleBinResponse, GetDocumentByIdNotificationsData, GetDocumentByIdNotificationsResponse, PutDocumentByIdNotificationsData, PutDocumentByIdNotificationsResponse, PostDocumentByIdPublicAccessData, PostDocumentByIdPublicAccessResponse, DeleteDocumentByIdPublicAccessData, DeleteDocumentByIdPublicAccessResponse, GetDocumentByIdPublicAccessData, GetDocumentByIdPublicAccessResponse, PutDocumentByIdPublicAccessData, PutDocumentByIdPublicAccessResponse, PutDocumentByIdPublishData, PutDocumentByIdPublishResponse, PutDocumentByIdPublishWithDescendantsData, PutDocumentByIdPublishWithDescendantsResponse, GetDocumentByIdPublishedData, GetDocumentByIdPublishedResponse, GetDocumentByIdReferencedByData, GetDocumentByIdReferencedByResponse, GetDocumentByIdReferencedDescendantsData, GetDocumentByIdReferencedDescendantsResponse, PutDocumentByIdUnpublishData, PutDocumentByIdUnpublishResponse, PutDocumentByIdValidateData, PutDocumentByIdValidateResponse, PutUmbracoManagementApiV11DocumentByIdValidate11Data, PutUmbracoManagementApiV11DocumentByIdValidate11Response, GetDocumentAreReferencedData, GetDocumentAreReferencedResponse, GetDocumentConfigurationResponse, PutDocumentSortData, PutDocumentSortResponse, GetDocumentUrlsData, GetDocumentUrlsResponse, PostDocumentValidateData, PostDocumentValidateResponse, GetItemDocumentData, GetItemDocumentResponse, GetItemDocumentSearchData, GetItemDocumentSearchResponse, DeleteRecycleBinDocumentResponse, DeleteRecycleBinDocumentByIdData, DeleteRecycleBinDocumentByIdResponse, GetRecycleBinDocumentByIdOriginalParentData, GetRecycleBinDocumentByIdOriginalParentResponse, PutRecycleBinDocumentByIdRestoreData, PutRecycleBinDocumentByIdRestoreResponse, GetRecycleBinDocumentChildrenData, GetRecycleBinDocumentChildrenResponse, GetRecycleBinDocumentRootData, GetRecycleBinDocumentRootResponse, GetTreeDocumentAncestorsData, GetTreeDocumentAncestorsResponse, GetTreeDocumentChildrenData, GetTreeDocumentChildrenResponse, GetTreeDocumentRootData, GetTreeDocumentRootResponse, PostDocumentBlueprintData, PostDocumentBlueprintResponse, GetDocumentBlueprintByIdData, GetDocumentBlueprintByIdResponse, DeleteDocumentBlueprintByIdData, DeleteDocumentBlueprintByIdResponse, PutDocumentBlueprintByIdData, PutDocumentBlueprintByIdResponse, PutDocumentBlueprintByIdMoveData, PutDocumentBlueprintByIdMoveResponse, PostDocumentBlueprintFolderData, PostDocumentBlueprintFolderResponse, GetDocumentBlueprintFolderByIdData, GetDocumentBlueprintFolderByIdResponse, DeleteDocumentBlueprintFolderByIdData, DeleteDocumentBlueprintFolderByIdResponse, PutDocumentBlueprintFolderByIdData, PutDocumentBlueprintFolderByIdResponse, PostDocumentBlueprintFromDocumentData, PostDocumentBlueprintFromDocumentResponse, GetItemDocumentBlueprintData, GetItemDocumentBlueprintResponse, GetTreeDocumentBlueprintAncestorsData, GetTreeDocumentBlueprintAncestorsResponse, GetTreeDocumentBlueprintChildrenData, GetTreeDocumentBlueprintChildrenResponse, GetTreeDocumentBlueprintRootData, GetTreeDocumentBlueprintRootResponse, PostDocumentTypeData, PostDocumentTypeResponse, GetDocumentTypeByIdData, GetDocumentTypeByIdResponse, DeleteDocumentTypeByIdData, DeleteDocumentTypeByIdResponse, PutDocumentTypeByIdData, PutDocumentTypeByIdResponse, GetDocumentTypeByIdAllowedChildrenData, GetDocumentTypeByIdAllowedChildrenResponse, GetDocumentTypeByIdBlueprintData, GetDocumentTypeByIdBlueprintResponse, GetDocumentTypeByIdCompositionReferencesData, GetDocumentTypeByIdCompositionReferencesResponse, PostDocumentTypeByIdCopyData, PostDocumentTypeByIdCopyResponse, GetDocumentTypeByIdExportData, GetDocumentTypeByIdExportResponse, PutDocumentTypeByIdImportData, PutDocumentTypeByIdImportResponse, PutDocumentTypeByIdMoveData, PutDocumentTypeByIdMoveResponse, GetDocumentTypeAllowedAtRootData, GetDocumentTypeAllowedAtRootResponse, PostDocumentTypeAvailableCompositionsData, PostDocumentTypeAvailableCompositionsResponse, GetDocumentTypeConfigurationResponse, PostDocumentTypeFolderData, PostDocumentTypeFolderResponse, GetDocumentTypeFolderByIdData, GetDocumentTypeFolderByIdResponse, DeleteDocumentTypeFolderByIdData, DeleteDocumentTypeFolderByIdResponse, PutDocumentTypeFolderByIdData, PutDocumentTypeFolderByIdResponse, PostDocumentTypeImportData, PostDocumentTypeImportResponse, GetItemDocumentTypeData, GetItemDocumentTypeResponse, GetItemDocumentTypeSearchData, GetItemDocumentTypeSearchResponse, GetTreeDocumentTypeAncestorsData, GetTreeDocumentTypeAncestorsResponse, GetTreeDocumentTypeChildrenData, GetTreeDocumentTypeChildrenResponse, GetTreeDocumentTypeRootData, GetTreeDocumentTypeRootResponse, GetDocumentVersionData, GetDocumentVersionResponse, GetDocumentVersionByIdData, GetDocumentVersionByIdResponse, PutDocumentVersionByIdPreventCleanupData, PutDocumentVersionByIdPreventCleanupResponse, PostDocumentVersionByIdRollbackData, PostDocumentVersionByIdRollbackResponse, PostDynamicRootQueryData, PostDynamicRootQueryResponse, GetDynamicRootStepsResponse, GetHealthCheckGroupData, GetHealthCheckGroupResponse, GetHealthCheckGroupByNameData, GetHealthCheckGroupByNameResponse, PostHealthCheckGroupByNameCheckData, PostHealthCheckGroupByNameCheckResponse, PostHealthCheckExecuteActionData, PostHealthCheckExecuteActionResponse, GetHelpData, GetHelpResponse, GetImagingResizeUrlsData, GetImagingResizeUrlsResponse, GetImportAnalyzeData, GetImportAnalyzeResponse, GetIndexerData, GetIndexerResponse, GetIndexerByIndexNameData, GetIndexerByIndexNameResponse, PostIndexerByIndexNameRebuildData, PostIndexerByIndexNameRebuildResponse, GetInstallSettingsResponse, PostInstallSetupData, PostInstallSetupResponse, PostInstallValidateDatabaseData, PostInstallValidateDatabaseResponse, GetItemLanguageData, GetItemLanguageResponse, GetItemLanguageDefaultResponse, GetLanguageData, GetLanguageResponse, PostLanguageData, PostLanguageResponse, GetLanguageByIsoCodeData, GetLanguageByIsoCodeResponse, DeleteLanguageByIsoCodeData, DeleteLanguageByIsoCodeResponse, PutLanguageByIsoCodeData, PutLanguageByIsoCodeResponse, GetLogViewerLevelData, GetLogViewerLevelResponse, GetLogViewerLevelCountData, GetLogViewerLevelCountResponse, GetLogViewerLogData, GetLogViewerLogResponse, GetLogViewerMessageTemplateData, GetLogViewerMessageTemplateResponse, GetLogViewerSavedSearchData, GetLogViewerSavedSearchResponse, PostLogViewerSavedSearchData, PostLogViewerSavedSearchResponse, GetLogViewerSavedSearchByNameData, GetLogViewerSavedSearchByNameResponse, DeleteLogViewerSavedSearchByNameData, DeleteLogViewerSavedSearchByNameResponse, GetLogViewerValidateLogsSizeData, GetLogViewerValidateLogsSizeResponse, GetManifestManifestResponse, GetManifestManifestPrivateResponse, GetManifestManifestPublicResponse, GetCollectionMediaData, GetCollectionMediaResponse, GetItemMediaData, GetItemMediaResponse, GetItemMediaSearchData, GetItemMediaSearchResponse, PostMediaData, PostMediaResponse, GetMediaByIdData, GetMediaByIdResponse, DeleteMediaByIdData, DeleteMediaByIdResponse, PutMediaByIdData, PutMediaByIdResponse, GetMediaByIdAuditLogData, GetMediaByIdAuditLogResponse, PutMediaByIdMoveData, PutMediaByIdMoveResponse, PutMediaByIdMoveToRecycleBinData, PutMediaByIdMoveToRecycleBinResponse, GetMediaByIdReferencedByData, GetMediaByIdReferencedByResponse, GetMediaByIdReferencedDescendantsData, GetMediaByIdReferencedDescendantsResponse, PutMediaByIdValidateData, PutMediaByIdValidateResponse, GetMediaAreReferencedData, GetMediaAreReferencedResponse, GetMediaConfigurationResponse, PutMediaSortData, PutMediaSortResponse, GetMediaUrlsData, GetMediaUrlsResponse, PostMediaValidateData, PostMediaValidateResponse, DeleteRecycleBinMediaResponse, DeleteRecycleBinMediaByIdData, DeleteRecycleBinMediaByIdResponse, GetRecycleBinMediaByIdOriginalParentData, GetRecycleBinMediaByIdOriginalParentResponse, PutRecycleBinMediaByIdRestoreData, PutRecycleBinMediaByIdRestoreResponse, GetRecycleBinMediaChildrenData, GetRecycleBinMediaChildrenResponse, GetRecycleBinMediaRootData, GetRecycleBinMediaRootResponse, GetTreeMediaAncestorsData, GetTreeMediaAncestorsResponse, GetTreeMediaChildrenData, GetTreeMediaChildrenResponse, GetTreeMediaRootData, GetTreeMediaRootResponse, GetItemMediaTypeData, GetItemMediaTypeResponse, GetItemMediaTypeAllowedData, GetItemMediaTypeAllowedResponse, GetItemMediaTypeFoldersData, GetItemMediaTypeFoldersResponse, GetItemMediaTypeSearchData, GetItemMediaTypeSearchResponse, PostMediaTypeData, PostMediaTypeResponse, GetMediaTypeByIdData, GetMediaTypeByIdResponse, DeleteMediaTypeByIdData, DeleteMediaTypeByIdResponse, PutMediaTypeByIdData, PutMediaTypeByIdResponse, GetMediaTypeByIdAllowedChildrenData, GetMediaTypeByIdAllowedChildrenResponse, GetMediaTypeByIdCompositionReferencesData, GetMediaTypeByIdCompositionReferencesResponse, PostMediaTypeByIdCopyData, PostMediaTypeByIdCopyResponse, GetMediaTypeByIdExportData, GetMediaTypeByIdExportResponse, PutMediaTypeByIdImportData, PutMediaTypeByIdImportResponse, PutMediaTypeByIdMoveData, PutMediaTypeByIdMoveResponse, GetMediaTypeAllowedAtRootData, GetMediaTypeAllowedAtRootResponse, PostMediaTypeAvailableCompositionsData, PostMediaTypeAvailableCompositionsResponse, GetMediaTypeConfigurationResponse, PostMediaTypeFolderData, PostMediaTypeFolderResponse, GetMediaTypeFolderByIdData, GetMediaTypeFolderByIdResponse, DeleteMediaTypeFolderByIdData, DeleteMediaTypeFolderByIdResponse, PutMediaTypeFolderByIdData, PutMediaTypeFolderByIdResponse, PostMediaTypeImportData, PostMediaTypeImportResponse, GetTreeMediaTypeAncestorsData, GetTreeMediaTypeAncestorsResponse, GetTreeMediaTypeChildrenData, GetTreeMediaTypeChildrenResponse, GetTreeMediaTypeRootData, GetTreeMediaTypeRootResponse, GetFilterMemberData, GetFilterMemberResponse, GetItemMemberData, GetItemMemberResponse, GetItemMemberSearchData, GetItemMemberSearchResponse, PostMemberData, PostMemberResponse, GetMemberByIdData, GetMemberByIdResponse, DeleteMemberByIdData, DeleteMemberByIdResponse, PutMemberByIdData, PutMemberByIdResponse, GetMemberByIdReferencedByData, GetMemberByIdReferencedByResponse, GetMemberByIdReferencedDescendantsData, GetMemberByIdReferencedDescendantsResponse, PutMemberByIdValidateData, PutMemberByIdValidateResponse, GetMemberAreReferencedData, GetMemberAreReferencedResponse, GetMemberConfigurationResponse, PostMemberValidateData, PostMemberValidateResponse, GetItemMemberGroupData, GetItemMemberGroupResponse, GetMemberGroupData, GetMemberGroupResponse, PostMemberGroupData, PostMemberGroupResponse, GetMemberGroupByIdData, GetMemberGroupByIdResponse, DeleteMemberGroupByIdData, DeleteMemberGroupByIdResponse, PutMemberGroupByIdData, PutMemberGroupByIdResponse, GetTreeMemberGroupRootData, GetTreeMemberGroupRootResponse, GetItemMemberTypeData, GetItemMemberTypeResponse, GetItemMemberTypeSearchData, GetItemMemberTypeSearchResponse, PostMemberTypeData, PostMemberTypeResponse, GetMemberTypeByIdData, GetMemberTypeByIdResponse, DeleteMemberTypeByIdData, DeleteMemberTypeByIdResponse, PutMemberTypeByIdData, PutMemberTypeByIdResponse, GetMemberTypeByIdCompositionReferencesData, GetMemberTypeByIdCompositionReferencesResponse, PostMemberTypeByIdCopyData, PostMemberTypeByIdCopyResponse, PostMemberTypeAvailableCompositionsData, PostMemberTypeAvailableCompositionsResponse, GetMemberTypeConfigurationResponse, GetTreeMemberTypeRootData, GetTreeMemberTypeRootResponse, PostModelsBuilderBuildResponse, GetModelsBuilderDashboardResponse, GetModelsBuilderStatusResponse, GetObjectTypesData, GetObjectTypesResponse, GetOembedQueryData, GetOembedQueryResponse, PostPackageByNameRunMigrationData, PostPackageByNameRunMigrationResponse, GetPackageConfigurationResponse, GetPackageCreatedData, GetPackageCreatedResponse, PostPackageCreatedData, PostPackageCreatedResponse, GetPackageCreatedByIdData, GetPackageCreatedByIdResponse, DeletePackageCreatedByIdData, DeletePackageCreatedByIdResponse, PutPackageCreatedByIdData, PutPackageCreatedByIdResponse, GetPackageCreatedByIdDownloadData, GetPackageCreatedByIdDownloadResponse, GetPackageMigrationStatusData, GetPackageMigrationStatusResponse, GetItemPartialViewData, GetItemPartialViewResponse, PostPartialViewData, PostPartialViewResponse, GetPartialViewByPathData, GetPartialViewByPathResponse, DeletePartialViewByPathData, DeletePartialViewByPathResponse, PutPartialViewByPathData, PutPartialViewByPathResponse, PutPartialViewByPathRenameData, PutPartialViewByPathRenameResponse, PostPartialViewFolderData, PostPartialViewFolderResponse, GetPartialViewFolderByPathData, GetPartialViewFolderByPathResponse, DeletePartialViewFolderByPathData, DeletePartialViewFolderByPathResponse, GetPartialViewSnippetData, GetPartialViewSnippetResponse, GetPartialViewSnippetByIdData, GetPartialViewSnippetByIdResponse, GetTreePartialViewAncestorsData, GetTreePartialViewAncestorsResponse, GetTreePartialViewChildrenData, GetTreePartialViewChildrenResponse, GetTreePartialViewRootData, GetTreePartialViewRootResponse, DeletePreviewResponse, PostPreviewResponse, GetProfilingStatusResponse, PutProfilingStatusData, PutProfilingStatusResponse, GetPropertyTypeIsUsedData, GetPropertyTypeIsUsedResponse, PostPublishedCacheRebuildResponse, GetPublishedCacheRebuildStatusResponse, PostPublishedCacheReloadResponse, GetRedirectManagementData, GetRedirectManagementResponse, GetRedirectManagementByIdData, GetRedirectManagementByIdResponse, DeleteRedirectManagementByIdData, DeleteRedirectManagementByIdResponse, GetRedirectManagementStatusResponse, PostRedirectManagementStatusData, PostRedirectManagementStatusResponse, GetRelationByRelationTypeIdData, GetRelationByRelationTypeIdResponse, GetItemRelationTypeData, GetItemRelationTypeResponse, GetRelationTypeData, GetRelationTypeResponse, GetRelationTypeByIdData, GetRelationTypeByIdResponse, GetItemScriptData, GetItemScriptResponse, PostScriptData, PostScriptResponse, GetScriptByPathData, GetScriptByPathResponse, DeleteScriptByPathData, DeleteScriptByPathResponse, PutScriptByPathData, PutScriptByPathResponse, PutScriptByPathRenameData, PutScriptByPathRenameResponse, PostScriptFolderData, PostScriptFolderResponse, GetScriptFolderByPathData, GetScriptFolderByPathResponse, DeleteScriptFolderByPathData, DeleteScriptFolderByPathResponse, GetTreeScriptAncestorsData, GetTreeScriptAncestorsResponse, GetTreeScriptChildrenData, GetTreeScriptChildrenResponse, GetTreeScriptRootData, GetTreeScriptRootResponse, GetSearcherData, GetSearcherResponse, GetSearcherBySearcherNameQueryData, GetSearcherBySearcherNameQueryResponse, GetSecurityConfigurationResponse, PostSecurityForgotPasswordData, PostSecurityForgotPasswordResponse, PostSecurityForgotPasswordResetData, PostSecurityForgotPasswordResetResponse, PostSecurityForgotPasswordVerifyData, PostSecurityForgotPasswordVerifyResponse, GetSegmentData, GetSegmentResponse, GetServerConfigurationResponse, GetServerInformationResponse, GetServerStatusResponse, GetServerTroubleshootingResponse, GetServerUpgradeCheckResponse, GetItemStaticFileData, GetItemStaticFileResponse, GetTreeStaticFileAncestorsData, GetTreeStaticFileAncestorsResponse, GetTreeStaticFileChildrenData, GetTreeStaticFileChildrenResponse, GetTreeStaticFileRootData, GetTreeStaticFileRootResponse, GetItemStylesheetData, GetItemStylesheetResponse, PostStylesheetData, PostStylesheetResponse, GetStylesheetByPathData, GetStylesheetByPathResponse, DeleteStylesheetByPathData, DeleteStylesheetByPathResponse, PutStylesheetByPathData, PutStylesheetByPathResponse, PutStylesheetByPathRenameData, PutStylesheetByPathRenameResponse, PostStylesheetFolderData, PostStylesheetFolderResponse, GetStylesheetFolderByPathData, GetStylesheetFolderByPathResponse, DeleteStylesheetFolderByPathData, DeleteStylesheetFolderByPathResponse, GetTreeStylesheetAncestorsData, GetTreeStylesheetAncestorsResponse, GetTreeStylesheetChildrenData, GetTreeStylesheetChildrenResponse, GetTreeStylesheetRootData, GetTreeStylesheetRootResponse, GetTagData, GetTagResponse, GetTelemetryData, GetTelemetryResponse, GetTelemetryLevelResponse, PostTelemetryLevelData, PostTelemetryLevelResponse, GetItemTemplateData, GetItemTemplateResponse, GetItemTemplateSearchData, GetItemTemplateSearchResponse, PostTemplateData, PostTemplateResponse, GetTemplateByIdData, GetTemplateByIdResponse, DeleteTemplateByIdData, DeleteTemplateByIdResponse, PutTemplateByIdData, PutTemplateByIdResponse, GetTemplateConfigurationResponse, PostTemplateQueryExecuteData, PostTemplateQueryExecuteResponse, GetTemplateQuerySettingsResponse, GetTreeTemplateAncestorsData, GetTreeTemplateAncestorsResponse, GetTreeTemplateChildrenData, GetTreeTemplateChildrenResponse, GetTreeTemplateRootData, GetTreeTemplateRootResponse, PostTemporaryFileData, PostTemporaryFileResponse, GetTemporaryFileByIdData, GetTemporaryFileByIdResponse, DeleteTemporaryFileByIdData, DeleteTemporaryFileByIdResponse, GetTemporaryFileConfigurationResponse, PostUpgradeAuthorizeResponse, GetUpgradeSettingsResponse, GetFilterUserData, GetFilterUserResponse, GetItemUserData, GetItemUserResponse, PostUserData, PostUserResponse, DeleteUserData, DeleteUserResponse, GetUserData, GetUserResponse, GetUserByIdData, GetUserByIdResponse, DeleteUserByIdData, DeleteUserByIdResponse, PutUserByIdData, PutUserByIdResponse, GetUserById2FaData, GetUserById2FaResponse, DeleteUserById2FaByProviderNameData, DeleteUserById2FaByProviderNameResponse, GetUserByIdCalculateStartNodesData, GetUserByIdCalculateStartNodesResponse, PostUserByIdChangePasswordData, PostUserByIdChangePasswordResponse, PostUserByIdClientCredentialsData, PostUserByIdClientCredentialsResponse, GetUserByIdClientCredentialsData, GetUserByIdClientCredentialsResponse, DeleteUserByIdClientCredentialsByClientIdData, DeleteUserByIdClientCredentialsByClientIdResponse, PostUserByIdResetPasswordData, PostUserByIdResetPasswordResponse, DeleteUserAvatarByIdData, DeleteUserAvatarByIdResponse, PostUserAvatarByIdData, PostUserAvatarByIdResponse, GetUserConfigurationResponse, GetUserCurrentResponse, GetUserCurrent2FaResponse, DeleteUserCurrent2FaByProviderNameData, DeleteUserCurrent2FaByProviderNameResponse, PostUserCurrent2FaByProviderNameData, PostUserCurrent2FaByProviderNameResponse, GetUserCurrent2FaByProviderNameData, GetUserCurrent2FaByProviderNameResponse, PostUserCurrentAvatarData, PostUserCurrentAvatarResponse, PostUserCurrentChangePasswordData, PostUserCurrentChangePasswordResponse, GetUserCurrentConfigurationResponse, GetUserCurrentLoginProvidersResponse, GetUserCurrentPermissionsData, GetUserCurrentPermissionsResponse, GetUserCurrentPermissionsDocumentData, GetUserCurrentPermissionsDocumentResponse, GetUserCurrentPermissionsMediaData, GetUserCurrentPermissionsMediaResponse, PostUserDisableData, PostUserDisableResponse, PostUserEnableData, PostUserEnableResponse, PostUserInviteData, PostUserInviteResponse, PostUserInviteCreatePasswordData, PostUserInviteCreatePasswordResponse, PostUserInviteResendData, PostUserInviteResendResponse, PostUserInviteVerifyData, PostUserInviteVerifyResponse, PostUserSetUserGroupsData, PostUserSetUserGroupsResponse, PostUserUnlockData, PostUserUnlockResponse, PostUserDataData, PostUserDataResponse, GetUserDataData, GetUserDataResponse, PutUserDataData, PutUserDataResponse, GetUserDataByIdData, GetUserDataByIdResponse, GetFilterUserGroupData, GetFilterUserGroupResponse, GetItemUserGroupData, GetItemUserGroupResponse, DeleteUserGroupData, DeleteUserGroupResponse, PostUserGroupData, PostUserGroupResponse, GetUserGroupData, GetUserGroupResponse, GetUserGroupByIdData, GetUserGroupByIdResponse, DeleteUserGroupByIdData, DeleteUserGroupByIdResponse, PutUserGroupByIdData, PutUserGroupByIdResponse, DeleteUserGroupByIdUsersData, DeleteUserGroupByIdUsersResponse, PostUserGroupByIdUsersData, PostUserGroupByIdUsersResponse, GetItemWebhookData, GetItemWebhookResponse, GetWebhookData, GetWebhookResponse, PostWebhookData, PostWebhookResponse, GetWebhookByIdData, GetWebhookByIdResponse, DeleteWebhookByIdData, DeleteWebhookByIdResponse, PutWebhookByIdData, PutWebhookByIdResponse, GetWebhookByIdLogsData, GetWebhookByIdLogsResponse, GetWebhookEventsData, GetWebhookEventsResponse, GetWebhookLogsData, GetWebhookLogsResponse } from './types.gen'; export class CultureService { /** @@ -1491,6 +1491,7 @@ export class DocumentService { /** * @param data The data for the request. * @param data.query + * @param data.trashed * @param data.skip * @param data.take * @param data.parentId @@ -1504,6 +1505,7 @@ export class DocumentService { url: '/umbraco/management/api/v1/item/document/search', query: { query: data.query, + trashed: data.trashed, skip: data.skip, take: data.take, parentId: data.parentId, @@ -2504,6 +2506,7 @@ export class DocumentTypeService { /** * @param data The data for the request. * @param data.query + * @param data.isElement * @param data.skip * @param data.take * @returns unknown OK @@ -2515,6 +2518,7 @@ export class DocumentTypeService { url: '/umbraco/management/api/v1/item/document-type/search', query: { query: data.query, + isElement: data.isElement, skip: data.skip, take: data.take }, @@ -3498,6 +3502,7 @@ export class MediaService { /** * @param data The data for the request. * @param data.query + * @param data.trashed * @param data.skip * @param data.take * @param data.parentId @@ -3511,6 +3516,7 @@ export class MediaService { url: '/umbraco/management/api/v1/item/media/search', query: { query: data.query, + trashed: data.trashed, skip: data.skip, take: data.take, parentId: data.parentId, @@ -4823,6 +4829,58 @@ export class MemberService { }); } + /** + * @param data The data for the request. + * @param data.id + * @param data.skip + * @param data.take + * @returns unknown OK + * @throws ApiError + */ + public static getMemberByIdReferencedBy(data: GetMemberByIdReferencedByData): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/member/{id}/referenced-by', + path: { + id: data.id + }, + query: { + skip: data.skip, + take: data.take + }, + errors: { + 401: 'The resource is protected and requires an authentication token', + 403: 'The authenticated user does not have access to this resource' + } + }); + } + + /** + * @param data The data for the request. + * @param data.id + * @param data.skip + * @param data.take + * @returns unknown OK + * @throws ApiError + */ + public static getMemberByIdReferencedDescendants(data: GetMemberByIdReferencedDescendantsData): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/member/{id}/referenced-descendants', + path: { + id: data.id + }, + query: { + skip: data.skip, + take: data.take + }, + errors: { + 401: 'The resource is protected and requires an authentication token', + 403: 'The authenticated user does not have access to this resource' + } + }); + } + /** * @param data The data for the request. * @param data.id @@ -4849,6 +4907,30 @@ export class MemberService { }); } + /** + * @param data The data for the request. + * @param data.id + * @param data.skip + * @param data.take + * @returns unknown OK + * @throws ApiError + */ + public static getMemberAreReferenced(data: GetMemberAreReferencedData = {}): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/member/are-referenced', + query: { + id: data.id, + skip: data.skip, + take: data.take + }, + errors: { + 401: 'The resource is protected and requires an authentication token', + 403: 'The authenticated user does not have access to this resource' + } + }); + } + /** * @returns unknown OK * @throws ApiError diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts index 5e831e2da3..a1a97aa80d 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/types.gen.ts @@ -694,6 +694,7 @@ export type DocumentReferenceResponseModel = { name?: (string) | null; published?: (boolean) | null; documentType: (TrackedReferenceDocumentTypeModel); + variants: Array<(DocumentVariantItemResponseModel)>; }; export type DocumentResponseModel = { @@ -1406,6 +1407,13 @@ export enum MemberKindModel { API = 'Api' } +export type MemberReferenceResponseModel = { + $type: string; + id: string; + name?: (string) | null; + memberType: (TrackedReferenceMemberTypeModel); +}; + export type MemberResponseModel = { values: Array<(MemberValueResponseModel)>; variants: Array<(MemberVariantResponseModel)>; @@ -1751,7 +1759,7 @@ export type PagedIndexResponseModel = { export type PagedIReferenceResponseModel = { total: number; - items: Array<(DefaultReferenceResponseModel | DocumentReferenceResponseModel | MediaReferenceResponseModel)>; + items: Array<(DefaultReferenceResponseModel | DocumentReferenceResponseModel | MediaReferenceResponseModel | MemberReferenceResponseModel)>; }; export type PagedLanguageResponseModel = { @@ -2407,6 +2415,12 @@ export type TrackedReferenceMediaTypeModel = { name?: (string) | null; }; +export type TrackedReferenceMemberTypeModel = { + icon?: (string) | null; + alias?: (string) | null; + name?: (string) | null; +}; + export type UnknownTypePermissionPresentationModel = { $type: string; verbs: Array<(string)>; @@ -3357,6 +3371,7 @@ export type GetItemDocumentSearchData = { query?: string; skip?: number; take?: number; + trashed?: boolean; }; export type GetItemDocumentSearchResponse = ((PagedModelDocumentItemResponseModel)); @@ -3640,6 +3655,7 @@ export type GetItemDocumentTypeData = { export type GetItemDocumentTypeResponse = (Array<(DocumentTypeItemResponseModel)>); export type GetItemDocumentTypeSearchData = { + isElement?: boolean; query?: string; skip?: number; take?: number; @@ -3927,6 +3943,7 @@ export type GetItemMediaSearchData = { query?: string; skip?: number; take?: number; + trashed?: boolean; }; export type GetItemMediaSearchResponse = ((PagedModelMediaItemResponseModel)); @@ -4308,6 +4325,22 @@ export type PutMemberByIdData = { export type PutMemberByIdResponse = (string); +export type GetMemberByIdReferencedByData = { + id: string; + skip?: number; + take?: number; +}; + +export type GetMemberByIdReferencedByResponse = ((PagedIReferenceResponseModel)); + +export type GetMemberByIdReferencedDescendantsData = { + id: string; + skip?: number; + take?: number; +}; + +export type GetMemberByIdReferencedDescendantsResponse = ((PagedReferenceByIdModel)); + export type PutMemberByIdValidateData = { id: string; requestBody?: (UpdateMemberRequestModel); @@ -4315,6 +4348,14 @@ export type PutMemberByIdValidateData = { export type PutMemberByIdValidateResponse = (string); +export type GetMemberAreReferencedData = { + id?: Array<(string)>; + skip?: number; + take?: number; +}; + +export type GetMemberAreReferencedResponse = ((PagedReferenceByIdModel)); + export type GetMemberConfigurationResponse = ((MemberConfigurationResponseModel)); export type PostMemberValidateData = { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/tracked-reference.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/tracked-reference.data.ts index bbd02fb59b..1137b79c47 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/tracked-reference.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/tracked-reference.data.ts @@ -2,10 +2,11 @@ import type { DefaultReferenceResponseModel, DocumentReferenceResponseModel, MediaReferenceResponseModel, + MemberReferenceResponseModel, } from '@umbraco-cms/backoffice/external/backend-api'; export const items: Array< - DefaultReferenceResponseModel | DocumentReferenceResponseModel | MediaReferenceResponseModel + DefaultReferenceResponseModel | DocumentReferenceResponseModel | MediaReferenceResponseModel | MemberReferenceResponseModel > = [ { $type: 'DocumentReferenceResponseModel', @@ -17,6 +18,7 @@ export const items: Array< icon: 'icon-document', name: 'Simple Document Type', }, + variants: [] } satisfies DocumentReferenceResponseModel, { $type: 'DocumentReferenceResponseModel', @@ -28,6 +30,7 @@ export const items: Array< icon: 'icon-settings', name: 'Image Block', }, + variants: [] } satisfies DocumentReferenceResponseModel, { $type: 'MediaReferenceResponseModel', diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/info-app/global-components/workspace-info-app-layout.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/info-app/global-components/workspace-info-app-layout.element.ts index 3b6388299e..83a10560ff 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/info-app/global-components/workspace-info-app-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/info-app/global-components/workspace-info-app-layout.element.ts @@ -10,7 +10,9 @@ export class UmbWorkspaceInfoAppLayoutElement extends UmbLitElement { return html` - +
+ +
`; } @@ -20,6 +22,10 @@ export class UmbWorkspaceInfoAppLayoutElement extends UmbLitElement { uui-box { --uui-box-default-padding: 0; } + + #container { + padding-left: var(--uui-size-space-4) + } `, ]; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/document-reference-table.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/document-reference-table.element.ts index 5e73b4c2e9..e1c2d80d7f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/document-reference-table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/document-reference-table.element.ts @@ -6,6 +6,7 @@ import { type UmbReferenceModel, isDocumentReference, isMediaReference, + isMemberReference, isDefaultReference, } from '@umbraco-cms/backoffice/relations'; @@ -61,6 +62,9 @@ export class UmbDocumentReferenceTableElement extends UmbLitElement { if (isMediaReference(item)) { return item.mediaType.icon ?? 'icon-picture'; } + if (isMemberReference(item)) { + return item.memberType.icon ?? 'icon-user'; + } if (isDefaultReference(item)) { return item.icon ?? 'icon-document'; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/manifests.ts index f1c4effd40..ec4f69d43c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/entity-actions/manifests.ts @@ -14,7 +14,7 @@ export const manifests: Array = [ { type: 'entityAction', alias: 'Umb.EntityAction.Media.Delete', - name: 'Delete Media Entity Action ', + name: 'Delete Media Entity Action', kind: 'deleteWithRelation', forEntityTypes: [UMB_MEDIA_ENTITY_TYPE], meta: { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/info-app/media-references-workspace-info-app.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/info-app/media-references-workspace-info-app.element.ts index b1f46e6fd9..5a6151a8c4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/info-app/media-references-workspace-info-app.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/info-app/media-references-workspace-info-app.element.ts @@ -59,10 +59,6 @@ export class UmbMediaReferencesWorkspaceInfoAppElement extends UmbLitElement { ); } - protected override firstUpdated(): void { - this.#getReferences(); - } - async #getReferences() { if (!this.#mediaUnique) { throw new Error('Media unique is required'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/constants.ts index c2e40ebfe7..cc342219ab 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/constants.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/constants.ts @@ -4,6 +4,7 @@ export { UMB_MEMBER_VARIANT_CONTEXT } from './property-dataset-context/member-pr export * from './collection/constants.js'; export * from './entity-actions/constants.js'; export * from './item/constants.js'; +export * from './reference/constants.js'; export * from './repository/constants.js'; export * from './search/constants.js'; export * from './workspace/constants.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/entity-actions/manifests.ts index 933d3a563b..56072ee35b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/entity-actions/manifests.ts @@ -2,18 +2,20 @@ import { UMB_MEMBER_ITEM_REPOSITORY_ALIAS } from '../item/constants.js'; import { UMB_MEMBER_ENTITY_TYPE } from '../entity.js'; import { UMB_MEMBER_DETAIL_REPOSITORY_ALIAS } from '../repository/detail/manifests.js'; import { manifests as createManifests } from './create/manifests.js'; +import { UMB_MEMBER_REFERENCE_REPOSITORY_ALIAS } from '../reference/constants.js'; export const manifests: Array = [ { type: 'entityAction', - kind: 'delete', alias: 'Umb.EntityAction.Member.Delete', name: 'Delete Member Entity Action', + kind: 'deleteWithRelation', forEntityTypes: [UMB_MEMBER_ENTITY_TYPE], meta: { - detailRepositoryAlias: UMB_MEMBER_DETAIL_REPOSITORY_ALIAS, itemRepositoryAlias: UMB_MEMBER_ITEM_REPOSITORY_ALIAS, + detailRepositoryAlias: UMB_MEMBER_DETAIL_REPOSITORY_ALIAS, + referenceRepositoryAlias: UMB_MEMBER_REFERENCE_REPOSITORY_ALIAS, }, }, ...createManifests, -]; +]; \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/item/repository/types.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/item/repository/types.ts index 660b7d84fc..2a105e08b4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/item/repository/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/item/repository/types.ts @@ -11,10 +11,19 @@ export interface UmbMemberItemModel { icon: string; collection: UmbReferenceByUnique | null; }; - variants: Array; + variants: Array; kind: UmbMemberKindType; } +export interface UmbMemberItemVariantModel { + name: string; + culture: string | null; +} + +/** + * @deprecated Deprecated in favor of UmbMemberItemVariantModel. Will be removed in v17.0.0 + * @interface UmbMemberVariantItemModel + */ export interface UmbMemberVariantItemModel { name: string; culture: string | null; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/manifests.ts index 470f6503b3..7814ae8c8a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/manifests.ts @@ -5,6 +5,7 @@ import { manifests as memberPickerModalManifests } from './components/member-pic import { manifests as menuItemManifests } from './menu-item/manifests.js'; import { manifests as pickerManifests } from './picker/manifests.js'; import { manifests as propertyEditorManifests } from './property-editor/manifests.js'; +import { manifests as referenceManifests } from './reference/manifests.js'; import { manifests as repositoryManifests } from './repository/manifests.js'; import { manifests as searchManifests } from './search/manifests.js'; import { manifests as workspaceManifests } from './workspace/manifests.js'; @@ -19,6 +20,7 @@ export const manifests: Array = ...menuItemManifests, ...pickerManifests, ...propertyEditorManifests, + ...referenceManifests, ...repositoryManifests, ...searchManifests, ...workspaceManifests, diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/constants.ts new file mode 100644 index 0000000000..41a409dec1 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/constants.ts @@ -0,0 +1 @@ +export * from './repository/constants.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/index.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/index.ts new file mode 100644 index 0000000000..3d76f338dd --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/index.ts @@ -0,0 +1 @@ +export * from './repository/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/info-app/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/info-app/manifests.ts new file mode 100644 index 0000000000..7ebbb37e12 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/info-app/manifests.ts @@ -0,0 +1,18 @@ +import { UMB_MEMBER_WORKSPACE_ALIAS } from '../../workspace/constants.js'; +import { UMB_WORKSPACE_CONDITION_ALIAS } from '@umbraco-cms/backoffice/workspace'; + +export const manifests: Array = [ + { + type: 'workspaceInfoApp', + name: 'Member References Workspace Info App', + alias: 'Umb.WorkspaceInfoApp.Member.References', + element: () => import('./member-references-workspace-info-app.element.js'), + weight: 90, + conditions: [ + { + alias: UMB_WORKSPACE_CONDITION_ALIAS, + match: UMB_MEMBER_WORKSPACE_ALIAS, + }, + ], + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/info-app/member-references-workspace-info-app.element.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/info-app/member-references-workspace-info-app.element.ts new file mode 100644 index 0000000000..23828e7026 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/info-app/member-references-workspace-info-app.element.ts @@ -0,0 +1,161 @@ +import { UmbMemberReferenceRepository } from '../repository/index.js'; +import { UMB_MEMBER_WORKSPACE_CONTEXT } from '../../workspace/constants.js'; +import { css, customElement, html, nothing, repeat, state, when } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import type { UmbReferenceItemModel } from '@umbraco-cms/backoffice/relations'; +import type { UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui'; +import type { UmbEntityUnique } from '@umbraco-cms/backoffice/entity'; + +@customElement('umb-member-references-workspace-info-app') +export class UmbMemberReferencesWorkspaceInfoAppElement extends UmbLitElement { + #itemsPerPage = 10; + + #referenceRepository; + + @state() + private _currentPage = 1; + + @state() + private _total = 0; + + @state() + private _items?: Array = []; + + @state() + private _loading = true; + + #workspaceContext?: typeof UMB_MEMBER_WORKSPACE_CONTEXT.TYPE; + #memberUnique?: UmbEntityUnique; + + constructor() { + super(); + this.#referenceRepository = new UmbMemberReferenceRepository(this); + + this.consumeContext(UMB_MEMBER_WORKSPACE_CONTEXT, (context) => { + this.#workspaceContext = context; + this.#observeMemberUnique(); + }); + } + + #observeMemberUnique() { + this.observe( + this.#workspaceContext?.unique, + (unique) => { + if (!unique) { + this.#memberUnique = undefined; + this._items = []; + return; + } + + if (this.#memberUnique === unique) { + return; + } + + this.#memberUnique = unique; + this.#getReferences(); + }, + 'umbReferencesDocumentUniqueObserver', + ); + } + + async #getReferences() { + if (!this.#memberUnique) { + throw new Error('Member unique is required'); + } + + this._loading = true; + + const { data } = await this.#referenceRepository.requestReferencedBy( + this.#memberUnique, + (this._currentPage - 1) * this.#itemsPerPage, + this.#itemsPerPage, + ); + + if (!data) return; + + this._total = data.total; + this._items = data.items; + + this._loading = false; + } + + #onPageChange(event: UUIPaginationEvent) { + if (this._currentPage === event.target.current) return; + this._currentPage = event.target.current; + + this.#getReferences(); + } + + override render() { + if (!this._items?.length) return nothing; + return html` + + ${when( + this._loading, + () => html``, + () => html`${this.#renderItems()} ${this.#renderPagination()}`, + )} + + `; + } + + #renderItems() { + if (!this._items) return; + return html` + + ${repeat( + this._items, + (item) => item.unique, + (item) => html``, + )} + + `; + } + + #renderPagination() { + if (!this._total) return nothing; + + const totalPages = Math.ceil(this._total / this.#itemsPerPage); + + if (totalPages <= 1) return nothing; + + return html` + + `; + } + + static override styles = [ + UmbTextStyles, + css` + :host { + display: contents; + } + + uui-table-cell { + color: var(--uui-color-text-alt); + } + + uui-pagination { + flex: 1; + display: inline-block; + } + + .pagination { + display: flex; + justify-content: center; + margin-top: var(--uui-size-space-4); + } + `, + ]; +} + +export default UmbMemberReferencesWorkspaceInfoAppElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-member-references-workspace-info-app': UmbMemberReferencesWorkspaceInfoAppElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/manifests.ts new file mode 100644 index 0000000000..cad6350ec8 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/manifests.ts @@ -0,0 +1,4 @@ +import { manifests as repositoryManifests } from './repository/manifests.js'; +import { manifests as infoAppManifests } from './info-app/manifests.js'; + +export const manifests: Array = [...repositoryManifests, ...infoAppManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/constants.ts new file mode 100644 index 0000000000..b715312e79 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/constants.ts @@ -0,0 +1 @@ +export const UMB_MEMBER_REFERENCE_REPOSITORY_ALIAS = 'Umb.Repository.Member.Reference'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/index.ts new file mode 100644 index 0000000000..25fce74586 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/index.ts @@ -0,0 +1 @@ +export * from './member-reference.repository.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/manifests.ts new file mode 100644 index 0000000000..745fc200fc --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/manifests.ts @@ -0,0 +1,19 @@ +import { UMB_MEMBER_REFERENCE_REPOSITORY_ALIAS } from './constants.js'; +import { UMB_MANAGEMENT_API_DATA_SOURCE_ALIAS } from '@umbraco-cms/backoffice/repository'; + +export const manifests: Array = [ + { + type: 'repository', + alias: UMB_MEMBER_REFERENCE_REPOSITORY_ALIAS, + name: 'Member Reference Repository', + api: () => import('./member-reference.repository.js'), + }, + { + type: 'dataSourceDataMapping', + alias: 'Umb.DataSourceDataMapping.ManagementApi.MemberReferenceResponse', + name: 'Member Reference Response Management Api Data Mapping', + api: () => import('./member-reference-response.management-api.mapping.js'), + forDataSource: UMB_MANAGEMENT_API_DATA_SOURCE_ALIAS, + forDataModel: 'MemberReferenceResponseModel', + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference-response.management-api.mapping.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference-response.management-api.mapping.ts new file mode 100644 index 0000000000..e6418503e8 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference-response.management-api.mapping.ts @@ -0,0 +1,32 @@ +import { UMB_MEMBER_ENTITY_TYPE } from '../../entity.js'; +import type { UmbMemberReferenceModel } from './types.js'; +import type { MemberReferenceResponseModel } from '@umbraco-cms/backoffice/external/backend-api'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbDataSourceDataMapping } from '@umbraco-cms/backoffice/repository'; + +export class UmbMemberReferenceResponseManagementApiDataMapping + extends UmbControllerBase + implements UmbDataSourceDataMapping +{ + async map(data: MemberReferenceResponseModel): Promise { + return { + entityType: UMB_MEMBER_ENTITY_TYPE, + memberType: { + alias: data.memberType.alias, + icon: data.memberType.icon, + name: data.memberType.name, + }, + name: data.name, + // TODO: this is a hardcoded array until the server can return the correct variants array + variants: [ + { + culture: null, + name: data.name ?? '', + }, + ], + unique: data.id, + }; + } +} + +export { UmbMemberReferenceResponseManagementApiDataMapping as api }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference.repository.ts new file mode 100644 index 0000000000..4db055d64f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference.repository.ts @@ -0,0 +1,36 @@ +import { UmbMemberReferenceServerDataSource } from './member-reference.server.data.js'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbEntityReferenceRepository } from '@umbraco-cms/backoffice/relations'; +import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; +import type { UmbRepositoryResponse, UmbPagedModel } from '@umbraco-cms/backoffice/repository'; + +export class UmbMemberReferenceRepository extends UmbControllerBase implements UmbEntityReferenceRepository { + #referenceSource: UmbMemberReferenceServerDataSource; + + constructor(host: UmbControllerHost) { + super(host); + this.#referenceSource = new UmbMemberReferenceServerDataSource(this); + } + + async requestReferencedBy(unique: string, skip = 0, take = 20) { + if (!unique) throw new Error(`unique is required`); + return this.#referenceSource.getReferencedBy(unique, skip, take); + } + + async requestDescendantsWithReferences(unique: string, skip = 0, take = 20) { + if (!unique) throw new Error(`unique is required`); + return this.#referenceSource.getReferencedDescendants(unique, skip, take); + } + + async requestAreReferenced( + uniques: Array, + skip?: number, + take?: number, + ): Promise>> { + if (!uniques || uniques.length === 0) throw new Error(`uniques is required`); + return this.#referenceSource.getAreReferenced(uniques, skip, take); + } +} + +export default UmbMemberReferenceRepository; diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference.server.data.ts new file mode 100644 index 0000000000..3ad6b90a6b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/member-reference.server.data.ts @@ -0,0 +1,121 @@ +import { UMB_MEMBER_ENTITY_TYPE } from '../../entity.js'; +import { MemberService } from '@umbraco-cms/backoffice/external/backend-api'; +import { UmbManagementApiDataMapper } from '@umbraco-cms/backoffice/repository'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; +import type { UmbEntityReferenceDataSource, UmbReferenceItemModel } from '@umbraco-cms/backoffice/relations'; +import type { UmbPagedModel, UmbDataSourceResponse } from '@umbraco-cms/backoffice/repository'; + +/** + * @class UmbMemberReferenceServerDataSource + * @implements {UmbEntityReferenceDataSource} + */ +export class UmbMemberReferenceServerDataSource extends UmbControllerBase implements UmbEntityReferenceDataSource { + #dataMapper = new UmbManagementApiDataMapper(this); + + /** + * Fetches the item for the given unique from the server + * @param {string} unique - The unique identifier of the item to fetch + * @param {number} skip - The number of items to skip + * @param {number} take - The number of items to take + * @returns {Promise>>} - Items that are referenced by the given unique + * @memberof UmbMemberReferenceServerDataSource + */ + async getReferencedBy( + unique: string, + skip: number = 0, + take: number = 20, + ): Promise>> { + const { data, error } = await tryExecuteAndNotify( + this, + MemberService.getMemberByIdReferencedBy({ id: unique, skip, take }), + ); + + if (data) { + const promises = data.items.map(async (item) => { + return this.#dataMapper.map({ + forDataModel: item.$type, + data: item, + fallback: async () => { + return { + ...item, + unique: item.id, + entityType: 'unknown', + }; + }, + }); + }); + + const items = await Promise.all(promises); + + return { data: { items, total: data.total } }; + } + + return { data, error }; + } + + /** + * Checks if the items are referenced by other items + * @param {Array} uniques - The unique identifiers of the items to fetch + * @param {number} skip - The number of items to skip + * @param {number} take - The number of items to take + * @returns {Promise>>} - Items that are referenced by other items + * @memberof UmbMemberReferenceServerDataSource + */ + async getAreReferenced( + uniques: Array, + skip: number = 0, + take: number = 20, + ): Promise>> { + const { data, error } = await tryExecuteAndNotify( + this, + MemberService.getMemberAreReferenced({ id: uniques, skip, take }), + ); + + if (data) { + const items: Array = data.items.map((item) => { + return { + unique: item.id, + entityType: UMB_MEMBER_ENTITY_TYPE, + }; + }); + + return { data: { items, total: data.total } }; + } + + return { data, error }; + } + + /** + * Returns any descendants of the given unique that is referenced by other items + * @param {string} unique - The unique identifier of the item to fetch descendants for + * @param {number} skip - The number of items to skip + * @param {number} take - The number of items to take + * @returns {Promise>>} - Any descendants of the given unique that is referenced by other items + * @memberof UmbMemberReferenceServerDataSource + */ + async getReferencedDescendants( + unique: string, + skip: number = 0, + take: number = 20, + ): Promise>> { + const { data, error } = await tryExecuteAndNotify( + this, + MemberService.getMemberByIdReferencedDescendants({ id: unique, skip, take }), + ); + + if (data) { + const items: Array = data.items.map((item) => { + return { + unique: item.id, + entityType: UMB_MEMBER_ENTITY_TYPE, + }; + }); + + return { data: { items, total: data.total } }; + } + + return { data, error }; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/types.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/types.ts new file mode 100644 index 0000000000..bc62433db5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/reference/repository/types.ts @@ -0,0 +1,14 @@ +import type { UmbMemberItemVariantModel } from '../../item/types.js'; +import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; +import type { TrackedReferenceMemberTypeModel } from '@umbraco-cms/backoffice/external/backend-api'; + +export interface UmbMemberReferenceModel extends UmbEntityModel { + /** + * @deprecated use name on the variant array instead + * @type {(string | null)} + * @memberof UmbMemberReferenceModel + */ + name?: string | null; + memberType: TrackedReferenceMemberTypeModel; + variants: Array; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/views/member/member-workspace-view-member-info.element.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/views/member/member-workspace-view-member-info.element.ts index 090f63cee1..4f6e625a1c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/views/member/member-workspace-view-member-info.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/views/member/member-workspace-view-member-info.element.ts @@ -8,7 +8,7 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/workspace'; import { UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/workspace'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; -import { UmbMemberTypeItemRepository } from '@umbraco-cms/backoffice/member-type'; +import { UMB_MEMBER_TYPE_ENTITY_TYPE, UmbMemberTypeItemRepository } from '@umbraco-cms/backoffice/member-type'; import { UMB_SECTION_USER_PERMISSION_CONDITION_ALIAS } from '@umbraco-cms/backoffice/section'; import { UMB_SETTINGS_SECTION_ALIAS } from '@umbraco-cms/backoffice/settings'; import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry'; @@ -51,7 +51,7 @@ export class UmbMemberWorkspaceViewMemberInfoElement extends UmbLitElement imple new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL) .addAdditionalPath('member-type') .onSetup(() => { - return { data: { entityType: 'member-type', preset: {} } }; + return { data: { entityType: UMB_MEMBER_TYPE_ENTITY_TYPE, preset: {} } }; }) .observeRouteBuilder((routeBuilder) => { this._editMemberTypePath = routeBuilder({}); diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/views/member/member-workspace-view-member.element.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/views/member/member-workspace-view-member.element.ts index de613acd6f..b8a2ccb8cc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/views/member/member-workspace-view-member.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member/workspace/member/views/member/member-workspace-view-member.element.ts @@ -198,6 +198,10 @@ export class UmbMemberWorkspaceViewMemberElement extends UmbLitElement implement + +
+ +
`; } @@ -269,6 +273,9 @@ export class UmbMemberWorkspaceViewMemberElement extends UmbLitElement implement #left-column { /* Is there a way to make the wrapped right column grow only when wrapped? */ flex: 9999 1 500px; + display: flex; + flex-direction: column; + gap: var(--uui-size-space-4); } #right-column { flex: 1 1 350px; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/reference/types.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/reference/types.ts index 599ee7559b..2567a3ece5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/reference/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/reference/types.ts @@ -4,6 +4,7 @@ import type { DefaultReferenceResponseModel, DocumentReferenceResponseModel, MediaReferenceResponseModel, + MemberReferenceResponseModel, } from '@umbraco-cms/backoffice/external/backend-api'; import type { UmbDataSourceResponse, UmbPagedModel, UmbRepositoryResponse } from '@umbraco-cms/backoffice/repository'; @@ -13,7 +14,8 @@ export interface UmbReferenceItemModel extends UmbEntityModel {} export type UmbReferenceModel = | DefaultReferenceResponseModel | DocumentReferenceResponseModel - | MediaReferenceResponseModel; + | MediaReferenceResponseModel + | MemberReferenceResponseModel; export interface UmbEntityReferenceRepository extends UmbApi { requestReferencedBy( diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/utils.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/utils.ts index 6d1fab486c..cfe15b7fa7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/utils.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/utils.ts @@ -3,6 +3,7 @@ import type { DefaultReferenceResponseModel, DocumentReferenceResponseModel, MediaReferenceResponseModel, + MemberReferenceResponseModel, } from '@umbraco-cms/backoffice/external/backend-api'; /** @@ -21,6 +22,14 @@ export function isMediaReference(item: UmbReferenceModel): item is MediaReferenc return typeof (item as MediaReferenceResponseModel).mediaType !== 'undefined'; } +/** + * + * @param item + */ +export function isMemberReference(item: UmbReferenceModel): item is MemberReferenceResponseModel { + return typeof (item as MemberReferenceResponseModel).memberType !== 'undefined'; +} + /** * * @param item diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs index def5d3cafc..610bb87c2f 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs @@ -225,20 +225,22 @@ public class RelationRepositoryTest : UmbracoIntegrationTest RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias); var relatedContentRelType = RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedDocumentAlias); + var relatedMemberRelType = + RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMemberAlias); - parents = repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 0, 11, out totalRecords, new[] { relatedContentRelType.Id, relatedMediaRelType.Id }).ToList(); + parents = repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 0, 11, out totalRecords, [relatedContentRelType.Id, relatedMediaRelType.Id, relatedMemberRelType.Id]).ToList(); Assert.AreEqual(6, totalRecords); Assert.AreEqual(6, parents.Count); - parents = repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 1, 11, out totalRecords, new[] { relatedContentRelType.Id, relatedMediaRelType.Id }).ToList(); + parents = repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 1, 11, out totalRecords, [relatedContentRelType.Id, relatedMediaRelType.Id, relatedMemberRelType.Id]).ToList(); Assert.AreEqual(6, totalRecords); Assert.AreEqual(0, parents.Count); - parents = repository.GetPagedParentEntitiesByChildId(createdContent[0].Id, 0, 6, out totalRecords, new[] { relatedContentRelType.Id, relatedMediaRelType.Id }).ToList(); + parents = repository.GetPagedParentEntitiesByChildId(createdContent[0].Id, 0, 6, out totalRecords, [relatedContentRelType.Id, relatedMediaRelType.Id, relatedMemberRelType.Id]).ToList(); Assert.AreEqual(3, totalRecords); Assert.AreEqual(3, parents.Count); - parents = repository.GetPagedParentEntitiesByChildId(createdContent[0].Id, 1, 6, out totalRecords, new[] { relatedContentRelType.Id, relatedMediaRelType.Id }).ToList(); + parents = repository.GetPagedParentEntitiesByChildId(createdContent[0].Id, 1, 6, out totalRecords, [relatedContentRelType.Id, relatedMediaRelType.Id, relatedMemberRelType.Id]).ToList(); Assert.AreEqual(3, totalRecords); Assert.AreEqual(0, parents.Count); } @@ -281,15 +283,15 @@ public class RelationRepositoryTest : UmbracoIntegrationTest var repository = CreateRepository(ScopeProvider, out _); // Get parent entities for child id - var parents = repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 6, out var totalRecords) + var parents = repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 9, out var totalRecords) .ToList(); - Assert.AreEqual(6, totalRecords); - Assert.AreEqual(6, parents.Count); + Assert.AreEqual(9, totalRecords); + Assert.AreEqual(9, parents.Count); // Add the next page - parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 1, 6, out totalRecords)); - Assert.AreEqual(6, totalRecords); - Assert.AreEqual(6, parents.Count); + parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 1, 9, out totalRecords)); + Assert.AreEqual(9, totalRecords); + Assert.AreEqual(9, parents.Count); var contentEntities = parents.OfType().ToList(); var mediaEntities = parents.OfType().ToList(); @@ -297,7 +299,7 @@ public class RelationRepositoryTest : UmbracoIntegrationTest Assert.AreEqual(3, contentEntities.Count); Assert.AreEqual(3, mediaEntities.Count); - Assert.AreEqual(0, memberEntities.Count); + Assert.AreEqual(3, memberEntities.Count); // only of a certain type parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Media.GetGuid())); @@ -307,20 +309,22 @@ public class RelationRepositoryTest : UmbracoIntegrationTest Assert.AreEqual(3, totalRecords); parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Member.GetGuid())); - Assert.AreEqual(0, totalRecords); + Assert.AreEqual(3, totalRecords); // Test getting relations of specified relation types var relatedMediaRelType = RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias); var relatedContentRelType = RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedDocumentAlias); + var relatedMemberRelType = + RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMemberAlias); - parents = repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 6, out totalRecords, new[] { relatedContentRelType.Id, relatedMediaRelType.Id }).ToList(); - Assert.AreEqual(3, totalRecords); - Assert.AreEqual(3, parents.Count); + parents = repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 6, out totalRecords, [relatedContentRelType.Id, relatedMediaRelType.Id, relatedMemberRelType.Id]).ToList(); + Assert.AreEqual(6, totalRecords); + Assert.AreEqual(6, parents.Count); - parents = repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 1, 6, out totalRecords, new[] { relatedContentRelType.Id, relatedMediaRelType.Id }).ToList(); - Assert.AreEqual(3, totalRecords); + parents = repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 1, 6, out totalRecords, [relatedContentRelType.Id, relatedMediaRelType.Id, relatedMemberRelType.Id]).ToList(); + Assert.AreEqual(6, totalRecords); Assert.AreEqual(0, parents.Count); } } @@ -368,6 +372,8 @@ public class RelationRepositoryTest : UmbracoIntegrationTest RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias); var relatedContentRelType = RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedDocumentAlias); + var relatedMemberRelType = + RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMemberAlias); // Relate content to media foreach (var content in createdContent) @@ -387,6 +393,15 @@ public class RelationRepositoryTest : UmbracoIntegrationTest } } + // Relate content to member + foreach (var content in createdContent) + { + foreach (var member in createdMembers) + { + RelationService.Relate(content.Id, member.Id, relatedMemberRelType); + } + } + // Relate members to media foreach (var member in createdMembers) { diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationTypeRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationTypeRepositoryTest.cs index 2fbf06bb6c..009a5efccd 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationTypeRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationTypeRepositoryTest.cs @@ -100,7 +100,7 @@ public class RelationTypeRepositoryTest : UmbracoIntegrationTest var repository = CreateRepository(provider); // Act - var relationType = repository.Get(8) as IRelationTypeWithIsDependency; + var relationType = repository.Get(9) as IRelationTypeWithIsDependency; // Assert Assert.That(relationType, Is.Not.Null); @@ -130,7 +130,7 @@ public class RelationTypeRepositoryTest : UmbracoIntegrationTest Assert.That(relationTypes, Is.Not.Null); Assert.That(relationTypes.Any(), Is.True); Assert.That(relationTypes.Any(x => x == null), Is.False); - Assert.That(relationTypes.Count(), Is.EqualTo(8)); + Assert.That(relationTypes.Count(), Is.EqualTo(9)); } } @@ -165,7 +165,7 @@ public class RelationTypeRepositoryTest : UmbracoIntegrationTest // Act var exists = repository.Exists(3); - var doesntExist = repository.Exists(9); + var doesntExist = repository.Exists(99); // Assert Assert.That(exists, Is.True); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/RelationServiceTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/RelationServiceTests.cs index 06c39098ee..935915740b 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/RelationServiceTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/RelationServiceTests.cs @@ -26,6 +26,10 @@ public class RelationServiceTests : UmbracoIntegrationTest private IMediaService MediaService => GetRequiredService(); + private IMemberTypeService MemberTypeService => GetRequiredService(); + + private IMemberService MemberService => GetRequiredService(); + private IRelationService RelationService => GetRequiredService(); [Test] @@ -115,6 +119,39 @@ public class RelationServiceTests : UmbracoIntegrationTest Assert.AreEqual(6, entities.Count); } + [Test] + public void Return_List_Of_Content_Items_Where_Member_Item_Referenced() + { + var memberType = MemberTypeBuilder.CreateSimpleMemberType("testMemberType", "Test Member Type"); + MemberTypeService.Save(memberType); + var member = MemberBuilder.CreateSimpleMember(memberType, "Test Member", "test@test.com", "xxxxxxxx", "testMember"); + MemberService.Save(member); + + var ct = ContentTypeBuilder.CreateTextPageContentType("richTextTest"); + ct.AllowedTemplates = Enumerable.Empty(); + ContentTypeService.Save(ct); + + void CreateContentWithMemberRefs() + { + var content = ContentBuilder.CreateTextpageContent(ct, "my content 2", -1); + + // 'bodyText' is a property with a RTE property editor which we knows automatically tracks relations + content.Properties["bodyText"].SetValue(@"
"); + ContentService.Save(content); + } + + for (var i = 0; i < 6; i++) + { + CreateContentWithMemberRefs(); // create 6 content items referencing the same member + } + + var relations = RelationService.GetByChildId(member.Id, Constants.Conventions.RelationTypes.RelatedMemberAlias).ToList(); + Assert.AreEqual(6, relations.Count); + + var entities = RelationService.GetParentEntitiesFromRelations(relations).ToList(); + Assert.AreEqual(6, entities.Count); + } + [Test] public void Can_Create_RelationType_Without_Name() { diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs index f992aa57b1..3b063ee9b0 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TrackRelationsTests.cs @@ -23,6 +23,10 @@ public class TrackRelationsTests : UmbracoIntegrationTestWithContent private IMediaService MediaService => GetRequiredService(); + private IMemberTypeService MemberTypeService => GetRequiredService(); + + private IMemberService MemberService => GetRequiredService(); + private IRelationService RelationService => GetRequiredService(); // protected override void CustomTestSetup(IUmbracoBuilder builder) @@ -42,6 +46,11 @@ public class TrackRelationsTests : UmbracoIntegrationTestWithContent MediaService.Save(m1); MediaService.Save(m2); + var memberType = MemberTypeBuilder.CreateSimpleMemberType("testMemberType", "Test Member Type"); + MemberTypeService.Save(memberType); + var member = MemberBuilder.CreateSimpleMember(memberType, "Test Member", "test@test.com", "xxxxxxxx", "testMember"); + MemberService.Save(member); + var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); @@ -62,17 +71,24 @@ public class TrackRelationsTests : UmbracoIntegrationTestWithContent

hello +

+

+ +

"); ContentService.Save(c2); var relations = RelationService.GetByParentId(c2.Id).ToList(); - Assert.AreEqual(3, relations.Count); + Assert.AreEqual(4, relations.Count); Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedMediaAlias, relations[0].RelationType.Alias); Assert.AreEqual(m1.Id, relations[0].ChildId); Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedMediaAlias, relations[1].RelationType.Alias); Assert.AreEqual(m2.Id, relations[1].ChildId); Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedDocumentAlias, relations[2].RelationType.Alias); Assert.AreEqual(c1.Id, relations[2].ChildId); + Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedMemberAlias, relations[3].RelationType.Alias); + Assert.AreEqual(member.Id, relations[3].ChildId); + } }