V13: relation type controller (#13856)
* Create RelationTypeControllerBase.cs * Implement ByKey endpoint * Move controllers * Implement ByRelationTypeKeyRelationController * Refactor relation service to use skip/take in interface * change httpget * Implement object types endpoint * Add ObjectTypeViewModelFactory.cs * Change signature to IActionResult * Implement CreateRelationTypeController.cs * Implement CreateRelationTypeController.cs * Add optional key parameter to RelationType * Add optional key to RelationTypeSavingViewModel * Update ProducsResponseType * Implement UpdateRelationTypeController * Update routes * Implement DeleteRelationTypeController * Remove key from UpdatingViewmoDel * Implement UpdatingViewModel factory method * Update relationType factory * Fix paging for object types * Implement CreateAsync * Update create action to use CreateAsync * Implement update async * Add default implementations to avoid breaking changes * actually use userIds * Add ProducesResponseType status 400 to endpoints * Implement new DeleteAsync method * Update OpenApi.json * Add mapping to DI * Update 404 to return proper HTTP status * Add not found to ByKey action * Rename viewmodels to request/response * Update OpenApi.json * All RelationServiceTests.cs * Add allowed object types test * Fix grouping * Implement AllowedRelationObjectTypesService.cs * Refactor view model factory to use new service * Implement non-happy path tests * Implement allowed child/parent object types * refactor test to return proper relationTypeOperationStatus * Add can create relation type with key * Add Id test * formatting * Refactor service to have validation logic in save method * move object types endpoint to own silo * Delete unused using * Update OpenApi.json * Update OpenApi.json * Update tests to user proper child/parent * Implement RelationTypeBaseModel * Update OpenApi.json * Use array instead of enumerable * Rename view model factory to presentation factory * Rename GetPagedByRelationTypeKey * Rename IRelationViewModelFactory * Rename IRelationTypeViewModelFactory * Update error description * Update OpenApi.json * Update OpenApi.json --------- Co-authored-by: Zeegaan <nge@umbraco.dk> Co-authored-by: Nikolaj <nikolajlauridsen@protonmail.ch>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
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.RelationType;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.ObjectTypes;
|
||||
|
||||
public class AllowedObjectTypesController : ObjectTypesControllerBase
|
||||
{
|
||||
private readonly IObjectTypePresentationFactory _objectTypePresentationFactory;
|
||||
|
||||
public AllowedObjectTypesController(IObjectTypePresentationFactory objectTypePresentationFactory) => _objectTypePresentationFactory = objectTypePresentationFactory;
|
||||
|
||||
[HttpGet]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<ObjectTypeResponseModel>), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> Allowed(int skip = 0, int take = 100)
|
||||
{
|
||||
ObjectTypeResponseModel[] objectTypes = _objectTypePresentationFactory.Create().ToArray();
|
||||
|
||||
return await Task.FromResult(Ok(new PagedViewModel<ObjectTypeResponseModel>
|
||||
{
|
||||
Total = objectTypes.Length,
|
||||
Items = objectTypes.Skip(skip).Take(take),
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.ObjectTypes;
|
||||
|
||||
[ApiController]
|
||||
[VersionedApiBackOfficeRoute("object-types")]
|
||||
[ApiExplorerSettings(GroupName = "Object Types")]
|
||||
[ApiVersion("1.0")]
|
||||
public class ObjectTypesControllerBase : ManagementApiControllerBase
|
||||
{
|
||||
}
|
||||
@@ -12,14 +12,14 @@ namespace Umbraco.Cms.Api.Management.Controllers.Relation;
|
||||
public class ByChildRelationController : RelationControllerBase
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IRelationViewModelFactory _relationViewModelFactory;
|
||||
private readonly IRelationPresentationFactory _relationPresentationFactory;
|
||||
|
||||
public ByChildRelationController(
|
||||
IRelationService relationService,
|
||||
IRelationViewModelFactory relationViewModelFactory)
|
||||
IRelationPresentationFactory relationPresentationFactory)
|
||||
{
|
||||
_relationService = relationService;
|
||||
_relationViewModelFactory = relationViewModelFactory;
|
||||
_relationPresentationFactory = relationPresentationFactory;
|
||||
}
|
||||
|
||||
[HttpGet("child-relation/{childId:int}")]
|
||||
@@ -34,12 +34,12 @@ public class ByChildRelationController : RelationControllerBase
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(relationTypeAlias) == false)
|
||||
{
|
||||
result = _relationViewModelFactory.CreateMultiple(relations.Where(x =>
|
||||
result = _relationPresentationFactory.CreateMultiple(relations.Where(x =>
|
||||
x.RelationType.Alias.InvariantEquals(relationTypeAlias))).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = _relationViewModelFactory.CreateMultiple(relations).ToArray();
|
||||
result = _relationPresentationFactory.CreateMultiple(relations).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,12 +10,12 @@ namespace Umbraco.Cms.Api.Management.Controllers.Relation;
|
||||
public class ByIdRelationController : RelationControllerBase
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IRelationViewModelFactory _relationViewModelFactory;
|
||||
private readonly IRelationPresentationFactory _relationPresentationFactory;
|
||||
|
||||
public ByIdRelationController(IRelationService relationService, IRelationViewModelFactory relationViewModelFactory)
|
||||
public ByIdRelationController(IRelationService relationService, IRelationPresentationFactory relationPresentationFactory)
|
||||
{
|
||||
_relationService = relationService;
|
||||
_relationViewModelFactory = relationViewModelFactory;
|
||||
_relationPresentationFactory = relationPresentationFactory;
|
||||
}
|
||||
|
||||
[HttpGet("{id:int}")]
|
||||
@@ -30,6 +30,6 @@ public class ByIdRelationController : RelationControllerBase
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return await Task.FromResult(Ok(_relationViewModelFactory.Create(relation)));
|
||||
return await Task.FromResult(Ok(_relationPresentationFactory.Create(relation)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
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.Relation;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.New.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Relation;
|
||||
|
||||
public class ByRelationTypeKeyRelationController : RelationControllerBase
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IRelationPresentationFactory _relationPresentationFactory;
|
||||
|
||||
public ByRelationTypeKeyRelationController(IRelationService relationService, IRelationPresentationFactory relationPresentationFactory)
|
||||
{
|
||||
_relationService = relationService;
|
||||
_relationPresentationFactory = relationPresentationFactory;
|
||||
}
|
||||
|
||||
[HttpGet("type/{key:guid}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<RelationViewModel>), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> ByRelationTypeKey(Guid key, int skip = 0, int take = 100)
|
||||
{
|
||||
Attempt<PagedModel<IRelation>, RelationOperationStatus> relationsAttempt = await _relationService.GetPagedByRelationTypeKey(key, skip, take);
|
||||
|
||||
if (relationsAttempt.Success is false)
|
||||
{
|
||||
return await Task.FromResult(RelationOperationStatusResult(relationsAttempt.Status));
|
||||
}
|
||||
|
||||
IEnumerable<RelationViewModel> mappedRelations = relationsAttempt.Result.Items.Select(_relationPresentationFactory.Create);
|
||||
|
||||
return await Task.FromResult(Ok(new PagedViewModel<RelationViewModel>
|
||||
{
|
||||
Total = relationsAttempt.Result.Total,
|
||||
Items = mappedRelations,
|
||||
}));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.Builders;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Relation;
|
||||
|
||||
@@ -10,5 +12,12 @@ namespace Umbraco.Cms.Api.Management.Controllers.Relation;
|
||||
// TODO: Implement Authentication
|
||||
public abstract class RelationControllerBase : ManagementApiControllerBase
|
||||
{
|
||||
|
||||
protected IActionResult RelationOperationStatusResult(RelationOperationStatus status) =>
|
||||
status switch
|
||||
{
|
||||
RelationOperationStatus.RelationTypeNotFound => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Relation type not found")
|
||||
.WithDetail("The relation type could not be found.")
|
||||
.Build()),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.RelationType.Query;
|
||||
|
||||
public class ByKeyRelationTypeController : RelationTypeControllerBase
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IUmbracoMapper _mapper;
|
||||
|
||||
public ByKeyRelationTypeController(IRelationService relationService, IUmbracoMapper mapper)
|
||||
{
|
||||
_relationService = relationService;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
[HttpGet("{key:guid}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(RelationTypeResponseModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> ByKey(Guid key)
|
||||
{
|
||||
IRelationType? relationType = _relationService.GetRelationTypeById(key);
|
||||
if (relationType is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
RelationTypeResponseModel mappedRelationType = _mapper.Map<RelationTypeResponseModel>(relationType)!;
|
||||
|
||||
return await Task.FromResult(Ok(mappedRelationType));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.RelationType.Query;
|
||||
|
||||
public class CreateRelationTypeController : RelationTypeControllerBase
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IRelationTypePresentationFactory _relationTypePresentationFactory;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public CreateRelationTypeController(IRelationService relationService,
|
||||
IRelationTypePresentationFactory relationTypePresentationFactory,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
{
|
||||
_relationService = relationService;
|
||||
_relationTypePresentationFactory = relationTypePresentationFactory;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> Create(CreateRelationTypeRequestModel createRelationTypeRequestModel)
|
||||
{
|
||||
IRelationType relationTypePersisted = _relationTypePresentationFactory.CreateRelationType(createRelationTypeRequestModel);
|
||||
|
||||
Attempt<IRelationType, RelationTypeOperationStatus> result = await _relationService.CreateAsync(relationTypePersisted, CurrentUserId(_backOfficeSecurityAccessor));
|
||||
|
||||
return result.Success
|
||||
? await Task.FromResult(CreatedAtAction<ByKeyRelationTypeController>(controller => nameof(controller.ByKey), relationTypePersisted.Key))
|
||||
: RelationTypeOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.RelationType.Query;
|
||||
|
||||
public class DeleteRelationTypeController : RelationTypeControllerBase
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public DeleteRelationTypeController(IRelationService relationService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
{
|
||||
_relationService = relationService;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
[HttpDelete("{key:guid}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> Delete(Guid key)
|
||||
{
|
||||
Attempt<IRelationType?, RelationTypeOperationStatus> result = await _relationService.DeleteAsync(key, CurrentUserId(_backOfficeSecurityAccessor));
|
||||
return result.Success ? await Task.FromResult(Ok()) : RelationTypeOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.Builders;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.RelationType.Query;
|
||||
|
||||
[ApiController]
|
||||
[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.RelationType}")]
|
||||
[ApiExplorerSettings(GroupName = "Relation Type")]
|
||||
[ApiVersion("1.0")]
|
||||
public class RelationTypeControllerBase : ManagementApiControllerBase
|
||||
{
|
||||
protected IActionResult RelationTypeOperationStatusResult(RelationTypeOperationStatus status) =>
|
||||
status switch
|
||||
{
|
||||
RelationTypeOperationStatus.InvalidId => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Invalid id")
|
||||
.WithDetail("Can not assign an Id when creating a relation type")
|
||||
.Build()),
|
||||
RelationTypeOperationStatus.CancelledByNotification => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Cancelled by notification")
|
||||
.WithDetail("A notification handler prevented the relation type operation.")
|
||||
.Build()),
|
||||
RelationTypeOperationStatus.KeyAlreadyExists => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Key already exists")
|
||||
.WithDetail("An entity with the given key already exists")
|
||||
.Build()),
|
||||
RelationTypeOperationStatus.NotFound => NotFound(new ProblemDetailsBuilder()
|
||||
.WithTitle("Relation type not found")
|
||||
.WithDetail("A relation type with the given key does not exist")
|
||||
.Build()),
|
||||
RelationTypeOperationStatus.InvalidChildObjectType => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Invalid child object type")
|
||||
.WithDetail("The child object type is not allowed")
|
||||
.Build()),
|
||||
RelationTypeOperationStatus.InvalidParentObjectType => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Invalid parent object type")
|
||||
.WithDetail("The parent object type is not allowed")
|
||||
.Build()),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.Builders;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.RelationType.Query;
|
||||
|
||||
public class UpdateRelationTypeController : RelationTypeControllerBase
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IRelationTypePresentationFactory _relationTypePresentationFactory;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public UpdateRelationTypeController(
|
||||
IRelationService relationService,
|
||||
IRelationTypePresentationFactory relationTypePresentationFactory,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
{
|
||||
_relationService = relationService;
|
||||
_relationTypePresentationFactory = relationTypePresentationFactory;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
[HttpPut("{key:guid}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(RelationTypeResponseModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> Update(Guid key, UpdateRelationTypeRequestModel updateRelationTypeSavingViewModel)
|
||||
{
|
||||
IRelationType? persistedRelationType = _relationService.GetRelationTypeById(key);
|
||||
|
||||
if (persistedRelationType is null)
|
||||
{
|
||||
ProblemDetails problemDetails = new ProblemDetailsBuilder()
|
||||
.WithTitle("Could not find relation type")
|
||||
.WithDetail($"Relation type with key {key} could not be found")
|
||||
.Build();
|
||||
return NotFound(problemDetails);
|
||||
}
|
||||
|
||||
_relationTypePresentationFactory.MapUpdateModelToRelationType(updateRelationTypeSavingViewModel, persistedRelationType);
|
||||
|
||||
Attempt<IRelationType, RelationTypeOperationStatus> result = await _relationService.UpdateAsync(persistedRelationType, CurrentUserId(_backOfficeSecurityAccessor));
|
||||
|
||||
return result.Success ? await Task.FromResult(Ok()) : RelationTypeOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.Mapping.RelationType;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.DependencyInjection;
|
||||
|
||||
internal static class RelationTypesBuilderExtensions
|
||||
{
|
||||
internal static IUmbracoBuilder AddRelationTypes(this IUmbracoBuilder builder)
|
||||
{
|
||||
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>()
|
||||
.Add<RelationTypeViewModelsMapDefinition>();
|
||||
|
||||
builder.Services.AddTransient<IObjectTypePresentationFactory, ObjectTypePresentationFactory>();
|
||||
builder.Services.AddTransient<IRelationTypePresentationFactory, RelationTypePresentationFactory>();
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ internal static class TrackedReferencesBuilderExtensions
|
||||
{
|
||||
internal static IUmbracoBuilder AddTrackedReferences(this IUmbracoBuilder builder)
|
||||
{
|
||||
builder.Services.AddTransient<IRelationViewModelFactory, RelationViewModelFactory>();
|
||||
builder.Services.AddTransient<IRelationPresentationFactory, RelationPresentationFactory>();
|
||||
|
||||
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>()
|
||||
.Add<TrackedReferenceViewModelsMapDefinition>()
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public interface IObjectTypePresentationFactory
|
||||
{
|
||||
IEnumerable<ObjectTypeResponseModel> Create();
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Api.Management.ViewModels.Relation;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public interface IRelationViewModelFactory
|
||||
public interface IRelationPresentationFactory
|
||||
{
|
||||
RelationViewModel Create(IRelation relation);
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public interface IRelationTypePresentationFactory
|
||||
{
|
||||
IRelationType CreateRelationType(CreateRelationTypeRequestModel createRelationTypeRequestModel);
|
||||
|
||||
void MapUpdateModelToRelationType(UpdateRelationTypeRequestModel updateRelationTypeRequestModel, IRelationType target);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public class ObjectTypePresentationFactory : IObjectTypePresentationFactory
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
|
||||
public ObjectTypePresentationFactory(IRelationService relationService)
|
||||
{
|
||||
_relationService = relationService;
|
||||
}
|
||||
|
||||
public IEnumerable<ObjectTypeResponseModel> Create()
|
||||
=> _relationService
|
||||
.GetAllowedObjectTypes()
|
||||
.Select(umbracoObjectType => new ObjectTypeResponseModel
|
||||
{
|
||||
Id = umbracoObjectType.GetGuid(),
|
||||
Name = umbracoObjectType.GetFriendlyName(),
|
||||
});
|
||||
}
|
||||
@@ -6,12 +6,12 @@ using Umbraco.Cms.Api.Management.ViewModels.Relation;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public class RelationViewModelFactory : IRelationViewModelFactory
|
||||
public class RelationPresentationFactory : IRelationPresentationFactory
|
||||
{
|
||||
private readonly IRelationService _relationService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public RelationViewModelFactory(IRelationService relationService, IUmbracoMapper umbracoMapper)
|
||||
public RelationPresentationFactory(IRelationService relationService, IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_relationService = relationService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
@@ -0,0 +1,37 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public class RelationTypePresentationFactory : IRelationTypePresentationFactory
|
||||
{
|
||||
private readonly IShortStringHelper _shortStringHelper;
|
||||
|
||||
public RelationTypePresentationFactory(IShortStringHelper shortStringHelper) => _shortStringHelper = shortStringHelper;
|
||||
|
||||
public IRelationType CreateRelationType(CreateRelationTypeRequestModel createRelationTypeRequestModel) =>
|
||||
new RelationType(
|
||||
createRelationTypeRequestModel.Name,
|
||||
createRelationTypeRequestModel.Name.ToSafeAlias(_shortStringHelper, true),
|
||||
createRelationTypeRequestModel.IsBidirectional,
|
||||
createRelationTypeRequestModel.ParentObjectType,
|
||||
createRelationTypeRequestModel.ChildObjectType,
|
||||
createRelationTypeRequestModel.IsDependency,
|
||||
createRelationTypeRequestModel.Key);
|
||||
|
||||
public void MapUpdateModelToRelationType(UpdateRelationTypeRequestModel updateRelationTypeRequestModel, IRelationType target)
|
||||
{
|
||||
target.Name = updateRelationTypeRequestModel.Name;
|
||||
target.Alias = updateRelationTypeRequestModel.Name.ToSafeAlias(_shortStringHelper, true);
|
||||
target.ChildObjectType = updateRelationTypeRequestModel.ChildObjectType;
|
||||
target.IsBidirectional = updateRelationTypeRequestModel.IsBidirectional;
|
||||
if (target is IRelationTypeWithIsDependency targetWithIsDependency)
|
||||
{
|
||||
targetWithIsDependency.IsDependency = updateRelationTypeRequestModel.IsDependency;
|
||||
}
|
||||
|
||||
target.ParentObjectType = updateRelationTypeRequestModel.ParentObjectType;
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ public class ManagementApiComposer : IComposer
|
||||
.AddTrackedReferences()
|
||||
.AddDataTypes()
|
||||
.AddTemplates()
|
||||
.AddRelationTypes()
|
||||
.AddLogViewer()
|
||||
.AddUserGroups()
|
||||
.AddPackages()
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Mapping.RelationType;
|
||||
|
||||
public class RelationTypeViewModelsMapDefinition : IMapDefinition
|
||||
{
|
||||
public void DefineMaps(IUmbracoMapper mapper)
|
||||
{
|
||||
mapper.Define<IRelationType, RelationTypeResponseModel>((_, _) => new RelationTypeResponseModel(), Map);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private void Map(IRelationType source, RelationTypeResponseModel target, MapperContext context)
|
||||
{
|
||||
target.ChildObjectType = source.ChildObjectType;
|
||||
target.IsBidirectional = source.IsBidirectional;
|
||||
|
||||
if (source is IRelationTypeWithIsDependency sourceWithIsDependency)
|
||||
{
|
||||
target.IsDependency = sourceWithIsDependency.IsDependency;
|
||||
}
|
||||
|
||||
target.Key = source.Key;
|
||||
target.Name = source.Name ?? string.Empty;
|
||||
target.Alias = source.Alias;
|
||||
target.ParentObjectType = source.ParentObjectType;
|
||||
target.Path = "-1," + source.Id;
|
||||
|
||||
target.IsSystemRelationType = source.IsSystemRelationType();
|
||||
|
||||
// Set the "friendly" and entity names for the parent and child object types
|
||||
if (source.ParentObjectType.HasValue)
|
||||
{
|
||||
UmbracoObjectTypes objType = ObjectTypes.GetUmbracoObjectType(source.ParentObjectType.Value);
|
||||
target.ParentObjectTypeName = objType.GetFriendlyName();
|
||||
}
|
||||
|
||||
if (source.ChildObjectType.HasValue)
|
||||
{
|
||||
UmbracoObjectTypes objType = ObjectTypes.GetUmbracoObjectType(source.ChildObjectType.Value);
|
||||
target.ChildObjectTypeName = objType.GetFriendlyName();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3784,6 +3784,46 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/object-types": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Object Types"
|
||||
],
|
||||
"operationId": "GetObjectTypes",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedObjectTypeResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/package/{name}/run-migration": {
|
||||
"post": {
|
||||
"tags": [
|
||||
@@ -4511,6 +4551,188 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/relation-type": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Relation Type"
|
||||
],
|
||||
"operationId": "PostRelationType",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/CreateRelationTypeRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"headers": {
|
||||
"Location": {
|
||||
"description": "Location of the newly created resource",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"description": "Location of the newly created resource",
|
||||
"format": "uri"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetailsModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/relation-type/{key}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Relation Type"
|
||||
],
|
||||
"operationId": "GetRelationTypeByKey",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/RelationTypeResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Relation Type"
|
||||
],
|
||||
"operationId": "DeleteRelationTypeByKey",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetailsModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"tags": [
|
||||
"Relation Type"
|
||||
],
|
||||
"operationId": "PutRelationTypeByKey",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/UpdateRelationTypeRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/RelationTypeResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetailsModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetailsModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/tree/relation-type/item": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -4687,6 +4909,55 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/relation/type/{key}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Relation"
|
||||
],
|
||||
"operationId": "GetRelationTypeByKey",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedRelationModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/tree/script/children": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -6569,6 +6840,22 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CreateRelationTypeRequestModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/RelationTypeBaseModel"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CultureModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -7919,6 +8206,20 @@
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"ObjectTypeResponseModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"OkResultModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -8567,6 +8868,30 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedObjectTypeResponseModel": {
|
||||
"required": [
|
||||
"items",
|
||||
"total"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ObjectTypeResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedPackageDefinitionModel": {
|
||||
"required": [
|
||||
"items",
|
||||
@@ -9136,6 +9461,64 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RelationTypeBaseModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"isBidirectional": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"parentObjectType": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"nullable": true
|
||||
},
|
||||
"childObjectType": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"nullable": true
|
||||
},
|
||||
"isDependency": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RelationTypeResponseModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/RelationTypeBaseModel"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"alias": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"isSystemRelationType": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"parentObjectTypeName": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"childObjectTypeName": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"RuntimeLevelModel": {
|
||||
"enum": [
|
||||
"Unknown",
|
||||
@@ -9495,6 +9878,15 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UpdateRelationTypeRequestModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/RelationTypeBaseModel"
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UpgradeSettingsModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
|
||||
public class CreateRelationTypeRequestModel : RelationTypeBaseModel
|
||||
{
|
||||
public Guid? Key { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
|
||||
public class ObjectTypeResponseModel
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
|
||||
public class RelationTypeBaseModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the model.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the RelationType is Bidirectional (true) or Parent to Child (false)
|
||||
/// </summary>
|
||||
public bool IsBidirectional { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the parent object type ID.
|
||||
/// </summary>
|
||||
public Guid? ParentObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child object type ID.
|
||||
/// </summary>
|
||||
public Guid? ChildObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the RelationType should be returned in "Used by"-queries.
|
||||
/// </summary>
|
||||
public bool IsDependency { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
|
||||
public class RelationTypeResponseModel : RelationTypeBaseModel
|
||||
{
|
||||
public Guid Key { get; set; }
|
||||
|
||||
public string? Alias { get; set; }
|
||||
|
||||
public string Path { get; set; } = string.Empty;
|
||||
|
||||
public bool IsSystemRelationType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Parent's object type name.
|
||||
/// </summary>
|
||||
public string? ParentObjectTypeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Child's object type name.
|
||||
/// </summary>
|
||||
public string? ChildObjectTypeName { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.RelationType;
|
||||
|
||||
public class UpdateRelationTypeRequestModel : RelationTypeBaseModel
|
||||
{
|
||||
}
|
||||
@@ -22,7 +22,8 @@ public class RelationType : EntityBase, IRelationTypeWithIsDependency
|
||||
{
|
||||
}
|
||||
|
||||
public RelationType(string? name, string? alias, bool isBidrectional, Guid? parentObjectType, Guid? childObjectType, bool isDependency){
|
||||
public RelationType(string? name, string? alias, bool isBidrectional, Guid? parentObjectType, Guid? childObjectType, bool isDependency, Guid? key = null)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
@@ -47,6 +48,11 @@ public class RelationType : EntityBase, IRelationTypeWithIsDependency
|
||||
nameof(alias));
|
||||
}
|
||||
|
||||
if (key.HasValue)
|
||||
{
|
||||
Key = key.Value;
|
||||
}
|
||||
|
||||
_name = name;
|
||||
_alias = alias;
|
||||
_isBidirectional = isBidrectional;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.New.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -169,7 +171,18 @@ public interface IRelationService : IService
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalChildren"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IRelation> GetPagedByRelationTypeId(int relationTypeId, long pageIndex, int pageSize, out long totalRecords, Ordering? ordering = null);
|
||||
IEnumerable<IRelation> GetPagedByRelationTypeId(int relationTypeId, long pageIndex, int pageSize, out long totalRecords, Ordering? ordering = null);/// <summary>
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paged result of <see cref="IRelation" />
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="ordering"></param>
|
||||
/// <returns></returns>
|
||||
Task<Attempt<PagedModel<IRelation>, RelationOperationStatus>> GetPagedByRelationTypeKey(Guid key, int skip, int take, Ordering? ordering = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Child object from a Relation as an <see cref="IUmbracoEntity" />
|
||||
@@ -333,6 +346,22 @@ public interface IRelationService : IService
|
||||
/// <param name="relationType">RelationType to Save</param>
|
||||
void Save(IRelationType relationType);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a <see cref="IRelationType" />
|
||||
/// </summary>
|
||||
/// <param name="relationType">RelationType to Save</param>
|
||||
/// <param name="userId">Id of the user thats saving the relation type</param>
|
||||
/// <returns>A <see cref="Attempt"/> with a status of whether the operations was a success or failure</returns>
|
||||
Task<Attempt<IRelationType, RelationTypeOperationStatus>> CreateAsync(IRelationType relationType, int userId) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Saves a <see cref="IRelationType" />
|
||||
/// </summary>
|
||||
/// <param name="relationType">RelationType to Save</param>
|
||||
/// <param name="userId">Id of the user thats saving the relation type</param>
|
||||
/// <returns>A <see cref="Attempt"/> with a status of whether the operations was a success or failure</returns>
|
||||
Task<Attempt<IRelationType, RelationTypeOperationStatus>> UpdateAsync(IRelationType relationType, int userId) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a <see cref="IRelation" />
|
||||
/// </summary>
|
||||
@@ -345,9 +374,23 @@ public interface IRelationService : IService
|
||||
/// <param name="relationType">RelationType to Delete</param>
|
||||
void Delete(IRelationType relationType);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a <see cref="IRelationType" />
|
||||
/// </summary>
|
||||
/// <param name="key">Key of the relation type to delete</param>
|
||||
/// <param name="userId">Id of the user that is deleting the relation type</param>
|
||||
/// <returns><placeholder>A <see cref="Task"/> representing the asynchronous operation.</placeholder></returns>
|
||||
Task<Attempt<IRelationType?, RelationTypeOperationStatus>> DeleteAsync(Guid key, int userId) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all <see cref="IRelation" /> objects based on the passed in <see cref="IRelationType" />
|
||||
/// </summary>
|
||||
/// <param name="relationType"><see cref="IRelationType" /> to Delete Relations for</param>
|
||||
void DeleteRelationsOfType(IRelationType relationType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all allowed parent/child object types for a given <see cref="IRelationType" /> />
|
||||
/// </summary>
|
||||
/// <returns>All of the allowed <see cref="UmbracoObjectTypes"/>.</returns>
|
||||
IEnumerable<UmbracoObjectTypes> GetAllowedObjectTypes();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
public enum RelationOperationStatus
|
||||
{
|
||||
Success,
|
||||
RelationTypeNotFound,
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
public enum RelationTypeOperationStatus
|
||||
{
|
||||
Success,
|
||||
NotFound,
|
||||
KeyAlreadyExists,
|
||||
CancelledByNotification,
|
||||
InvalidId,
|
||||
InvalidChildObjectType,
|
||||
InvalidParentObjectType,
|
||||
}
|
||||
@@ -6,7 +6,9 @@ using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Persistence.Querying;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.New.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -17,7 +19,14 @@ public class RelationService : RepositoryService, IRelationService
|
||||
private readonly IRelationRepository _relationRepository;
|
||||
private readonly IRelationTypeRepository _relationTypeRepository;
|
||||
|
||||
public RelationService(ICoreScopeProvider uowProvider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IEntityService entityService, IRelationRepository relationRepository, IRelationTypeRepository relationTypeRepository, IAuditRepository auditRepository)
|
||||
public RelationService(
|
||||
ICoreScopeProvider uowProvider,
|
||||
ILoggerFactory loggerFactory,
|
||||
IEventMessagesFactory eventMessagesFactory,
|
||||
IEntityService entityService,
|
||||
IRelationRepository relationRepository,
|
||||
IRelationTypeRepository relationTypeRepository,
|
||||
IAuditRepository auditRepository)
|
||||
: base(uowProvider, loggerFactory, eventMessagesFactory)
|
||||
{
|
||||
_relationRepository = relationRepository;
|
||||
@@ -239,6 +248,24 @@ public class RelationService : RepositoryService, IRelationService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Attempt<PagedModel<IRelation>, RelationOperationStatus>> GetPagedByRelationTypeKey(Guid key, int skip, int take, Ordering? ordering = null)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
IRelationType? relationType = _relationTypeRepository.Get(key);
|
||||
if (relationType is null)
|
||||
{
|
||||
return await Task.FromResult(Attempt.FailWithStatus<PagedModel<IRelation>, RelationOperationStatus>(RelationOperationStatus.RelationTypeNotFound, null!));
|
||||
}
|
||||
|
||||
PaginationHelper.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize);
|
||||
|
||||
IQuery<IRelation> query = Query<IRelation>().Where(x => x.RelationTypeId == relationType.Id);
|
||||
IEnumerable<IRelation> relations = _relationRepository.GetPagedRelationsByQuery(query, pageNumber, pageSize, out var totalRecords, ordering);
|
||||
return await Task.FromResult(Attempt.SucceedWithStatus(RelationOperationStatus.Success, new PagedModel<IRelation>(totalRecords, relations)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IUmbracoEntity? GetChildEntityFromRelation(IRelation relation)
|
||||
{
|
||||
@@ -512,6 +539,72 @@ public class RelationService : RepositoryService, IRelationService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Attempt<IRelationType, RelationTypeOperationStatus>> CreateAsync(IRelationType relationType, int userId)
|
||||
{
|
||||
if (relationType.Id != 0)
|
||||
{
|
||||
return Attempt.FailWithStatus(RelationTypeOperationStatus.InvalidId, relationType);
|
||||
}
|
||||
|
||||
return await SaveAsync(
|
||||
relationType,
|
||||
() => _relationTypeRepository.Get(relationType.Key) is not null ? RelationTypeOperationStatus.KeyAlreadyExists : RelationTypeOperationStatus.Success,
|
||||
AuditType.New,
|
||||
$"Created relation type: {relationType.Name}",
|
||||
userId);
|
||||
}
|
||||
|
||||
public async Task<Attempt<IRelationType, RelationTypeOperationStatus>> UpdateAsync(IRelationType relationType, int userId) =>
|
||||
await SaveAsync(
|
||||
relationType,
|
||||
() => _relationTypeRepository.Get(relationType.Key) is null ? RelationTypeOperationStatus.NotFound : RelationTypeOperationStatus.Success,
|
||||
AuditType.Save,
|
||||
$"Created relation type: {relationType.Name}",
|
||||
userId);
|
||||
|
||||
private async Task<Attempt<IRelationType, RelationTypeOperationStatus>> SaveAsync(IRelationType relationType, Func<RelationTypeOperationStatus> operationValidation, AuditType auditType, string auditMessage, int userId)
|
||||
{
|
||||
// Validate that parent & child object types are allowed
|
||||
UmbracoObjectTypes[] allowedObjectTypes = GetAllowedObjectTypes().ToArray();
|
||||
var childObjectTypeAllowed = allowedObjectTypes.Any(x => x.GetGuid() == relationType.ChildObjectType);
|
||||
if (childObjectTypeAllowed is false)
|
||||
{
|
||||
return Attempt.FailWithStatus(RelationTypeOperationStatus.InvalidChildObjectType, relationType);
|
||||
}
|
||||
|
||||
var parentObjectTypeAllowed = allowedObjectTypes.Any(x => x.GetGuid() == relationType.ParentObjectType);
|
||||
|
||||
if (parentObjectTypeAllowed is false)
|
||||
{
|
||||
return Attempt.FailWithStatus(RelationTypeOperationStatus.InvalidParentObjectType, relationType);
|
||||
}
|
||||
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
|
||||
{
|
||||
RelationTypeOperationStatus status = operationValidation();
|
||||
if (status != RelationTypeOperationStatus.Success)
|
||||
{
|
||||
return Attempt.FailWithStatus(status, relationType);
|
||||
}
|
||||
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
var savingNotification = new RelationTypeSavingNotification(relationType, eventMessages);
|
||||
if (scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return Attempt.FailWithStatus(RelationTypeOperationStatus.CancelledByNotification, relationType);
|
||||
}
|
||||
|
||||
_relationTypeRepository.Save(relationType);
|
||||
Audit(auditType, userId, relationType.Id, auditMessage);
|
||||
scope.Complete();
|
||||
scope.Notifications.Publish(
|
||||
new RelationTypeSavedNotification(relationType, eventMessages).WithStateFrom(savingNotification));
|
||||
}
|
||||
|
||||
return await Task.FromResult(Attempt.SucceedWithStatus(RelationTypeOperationStatus.Success, relationType));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Delete(IRelation relation)
|
||||
{
|
||||
@@ -552,6 +645,32 @@ public class RelationService : RepositoryService, IRelationService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Attempt<IRelationType?, RelationTypeOperationStatus>> DeleteAsync(Guid key, int userId)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
|
||||
{
|
||||
IRelationType? relationType = _relationTypeRepository.Get(key);
|
||||
if (relationType is null)
|
||||
{
|
||||
return Attempt.FailWithStatus<IRelationType?, RelationTypeOperationStatus>(RelationTypeOperationStatus.NotFound, null);
|
||||
}
|
||||
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
var deletingNotification = new RelationTypeDeletingNotification(relationType, eventMessages);
|
||||
if (scope.Notifications.PublishCancelable(deletingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return Attempt.FailWithStatus<IRelationType?, RelationTypeOperationStatus>(RelationTypeOperationStatus.CancelledByNotification, null);
|
||||
}
|
||||
|
||||
_relationTypeRepository.Delete(relationType);
|
||||
Audit(AuditType.Delete, userId, relationType.Id, "Deleted relation type");
|
||||
scope.Notifications.Publish(new RelationTypeDeletedNotification(relationType, eventMessages).WithStateFrom(deletingNotification));
|
||||
scope.Complete();
|
||||
return await Task.FromResult(Attempt.SucceedWithStatus<IRelationType?, RelationTypeOperationStatus>(RelationTypeOperationStatus.Success, relationType));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DeleteRelationsOfType(IRelationType relationType)
|
||||
{
|
||||
@@ -584,6 +703,21 @@ public class RelationService : RepositoryService, IRelationService
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<UmbracoObjectTypes> GetAllowedObjectTypes() =>
|
||||
new[]
|
||||
{
|
||||
UmbracoObjectTypes.Document,
|
||||
UmbracoObjectTypes.Media,
|
||||
UmbracoObjectTypes.Member,
|
||||
UmbracoObjectTypes.DocumentType,
|
||||
UmbracoObjectTypes.MediaType,
|
||||
UmbracoObjectTypes.MemberType,
|
||||
UmbracoObjectTypes.DataType,
|
||||
UmbracoObjectTypes.MemberGroup,
|
||||
UmbracoObjectTypes.ROOT,
|
||||
UmbracoObjectTypes.RecycleBin,
|
||||
};
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private IRelationType? GetRelationType(string relationTypeAlias)
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
using Castle.Components.DictionaryAdapter.Xml;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Tests.Common.Testing;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class RelationServiceTests : UmbracoIntegrationTest
|
||||
{
|
||||
private IRelationService RelationService => GetRequiredService<IRelationService>();
|
||||
|
||||
[Test]
|
||||
[TestCase(true, true)]
|
||||
[TestCase(false, true)]
|
||||
[TestCase(true, false)]
|
||||
[TestCase(false, false)]
|
||||
public async Task Can_Create_Relation_Types_With_Bi_Directional_And_Is_Dependency(bool isBiDirectional, bool isDependency)
|
||||
{
|
||||
IRelationTypeWithIsDependency relationType = new RelationTypeBuilder()
|
||||
.WithChildObjectType(Constants.ObjectTypes.DocumentType)
|
||||
.WithParentObjectType(Constants.ObjectTypes.MediaType)
|
||||
.WithIsBidirectional(isBiDirectional)
|
||||
.WithIsDependency(isDependency)
|
||||
.Build();
|
||||
|
||||
Attempt<IRelationType, RelationTypeOperationStatus> result = await RelationService.CreateAsync(relationType, Constants.Security.SuperUserId);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(RelationTypeOperationStatus.Success, result.Status);
|
||||
});
|
||||
|
||||
AssertRelationTypesAreSame(relationType, result.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(Constants.ObjectTypes.Strings.Document, Constants.ObjectTypes.Strings.Media)]
|
||||
[TestCase(Constants.ObjectTypes.Strings.Member, Constants.ObjectTypes.Strings.DocumentType)]
|
||||
[TestCase(Constants.ObjectTypes.Strings.MediaType, Constants.ObjectTypes.Strings.MemberType)]
|
||||
[TestCase(Constants.ObjectTypes.Strings.DataType, Constants.ObjectTypes.Strings.MemberGroup)]
|
||||
[TestCase(Constants.ObjectTypes.Strings.Document, Constants.ObjectTypes.Strings.ContentRecycleBin)]
|
||||
[TestCase(Constants.ObjectTypes.Strings.Document, Constants.ObjectTypes.Strings.SystemRoot)]
|
||||
public async Task Can_Create_Relation_Types_With_Allowed_Object_Types(string childObjectTypeGuid, string parentObjectTypeGuid)
|
||||
{
|
||||
IRelationTypeWithIsDependency relationType = new RelationTypeBuilder()
|
||||
.WithChildObjectType(new Guid(childObjectTypeGuid))
|
||||
.WithParentObjectType(new Guid(parentObjectTypeGuid))
|
||||
.Build();
|
||||
|
||||
Attempt<IRelationType, RelationTypeOperationStatus> result = await RelationService.CreateAsync(relationType, Constants.Security.SuperUserId);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(RelationTypeOperationStatus.Success, result.Status);
|
||||
});
|
||||
AssertRelationTypesAreSame(relationType, result.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(Constants.ObjectTypes.Strings.Document, "53E492BD-F242-40A7-8F21-7D649463DD23", RelationTypeOperationStatus.InvalidChildObjectType)]
|
||||
[TestCase("E7524E34-F84F-43DE-92E2-25999785B7EA", Constants.ObjectTypes.Strings.DataType, RelationTypeOperationStatus.InvalidParentObjectType)]
|
||||
[TestCase("00000000-0000-0000-0000-000000000000", Constants.ObjectTypes.Strings.Document, RelationTypeOperationStatus.InvalidParentObjectType)]
|
||||
[TestCase(Constants.ObjectTypes.Strings.IdReservation, Constants.ObjectTypes.Strings.Document, RelationTypeOperationStatus.InvalidParentObjectType)]
|
||||
public async Task Cannot_Create_Relation_Types_With_Disallowed_Object_Types(string parentObjectTypeGuid, string childObjectTypeGuid, RelationTypeOperationStatus relationTypeOperationStatus)
|
||||
{
|
||||
IRelationTypeWithIsDependency relationType = new RelationTypeBuilder()
|
||||
.WithChildObjectType(new Guid(childObjectTypeGuid))
|
||||
.WithParentObjectType(new Guid(parentObjectTypeGuid))
|
||||
.Build();
|
||||
|
||||
Attempt<IRelationType, RelationTypeOperationStatus> result = await RelationService.CreateAsync(relationType, Constants.Security.SuperUserId);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsFalse(result.Success);
|
||||
Assert.AreEqual(relationTypeOperationStatus, result.Status);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Create_Relation_Type_With_Key()
|
||||
{
|
||||
const string key = "82E7631C-0417-460C-91C1-F65784627143";
|
||||
IRelationTypeWithIsDependency relationType = new RelationTypeBuilder()
|
||||
.WithChildObjectType(Constants.ObjectTypes.DocumentType)
|
||||
.WithParentObjectType(Constants.ObjectTypes.DocumentType)
|
||||
.WithKey(new Guid(key))
|
||||
.Build();
|
||||
|
||||
Attempt<IRelationType, RelationTypeOperationStatus> result = await RelationService.CreateAsync(relationType, Constants.Security.SuperUserId);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(RelationTypeOperationStatus.Success, result.Status);
|
||||
Assert.IsTrue(string.Equals(key, result.Result.Key.ToString(), StringComparison.OrdinalIgnoreCase));
|
||||
});
|
||||
|
||||
AssertRelationTypesAreSame(relationType, result.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(-1000000)]
|
||||
[TestCase(-1)]
|
||||
[TestCase(100)]
|
||||
[TestCase(10000000)]
|
||||
public async Task Cannot_Create_Relation_Types_With_Id(int id)
|
||||
{
|
||||
IRelationTypeWithIsDependency relationType = new RelationTypeBuilder()
|
||||
.WithChildObjectType(Constants.ObjectTypes.DocumentType)
|
||||
.WithParentObjectType(Constants.ObjectTypes.DocumentType)
|
||||
.WithId(id)
|
||||
.Build();
|
||||
|
||||
Attempt<IRelationType, RelationTypeOperationStatus> result = await RelationService.CreateAsync(relationType, Constants.Security.SuperUserId);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsFalse(result.Success);
|
||||
Assert.AreEqual(RelationTypeOperationStatus.InvalidId, result.Status);
|
||||
});
|
||||
}
|
||||
|
||||
private void AssertRelationTypesAreSame(IRelationTypeWithIsDependency relationType, IRelationType result)
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(relationType.Name, result.Name);
|
||||
Assert.AreEqual(relationType.ParentObjectType, result.ParentObjectType);
|
||||
Assert.AreEqual(relationType.ChildObjectType, result.ChildObjectType);
|
||||
Assert.AreEqual(relationType.IsBidirectional, result.IsBidirectional);
|
||||
var asWithDependency = (IRelationTypeWithIsDependency)result;
|
||||
Assert.AreEqual(relationType.IsDependency, asWithDependency.IsDependency);
|
||||
});
|
||||
var persistedRelationType = RelationService.GetRelationTypeById(result.Key);
|
||||
|
||||
Assert.AreEqual(result, persistedRelationType);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user