Browse Source

Updated domain object.

pull/208/head
Sebastian Stehle 8 years ago
parent
commit
08b610fb94
  1. 30
      src/Squidex.Domain.Apps.Entities/Apps/AppCommandMiddleware.cs
  2. 27
      src/Squidex.Domain.Apps.Entities/Apps/AppDomainObject.cs
  3. 28
      src/Squidex.Domain.Apps.Entities/Apps/Commands/AddPattern.cs
  4. 4
      src/Squidex.Domain.Apps.Entities/Apps/Commands/CreateApp.cs
  5. 17
      src/Squidex.Domain.Apps.Entities/Apps/Commands/DeletePattern.cs
  6. 23
      src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdatePattern.cs
  7. 97
      src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppPattern.cs
  8. 2
      src/Squidex.Domain.Apps.Entities/Apps/IAppEntity.cs
  9. 18
      src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs
  10. 3
      tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/AppPatternsTests.cs
  11. 44
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppCommandMiddlewareTests.cs
  12. 78
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppDomainObjectTests.cs
  13. 169
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppPatternsTests.cs

30
src/Squidex.Domain.Apps.Entities/Apps/AppCommandMiddleware.cs

@ -138,6 +138,36 @@ namespace Squidex.Domain.Apps.Entities.Apps
});
}
protected Task On(AddPattern command, CommandContext context)
{
return handler.UpdateAsync<AppDomainObject>(context, a =>
{
GuardAppPattern.CanAdd(a.State.Patterns, command);
a.AddPattern(command);
});
}
protected Task On(DeletePattern command, CommandContext context)
{
return handler.UpdateAsync<AppDomainObject>(context, a =>
{
GuardAppPattern.CanDelete(a.State.Patterns, command);
a.DeletePattern(command);
});
}
protected async Task On(UpdatePattern command, CommandContext context)
{
await handler.UpdateAsync<AppDomainObject>(context, a =>
{
GuardAppPattern.CanUpdate(a.State.Patterns, command);
a.UpdatePattern(command);
});
}
protected Task On(ChangePlan command, CommandContext context)
{
return handler.UpdateSyncedAsync<AppDomainObject>(context, async a =>

27
src/Squidex.Domain.Apps.Entities/Apps/AppDomainObject.cs

@ -123,6 +123,33 @@ namespace Squidex.Domain.Apps.Entities.Apps
return this;
}
public AppDomainObject AddPattern(AddPattern command)
{
ThrowIfNotCreated();
RaiseEvent(SimpleMapper.Map(command, new AppPatternAdded()));
return this;
}
public AppDomainObject DeletePattern(DeletePattern command)
{
ThrowIfNotCreated();
RaiseEvent(SimpleMapper.Map(command, new AppPatternDeleted()));
return this;
}
public AppDomainObject UpdatePattern(UpdatePattern command)
{
ThrowIfNotCreated();
RaiseEvent(SimpleMapper.Map(command, new AppPatternUpdated()));
return this;
}
private void RaiseEvent(AppEvent @event)
{
if (@event.AppId == null)

28
src/Squidex.Domain.Apps.Entities/Apps/Commands/AddPattern.cs

@ -0,0 +1,28 @@
// ==========================================================================
// AddPattern.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
namespace Squidex.Domain.Apps.Entities.Apps.Commands
{
public sealed class AddPattern : AppAggregateCommand
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Pattern { get; set; }
public string DefaultMessage { get; set; }
public AddPattern()
{
Id = Guid.NewGuid();
}
}
}

4
src/Squidex.Domain.Apps.Entities/Apps/Commands/CreateApp.cs

@ -13,10 +13,10 @@ namespace Squidex.Domain.Apps.Entities.Apps.Commands
{
public sealed class CreateApp : SquidexCommand, IAggregateCommand
{
public string Name { get; set; }
public Guid AppId { get; set; }
public string Name { get; set; }
Guid IAggregateCommand.AggregateId
{
get { return AppId; }

17
src/Squidex.Domain.Apps.Entities/Apps/Commands/DeletePattern.cs

@ -0,0 +1,17 @@
// ==========================================================================
// DeletePattern.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
namespace Squidex.Domain.Apps.Entities.Apps.Commands
{
public sealed class DeletePattern : AppAggregateCommand
{
public Guid Id { get; set; }
}
}

23
src/Squidex.Domain.Apps.Entities/Apps/Commands/UpdatePattern.cs

@ -0,0 +1,23 @@
// ==========================================================================
// UpdatePattern.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
namespace Squidex.Domain.Apps.Entities.Apps.Commands
{
public sealed class UpdatePattern : AppAggregateCommand
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Pattern { get; set; }
public string DefaultMessage { get; set; }
}
}

97
src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppPattern.cs

@ -0,0 +1,97 @@
// ==========================================================================
// GuardAppPattern.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Linq;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Apps.Guards
{
public static class GuardAppPattern
{
public static void CanAdd(AppPatterns patterns, AddPattern command)
{
Guard.NotNull(command, nameof(command));
Validate.It(() => "Cannot add pattern.", error =>
{
if (string.IsNullOrWhiteSpace(command.Name))
{
error(new ValidationError("Pattern name can not be empty.", nameof(command.Name)));
}
if (patterns.Values.Any(x => x.Name.Equals(command.Name, StringComparison.OrdinalIgnoreCase)))
{
error(new ValidationError("Pattern name is already assigned.", nameof(command.Name)));
}
if (string.IsNullOrWhiteSpace(command.Pattern))
{
error(new ValidationError("Pattern can not be empty.", nameof(command.Pattern)));
}
else if (!command.Pattern.IsValidRegex())
{
error(new ValidationError("Pattern is not a valid regular expression.", nameof(command.Pattern)));
}
if (patterns.Values.Any(x => x.Pattern == command.Pattern))
{
error(new ValidationError("Pattern already exists.", nameof(command.Pattern)));
}
});
}
public static void CanDelete(AppPatterns patterns, DeletePattern command)
{
Guard.NotNull(command, nameof(command));
if (!patterns.ContainsKey(command.Id))
{
throw new DomainObjectNotFoundException(command.Id.ToString(), typeof(AppPattern));
}
}
public static void CanUpdate(AppPatterns patterns, UpdatePattern command)
{
Guard.NotNull(command, nameof(command));
if (!patterns.ContainsKey(command.Id))
{
throw new DomainObjectNotFoundException(command.Id.ToString(), typeof(AppPattern));
}
Validate.It(() => "Cannot update pattern.", error =>
{
if (string.IsNullOrWhiteSpace(command.Name))
{
error(new ValidationError("Pattern name can not be empty.", nameof(command.Name)));
}
if (patterns.Any(x => x.Key != command.Id && x.Value.Name.Equals(command.Name, StringComparison.OrdinalIgnoreCase)))
{
error(new ValidationError("Pattern name is already assigned.", nameof(command.Name)));
}
if (string.IsNullOrWhiteSpace(command.Pattern))
{
error(new ValidationError("Pattern can not be empty.", nameof(command.Pattern)));
}
else if (!command.Pattern.IsValidRegex())
{
error(new ValidationError("Pattern is not a valid regular expression.", nameof(command.Pattern)));
}
if (patterns.Any(x => x.Key != command.Id && x.Value.Pattern == command.Pattern))
{
error(new ValidationError("Pattern already exists.", nameof(command.Pattern)));
}
});
}
}
}

2
src/Squidex.Domain.Apps.Entities/Apps/IAppEntity.cs

@ -18,6 +18,8 @@ namespace Squidex.Domain.Apps.Entities.Apps
AppClients Clients { get; }
AppPatterns Patterns { get; }
AppContributors Contributors { get; }
LanguagesConfig LanguagesConfig { get; }

18
src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs

@ -31,6 +31,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.State
[JsonProperty]
public AppClients Clients { get; set; } = AppClients.Empty;
[JsonProperty]
public AppPatterns Patterns { get; set; } = AppPatterns.Empty;
[JsonProperty]
public AppContributors Contributors { get; set; } = AppContributors.Empty;
@ -77,6 +80,21 @@ namespace Squidex.Domain.Apps.Entities.Apps.State
Clients = Clients.Revoke(@event.Id);
}
protected void On(AppPatternAdded @event)
{
Patterns = Patterns.Add(@event.Id, @event.Name, @event.Pattern, @event.DefaultMessage);
}
protected void On(AppPatternDeleted @event)
{
Patterns = Patterns.Remove(@event.Id);
}
protected void On(AppPatternUpdated @event)
{
Patterns = Patterns.Update(@event.Id, @event.Name, @event.Pattern, @event.DefaultMessage);
}
protected void On(AppLanguageAdded @event)
{
LanguagesConfig = LanguagesConfig.Set(new LanguageConfig(@event.Language));

3
tests/Squidex.Domain.Apps.Core.Tests/Model/Apps/AppPatternsTests.cs

@ -7,7 +7,6 @@
// ==========================================================================
using System;
using System.Linq;
using FluentAssertions;
using Squidex.Domain.Apps.Core.Apps;
using Xunit;
@ -25,8 +24,6 @@ namespace Squidex.Domain.Apps.Core.Model.Apps
public AppPatternsTests()
{
defaultPatterns = AppPatterns.Empty.Add(firstId, "Default", "Default Pattern", "Message");
id = Guid.NewGuid();
}
[Fact]

44
tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppCommandMiddlewareTests.cs

@ -26,10 +26,11 @@ namespace Squidex.Domain.Apps.Entities.Apps
private readonly IAppPlansProvider appPlansProvider = A.Fake<IAppPlansProvider>();
private readonly IAppPlanBillingManager appPlansBillingManager = A.Fake<IAppPlanBillingManager>();
private readonly IUserResolver userResolver = A.Fake<IUserResolver>();
private readonly AppDomainObject app = new AppDomainObject();
private readonly Language language = Language.DE;
private readonly string contributorId = Guid.NewGuid().ToString();
private readonly string clientName = "client";
private readonly Guid patternId = Guid.NewGuid();
private readonly AppDomainObject app = new AppDomainObject();
private readonly AppCommandMiddleware sut;
protected override Guid Id
@ -232,6 +233,47 @@ namespace Squidex.Domain.Apps.Entities.Apps
});
}
[Fact]
public async Task AddPattern_should_update_domain_object()
{
CreateApp();
var context = CreateContextForCommand(new AddPattern { Name = "Any", Pattern = ".*" });
await TestUpdate(app, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task UpdatePattern_should_update_domain()
{
CreateApp()
.AddPattern(CreateCommand(new AddPattern { Id = patternId, Name = "Any", Pattern = "." }));
var context = CreateContextForCommand(new UpdatePattern { Id = patternId, Name = "Number", Pattern = "[0-9]" });
await TestUpdate(app, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task DeletePattern_should_update_domain_object()
{
CreateApp()
.AddPattern(CreateCommand(new AddPattern { Id = patternId, Name = "Any", Pattern = "." }));
var context = CreateContextForCommand(new DeletePattern { Id = patternId });
await TestUpdate(app, async _ =>
{
await sut.HandleAsync(context);
});
}
private AppDomainObject CreateApp()
{
app.Create(CreateCommand(new CreateApp { AppId = AppId, Name = AppName }));

78
tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppDomainObjectTests.cs

@ -24,6 +24,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
private readonly string clientId = "client";
private readonly string clientNewName = "My Client";
private readonly string planId = "premium";
private readonly Guid patternId = Guid.NewGuid();
private readonly AppDomainObject sut = new AppDomainObject();
protected override Guid Id
@ -281,6 +282,83 @@ namespace Squidex.Domain.Apps.Entities.Apps
);
}
[Fact]
public void AddPattern_should_throw_exception_if_app_not_created()
{
Assert.Throws<DomainException>(() => sut.AddPattern(CreateCommand(new AddPattern { Id = patternId, Name = "Any", Pattern = ".*" })));
}
[Fact]
public void AddPattern_should_create_events()
{
CreateApp();
sut.AddPattern(CreateCommand(new AddPattern { Id = patternId, Name = "Any", Pattern = ".*", DefaultMessage = "Msg" }));
Assert.Single(sut.State.Patterns);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new AppPatternAdded { Id = patternId, Name = "Any", Pattern = ".*", DefaultMessage = "Msg" })
);
}
[Fact]
public void DeletePattern_should_throw_exception_if_app_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.DeletePattern(CreateCommand(new DeletePattern
{
Id = Guid.NewGuid()
}));
});
}
[Fact]
public void DeletePattern_should_create_events()
{
CreateApp();
CreatePattern();
sut.DeletePattern(CreateCommand(new DeletePattern { Id = patternId }));
Assert.Empty(sut.State.Patterns);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new AppPatternDeleted { Id = patternId })
);
}
[Fact]
public void UpdatePattern_should_throw_exception_if_app_not_created()
{
Assert.Throws<DomainException>(() => sut.UpdatePattern(CreateCommand(new UpdatePattern { Id = patternId, Name = "Any", Pattern = ".*" })));
}
[Fact]
public void UpdatePattern_should_create_events()
{
CreateApp();
CreatePattern();
sut.UpdatePattern(CreateCommand(new UpdatePattern { Id = patternId, Name = "Any", Pattern = ".*", DefaultMessage = "Msg" }));
Assert.Single(sut.State.Patterns);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new AppPatternUpdated { Id = patternId, Name = "Any", Pattern = ".*", DefaultMessage = "Msg" })
);
}
private void CreatePattern()
{
sut.AddPattern(CreateCommand(new AddPattern { Id = patternId, Name = "Name", Pattern = ".*" }));
sut.ClearUncommittedEvents();
}
private void CreateApp()
{
sut.Create(CreateCommand(new CreateApp { Name = AppName }));

169
tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppPatternsTests.cs

@ -0,0 +1,169 @@
// ==========================================================================
// GuardAppPatternsTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Apps.Guards;
using Squidex.Infrastructure;
using Xunit;
#pragma warning disable SA1310 // Field names must not contain underscore
namespace Squidex.Domain.Apps.Write.Apps.Guards
{
public class GuardAppPatternsTests
{
private readonly Guid patternId = Guid.NewGuid();
private readonly AppPatterns patterns_0 = AppPatterns.Empty;
[Fact]
public void CanAdd_should_throw_exception_if_name_empty()
{
var command = new AddPattern { Id = patternId, Name = string.Empty, Pattern = ".*" };
Assert.Throws<ValidationException>(() => GuardAppPattern.CanAdd(patterns_0, command));
}
[Fact]
public void CanAdd_should_throw_exception_if_id_empty_guid()
{
var command = new AddPattern { Name = string.Empty, Pattern = ".*" };
Assert.Throws<ValidationException>(() => GuardAppPattern.CanAdd(patterns_0, command));
}
[Fact]
public void CanAdd_should_throw_exception_if_pattern_empty()
{
var command = new AddPattern { Id = patternId, Name = "any", Pattern = string.Empty };
Assert.Throws<ValidationException>(() => GuardAppPattern.CanAdd(patterns_0, command));
}
[Fact]
public void CanAdd_should_throw_exception_if_pattern_not_valid()
{
var command = new AddPattern { Id = patternId, Name = "any", Pattern = "[0-9{1}" };
Assert.Throws<ValidationException>(() => GuardAppPattern.CanAdd(patterns_0, command));
}
[Fact]
public void CanAdd_should_throw_exception_if_name_exists()
{
var patterns_1 = patterns_0.Add(Guid.NewGuid(), "any", "[a-z]", "Message");
var command = new AddPattern { Id = patternId, Name = "any", Pattern = ".*" };
Assert.Throws<ValidationException>(() => GuardAppPattern.CanAdd(patterns_1, command));
}
[Fact]
public void CanAdd_should_not_throw_exception_if_success()
{
var command = new AddPattern { Id = patternId, Name = "any", Pattern = ".*" };
GuardAppPattern.CanAdd(patterns_0, command);
}
[Fact]
public void CanDelete_should_throw_exception_if_pattern_not_found()
{
var command = new DeletePattern { Id = patternId };
Assert.Throws<DomainObjectNotFoundException>(() => GuardAppPattern.CanDelete(patterns_0, command));
}
[Fact]
public void CanDelete_should_not_throw_exception_if_success()
{
var patterns_1 = patterns_0.Add(patternId, "any", ".*", "Message");
var command = new DeletePattern { Id = patternId };
GuardAppPattern.CanDelete(patterns_1, command);
}
[Fact]
public void CanUpdate_should_throw_exception_if_name_empty()
{
var patterns_1 = patterns_0.Add(patternId, "any", ".*", "Message");
var command = new UpdatePattern { Id = patternId, Name = string.Empty, Pattern = ".*" };
Assert.Throws<ValidationException>(() => GuardAppPattern.CanUpdate(patterns_1, command));
}
[Fact]
public void CanUpdate_should_throw_exception_if_pattern_empty()
{
var patterns_1 = patterns_0.Add(patternId, "any", ".*", "Message");
var command = new UpdatePattern { Id = patternId, Name = "any", Pattern = string.Empty };
Assert.Throws<ValidationException>(() => GuardAppPattern.CanUpdate(patterns_1, command));
}
[Fact]
public void CanUpdate_should_throw_exception_if_pattern_not_valid()
{
var patterns_1 = patterns_0.Add(patternId, "any", ".*", "Message");
var command = new UpdatePattern { Id = patternId, Name = "any", Pattern = "[0-9{1}" };
Assert.Throws<ValidationException>(() => GuardAppPattern.CanUpdate(patterns_1, command));
}
[Fact]
public void CanUpdate_should_throw_exception_if_name_exists()
{
var id1 = Guid.NewGuid();
var id2 = Guid.NewGuid();
var patterns_1 = patterns_0.Add(id1, "Pattern1", "[0-5]", "Message");
var patterns_2 = patterns_1.Add(id2, "Pattern2", "[0-4]", "Message");
var command = new UpdatePattern { Id = id2, Name = "Pattern1", Pattern = "[0-4]" };
Assert.Throws<ValidationException>(() => GuardAppPattern.CanUpdate(patterns_2, command));
}
[Fact]
public void CanUpdate_should_throw_exception_if_pattern_exists()
{
var id1 = Guid.NewGuid();
var id2 = Guid.NewGuid();
var patterns_1 = patterns_0.Add(id1, "Pattern1", "[0-5]", "Message");
var patterns_2 = patterns_1.Add(id2, "Pattern2", "[0-4]", "Message");
var command = new UpdatePattern { Id = id2, Name = "Pattern2", Pattern = "[0-5]" };
Assert.Throws<ValidationException>(() => GuardAppPattern.CanUpdate(patterns_2, command));
}
[Fact]
public void CanUpdate_should_throw_exception_if_pattern_does_not_exists()
{
var command = new UpdatePattern { Id = patternId, Name = "Pattern1", Pattern = ".*" };
Assert.Throws<DomainObjectNotFoundException>(() => GuardAppPattern.CanUpdate(patterns_0, command));
}
[Fact]
public void CanUpdate_should_not_throw_exception_if_pattern_exist_with_valid_command()
{
var patterns_1 = patterns_0.Add(patternId, "any", ".*", "Message");
var command = new UpdatePattern { Id = patternId, Name = "Pattern1", Pattern = ".*" };
GuardAppPattern.CanUpdate(patterns_1, command);
}
}
}
Loading…
Cancel
Save