From e64619ea7cda4148be69b942f884681f064ef8ee Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 21 Sep 2021 19:21:53 +0200 Subject: [PATCH] Simplify schema builders and add missing field builders. --- .../Samples/Middleware/TemplateInstance.cs | 21 +++-- .../Samples/Middleware/TemplateMiddleware.cs | 21 +++-- .../Templates/Builders/ArrayFieldBuilder.cs | 84 +++++++++++++----- .../Templates/Builders/AssetFieldBuilder.cs | 37 +------- .../Templates/Builders/BooleanFieldBuilder.cs | 17 +--- .../Builders/ComponentFieldBuilder.cs | 20 +++++ .../Builders/ComponentsFieldBuilder.cs | 20 +++++ .../Builders/DateTimeFieldBuilder.cs | 17 +--- .../Apps/Templates/Builders/FieldBuilder.cs | 51 ++++++----- .../Templates/Builders/JsonFieldBuilder.cs | 7 +- .../Templates/Builders/NumberFieldBuilder.cs | 7 +- .../Builders/ReferencesFieldBuilder.cs | 18 +--- .../Apps/Templates/Builders/SchemaBuilder.cs | 76 ++++++++++------ .../Templates/Builders/StringFieldBuilder.cs | 73 +-------------- .../Templates/Builders/TagsFieldBuilder.cs | 17 +--- .../Apps/Templates/Builders/UIFieldBuilder.cs | 20 +++++ .../Apps/Templates/CreateBlog.cs | 21 ++++- .../Apps/Templates/CreateProfile.cs | 70 ++++++++++++--- .../History/NotifoService.cs | 88 ++++++++----------- 19 files changed, 374 insertions(+), 311 deletions(-) create mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentFieldBuilder.cs create mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentsFieldBuilder.cs create mode 100644 backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/UIFieldBuilder.cs diff --git a/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateInstance.cs b/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateInstance.cs index 4e7c53d1b..0bf014a78 100644 --- a/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateInstance.cs +++ b/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateInstance.cs @@ -6,6 +6,7 @@ // ========================================================================== using System.Threading.Tasks; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Apps.Templates; using Squidex.Domain.Apps.Entities.Apps.Templates.Builders; @@ -20,16 +21,26 @@ namespace Squidex.Extensions.Samples.Middleware var schema = SchemaBuilder.Create("Blogs") .AddString("Title", f => f - .Length(100) + .Properties(p => p with + { + MaxLength = 100 + }) .Required()) .AddString("Slug", f => f - .Length(100) + .Properties(p => p with + { + MaxLength = 100 + }) .Required() .Disabled()) .AddString("Text", f => f - .Length(1000) - .Required() - .AsRichText()) + .Properties(p => p with + { + Editor = StringFieldEditor.RichText, + MaxLength = 1000, + MinLength = 200 + }) + .Required()) .Build(); return publish(schema); diff --git a/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateMiddleware.cs b/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateMiddleware.cs index 60736e1b2..0e9e43bb8 100644 --- a/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateMiddleware.cs +++ b/backend/extensions/Squidex.Extensions/Samples/Middleware/TemplateMiddleware.cs @@ -7,6 +7,7 @@ using System; using System.Threading.Tasks; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Templates.Builders; @@ -35,16 +36,26 @@ namespace Squidex.Extensions.Samples.Middleware var schema = SchemaBuilder.Create("Pages") .AddString("Title", f => f - .Length(100) + .Properties(p => p with + { + MaxLength = 100 + }) .Required()) .AddString("Slug", f => f - .Length(100) + .Properties(p => p with + { + MaxLength = 100 + }) .Required() .Disabled()) .AddString("Text", f => f - .Length(1000) - .Required() - .AsRichText()) + .Properties(p => p with + { + Editor = StringFieldEditor.RichText, + MaxLength = 1000, + MinLength = 200 + }) + .Required()) .Build(); await publish(schema); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ArrayFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ArrayFieldBuilder.cs index 6ccf9028c..ae0688bc7 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ArrayFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ArrayFieldBuilder.cs @@ -13,96 +13,134 @@ using Squidex.Text; namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { - public class ArrayFieldBuilder : FieldBuilder + public sealed class ArrayFieldBuilder : FieldBuilder { private UpsertSchemaField TypedField { get => (UpsertSchemaField)Field; } - public ArrayFieldBuilder(UpsertSchemaField field, CreateSchema schema) - : base(field, schema) + public ArrayFieldBuilder(UpsertSchemaField field, ArrayFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) { } public ArrayFieldBuilder AddAssets(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new AssetFieldBuilder(field, Schema)); + configure(new AssetFieldBuilder(field, properties, Schema)); return this; } public ArrayFieldBuilder AddBoolean(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new BooleanFieldBuilder(field, Schema)); + configure(new BooleanFieldBuilder(field, properties, Schema)); return this; } public ArrayFieldBuilder AddDateTime(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new DateTimeFieldBuilder(field, Schema)); + configure(new DateTimeFieldBuilder(field, properties, Schema)); + + return this; + } + + public ArrayFieldBuilder AddComponent(string name, Action configure) + { + var (field, properties) = AddField(name); + + configure(new ComponentFieldBuilder(field, properties, Schema)); + + return this; + } + + public ArrayFieldBuilder AddComponents(string name, Action configure) + { + var (field, properties) = AddField(name); + + configure(new ComponentsFieldBuilder(field, properties, Schema)); return this; } public ArrayFieldBuilder AddJson(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new JsonFieldBuilder(field, Schema)); + configure(new JsonFieldBuilder(field, properties, Schema)); return this; } public ArrayFieldBuilder AddNumber(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new NumberFieldBuilder(field, Schema)); + configure(new NumberFieldBuilder(field, properties, Schema)); return this; } public ArrayFieldBuilder AddReferences(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new ReferencesFieldBuilder(field, Schema)); + configure(new ReferencesFieldBuilder(field, properties, Schema)); return this; } public ArrayFieldBuilder AddString(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new StringFieldBuilder(field, Schema)); + configure(new StringFieldBuilder(field, properties, Schema)); return this; } - private UpsertSchemaNestedField AddField(string name) where T : FieldProperties, new() + public ArrayFieldBuilder AddTags(string name, Action configure) { + var (field, properties) = AddField(name); + + configure(new TagsFieldBuilder(field, properties, Schema)); + + return this; + } + + public ArrayFieldBuilder AddUI(string name, Action configure) + { + var (field, properties) = AddField(name); + + configure(new UIFieldBuilder(field, properties, Schema)); + + return this; + } + + private (UpsertSchemaNestedField, T) AddField(string name) where T : FieldProperties, new() + { + var properties = new T + { + Label = name + }; + var nestedField = new UpsertSchemaNestedField { Name = name.ToCamelCase(), - Properties = new T - { - Label = name - } + Properties = properties }; TypedField.Nested ??= Array.Empty(); TypedField.Nested = TypedField.Nested.Union(new[] { nestedField }).ToArray(); - return nestedField; + return (nestedField, properties); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs index 346e248c8..47648668c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/AssetFieldBuilder.cs @@ -5,47 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Schemas.Commands; namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { - public class AssetFieldBuilder : FieldBuilder + public sealed class AssetFieldBuilder : FieldBuilder { - public AssetFieldBuilder(UpsertSchemaFieldBase field, CreateSchema schema) - : base(field, schema) + public AssetFieldBuilder(UpsertSchemaFieldBase field, AssetsFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) { } - - public AssetFieldBuilder MustBeImage() - { - Properties(p => p with - { - ExpectedType = AssetType.Image - }); - - return this; - } - - public AssetFieldBuilder MustBe(AssetType type) - { - Properties(p => p with - { - ExpectedType = type - }); - - return this; - } - - public AssetFieldBuilder RequireSingle() - { - Properties(p => p with - { - MaxItems = 1 - }); - - return this; - } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs index d1cab5e80..1b3f93d02 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/BooleanFieldBuilder.cs @@ -10,22 +10,11 @@ using Squidex.Domain.Apps.Entities.Schemas.Commands; namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { - public class BooleanFieldBuilder : FieldBuilder + public sealed class BooleanFieldBuilder : FieldBuilder { - public BooleanFieldBuilder(UpsertSchemaFieldBase field, CreateSchema schema) - : base(field, schema) + public BooleanFieldBuilder(UpsertSchemaFieldBase field, BooleanFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) { } - - public BooleanFieldBuilder AsToggle() - { - Properties(p => p with - { - Editor = BooleanFieldEditor.Toggle, - EditorUrl = null - }); - - return this; - } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentFieldBuilder.cs new file mode 100644 index 000000000..6704f03f0 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentFieldBuilder.cs @@ -0,0 +1,20 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Entities.Schemas.Commands; + +namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders +{ + public sealed class ComponentFieldBuilder : FieldBuilder + { + public ComponentFieldBuilder(UpsertSchemaFieldBase field, ComponentFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) + { + } + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentsFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentsFieldBuilder.cs new file mode 100644 index 000000000..0d8a6581a --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ComponentsFieldBuilder.cs @@ -0,0 +1,20 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Entities.Schemas.Commands; + +namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders +{ + public sealed class ComponentsFieldBuilder : FieldBuilder + { + public ComponentsFieldBuilder(UpsertSchemaFieldBase field, ComponentsFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) + { + } + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs index 4ed161cd7..862f5964b 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/DateTimeFieldBuilder.cs @@ -10,22 +10,11 @@ using Squidex.Domain.Apps.Entities.Schemas.Commands; namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { - public class DateTimeFieldBuilder : FieldBuilder + public sealed class DateTimeFieldBuilder : FieldBuilder { - public DateTimeFieldBuilder(UpsertSchemaFieldBase field, CreateSchema schema) - : base(field, schema) + public DateTimeFieldBuilder(UpsertSchemaFieldBase field, DateTimeFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) { } - - public DateTimeFieldBuilder AsDateTime() - { - Properties(p => p with - { - Editor = DateTimeFieldEditor.DateTime, - EditorUrl = null - }); - - return this; - } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs index f0b5615bb..23e04a59f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/FieldBuilder.cs @@ -15,59 +15,68 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders public abstract class FieldBuilder { protected UpsertSchemaFieldBase Field { get; init; } + protected CreateSchema Schema { get; init; } } - public abstract class FieldBuilder : FieldBuilder - where T : FieldBuilder + public abstract class FieldBuilder : FieldBuilder where T : FieldBuilder where TProperties : FieldProperties { - protected FieldBuilder(UpsertSchemaFieldBase field, CreateSchema schema) + private TProperties properties; + + protected FieldBuilder(UpsertSchemaFieldBase field, TProperties properties, CreateSchema schema) { + this.properties = properties; + Field = field; Schema = schema; } - public T Label(string? label) + public T Localizable() { - Field.Properties = Field.Properties with { Label = label }; + if (Field is UpsertSchemaField localizableField) + { + localizableField.Partitioning = Partitioning.Language.Key; + } return (T)(object)this; } - public T Hints(string? hints) + public T Disabled(bool isDisabled = true) { - Field.Properties = Field.Properties with { Hints = hints }; + Field.IsDisabled = isDisabled; return (T)(object)this; } - public T Localizable() + public T Hidden(bool isHidden = true) { - if (Field is UpsertSchemaField localizableField) - { - localizableField.Partitioning = Partitioning.Language.Key; - } + Field.IsHidden = isHidden; return (T)(object)this; } - public T Disabled() + public T Label(string? label) { - Field.IsDisabled = true; - - return (T)(object)this; + return Properties(x => x with { Label = label }); } - public T Required() + public T Hints(string? hints) { - Field.Properties = Field.Properties with { IsRequired = true }; + return Properties(x => x with { Hints = hints }); + } - return (T)(object)this; + public T Required(bool isRequired = true) + { + return Properties(x => x with { IsRequired = isRequired }); } - protected void Properties(Func updater) where TProperties : FieldProperties + public T Properties(Func updater) { - Field.Properties = updater((TProperties)Field.Properties); + properties = updater(properties); + + Field.Properties = properties; + + return (T)(object)this; } public T ShowInList() diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs index 672c86407..7cd234bd2 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/JsonFieldBuilder.cs @@ -5,14 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Schemas.Commands; namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { - public class JsonFieldBuilder : FieldBuilder + public sealed class JsonFieldBuilder : FieldBuilder { - public JsonFieldBuilder(UpsertSchemaFieldBase field, CreateSchema schema) - : base(field, schema) + public JsonFieldBuilder(UpsertSchemaFieldBase field, JsonFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs index 7cb33b243..e4050488e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/NumberFieldBuilder.cs @@ -5,14 +5,15 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Schemas.Commands; namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { - public class NumberFieldBuilder : FieldBuilder + public sealed class NumberFieldBuilder : FieldBuilder { - public NumberFieldBuilder(UpsertSchemaFieldBase field, CreateSchema schema) - : base(field, schema) + public NumberFieldBuilder(UpsertSchemaFieldBase field, NumberFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) { } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ReferencesFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ReferencesFieldBuilder.cs index 0979dfdef..8241ec868 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ReferencesFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/ReferencesFieldBuilder.cs @@ -7,26 +7,14 @@ using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Schemas.Commands; -using Squidex.Infrastructure; -using Squidex.Infrastructure.Collections; namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { - public class ReferencesFieldBuilder : FieldBuilder + public sealed class ReferencesFieldBuilder : FieldBuilder { - public ReferencesFieldBuilder(UpsertSchemaFieldBase field, CreateSchema schema) - : base(field, schema) + public ReferencesFieldBuilder(UpsertSchemaFieldBase field, ReferencesFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) { } - - public ReferencesFieldBuilder WithSchemaId(DomainId id) - { - Properties(p => p with - { - SchemaIds = ImmutableList.Create(id) - }); - - return this; - } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs index 7757cab14..140d0b51f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs @@ -67,96 +67,122 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders return this; } + public SchemaBuilder AddArray(string name, Action configure) + { + var (field, properties) = AddField(name); + + configure(new ArrayFieldBuilder(field, properties, command)); + + return this; + } + public SchemaBuilder AddAssets(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new AssetFieldBuilder(field, command)); + configure(new AssetFieldBuilder(field, properties, command)); return this; } public SchemaBuilder AddBoolean(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new BooleanFieldBuilder(field, command)); + configure(new BooleanFieldBuilder(field, properties, command)); + + return this; + } + + public SchemaBuilder AddComponent(string name, Action configure) + { + var (field, properties) = AddField(name); + + configure(new ComponentFieldBuilder(field, properties, command)); + + return this; + } + + public SchemaBuilder AddComponents(string name, Action configure) + { + var (field, properties) = AddField(name); + + configure(new ComponentsFieldBuilder(field, properties, command)); return this; } public SchemaBuilder AddDateTime(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new DateTimeFieldBuilder(field, command)); + configure(new DateTimeFieldBuilder(field, properties, command)); return this; } public SchemaBuilder AddJson(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new JsonFieldBuilder(field, command)); + configure(new JsonFieldBuilder(field, properties, command)); return this; } public SchemaBuilder AddNumber(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new NumberFieldBuilder(field, command)); + configure(new NumberFieldBuilder(field, properties, command)); return this; } public SchemaBuilder AddReferences(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new ReferencesFieldBuilder(field, command)); + configure(new ReferencesFieldBuilder(field, properties, command)); return this; } public SchemaBuilder AddString(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new StringFieldBuilder(field, command)); + configure(new StringFieldBuilder(field, properties, command)); return this; } public SchemaBuilder AddTags(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new TagsFieldBuilder(field, command)); + configure(new TagsFieldBuilder(field, properties, command)); return this; } - public SchemaBuilder AddArray(string name, Action configure) + public SchemaBuilder AddUI(string name, Action configure) { - var field = AddField(name); + var (field, properties) = AddField(name); - configure(new ArrayFieldBuilder(field, command)); + configure(new UIFieldBuilder(field, properties, command)); return this; } - private UpsertSchemaField AddField(string name) where T : FieldProperties, new() + private (UpsertSchemaField, T) AddField(string name) where T : FieldProperties, new() { + var properties = new T { Label = name }; + var field = new UpsertSchemaField { Name = name.ToCamelCase(), - Properties = new T - { - Label = name - } + Properties = properties, }; if (command.Fields == null) @@ -168,7 +194,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders command.Fields = command.Fields.Union(Enumerable.Repeat(field, 1)).ToArray(); } - return field; + return (field, properties); } public CreateSchema Build() diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs index 8db1172ae..e0a6ed222 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/StringFieldBuilder.cs @@ -7,81 +7,14 @@ using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Schemas.Commands; -using Squidex.Infrastructure.Collections; namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { - public class StringFieldBuilder : FieldBuilder + public sealed class StringFieldBuilder : FieldBuilder { - public StringFieldBuilder(UpsertSchemaFieldBase field, CreateSchema schema) - : base(field, schema) + public StringFieldBuilder(UpsertSchemaFieldBase field, StringFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) { } - - public StringFieldBuilder AsTextArea() - { - Properties(p => p with - { - EditorUrl = null, - Editor = StringFieldEditor.TextArea - }); - - return this; - } - - public StringFieldBuilder AsRichText() - { - Properties(p => p with - { - EditorUrl = null, - Editor = StringFieldEditor.RichText - }); - - return this; - } - - public StringFieldBuilder AsDropDown(params string[] values) - { - Properties(p => p with - { - AllowedValues = ImmutableList.Create(values), - EditorUrl = null, - Editor = StringFieldEditor.Dropdown - }); - - return this; - } - - public StringFieldBuilder Unique() - { - Properties(p => p with - { - IsUnique = true - }); - - return this; - } - - public StringFieldBuilder Pattern(string pattern, string? message = null) - { - Properties(p => p with - { - Pattern = pattern, - PatternMessage = message - }); - - return this; - } - - public StringFieldBuilder Length(int maxLength, int minLength = 0) - { - Properties(p => p with - { - MaxLength = maxLength, - MinLength = minLength - }); - - return this; - } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs index 7ebb417be..45db55305 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/TagsFieldBuilder.cs @@ -7,25 +7,14 @@ using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Schemas.Commands; -using Squidex.Infrastructure.Collections; namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders { - public class TagsFieldBuilder : FieldBuilder + public sealed class TagsFieldBuilder : FieldBuilder { - public TagsFieldBuilder(UpsertSchemaField field, CreateSchema schema) - : base(field, schema) + public TagsFieldBuilder(UpsertSchemaFieldBase field, TagsFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) { } - - public TagsFieldBuilder WithAllowedValues(params string[] values) - { - Properties(p => p with - { - AllowedValues = ImmutableList.Create(values) - }); - - return this; - } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/UIFieldBuilder.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/UIFieldBuilder.cs new file mode 100644 index 000000000..ca4be917a --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/UIFieldBuilder.cs @@ -0,0 +1,20 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Entities.Schemas.Commands; + +namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders +{ + public sealed class UIFieldBuilder : FieldBuilder + { + public UIFieldBuilder(UpsertSchemaFieldBase field, UIFieldProperties properties, CreateSchema schema) + : base(field, properties, schema) + { + } + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlog.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlog.cs index 19f21afb8..56cf297d7 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlog.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlog.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Apps.Templates.Builders; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Infrastructure; @@ -67,12 +68,18 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates var schema = SchemaBuilder.Create("Posts") .AddString("Title", f => f - .Length(100) + .Properties(p => p with + { + MaxLength = 100 + }) .Required() .ShowInList() .Hints("The title of the post.")) .AddString("Text", f => f - .AsRichText() + .Properties(p => p with + { + Editor = StringFieldEditor.RichText + }) .Required() .Hints("The text of the post.")) .AddString("Slug", f => f @@ -92,12 +99,18 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates var schema = SchemaBuilder.Create("Pages") .AddString("Title", f => f - .Length(100) + .Properties(p => p with + { + MaxLength = 100 + }) .Required() .ShowInList() .Hints("The title of the page.")) .AddString("Text", f => f - .AsRichText() + .Properties(p => p with + { + Editor = StringFieldEditor.RichText + }) .Required() .Hints("The text of the page.")) .AddString("Slug", f => f diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfile.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfile.cs index 92cbbc06a..9c0802526 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfile.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfile.cs @@ -6,10 +6,13 @@ // ========================================================================== using System.Threading.Tasks; +using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Apps.Templates.Builders; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Infrastructure; +using Squidex.Infrastructure.Collections; namespace Squidex.Domain.Apps.Entities.Apps.Templates { @@ -64,17 +67,31 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates .ShowInList() .Hints("Your last name.")) .AddAssets("Image", f => f - .MustBeImage() + .Properties(p => p with + { + ExpectedType = AssetType.Image, + MaxItems = 1, + MinItems = 1 + }) .Hints("Your profile image.")) .AddString("Profession", f => f - .AsTextArea() + .Properties(p => p with + { + Editor = StringFieldEditor.TextArea + }) .Required() .Hints("Describe your profession.")) .AddString("Summary", f => f - .AsTextArea() + .Properties(p => p with + { + Editor = StringFieldEditor.TextArea + }) .Hints("Write a short summary about yourself.")) .AddString("Legal Terms", f => f - .AsTextArea() + .Properties(p => p with + { + Editor = StringFieldEditor.TextArea + }) .Hints("The terms to fulfill legal requirements.")) .AddString("Github Link", f => f .Hints("An optional link to your Github account.")) @@ -102,15 +119,23 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates .ShowInList() .Hints("The name of your project.")) .AddString("Description", f => f - .AsTextArea() + .Properties(p => p with + { + Editor = StringFieldEditor.TextArea + }) .Required() .Hints("Describe your project.")) .AddAssets("Image", f => f - .MustBeImage() + .Properties(p => p with + { + ExpectedType = AssetType.Image, + MaxItems = 1, + MinItems = 1 + }) .Required() .Hints("An image or screenshot for your project.")) .AddString("Label", f => f - .AsTextArea() + .Properties(p => p with { Editor = StringFieldEditor.TextArea }) .Hints("An optional label to categorize your project, e.g. 'Open Source'.")) .AddString("Link", f => f .Hints("An optional link to your project.")) @@ -136,7 +161,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates .ShowInList() .Hints("The company or organization you worked for.")) .AddAssets("Logo", f => f - .MustBeImage() + .Properties(p => p with + { + ExpectedType = AssetType.Image, + MaxItems = 1, + MinItems = 1 + }) .Hints("The logo of the company or organization you worked for.")) .AddDateTime("From", f => f .Required() @@ -163,7 +193,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates .ShowInList() .Hints("The school or university.")) .AddAssets("Logo", f => f - .MustBeImage() + .Properties(p => p with + { + ExpectedType = AssetType.Image, + MaxItems = 1, + MinItems = 1 + }) .Hints("The logo of the school or university.")) .AddDateTime("From", f => f .Required() @@ -186,7 +221,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates .ShowInList() .Hints("The name or title of your publication.")) .AddAssets("Cover", f => f - .MustBeImage() + .Properties(p => p with + { + ExpectedType = AssetType.Image, + MaxItems = 1, + MinItems = 1 + }) .Hints("The cover of your publication.")) .AddString("Description", f => f .Hints("Describe the content of your publication.")) @@ -208,7 +248,15 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates .ShowInList() .Hints("The name of the skill.")) .AddString("Experience", f => f - .AsDropDown("Beginner", "Advanced", "Professional", "Expert") + .Properties(p => p with + { + AllowedValues = ImmutableList.Create( + "Beginner", + "Advanced", + "Professional", + "Expert"), + Editor = StringFieldEditor.Dropdown, + }) .Required() .ShowInList() .Hints("The level of experience.")) diff --git a/backend/src/Squidex.Domain.Apps.Entities/History/NotifoService.cs b/backend/src/Squidex.Domain.Apps.Entities/History/NotifoService.cs index 20e7f0c80..1452a1a3c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/History/NotifoService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/History/NotifoService.cs @@ -24,6 +24,8 @@ using Squidex.Log; using Squidex.Shared.Identity; using Squidex.Shared.Users; +#pragma warning disable MA0073 // Avoid comparison with bool constant + namespace Squidex.Domain.Apps.Entities.History { public class NotifoService : IUserEvents @@ -167,32 +169,16 @@ namespace Squidex.Domain.Apps.Entities.History var maxAge = now - MaxAge; var batches = events - .Where(x => !x.AppEvent.Headers.Restored()) - .Where(x => IsNewer(x.AppEvent.Headers, maxAge)) - .Where(x => IsComment(x.AppEvent.Payload) || x.HistoryEvent != null) + .Where(x => x.AppEvent.Headers.Restored() == false) + .Where(x => x.AppEvent.Headers.Timestamp() > maxAge) + .SelectMany(x => CreateRequests(x.AppEvent, x.HistoryEvent)) .Batch(50); foreach (var batch in batches) { - var requests = new List(); - - foreach (var @event in batch) - { - var payload = @event.AppEvent.Payload; - - if (payload is CommentCreated comment && IsComment(payload)) - { - AddMentions(requests, comment); - } - else if (@event.HistoryEvent != null) - { - AddHistoryEvent(requests, @event.HistoryEvent, payload); - } - } - var request = new PublishManyDto { - Requests = requests + Requests = batch.ToList() }; await client.Events.PostEventsAsync(options.AppId, request); @@ -269,7 +255,22 @@ namespace Squidex.Domain.Apps.Entities.History } } - private void AddHistoryEvent(List requests, HistoryEvent historyEvent, AppEvent payload) + private IEnumerable CreateRequests(Envelope appEvent, HistoryEvent? historyEvent) + { + if (appEvent.Payload is CommentCreated comment && comment.Mentions?.Length > 0) + { + foreach (var userId in comment.Mentions) + { + yield return CreateMentionRequest(comment, userId); + } + } + else if (historyEvent != null) + { + yield return CreateHistoryRequest(historyEvent, appEvent.Payload); + } + } + + private PublishDto CreateHistoryRequest(HistoryEvent historyEvent, AppEvent payload) { var publishRequest = new PublishDto { @@ -295,47 +296,34 @@ namespace Squidex.Domain.Apps.Entities.History SetUser(payload, publishRequest); SetTopic(payload, publishRequest, historyEvent); - requests.Add(publishRequest); + return publishRequest; } - private static void AddMentions(List requests, CommentCreated comment) + private static PublishDto CreateMentionRequest(CommentCreated comment, string userId) { - foreach (var userId in comment.Mentions!) + var publishRequest = new PublishDto { - var publishRequest = new PublishDto - { - Topic = $"users/{userId}" - }; - - publishRequest.Properties["SquidexApp"] = comment.AppId.Name; + Topic = $"users/{userId}" + }; - publishRequest.Preformatted = new NotificationFormattingDto - { - Subject = - { - ["en"] = comment.Text - } - }; + publishRequest.Properties["SquidexApp"] = comment.AppId.Name; - if (comment.Url?.IsAbsoluteUri == true) + publishRequest.Preformatted = new NotificationFormattingDto + { + Subject = { - publishRequest.Preformatted.LinkUrl["en"] = comment.Url.ToString(); + ["en"] = comment.Text } + }; - SetUser(comment, publishRequest); - - requests.Add(publishRequest); + if (comment.Url?.IsAbsoluteUri == true) + { + publishRequest.Preformatted.LinkUrl["en"] = comment.Url.ToString(); } - } - private static bool IsNewer(EnvelopeHeaders headers, Instant maxAge) - { - return headers.Timestamp() > maxAge; - } + SetUser(comment, publishRequest); - private static bool IsComment(AppEvent appEvent) - { - return appEvent is CommentCreated comment && comment.Mentions?.Length > 0; + return publishRequest; } private static void SetUser(AppEvent appEvent, PublishDto publishRequest)