-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
296 additions
and
10 deletions.
There are no files selected for viewing
77 changes: 77 additions & 0 deletions
77
backend/src/Logitar.Cms.Core/FieldTypes/Commands/UpdateFieldTypeCommandHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
using FluentValidation; | ||
using Logitar.Cms.Contracts.FieldTypes; | ||
using Logitar.Cms.Core.FieldTypes.Properties; | ||
using Logitar.Cms.Core.FieldTypes.Validators; | ||
using Logitar.Identity.Contracts.Settings; | ||
using Logitar.Identity.Domain.Shared; | ||
using MediatR; | ||
|
||
namespace Logitar.Cms.Core.FieldTypes.Commands; | ||
|
||
internal class UpdateFieldTypeCommandHandler : IRequestHandler<UpdateFieldTypeCommand, FieldType?> | ||
{ | ||
private readonly IFieldTypeQuerier _fieldTypeQuerier; | ||
private readonly IFieldTypeRepository _fieldTypeRepository; | ||
private readonly ISender _sender; | ||
|
||
public UpdateFieldTypeCommandHandler(IFieldTypeQuerier fieldTypeQuerier, IFieldTypeRepository fieldTypeRepository, ISender sender) | ||
{ | ||
_fieldTypeQuerier = fieldTypeQuerier; | ||
_fieldTypeRepository = fieldTypeRepository; | ||
_sender = sender; | ||
} | ||
|
||
public async Task<FieldType?> Handle(UpdateFieldTypeCommand command, CancellationToken cancellationToken) | ||
{ | ||
FieldTypeId id = new(command.Id); | ||
FieldTypeAggregate? fieldType = await _fieldTypeRepository.LoadAsync(id, cancellationToken); | ||
if (fieldType == null) | ||
{ | ||
return null; | ||
} | ||
|
||
IUniqueNameSettings uniqueNameSettings = FieldTypeAggregate.UniqueNameSettings; | ||
|
||
UpdateFieldTypePayload payload = command.Payload; | ||
new UpdateFieldTypeValidator(uniqueNameSettings, fieldType.DataType).ValidateAndThrow(payload); | ||
|
||
if (!string.IsNullOrWhiteSpace(payload.UniqueName)) | ||
{ | ||
fieldType.UniqueName = new UniqueNameUnit(uniqueNameSettings, payload.UniqueName); | ||
} | ||
if (payload.DisplayName != null) | ||
{ | ||
fieldType.DisplayName = DisplayNameUnit.TryCreate(payload.DisplayName.Value); | ||
} | ||
if (payload.Description != null) | ||
{ | ||
fieldType.Description = DescriptionUnit.TryCreate(payload.Description.Value); | ||
} | ||
fieldType.Update(command.ActorId); | ||
|
||
if (payload.BooleanProperties != null) | ||
{ | ||
fieldType.SetProperties(new ReadOnlyBooleanProperties(payload.BooleanProperties), command.ActorId); | ||
} | ||
if (payload.DateTimeProperties != null) | ||
{ | ||
fieldType.SetProperties(new ReadOnlyDateTimeProperties(payload.DateTimeProperties), command.ActorId); | ||
} | ||
if (payload.NumberProperties != null) | ||
{ | ||
fieldType.SetProperties(new ReadOnlyNumberProperties(payload.NumberProperties), command.ActorId); | ||
} | ||
if (payload.StringProperties != null) | ||
{ | ||
fieldType.SetProperties(new ReadOnlyStringProperties(payload.StringProperties), command.ActorId); | ||
} | ||
if (payload.TextProperties != null) | ||
{ | ||
fieldType.SetProperties(new ReadOnlyTextProperties(payload.TextProperties), command.ActorId); | ||
} | ||
|
||
await _sender.Send(new SaveFieldTypeCommand(fieldType), cancellationToken); | ||
|
||
return await _fieldTypeQuerier.ReadAsync(fieldType, cancellationToken); | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
backend/src/Logitar.Cms.Core/FieldTypes/Validators/UpdateFieldTypeValidator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
using FluentValidation; | ||
using Logitar.Cms.Contracts.FieldTypes; | ||
using Logitar.Identity.Contracts.Settings; | ||
using Logitar.Identity.Domain.Shared; | ||
|
||
namespace Logitar.Cms.Core.FieldTypes.Validators; | ||
|
||
public class UpdateFieldTypeValidator : AbstractValidator<UpdateFieldTypePayload> | ||
{ | ||
public UpdateFieldTypeValidator(IUniqueNameSettings uniqueNameSettings, DataType dataType) | ||
{ | ||
When(x => !string.IsNullOrWhiteSpace(x.UniqueName), () => RuleFor(x => x.UniqueName!).SetValidator(new UniqueNameValidator(uniqueNameSettings))); | ||
When(x => !string.IsNullOrWhiteSpace(x.DisplayName?.Value), () => RuleFor(x => x.DisplayName!.Value!).SetValidator(new DisplayNameValidator())); | ||
When(x => !string.IsNullOrWhiteSpace(x.Description?.Value), () => RuleFor(x => x.Description!.Value!).SetValidator(new DescriptionValidator())); | ||
|
||
switch (dataType) | ||
{ | ||
case DataType.Boolean: | ||
When(x => x.BooleanProperties != null, () => RuleFor(x => x.BooleanProperties!).SetValidator(new BooleanPropertiesValidator())); | ||
RuleFor(x => x.DateTimeProperties).Null(); | ||
RuleFor(x => x.NumberProperties).Null(); | ||
RuleFor(x => x.StringProperties).Null(); | ||
RuleFor(x => x.TextProperties).Null(); | ||
break; | ||
case DataType.DateTime: | ||
RuleFor(x => x.BooleanProperties).Null(); | ||
When(x => x.DateTimeProperties != null, () => RuleFor(x => x.DateTimeProperties!).SetValidator(new DateTimePropertiesValidator())); | ||
RuleFor(x => x.NumberProperties).Null(); | ||
RuleFor(x => x.StringProperties).Null(); | ||
RuleFor(x => x.TextProperties).Null(); | ||
break; | ||
case DataType.Number: | ||
RuleFor(x => x.BooleanProperties).Null(); | ||
RuleFor(x => x.DateTimeProperties).Null(); | ||
When(x => x.NumberProperties != null, () => RuleFor(x => x.NumberProperties!).SetValidator(new NumberPropertiesValidator())); | ||
RuleFor(x => x.StringProperties).Null(); | ||
RuleFor(x => x.TextProperties).Null(); | ||
break; | ||
case DataType.String: | ||
RuleFor(x => x.BooleanProperties).Null(); | ||
RuleFor(x => x.DateTimeProperties).Null(); | ||
RuleFor(x => x.NumberProperties).Null(); | ||
When(x => x.StringProperties != null, () => RuleFor(x => x.StringProperties!).SetValidator(new StringPropertiesValidator())); | ||
RuleFor(x => x.TextProperties).Null(); | ||
break; | ||
case DataType.Text: | ||
RuleFor(x => x.BooleanProperties).Null(); | ||
RuleFor(x => x.DateTimeProperties).Null(); | ||
RuleFor(x => x.NumberProperties).Null(); | ||
RuleFor(x => x.StringProperties).Null(); | ||
When(x => x.TextProperties != null, () => RuleFor(x => x.TextProperties!).SetValidator(new TextPropertiesValidator())); | ||
break; | ||
default: | ||
throw new DataTypeNotSupportedException(dataType); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
...gitar.Cms.Core.IntegrationTests/FieldTypes/Commands/UpdateFieldTypeCommandHandlerTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using Logitar.Cms.Contracts; | ||
using Logitar.Cms.Contracts.FieldTypes; | ||
using Logitar.Cms.Contracts.FieldTypes.Properties; | ||
using Logitar.Cms.Core.FieldTypes.Properties; | ||
using Logitar.Identity.Domain.Shared; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Logitar.Cms.Core.FieldTypes.Commands; | ||
|
||
[Trait(Traits.Category, Categories.Integration)] | ||
public class UpdateFieldTypeCommandHandlerTests : IntegrationTests | ||
{ | ||
private readonly IFieldTypeRepository _fieldTypeRepository; | ||
|
||
private readonly FieldTypeAggregate _fieldType; | ||
|
||
public UpdateFieldTypeCommandHandlerTests() : base() | ||
{ | ||
_fieldTypeRepository = ServiceProvider.GetRequiredService<IFieldTypeRepository>(); | ||
|
||
_fieldType = new(new UniqueNameUnit(FieldTypeAggregate.UniqueNameSettings, "ArticleTitle"), new ReadOnlyStringProperties()); | ||
} | ||
|
||
public override async Task InitializeAsync() | ||
{ | ||
await base.InitializeAsync(); | ||
|
||
await _fieldTypeRepository.SaveAsync(_fieldType); | ||
} | ||
|
||
[Fact(DisplayName = "It should update an existing field type.")] | ||
public async Task It_should_update_an_existing_field_type() | ||
{ | ||
UpdateFieldTypePayload payload = new() | ||
{ | ||
DisplayName = new Change<string>(" Article Title "), | ||
StringProperties = new StringProperties | ||
{ | ||
MinimumLength = 1, | ||
MaximumLength = 100 | ||
} | ||
}; | ||
UpdateFieldTypeCommand command = new(_fieldType.Id.ToGuid(), payload); | ||
FieldType? fieldType = await Pipeline.ExecuteAsync(command); | ||
Assert.NotNull(fieldType); | ||
|
||
Assert.Equal(_fieldType.Id.ToGuid(), fieldType.Id); | ||
Assert.Equal(4, fieldType.Version); | ||
Assert.Equal(Contracts.Actors.Actor.System, fieldType.CreatedBy); | ||
Assert.Equal(_fieldType.CreatedOn.AsUniversalTime(), fieldType.CreatedOn); | ||
Assert.Equal(Actor, fieldType.UpdatedBy); | ||
Assert.True(fieldType.CreatedOn < fieldType.UpdatedOn); | ||
|
||
Assert.Equal(_fieldType.UniqueName.Value, fieldType.UniqueName); | ||
Assert.NotNull(payload.DisplayName.Value); | ||
Assert.Equal(payload.DisplayName.Value.Trim(), fieldType.DisplayName); | ||
Assert.Null(fieldType.Description); | ||
Assert.Equal(DataType.String, fieldType.DataType); | ||
Assert.Null(fieldType.BooleanProperties); | ||
Assert.Null(fieldType.DateTimeProperties); | ||
Assert.Null(fieldType.NumberProperties); | ||
Assert.Equal(payload.StringProperties, fieldType.StringProperties); | ||
Assert.Null(fieldType.TextProperties); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
...ests/Logitar.Cms.Core.UnitTests/FieldTypes/Commands/UpdateFieldTypeCommandHandlerTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
using FluentValidation.Results; | ||
using Logitar.Cms.Contracts; | ||
using Logitar.Cms.Contracts.FieldTypes; | ||
using Logitar.Cms.Contracts.FieldTypes.Properties; | ||
using Logitar.Cms.Core.FieldTypes.Properties; | ||
using Logitar.Identity.Domain.Shared; | ||
using MediatR; | ||
using Moq; | ||
|
||
namespace Logitar.Cms.Core.FieldTypes.Commands; | ||
|
||
[Trait(Traits.Category, Categories.Unit)] | ||
public class UpdateFieldTypeCommandHandlerTests | ||
{ | ||
private readonly CancellationToken _cancellationToken = default; | ||
|
||
private readonly Mock<IFieldTypeQuerier> _fieldTypeQuerier = new(); | ||
private readonly Mock<IFieldTypeRepository> _fieldTypeRepository = new(); | ||
private readonly Mock<ISender> _sender = new(); | ||
|
||
private readonly UpdateFieldTypeCommandHandler _handler; | ||
|
||
public UpdateFieldTypeCommandHandlerTests() | ||
{ | ||
_handler = new(_fieldTypeQuerier.Object, _fieldTypeRepository.Object, _sender.Object); | ||
} | ||
|
||
[Fact(DisplayName = "It should return null when the field type is not found.")] | ||
public async Task It_should_return_null_when_the_field_type_is_not_found() | ||
{ | ||
UpdateFieldTypePayload payload = new(); | ||
UpdateFieldTypeCommand command = new(Guid.Empty, payload); | ||
Assert.Null(await _handler.Handle(command, _cancellationToken)); | ||
} | ||
|
||
[Fact(DisplayName = "It should throw ValidationException when the payload is not valid.")] | ||
public async Task It_should_throw_ValidationException_when_the_payload_is_not_valid() | ||
{ | ||
FieldTypeAggregate fieldType = new(new UniqueNameUnit(FieldTypeAggregate.UniqueNameSettings, "ArticleTitle"), new ReadOnlyStringProperties()); | ||
_fieldTypeRepository.Setup(x => x.LoadAsync(fieldType.Id, _cancellationToken)).ReturnsAsync(fieldType); | ||
|
||
UpdateFieldTypePayload payload = new() | ||
{ | ||
StringProperties = new StringProperties(), | ||
TextProperties = new TextProperties() | ||
}; | ||
UpdateFieldTypeCommand command = new(fieldType.Id.ToGuid(), payload); | ||
var exception = await Assert.ThrowsAsync<FluentValidation.ValidationException>(async () => await _handler.Handle(command, _cancellationToken)); | ||
ValidationFailure error = Assert.Single(exception.Errors); | ||
Assert.Equal("NullValidator", error.ErrorCode); | ||
Assert.Equal("TextProperties", error.PropertyName); | ||
} | ||
|
||
[Fact(DisplayName = "It should update an existing field type.")] | ||
public async Task It_should_update_an_existing_field_type() | ||
{ | ||
FieldTypeAggregate fieldType = new(new UniqueNameUnit(FieldTypeAggregate.UniqueNameSettings, "ArticleTitle"), new ReadOnlyStringProperties()); | ||
_fieldTypeRepository.Setup(x => x.LoadAsync(fieldType.Id, _cancellationToken)).ReturnsAsync(fieldType); | ||
|
||
UpdateFieldTypePayload payload = new() | ||
{ | ||
DisplayName = new Change<string>(" Article Title "), | ||
Description = new Change<string>(" "), | ||
StringProperties = new StringProperties(minimumLength: 1, maximumLength: 100, pattern: null) | ||
}; | ||
UpdateFieldTypeCommand command = new(fieldType.Id.ToGuid(), payload); | ||
ActivityHelper.Contextualize(command); | ||
await _handler.Handle(command, _cancellationToken); | ||
|
||
_sender.Verify(x => x.Send(It.Is<SaveFieldTypeCommand>(y => y.FieldType.Id == fieldType.Id | ||
&& y.FieldType.UniqueName == fieldType.UniqueName | ||
&& y.FieldType.DisplayName != null && payload.DisplayName.Value != null && y.FieldType.DisplayName.Value == payload.DisplayName.Value.Trim() | ||
&& y.FieldType.Description == null | ||
&& y.FieldType.DataType == DataType.String | ||
&& ((ReadOnlyStringProperties)y.FieldType.Properties).MinimumLength == payload.StringProperties.MinimumLength | ||
&& ((ReadOnlyStringProperties)y.FieldType.Properties).MaximumLength == payload.StringProperties.MaximumLength | ||
&& ((ReadOnlyStringProperties)y.FieldType.Properties).Pattern == payload.StringProperties.Pattern | ||
), _cancellationToken), Times.Once()); | ||
} | ||
} |