diff --git a/src/Squidex.Events/Assets/AssetCreated.cs b/src/Squidex.Events/Assets/AssetCreated.cs new file mode 100644 index 000000000..377609575 --- /dev/null +++ b/src/Squidex.Events/Assets/AssetCreated.cs @@ -0,0 +1,18 @@ +// ========================================================================== +// AssetCreated.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using Squidex.Infrastructure; + +namespace Squidex.Events.Assets +{ + [TypeName("AssetCreatedEvent")] + public class AssetCreated : AssetEvent + { + public string Name { get; set; } + } +} diff --git a/src/Squidex.Events/Assets/AssetDeleted.cs b/src/Squidex.Events/Assets/AssetDeleted.cs new file mode 100644 index 000000000..6299e5ce4 --- /dev/null +++ b/src/Squidex.Events/Assets/AssetDeleted.cs @@ -0,0 +1,17 @@ +// ========================================================================== +// AssetDeleted.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using Squidex.Infrastructure; + +namespace Squidex.Events.Assets +{ + [TypeName("AssetDeletedEvent")] + public sealed class AssetDeleted : AssetEvent + { + } +} diff --git a/src/Squidex.Events/Assets/AssetEvent.cs b/src/Squidex.Events/Assets/AssetEvent.cs new file mode 100644 index 000000000..f09c85a94 --- /dev/null +++ b/src/Squidex.Events/Assets/AssetEvent.cs @@ -0,0 +1,18 @@ +// ========================================================================== +// AssertEvent.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using System; +using Squidex.Infrastructure.CQRS.Events; + +namespace Squidex.Events.Assets +{ + public abstract class AssetEvent : IEvent + { + public Guid AssetId { get; set; } + } +} diff --git a/src/Squidex.Events/Assets/AssetRenamed.cs b/src/Squidex.Events/Assets/AssetRenamed.cs new file mode 100644 index 000000000..8eaea32f0 --- /dev/null +++ b/src/Squidex.Events/Assets/AssetRenamed.cs @@ -0,0 +1,18 @@ +// ========================================================================== +// AssetRenamed.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using Squidex.Infrastructure; + +namespace Squidex.Events.Assets +{ + [TypeName("AssetRenamedEvent")] + public class AssetRenamed : AssetEvent + { + public string Name { get; set; } + } +} diff --git a/src/Squidex.Write/Assets/AssetDomainObject.cs b/src/Squidex.Write/Assets/AssetDomainObject.cs new file mode 100644 index 000000000..fffa687fe --- /dev/null +++ b/src/Squidex.Write/Assets/AssetDomainObject.cs @@ -0,0 +1,118 @@ +// ========================================================================== +// AssetDomainObject.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using System; +using Squidex.Events.Assets; +using Squidex.Infrastructure; +using Squidex.Infrastructure.CQRS; +using Squidex.Infrastructure.CQRS.Events; +using Squidex.Infrastructure.Dispatching; +using Squidex.Infrastructure.Reflection; +using Squidex.Write.Assets.Commands; + +namespace Squidex.Write.Assets +{ + public class AssetDomainObject : DomainObject + { + private bool isDeleted; + private string name; + + public bool IsDeleted + { + get { return isDeleted; } + } + + public string Name + { + get { return name; } + } + + public AssetDomainObject(Guid id, int version) + : base(id, version) + { + } + + protected void On(AssetCreated @event) + { + name = @event.Name; + } + + protected void On(AssetRenamed @event) + { + name = @event.Name; + } + + protected void On(AssetDeleted @event) + { + isDeleted = true; + } + + public AssetDomainObject Create(CreateAsset command) + { + Guard.Valid(command, nameof(command), () => "Cannot create content"); + + VerifyNotCreated(); + + RaiseEvent(SimpleMapper.Map(command, new AssetCreated())); + + return this; + } + + public AssetDomainObject Delete(DeleteAsset command) + { + Guard.NotNull(command, nameof(command)); + + VerifyCreatedAndNotDeleted(); + + RaiseEvent(SimpleMapper.Map(command, new AssetDeleted())); + + return this; + } + + public AssetDomainObject Rename(RenameAsset command) + { + Guard.NotNull(command, nameof(command)); + + VerifyCreatedAndNotDeleted(); + VerifyDifferentNames(command.Name, () => "Cannot rename asset."); + + RaiseEvent(SimpleMapper.Map(command, new AssetRenamed())); + + return this; + } + + private void VerifyDifferentNames(string newName, Func message) + { + if (string.Equals(name, newName)) + { + throw new ValidationException(message(), new ValidationError("The asset already has this name.", "Name")); + } + } + + private void VerifyNotCreated() + { + if (!string.IsNullOrWhiteSpace(name)) + { + throw new DomainException("Asset has already been created."); + } + } + + private void VerifyCreatedAndNotDeleted() + { + if (isDeleted || !string.IsNullOrWhiteSpace(name)) + { + throw new DomainException("Asset has already been deleted or not created yet."); + } + } + + protected override void DispatchEvent(Envelope @event) + { + this.DispatchAction(@event.Payload); + } + } +} diff --git a/src/Squidex.Write/Assets/Commands/AssetAggregateCommand.cs b/src/Squidex.Write/Assets/Commands/AssetAggregateCommand.cs new file mode 100644 index 000000000..10d70b1c1 --- /dev/null +++ b/src/Squidex.Write/Assets/Commands/AssetAggregateCommand.cs @@ -0,0 +1,23 @@ +// ========================================================================== +// AssetAggregateCommand.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using System; +using Squidex.Infrastructure.CQRS.Commands; + +namespace Squidex.Write.Assets.Commands +{ + public abstract class AssetAggregateCommand : AppCommand, IAggregateCommand + { + public Guid AssetId { get; set; } + + Guid IAggregateCommand.AggregateId + { + get { return AssetId; } + } + } +} diff --git a/src/Squidex.Write/Assets/Commands/CreateAsset.cs b/src/Squidex.Write/Assets/Commands/CreateAsset.cs new file mode 100644 index 000000000..74b9af323 --- /dev/null +++ b/src/Squidex.Write/Assets/Commands/CreateAsset.cs @@ -0,0 +1,26 @@ +// ========================================================================== +// CreateAsset.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using System.Collections.Generic; +using Squidex.Infrastructure; + +namespace Squidex.Write.Assets.Commands +{ + public sealed class CreateAsset : AssetAggregateCommand, IValidatable + { + public string Name { get; set; } + + public void Validate(IList errors) + { + if (!Name.IsSlug()) + { + errors.Add(new ValidationError("Name must be a valid slug", nameof(Name))); + } + } + } +} diff --git a/src/Squidex.Write/Assets/Commands/DeleteAsset.cs b/src/Squidex.Write/Assets/Commands/DeleteAsset.cs new file mode 100644 index 000000000..f362e7a7d --- /dev/null +++ b/src/Squidex.Write/Assets/Commands/DeleteAsset.cs @@ -0,0 +1,14 @@ +// ========================================================================== +// DeleteAsset.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +namespace Squidex.Write.Assets.Commands +{ + public sealed class DeleteAsset : AssetAggregateCommand + { + } +} diff --git a/src/Squidex.Write/Assets/Commands/RenameAsset.cs b/src/Squidex.Write/Assets/Commands/RenameAsset.cs new file mode 100644 index 000000000..078a8fc31 --- /dev/null +++ b/src/Squidex.Write/Assets/Commands/RenameAsset.cs @@ -0,0 +1,26 @@ +// ========================================================================== +// RenameAsset.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using System.Collections.Generic; +using Squidex.Infrastructure; + +namespace Squidex.Write.Assets.Commands +{ + public sealed class RenameAsset : AssetAggregateCommand, IValidatable + { + public string Name { get; set; } + + public void Validate(IList errors) + { + if (!string.IsNullOrWhiteSpace(Name)) + { + errors.Add(new ValidationError("Name must not be null or empty.", nameof(Name))); + } + } + } +}