mirror of https://github.com/Squidex/squidex.git
46 changed files with 868 additions and 115 deletions
@ -0,0 +1,23 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentCreated.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Newtonsoft.Json.Linq; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
|
||||
|
namespace Squidex.Events.Contents |
||||
|
{ |
||||
|
[TypeName("ContentCreatedEvent")] |
||||
|
public class ContentCreated : IEvent |
||||
|
{ |
||||
|
public Guid SchemaId { get; set; } |
||||
|
|
||||
|
public JObject Data { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentDeleted.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
|
||||
|
namespace Squidex.Events.Contents |
||||
|
{ |
||||
|
[TypeName("ContentDeletedEvent")] |
||||
|
public class ContentDeleted : IEvent |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentUpdated.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Newtonsoft.Json.Linq; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
|
||||
|
namespace Squidex.Events.Contents |
||||
|
{ |
||||
|
[TypeName("ContentUpdatedEvent")] |
||||
|
public class ContentUpdated : IEvent |
||||
|
{ |
||||
|
public JObject Data { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
// ==========================================================================
|
||||
|
// CreateContent.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Write.Contents.Commands |
||||
|
{ |
||||
|
public class CreateContent : ContentDataCommand |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
// ==========================================================================
|
||||
|
// DeleteContent.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Write.Contents.Commands |
||||
|
{ |
||||
|
public class DeleteContent : SchemaCommand |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
// ==========================================================================
|
||||
|
// UpdateContent.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Write.Contents.Commands |
||||
|
{ |
||||
|
public class UpdateContent : ContentDataCommand |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,89 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentCommandHandler.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Squidex.Infrastructure.Dispatching; |
||||
|
using Squidex.Read.Apps.Services; |
||||
|
using Squidex.Read.Schemas.Services; |
||||
|
using Squidex.Write.Contents.Commands; |
||||
|
|
||||
|
namespace Squidex.Write.Contents |
||||
|
{ |
||||
|
public class ContentCommandHandler : ICommandHandler |
||||
|
{ |
||||
|
private readonly IAggregateHandler handler; |
||||
|
private readonly IAppProvider appProvider; |
||||
|
private readonly ISchemaProvider schemaProvider; |
||||
|
|
||||
|
public ContentCommandHandler( |
||||
|
IAggregateHandler handler, |
||||
|
IAppProvider appProvider, |
||||
|
ISchemaProvider schemaProvider) |
||||
|
{ |
||||
|
Guard.NotNull(handler, nameof(handler)); |
||||
|
Guard.NotNull(appProvider, nameof(appProvider)); |
||||
|
Guard.NotNull(schemaProvider, nameof(schemaProvider)); |
||||
|
|
||||
|
this.handler = handler; |
||||
|
this.appProvider = appProvider; |
||||
|
this.schemaProvider = schemaProvider; |
||||
|
} |
||||
|
|
||||
|
protected async Task On(CreateContent command, CommandContext context) |
||||
|
{ |
||||
|
await ValidateAsync(command, () => "Failed to create content"); |
||||
|
|
||||
|
await handler.CreateAsync<ContentDomainObject>(command, s => |
||||
|
{ |
||||
|
s.Create(command); |
||||
|
|
||||
|
context.Succeed(command.AggregateId); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
protected async Task On(UpdateContent command, CommandContext context) |
||||
|
{ |
||||
|
await ValidateAsync(command, () => "Failed to update content"); |
||||
|
|
||||
|
await handler.UpdateAsync<ContentDomainObject>(command, s => s.Update(command)); |
||||
|
} |
||||
|
|
||||
|
protected Task On(DeleteContent command, CommandContext context) |
||||
|
{ |
||||
|
return handler.UpdateAsync<ContentDomainObject>(command, s => s.Delete(command)); |
||||
|
} |
||||
|
|
||||
|
public Task<bool> HandleAsync(CommandContext context) |
||||
|
{ |
||||
|
return context.IsHandled ? Task.FromResult(false) : this.DispatchActionAsync(context.Command, context); |
||||
|
} |
||||
|
|
||||
|
private async Task ValidateAsync(ContentDataCommand command, Func<string> message) |
||||
|
{ |
||||
|
Guard.Valid(command, nameof(command), message); |
||||
|
|
||||
|
var taskForApp = appProvider.FindAppByIdAsync(command.AppId); |
||||
|
var taskForSchema = schemaProvider.FindSchemaByIdAsync(command.SchemaId); |
||||
|
|
||||
|
await Task.WhenAll(taskForApp, taskForSchema); |
||||
|
|
||||
|
var errors = new List<ValidationError>(); |
||||
|
|
||||
|
await taskForSchema.Result.Schema.ValidateAsync(command.Data, errors, new HashSet<Language>(taskForApp.Result.Languages)); |
||||
|
|
||||
|
if (errors.Count > 0) |
||||
|
{ |
||||
|
throw new ValidationException(message(), errors); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentDataCommand.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using Newtonsoft.Json.Linq; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Write.Contents |
||||
|
{ |
||||
|
public class ContentDataCommand : SchemaCommand, IValidatable |
||||
|
{ |
||||
|
public JObject Data { get; set; } |
||||
|
|
||||
|
public void Validate(IList<ValidationError> errors) |
||||
|
{ |
||||
|
if (Data == null) |
||||
|
{ |
||||
|
errors.Add(new ValidationError("Data cannot be null", nameof(Data))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,99 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentDomainObject.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Squidex.Events.Contents; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
using Squidex.Infrastructure.Dispatching; |
||||
|
using Squidex.Infrastructure.Reflection; |
||||
|
using Squidex.Write.Contents.Commands; |
||||
|
|
||||
|
namespace Squidex.Write.Contents |
||||
|
{ |
||||
|
public class ContentDomainObject : DomainObject |
||||
|
{ |
||||
|
private bool isDeleted; |
||||
|
private bool isCreated; |
||||
|
|
||||
|
public bool IsDeleted |
||||
|
{ |
||||
|
get { return isDeleted; } |
||||
|
} |
||||
|
|
||||
|
public ContentDomainObject(Guid id, int version) |
||||
|
: base(id, version) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected void On(ContentCreated @event) |
||||
|
{ |
||||
|
isCreated = true; |
||||
|
} |
||||
|
|
||||
|
protected void On(ContentDeleted @event) |
||||
|
{ |
||||
|
isDeleted = true; |
||||
|
} |
||||
|
|
||||
|
public ContentDomainObject Create(CreateContent command) |
||||
|
{ |
||||
|
Guard.Valid(command, nameof(command), () => "Cannot create content"); |
||||
|
|
||||
|
VerifyNotCreated(); |
||||
|
|
||||
|
RaiseEvent(SimpleMapper.Map(command, new ContentCreated())); |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public ContentDomainObject Update(UpdateContent command) |
||||
|
{ |
||||
|
Guard.Valid(command, nameof(command), () => "Cannot update content"); |
||||
|
|
||||
|
VerifyCreatedAndNotDeleted(); |
||||
|
|
||||
|
RaiseEvent(SimpleMapper.Map(command, new ContentUpdated())); |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public ContentDomainObject Delete(DeleteContent command) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
|
||||
|
VerifyCreatedAndNotDeleted(); |
||||
|
|
||||
|
RaiseEvent(SimpleMapper.Map(command, new ContentDeleted())); |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
private void VerifyNotCreated() |
||||
|
{ |
||||
|
if (isCreated) |
||||
|
{ |
||||
|
throw new DomainException("Content has already been created."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void VerifyCreatedAndNotDeleted() |
||||
|
{ |
||||
|
if (isDeleted || !isCreated) |
||||
|
{ |
||||
|
throw new DomainException("Content has already been deleted or not created yet."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override void DispatchEvent(Envelope<IEvent> @event) |
||||
|
{ |
||||
|
this.DispatchAction(@event.Payload); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ISchemaCommand.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace Squidex.Write |
||||
|
{ |
||||
|
public interface ISchemaCommand : IAppCommand |
||||
|
{ |
||||
|
Guid SchemaId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
// ==========================================================================
|
||||
|
// SchemaAggregateCommand.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace Squidex.Write |
||||
|
{ |
||||
|
public abstract class SchemaAggregateCommand : AppCommand, ISchemaCommand |
||||
|
{ |
||||
|
Guid ISchemaCommand.SchemaId |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
return AggregateId; |
||||
|
} |
||||
|
set |
||||
|
{ |
||||
|
AggregateId = value; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Squidex.Write |
||||
|
{ |
||||
|
public abstract class SchemaCommand : AppCommand, ISchemaCommand |
||||
|
{ |
||||
|
public Guid SchemaId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -1,69 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// EnrichWithSchemaAggregateIdHandler.cs
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure; |
|
||||
using Squidex.Infrastructure; |
|
||||
using Squidex.Infrastructure.CQRS.Commands; |
|
||||
using Squidex.Read.Schemas.Services; |
|
||||
using Squidex.Write; |
|
||||
using Squidex.Write.Schemas; |
|
||||
|
|
||||
// ReSharper disable InvertIf
|
|
||||
|
|
||||
namespace Squidex.Pipeline.CommandHandlers |
|
||||
{ |
|
||||
public sealed class EnrichWithSchemaAggregateIdHandler : ICommandHandler |
|
||||
{ |
|
||||
private readonly ISchemaProvider schemaProvider; |
|
||||
private readonly IActionContextAccessor actionContextAccessor; |
|
||||
|
|
||||
public EnrichWithSchemaAggregateIdHandler(ISchemaProvider schemaProvider, IActionContextAccessor actionContextAccessor) |
|
||||
{ |
|
||||
this.schemaProvider = schemaProvider; |
|
||||
|
|
||||
this.actionContextAccessor = actionContextAccessor; |
|
||||
} |
|
||||
|
|
||||
public async Task<bool> HandleAsync(CommandContext context) |
|
||||
{ |
|
||||
var aggregateCommand = context.Command as IAggregateCommand; |
|
||||
|
|
||||
if (aggregateCommand == null || aggregateCommand.AggregateId != Guid.Empty) |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
var appCommand = context.Command as IAppCommand; |
|
||||
|
|
||||
if (appCommand == null) |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
var routeValues = actionContextAccessor.ActionContext.RouteData.Values; |
|
||||
|
|
||||
if (routeValues.ContainsKey("name")) |
|
||||
{ |
|
||||
var schemaName = routeValues["name"].ToString(); |
|
||||
|
|
||||
var schema = await schemaProvider.ProvideSchemaByNameAsync(appCommand.AppId, schemaName); |
|
||||
|
|
||||
if (schema == null) |
|
||||
{ |
|
||||
throw new DomainObjectNotFoundException(schemaName, typeof(SchemaDomainObject)); |
|
||||
} |
|
||||
|
|
||||
aggregateCommand.AggregateId = schema.Id; |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,59 @@ |
|||||
|
// ==========================================================================
|
||||
|
// EnrichWithSchemaIdHandler.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc.Infrastructure; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Squidex.Read.Schemas.Services; |
||||
|
using Squidex.Write; |
||||
|
using Squidex.Write.Schemas; |
||||
|
|
||||
|
// ReSharper disable InvertIf
|
||||
|
|
||||
|
namespace Squidex.Pipeline.CommandHandlers |
||||
|
{ |
||||
|
public sealed class EnrichWithSchemaIdHandler : ICommandHandler |
||||
|
{ |
||||
|
private readonly ISchemaProvider schemaProvider; |
||||
|
private readonly IActionContextAccessor actionContextAccessor; |
||||
|
|
||||
|
public EnrichWithSchemaIdHandler(ISchemaProvider schemaProvider, IActionContextAccessor actionContextAccessor) |
||||
|
{ |
||||
|
this.schemaProvider = schemaProvider; |
||||
|
|
||||
|
this.actionContextAccessor = actionContextAccessor; |
||||
|
} |
||||
|
|
||||
|
public async Task<bool> HandleAsync(CommandContext context) |
||||
|
{ |
||||
|
var schemaCommand = context.Command as ISchemaCommand; |
||||
|
|
||||
|
if (schemaCommand != null) |
||||
|
{ |
||||
|
var routeValues = actionContextAccessor.ActionContext.RouteData.Values; |
||||
|
|
||||
|
if (routeValues.ContainsKey("name")) |
||||
|
{ |
||||
|
var schemaName = routeValues["name"].ToString(); |
||||
|
|
||||
|
var schema = await schemaProvider.FindSchemaByNameAsync(schemaCommand.AppId, schemaName); |
||||
|
|
||||
|
if (schema == null) |
||||
|
{ |
||||
|
throw new DomainObjectNotFoundException(schemaName, typeof(SchemaDomainObject)); |
||||
|
} |
||||
|
|
||||
|
schemaCommand.SchemaId = schema.Id; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,130 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentCommandHandlerTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Moq; |
||||
|
using Newtonsoft.Json.Linq; |
||||
|
using Squidex.Core.Schemas; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Squidex.Read.Apps; |
||||
|
using Squidex.Read.Apps.Services; |
||||
|
using Squidex.Read.Schemas.Repositories; |
||||
|
using Squidex.Read.Schemas.Services; |
||||
|
using Squidex.Write.Contents.Commands; |
||||
|
using Squidex.Write.Utils; |
||||
|
using Xunit; |
||||
|
|
||||
|
// ReSharper disable ConvertToConstant.Local
|
||||
|
|
||||
|
namespace Squidex.Write.Contents |
||||
|
{ |
||||
|
public class ContentCommandHandlerTests : HandlerTestBase<ContentDomainObject> |
||||
|
{ |
||||
|
private readonly ContentCommandHandler sut; |
||||
|
private readonly ContentDomainObject content; |
||||
|
private readonly Mock<ISchemaProvider> schemaProvider = new Mock<ISchemaProvider>(); |
||||
|
private readonly Mock<IAppProvider> appProvider = new Mock<IAppProvider>(); |
||||
|
private readonly Mock<ISchemaEntityWithSchema> schemaEntity = new Mock<ISchemaEntityWithSchema>(); |
||||
|
private readonly Mock<IAppEntity> appEntity = new Mock<IAppEntity>(); |
||||
|
private readonly Guid schemaId = Guid.NewGuid(); |
||||
|
private readonly Guid appId = Guid.NewGuid(); |
||||
|
private readonly JObject data = new JObject(new JProperty("field", 1)); |
||||
|
|
||||
|
public ContentCommandHandlerTests() |
||||
|
{ |
||||
|
var schema = |
||||
|
Schema.Create("my-schema", new SchemaProperties()) |
||||
|
.AddOrUpdateField(new NumberField(1, "field", new NumberFieldProperties { IsRequired = true })); |
||||
|
|
||||
|
content = new ContentDomainObject(Id, 0); |
||||
|
|
||||
|
sut = new ContentCommandHandler(Handler, appProvider.Object, schemaProvider.Object); |
||||
|
|
||||
|
appEntity.Setup(x => x.Languages).Returns(new[] { Language.GetLanguage("de") }); |
||||
|
appProvider.Setup(x => x.FindAppByIdAsync(appId)).Returns(Task.FromResult(appEntity.Object)); |
||||
|
|
||||
|
schemaEntity.Setup(x => x.Schema).Returns(schema); |
||||
|
schemaProvider.Setup(x => x.FindSchemaByIdAsync(schemaId)).Returns(Task.FromResult(schemaEntity.Object)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Create_should_throw_exception_if_data_is_not_valid() |
||||
|
{ |
||||
|
var command = new CreateContent { AggregateId = Id, AppId = appId, SchemaId = schemaId, Data = new JObject() }; |
||||
|
var context = new CommandContext(command); |
||||
|
|
||||
|
await TestCreate(content, async _ => |
||||
|
{ |
||||
|
await Assert.ThrowsAsync<ValidationException>(() => sut.HandleAsync(context)); |
||||
|
}, false); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Create_should_create_content() |
||||
|
{ |
||||
|
var command = new CreateContent { AggregateId = Id, AppId = appId, SchemaId = schemaId, Data = data }; |
||||
|
var context = new CommandContext(command); |
||||
|
|
||||
|
await TestCreate(content, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
Assert.Equal(Id, context.Result<Guid>()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Update_should_throw_exception_if_data_is_not_valid() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
var command = new UpdateContent { AggregateId = Id, AppId = appId, SchemaId = schemaId, Data = new JObject() }; |
||||
|
var context = new CommandContext(command); |
||||
|
|
||||
|
await TestUpdate(content, async _ => |
||||
|
{ |
||||
|
await Assert.ThrowsAsync<ValidationException>(() => sut.HandleAsync(context)); |
||||
|
}, false); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Update_should_update_domain_object() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
var command = new UpdateContent { AggregateId = Id, AppId = appId, SchemaId = schemaId, Data = data }; |
||||
|
var context = new CommandContext(command); |
||||
|
|
||||
|
await TestUpdate(content, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Delete_should_update_domain_object() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
var command = new DeleteContent { AggregateId = Id }; |
||||
|
var context = new CommandContext(command); |
||||
|
|
||||
|
await TestUpdate(content, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private void CreateContent() |
||||
|
{ |
||||
|
content.Create(new CreateContent { Data = data }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,147 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentDomainObjectTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using FluentAssertions; |
||||
|
using Newtonsoft.Json.Linq; |
||||
|
using Squidex.Events.Contents; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
using Squidex.Write.Contents.Commands; |
||||
|
using Xunit; |
||||
|
|
||||
|
// ReSharper disable ConvertToConstant.Local
|
||||
|
|
||||
|
namespace Squidex.Write.Contents |
||||
|
{ |
||||
|
[Collection("Content")] |
||||
|
public class ContentDomainObjectTests |
||||
|
{ |
||||
|
private readonly Guid appId = Guid.NewGuid(); |
||||
|
private readonly ContentDomainObject sut; |
||||
|
private readonly JObject data = new JObject(); |
||||
|
|
||||
|
public ContentDomainObjectTests() |
||||
|
{ |
||||
|
sut = new ContentDomainObject(Guid.NewGuid(), 0); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_throw_if_created() |
||||
|
{ |
||||
|
sut.Create(new CreateContent { Data = data }); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => sut.Create(new CreateContent { Data = data })); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_throw_if_command_is_not_valid() |
||||
|
{ |
||||
|
Assert.Throws<ValidationException>(() => sut.Create(new CreateContent())); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_create_events() |
||||
|
{ |
||||
|
sut.Create(new CreateContent { Data = data, AppId = appId }); |
||||
|
|
||||
|
sut.GetUncomittedEvents().Select(x => x.Payload).ToArray() |
||||
|
.ShouldBeEquivalentTo( |
||||
|
new IEvent[] |
||||
|
{ |
||||
|
new ContentCreated { Data = data } |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => sut.Update(new UpdateContent { Data = data })); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_if_schema_is_deleted() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
DeleteContent(); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => sut.Update(new UpdateContent())); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_if_command_is_not_valid() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => sut.Update(new UpdateContent())); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_create_events() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
sut.Update(new UpdateContent { Data = data }); |
||||
|
|
||||
|
sut.GetUncomittedEvents().Select(x => x.Payload).ToArray() |
||||
|
.ShouldBeEquivalentTo( |
||||
|
new IEvent[] |
||||
|
{ |
||||
|
new ContentUpdated { Data = data } |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_throw_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => sut.Delete(new DeleteContent())); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_throw_if_already_deleted() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
DeleteContent(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => sut.Delete(new DeleteContent())); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_update_properties_create_events() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
sut.Delete(new DeleteContent()); |
||||
|
|
||||
|
Assert.True(sut.IsDeleted); |
||||
|
|
||||
|
sut.GetUncomittedEvents().Select(x => x.Payload).ToArray() |
||||
|
.ShouldBeEquivalentTo( |
||||
|
new IEvent[] |
||||
|
{ |
||||
|
new ContentDeleted() |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private void CreateContent() |
||||
|
{ |
||||
|
sut.Create(new CreateContent { Data = data, AppId = appId }); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
private void DeleteContent() |
||||
|
{ |
||||
|
sut.Delete(new DeleteContent()); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue