diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/AddField.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/AddField.cs index 0bcfb726c..fb569575b 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/AddField.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/AddField.cs @@ -9,11 +9,12 @@ using System.Collections.Generic; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Write.Schemas.Guards; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Write.Schemas.Commands { - public sealed class AddField : FieldCommand, IValidatable + public sealed class AddField : SchemaAggregateCommand, IValidatable { public string Name { get; set; } @@ -37,6 +38,15 @@ namespace Squidex.Domain.Apps.Write.Schemas.Commands { errors.Add(new ValidationError("Properties must be defined.", nameof(Properties))); } + else + { + var propertyErrors = SchemaFieldGuard.ValidateProperties(Properties); + + foreach (var error in propertyErrors) + { + errors.Add(error); + } + } } } } \ No newline at end of file diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchema.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchema.cs index 0e3d646b9..3563b9e0a 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchema.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchema.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using System.Linq; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.CQRS.Commands; @@ -62,19 +63,27 @@ namespace Squidex.Domain.Apps.Write.Schemas.Commands { if (!Name.IsSlug()) { - errors.Add(new ValidationError("Name must be a valid slug", nameof(Name))); + errors.Add(new ValidationError("Name must be a valid slug.", nameof(Name))); } if (Properties == null) { - errors.Add(new ValidationError("Properties must be specified", nameof(Properties))); + errors.Add(new ValidationError("Properties must be specified.", nameof(Properties))); } - var index = 0; - - foreach (var field in Fields) + if (Fields.Any()) { - field.Validate(index++, errors); + var index = 0; + + foreach (var field in Fields) + { + field.Validate(index++, errors); + } + + if (Fields.Select(x => x.Name).Distinct().Count() != Fields.Count) + { + errors.Add(new ValidationError("Fields cannot have duplicate names.", nameof(Fields))); + } } } } diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchemaField.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchemaField.cs index b178177d1..eaac093c7 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchemaField.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchemaField.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Write.Schemas.Guards; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Write.Schemas.Commands @@ -38,13 +39,22 @@ namespace Squidex.Domain.Apps.Write.Schemas.Commands if (!Name.IsPropertyName()) { - errors.Add(new ValidationError("Name must be a valid property name", $"{prefix}.{nameof(Name)}")); + errors.Add(new ValidationError("Name must be a valid property name.", $"{prefix}.{nameof(Name)}")); } if (Properties == null) { errors.Add(new ValidationError("Properties must be defined.", $"{prefix}.{nameof(Properties)}")); } + else + { + var propertyErrors = SchemaFieldGuard.ValidateProperties(Properties); + + foreach (var error in propertyErrors) + { + errors.Add(error); + } + } } } } diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/ReorderFields.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/ReorderFields.cs index ad9124d32..c930b6f09 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/ReorderFields.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/ReorderFields.cs @@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Write.Schemas.Commands { if (FieldIds == null) { - errors.Add(new ValidationError("Field ids must be specified", nameof(FieldIds))); + errors.Add(new ValidationError("Field ids must be specified.", nameof(FieldIds))); } } } diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateSchema.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateSchema.cs index 07fd69361..4cfa1ebc3 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateSchema.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateSchema.cs @@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Write.Schemas.Commands { if (Properties == null) { - errors.Add(new ValidationError("Properties must be specified", nameof(Properties))); + errors.Add(new ValidationError("Properties must be specified.", nameof(Properties))); } } } diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Guards/SchemaFieldGuard.cs b/src/Squidex.Domain.Apps.Write/Schemas/Guards/SchemaFieldGuard.cs index 1c9a08d85..fc1cd7afc 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Guards/SchemaFieldGuard.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Guards/SchemaFieldGuard.cs @@ -6,6 +6,7 @@ // All rights reserved. // ========================================================================== +using System; using System.Collections.Generic; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; @@ -14,11 +15,11 @@ namespace Squidex.Domain.Apps.Write.Schemas.Guards { public static class SchemaFieldGuard { - public static void GuardValidSchemaFieldName(string name) + public static void GuardCanAdd(Schema schema, string name) { if (!name.IsSlug()) { - var error = new ValidationError("Name must be a valid slug", "Name"); + var error = new ValidationError("Name must be a valid slug.", "Name"); throw new ValidationException("Cannot add a new field.", error); } @@ -102,7 +103,7 @@ namespace Squidex.Domain.Apps.Write.Schemas.Guards { if (a.MaxItems.HasValue && a.MinItems.HasValue && a.MinItems.Value >= a.MaxItems.Value) { - yield return new ValidationError("Max items must be greater than min items", + yield return new ValidationError("Max items must be greater than min items.", nameof(a.MinItems), nameof(a.MaxItems)); } @@ -114,7 +115,7 @@ namespace Squidex.Domain.Apps.Write.Schemas.Guards { if (!b.Editor.IsEnumValue()) { - yield return new ValidationError("Editor is not a valid value", + yield return new ValidationError("Editor is not a valid value.", nameof(b.Editor)); } @@ -125,7 +126,7 @@ namespace Squidex.Domain.Apps.Write.Schemas.Guards { if (!g.Editor.IsEnumValue()) { - yield return new ValidationError("Editor is not a valid value", + yield return new ValidationError("Editor is not a valid value.", nameof(g.Editor)); } @@ -136,7 +137,7 @@ namespace Squidex.Domain.Apps.Write.Schemas.Guards { if (r.MaxItems.HasValue && r.MinItems.HasValue && r.MinItems.Value >= r.MaxItems.Value) { - yield return new ValidationError("Max items must be greater than min items", + yield return new ValidationError("Max items must be greater than min items.", nameof(r.MinItems), nameof(r.MaxItems)); } @@ -148,25 +149,25 @@ namespace Squidex.Domain.Apps.Write.Schemas.Guards { if (!d.Editor.IsEnumValue()) { - yield return new ValidationError("Editor is not a valid value", + yield return new ValidationError("Editor is not a valid value.", nameof(d.Editor)); } if (d.DefaultValue.HasValue && d.MinValue.HasValue && d.DefaultValue.Value < d.MinValue.Value) { - yield return new ValidationError("Default value must be greater than min value", + yield return new ValidationError("Default value must be greater than min value.", nameof(d.DefaultValue)); } if (d.DefaultValue.HasValue && d.MaxValue.HasValue && d.DefaultValue.Value > d.MaxValue.Value) { - yield return new ValidationError("Default value must be less than max value", + yield return new ValidationError("Default value must be less than max value.", nameof(d.DefaultValue)); } if (d.MaxValue.HasValue && d.MinValue.HasValue && d.MinValue.Value >= d.MaxValue.Value) { - yield return new ValidationError("Max value must be greater than min value", + yield return new ValidationError("Max value must be greater than min value.", nameof(d.MinValue), nameof(d.MaxValue)); } @@ -175,13 +176,13 @@ namespace Squidex.Domain.Apps.Write.Schemas.Guards { if (!d.CalculatedDefaultValue.Value.IsEnumValue()) { - yield return new ValidationError("Calculated default value is not valid", + yield return new ValidationError("Calculated default value is not valid.", nameof(d.CalculatedDefaultValue)); } if (d.DefaultValue.HasValue) { - yield return new ValidationError("Calculated default value and default value cannot be used together", + yield return new ValidationError("Calculated default value and default value cannot be used together.", nameof(d.CalculatedDefaultValue), nameof(d.DefaultValue)); } @@ -194,38 +195,38 @@ namespace Squidex.Domain.Apps.Write.Schemas.Guards { if (!n.Editor.IsEnumValue()) { - yield return new ValidationError("Editor is not a valid value", + yield return new ValidationError("Editor is not a valid value.", nameof(n.Editor)); } if ((n.Editor == NumberFieldEditor.Radio || n.Editor == NumberFieldEditor.Dropdown) && (n.AllowedValues == null || n.AllowedValues.Count == 0)) { - yield return new ValidationError("Radio buttons or dropdown list need allowed values", + yield return new ValidationError("Radio buttons or dropdown list need allowed values.", nameof(n.AllowedValues)); } if (n.DefaultValue.HasValue && n.MinValue.HasValue && n.DefaultValue.Value < n.MinValue.Value) { - yield return new ValidationError("Default value must be greater than min value", + yield return new ValidationError("Default value must be greater than min value.", nameof(n.DefaultValue)); } if (n.DefaultValue.HasValue && n.MaxValue.HasValue && n.DefaultValue.Value > n.MaxValue.Value) { - yield return new ValidationError("Default value must be less than max value", + yield return new ValidationError("Default value must be less than max value.", nameof(n.DefaultValue)); } if (n.MaxValue.HasValue && n.MinValue.HasValue && n.MinValue.Value >= n.MaxValue.Value) { - yield return new ValidationError("Max value must be greater than min value", + yield return new ValidationError("Max value must be greater than min value.", nameof(n.MinValue), nameof(n.MaxValue)); } if (n.AllowedValues != null && n.AllowedValues.Count > 0 && (n.MinValue.HasValue || n.MaxValue.HasValue)) { - yield return new ValidationError("Either allowed values or min and max value can be defined", + yield return new ValidationError("Either allowed values or min and max value can be defined.", nameof(n.AllowedValues), nameof(n.MinValue), nameof(n.MaxValue)); @@ -238,32 +239,32 @@ namespace Squidex.Domain.Apps.Write.Schemas.Guards { if (!s.Editor.IsEnumValue()) { - yield return new ValidationError("Editor is not a valid value", + yield return new ValidationError("Editor is not a valid value.", nameof(s.Editor)); } if ((s.Editor == StringFieldEditor.Radio || s.Editor == StringFieldEditor.Dropdown) && (s.AllowedValues == null || s.AllowedValues.Count == 0)) { - yield return new ValidationError("Radio buttons or dropdown list need allowed values", + yield return new ValidationError("Radio buttons or dropdown list need allowed values.", nameof(s.AllowedValues)); } if (s.Pattern != null && !s.Pattern.IsValidRegex()) { - yield return new ValidationError("Pattern is not a valid expression", + yield return new ValidationError("Pattern is not a valid expression.", nameof(s.Pattern)); } if (s.MaxLength.HasValue && s.MinLength.HasValue && s.MinLength.Value >= s.MaxLength.Value) { - yield return new ValidationError("Max length must be greater than min length", + yield return new ValidationError("Max length must be greater than min length.", nameof(s.MinLength), nameof(s.MaxLength)); } if (s.AllowedValues != null && s.AllowedValues.Count > 0 && (s.MinLength.HasValue || s.MaxLength.HasValue)) { - yield return new ValidationError("Either allowed values or min and max length can be defined", + yield return new ValidationError("Either allowed values or min and max length can be defined.", nameof(s.AllowedValues), nameof(s.MinLength), nameof(s.MaxLength)); diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Guards/SchemaGuard.cs b/src/Squidex.Domain.Apps.Write/Schemas/Guards/SchemaGuard.cs index 6b1d1f43f..e490e1a21 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Guards/SchemaGuard.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Guards/SchemaGuard.cs @@ -6,6 +6,8 @@ // All rights reserved. // ========================================================================== +using System; +using System.Collections.Generic; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; @@ -17,12 +19,17 @@ namespace Squidex.Domain.Apps.Write.Schemas.Guards { if (!name.IsSlug()) { - var error = new ValidationError("Name must be a valid slug", "Name"); + var error = new ValidationError("Name must be a valid slug.", "Name"); throw new ValidationException("Cannot create a new schema", error); } } + internal static void GuardCanReorder(Schema schema, List fieldIds) + { + throw new NotImplementedException(); + } + public static void GuardCanPublish(Schema schema) { if (schema.IsPublished) diff --git a/src/Squidex.Domain.Apps.Write/Schemas/SchemaDomainObject.cs b/src/Squidex.Domain.Apps.Write/Schemas/SchemaDomainObject.cs index 85da26c26..336cb87c5 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/SchemaDomainObject.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/SchemaDomainObject.cs @@ -12,6 +12,7 @@ using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Events.Schemas; using Squidex.Domain.Apps.Events.Schemas.Utils; using Squidex.Domain.Apps.Write.Schemas.Commands; +using Squidex.Domain.Apps.Write.Schemas.Guards; using Squidex.Infrastructure; using Squidex.Infrastructure.CQRS; using Squidex.Infrastructure.CQRS.Events; @@ -150,6 +151,8 @@ namespace Squidex.Domain.Apps.Write.Schemas VerifyCreatedAndNotDeleted(); + SchemaFieldGuard.GuardCanAdd(schema, command.Name); + RaiseEvent(SimpleMapper.Map(command, new FieldAdded { FieldId = new NamedId(totalFields + 1, command.Name) })); return this; @@ -161,29 +164,9 @@ namespace Squidex.Domain.Apps.Write.Schemas VerifyCreatedAndNotDeleted(); - RaiseEvent(command, SimpleMapper.Map(command, new FieldUpdated())); - - return this; - } - - public SchemaDomainObject Reorder(ReorderFields command) - { - Guard.Valid(command, nameof(command), () => $"Cannot reorder fields for schema '{Id}'"); - - VerifyCreatedAndNotDeleted(); - - RaiseEvent(SimpleMapper.Map(command, new SchemaFieldsReordered())); - - return this; - } - - public SchemaDomainObject Update(UpdateSchema command) - { - Guard.Valid(command, nameof(command), () => $"Cannot update schema '{Id}'"); - - VerifyCreatedAndNotDeleted(); + SchemaFieldGuard.GuardCanDelete(schema, command.FieldId); - RaiseEvent(SimpleMapper.Map(command, new SchemaUpdated())); + RaiseEvent(command, SimpleMapper.Map(command, new FieldUpdated())); return this; } @@ -194,6 +177,8 @@ namespace Squidex.Domain.Apps.Write.Schemas VerifyCreatedAndNotDeleted(); + SchemaFieldGuard.GuardCanLock(schema, command.FieldId); + RaiseEvent(command, new FieldLocked()); return this; @@ -205,6 +190,8 @@ namespace Squidex.Domain.Apps.Write.Schemas VerifyCreatedAndNotDeleted(); + SchemaFieldGuard.GuardCanHide(schema, command.FieldId); + RaiseEvent(command, new FieldHidden()); return this; @@ -216,6 +203,8 @@ namespace Squidex.Domain.Apps.Write.Schemas VerifyCreatedAndNotDeleted(); + SchemaFieldGuard.GuardCanShow(schema, command.FieldId); + RaiseEvent(command, new FieldShown()); return this; @@ -227,6 +216,8 @@ namespace Squidex.Domain.Apps.Write.Schemas VerifyCreatedAndNotDeleted(); + SchemaFieldGuard.GuardCanDisable(schema, command.FieldId); + RaiseEvent(command, new FieldDisabled()); return this; @@ -238,6 +229,8 @@ namespace Squidex.Domain.Apps.Write.Schemas VerifyCreatedAndNotDeleted(); + SchemaFieldGuard.GuardCanEnable(schema, command.FieldId); + RaiseEvent(command, new FieldEnabled()); return this; @@ -249,17 +242,34 @@ namespace Squidex.Domain.Apps.Write.Schemas VerifyCreatedAndNotDeleted(); + SchemaFieldGuard.GuardCanDelete(schema, command.FieldId); + RaiseEvent(command, new FieldDeleted()); return this; } + public SchemaDomainObject Reorder(ReorderFields command) + { + Guard.Valid(command, nameof(command), () => $"Cannot reorder fields for schema '{Id}'"); + + VerifyCreatedAndNotDeleted(); + + SchemaGuard.GuardCanReorder(schema, command.FieldIds); + + RaiseEvent(SimpleMapper.Map(command, new SchemaFieldsReordered())); + + return this; + } + public SchemaDomainObject Publish(PublishSchema command) { Guard.NotNull(command, nameof(command)); VerifyCreatedAndNotDeleted(); + SchemaGuard.GuardCanPublish(schema); + RaiseEvent(SimpleMapper.Map(command, new SchemaPublished())); return this; @@ -271,6 +281,8 @@ namespace Squidex.Domain.Apps.Write.Schemas VerifyCreatedAndNotDeleted(); + SchemaGuard.GuardCanUnpublish(schema); + RaiseEvent(SimpleMapper.Map(command, new SchemaUnpublished())); return this; @@ -296,6 +308,17 @@ namespace Squidex.Domain.Apps.Write.Schemas return this; } + public SchemaDomainObject Update(UpdateSchema command) + { + Guard.Valid(command, nameof(command), () => $"Cannot update schema '{Id}'"); + + VerifyCreatedAndNotDeleted(); + + RaiseEvent(SimpleMapper.Map(command, new SchemaUpdated())); + + return this; + } + protected void RaiseEvent(FieldCommand fieldCommand, FieldEvent @event) { SimpleMapper.Map(fieldCommand, @event);