Browse Source

Validation for UI fields.

pull/359/head
Sebastian Stehle 7 years ago
parent
commit
c843f82f48
  1. 7
      src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs
  2. 13
      src/Squidex.Domain.Apps.Entities/Schemas/Guards/FieldPropertiesValidator.cs
  3. 15
      src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchema.cs
  4. 10
      src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchemaField.cs
  5. 4
      src/Squidex/app/features/schemas/pages/schema/field.component.html
  6. 14
      src/Squidex/app/theme/_bootstrap.scss
  7. 81
      tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaFieldTests.cs
  8. 39
      tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs

7
src/Squidex.Domain.Apps.Core.Model/Schemas/FieldExtensions.cs

@ -31,7 +31,12 @@ namespace Squidex.Domain.Apps.Core.Schemas
public static bool IsForApi<T>(this T field, bool withHidden = false) where T : IField
{
return (withHidden || !field.IsHidden) && !(field is IField<UIFieldProperties>);
return (withHidden || !field.IsHidden) && field.RawProperties.IsForApi();
}
public static bool IsForApi<T>(this T properties) where T : FieldProperties
{
return !(properties is UIFieldProperties);
}
public static Schema ReorderFields(this Schema schema, List<long> ids, long? parentId = null)

13
src/Squidex.Domain.Apps.Entities/Schemas/Guards/FieldPropertiesValidator.cs

@ -21,7 +21,18 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
public static IEnumerable<ValidationError> Validate(FieldProperties properties)
{
return properties?.Accept(Instance);
if (properties != null)
{
if (!properties.IsForApi() && properties.IsListField)
{
yield return new ValidationError("UI field cannot be a list field.", nameof(properties.IsListField));
}
foreach (var error in properties.Accept(Instance))
{
yield return error;
}
}
}
public IEnumerable<ValidationError> Visit(ArrayFieldProperties properties)

15
src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchema.cs

@ -13,6 +13,8 @@ using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Schemas.Commands;
using Squidex.Infrastructure;
#pragma warning disable IDE0060 // Remove unused parameter
namespace Squidex.Domain.Apps.Entities.Schemas.Guards
{
public static class GuardSchema
@ -199,6 +201,19 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
}
else
{
if (!field.Properties.IsForApi())
{
if (field.IsHidden)
{
e("UI field cannot be hidden.", $"{prefix}.{nameof(field.IsHidden)}");
}
if (field.IsDisabled)
{
e("UI field cannot be disabled.", $"{prefix}.{nameof(field.IsDisabled)}");
}
}
var errors = FieldPropertiesValidator.Validate(field.Properties);
errors.Foreach(x => x.WithPrefix($"{prefix}.{nameof(field.Properties)}").AddTo(e));

10
src/Squidex.Domain.Apps.Entities/Schemas/Guards/GuardSchemaField.cs

@ -101,6 +101,11 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
{
throw new DomainException("Schema field is already hidden.");
}
if (!field.IsForApi())
{
throw new DomainException("UI field cannot be hidden.");
}
}
public static void CanDisable(Schema schema, DisableField command)
@ -113,6 +118,11 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
{
throw new DomainException("Schema field is already disabled.");
}
if (!field.IsForApi())
{
throw new DomainException("UI field cannot be disabled.");
}
}
public static void CanDelete(Schema schema, DeleteField command)

4
src/Squidex/app/features/schemas/pages/schema/field.component.html

@ -25,7 +25,7 @@
</button>
<div class="dropdown dropdown-options">
<button type="button" class="btn btn-text-secondary ml-1" (click)="dropdown.toggle()" [class.active]="dropdown.isOpen | async" #optionsButton>
<button type="button" class="btn btn-text-secondary ml-1" (click)="dropdown.toggle()" [disabled]="!field.properties.isContentField && field.isLocked" [class.active]="dropdown.isOpen | async" #optionsButton>
<i class="icon-dots"></i>
</button>
<div class="dropdown-menu" *sqxModalView="dropdown;closeAlways:true" [sqxModalTarget]="optionsButton" @fade>
@ -45,7 +45,7 @@
</ng-container>
<ng-container *ngIf="!field.isLocked">
<div class="dropdown-divider" *ngIf="field.properties.isContentField"></div>
<div class="dropdown-divider"></div>
<a class="dropdown-item"
(sqxConfirmClick)="lockField()"

14
src/Squidex/app/theme/_bootstrap.scss

@ -197,6 +197,20 @@ a {
}
}
.dropdown-divider {
&:first-child {
display: none;
}
&:last-child {
display: none;
}
& + .dropdown-divider {
display: none;
}
}
//
// Dark vertical menu for dark panels.
//

81
tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaFieldTests.cs

@ -32,7 +32,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
.AddString(1, "field1", Partitioning.Invariant)
.AddString(2, "field2", Partitioning.Invariant)
.AddArray(3, "field3", Partitioning.Invariant, f => f
.AddNumber(301, "field301"));
.AddNumber(301, "field301"))
.AddUI(4, "field4", Partitioning.Invariant);
}
private static Action<Schema, T> A<T>(Action<Schema, T> method) where T : FieldCommand
@ -163,6 +164,32 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Assert.Throws<DomainException>(() => GuardSchemaField.CanDelete(schema_1, command));
}
[Fact]
public void CanDisable_should_throw_exception_if_already_disabled()
{
var command = new DisableField { FieldId = 1 };
var schema_1 = schema_0.UpdateField(1, f => f.Disable());
Assert.Throws<DomainException>(() => GuardSchemaField.CanDisable(schema_1, command));
}
[Fact]
public void CanDisable_should_throw_exception_if_ui_field()
{
var command = new DisableField { FieldId = 4 };
Assert.Throws<DomainException>(() => GuardSchemaField.CanDisable(schema_0, command));
}
[Fact]
public void CanEnable_should_throw_exception_if_already_enabled()
{
var command = new EnableField { FieldId = 1 };
Assert.Throws<DomainException>(() => GuardSchemaField.CanEnable(schema_0, command));
}
[Fact]
public void CanHide_should_throw_exception_if_locked()
{
@ -173,6 +200,32 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Assert.Throws<DomainException>(() => GuardSchemaField.CanHide(schema_1, command));
}
[Fact]
public void CanHide_should_throw_exception_if_already_hidden()
{
var command = new HideField { FieldId = 1 };
var schema_1 = schema_0.UpdateField(1, f => f.Hide());
Assert.Throws<DomainException>(() => GuardSchemaField.CanHide(schema_1, command));
}
[Fact]
public void CanHide_should_throw_exception_if_ui_field()
{
var command = new HideField { FieldId = 4 };
Assert.Throws<DomainException>(() => GuardSchemaField.CanHide(schema_0, command));
}
[Fact]
public void CanShow_should_throw_exception_if_already_visible()
{
var command = new ShowField { FieldId = 4 };
Assert.Throws<DomainException>(() => GuardSchemaField.CanShow(schema_0, command));
}
[Fact]
public void CanDelete_should_not_throw_exception_if_not_locked()
{
@ -199,6 +252,15 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
GuardSchemaField.CanUpdate(schema_0, command);
}
[Fact]
public void CanUpdate_should_throw_exception_if_marking_a_ui_field_as_list_field()
{
var command = new UpdateField { FieldId = 4, Properties = new UIFieldProperties { IsListField = true } };
ValidationAssert.Throws(() => GuardSchemaField.CanUpdate(schema_0, command),
new ValidationError("UI field cannot be a list field.", "Properties.IsListField"));
}
[Fact]
public void CanUpdate_should_throw_exception_if_properties_null()
{
@ -247,7 +309,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
[Fact]
public void CanAdd_should_throw_exception_if_properties_not_valid()
{
var command = new AddField { Name = "field4", Properties = invalidProperties };
var command = new AddField { Name = "field5", Properties = invalidProperties };
ValidationAssert.Throws(() => GuardSchemaField.CanAdd(schema_0, command),
new ValidationError("Max length must be greater or equal to min length.", "Properties.MinLength", "Properties.MaxLength"));
@ -256,7 +318,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
[Fact]
public void CanAdd_should_throw_exception_if_properties_null()
{
var command = new AddField { Name = "field4", Properties = null };
var command = new AddField { Name = "field5", Properties = null };
ValidationAssert.Throws(() => GuardSchemaField.CanAdd(schema_0, command),
new ValidationError("Properties is required.", "Properties"));
@ -265,12 +327,21 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
[Fact]
public void CanAdd_should_throw_exception_if_partitioning_not_valid()
{
var command = new AddField { Name = "field4", Partitioning = "INVALID_PARTITIONING", Properties = validProperties };
var command = new AddField { Name = "field5", Partitioning = "INVALID_PARTITIONING", Properties = validProperties };
ValidationAssert.Throws(() => GuardSchemaField.CanAdd(schema_0, command),
new ValidationError("Partitioning is not a valid value.", "Partitioning"));
}
[Fact]
public void CanAdd_should_throw_exception_if_creating_a_ui_field_as_list_field()
{
var command = new AddField { Name = "field5", Properties = new UIFieldProperties { IsListField = true } };
ValidationAssert.Throws(() => GuardSchemaField.CanAdd(schema_0, command),
new ValidationError("UI field cannot be a list field.", "Properties.IsListField"));
}
[Fact]
public void CanAdd_should_throw_exception_if_parent_not_exists()
{
@ -282,7 +353,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
[Fact]
public void CanAdd_should_not_throw_exception_if_field_not_exists()
{
var command = new AddField { Name = "field4", Properties = validProperties };
var command = new AddField { Name = "field5", Properties = validProperties };
GuardSchemaField.CanAdd(schema_0, command);
}

39
tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs

@ -341,6 +341,38 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
"Fields[1].Nested"));
}
[Fact]
public async Task CanCreate_should_throw_exception_if_ui_field_is_invalid()
{
var command = new CreateSchema
{
AppId = appId,
Fields = new List<UpsertSchemaField>
{
new UpsertSchemaField
{
Name = "field1",
Properties = new UIFieldProperties
{
IsListField = true
},
IsHidden = true,
IsDisabled = true,
Partitioning = Partitioning.Invariant.Key
}
},
Name = "new-schema"
};
await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider),
new ValidationError("UI field cannot be a list field.",
"Fields[1].Properties.IsListField"),
new ValidationError("UI field cannot be hidden.",
"Fields[1].IsHidden"),
new ValidationError("UI field cannot be disabled.",
"Fields[1].IsDisabled"));
}
[Fact]
public async Task CanCreate_should_not_throw_exception_if_command_is_valid()
{
@ -352,7 +384,12 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
new UpsertSchemaField
{
Name = "field1",
Properties = ValidProperties(),
Properties = new StringFieldProperties
{
IsListField = true
},
IsHidden = true,
IsDisabled = true,
Partitioning = Partitioning.Invariant.Key
},
new UpsertSchemaField

Loading…
Cancel
Save