diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonSchemaModel.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonSchemaModel.cs index bfbf2c709..f7812ad7b 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonSchemaModel.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/Json/JsonSchemaModel.cs @@ -32,10 +32,10 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json public SchemaProperties Properties { get; set; } [JsonProperty] - public JsonFieldModel[] Fields { get; set; } + public SchemaScripts Scripts { get; set; } [JsonProperty] - public IReadOnlyDictionary Scripts { get; set; } + public JsonFieldModel[] Fields { get; set; } [JsonProperty] public IReadOnlyDictionary PreviewUrls { get; set; } @@ -93,7 +93,7 @@ namespace Squidex.Domain.Apps.Core.Schemas.Json schema = schema.ChangeCategory(Category); } - if (Scripts?.Count > 0) + if (Scripts != null) { schema = schema.ConfigureScripts(Scripts); } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Schema.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/Schema.cs index 05ee7b068..edddf4103 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Schema.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/Schema.cs @@ -14,14 +14,13 @@ namespace Squidex.Domain.Apps.Core.Schemas { public sealed class Schema : Cloneable { - private static readonly Dictionary EmptyScripts = new Dictionary(); private static readonly Dictionary EmptyPreviewUrls = new Dictionary(); private readonly string name; private readonly bool isSingleton; private string category; private FieldCollection fields = FieldCollection.Empty; - private IReadOnlyDictionary scripts = EmptyScripts; private IReadOnlyDictionary previewUrls = EmptyPreviewUrls; + private SchemaScripts scripts = new SchemaScripts(); private SchemaProperties properties; private bool isPublished; @@ -60,11 +59,6 @@ namespace Squidex.Domain.Apps.Core.Schemas get { return fields.ByName; } } - public IReadOnlyDictionary Scripts - { - get { return scripts; } - } - public IReadOnlyDictionary PreviewUrls { get { return previewUrls; } @@ -75,6 +69,11 @@ namespace Squidex.Domain.Apps.Core.Schemas get { return fields; } } + public SchemaScripts Scripts + { + get { return scripts; } + } + public SchemaProperties Properties { get { return properties; } @@ -115,38 +114,39 @@ namespace Squidex.Domain.Apps.Core.Schemas } [Pure] - public Schema Publish() + public Schema ConfigureScripts(SchemaScripts newScripts) { return Clone(clone => { - clone.isPublished = true; + clone.scripts = newScripts ?? new SchemaScripts(); + clone.scripts.Freeze(); }); } [Pure] - public Schema Unpublish() + public Schema Publish() { return Clone(clone => { - clone.isPublished = false; + clone.isPublished = true; }); } [Pure] - public Schema ChangeCategory(string category) + public Schema Unpublish() { return Clone(clone => { - clone.category = category; + clone.isPublished = false; }); } [Pure] - public Schema ConfigureScripts(IReadOnlyDictionary scripts) + public Schema ChangeCategory(string category) { return Clone(clone => { - clone.scripts = scripts ?? EmptyScripts; + clone.category = category; }); } diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs new file mode 100644 index 000000000..b1d672216 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaExtensions.cs @@ -0,0 +1,55 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Infrastructure; +using System; + +namespace Squidex.Domain.Apps.Core.Schemas +{ + public static class SchemaExtensions + { + public static long MaxId(this Schema schema) + { + var id = 0L; + + foreach (var field in schema.Fields) + { + if (field is IArrayField arrayField) + { + foreach (var nestedField in arrayField.Fields) + { + id = Math.Max(id, nestedField.Id); + } + } + + id = Math.Max(id, field.Id); + } + + return id; + } + + public static string TypeName(this IField field) + { + return field.Name.ToPascalCase(); + } + + public static string DisplayName(this IField field) + { + return field.RawProperties.Label.WithFallback(field.TypeName()); + } + + public static string TypeName(this Schema schema) + { + return schema.Name.ToPascalCase(); + } + + public static string DisplayName(this Schema schema) + { + return schema.Properties.Label.WithFallback(schema.TypeName()); + } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaScripts.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaScripts.cs new file mode 100644 index 000000000..ae3990180 --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/SchemaScripts.cs @@ -0,0 +1,22 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Core.Schemas +{ + public sealed class SchemaScripts : Freezable + { + public string Change { get; set; } + + public string Create { get; set; } + + public string Update { get; set; } + + public string Delete { get; set; } + + public string Query { get; set; } + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/Scripts.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/Scripts.cs deleted file mode 100644 index 93eeeb474..000000000 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/Scripts.cs +++ /dev/null @@ -1,47 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using Squidex.Infrastructure; -using System.Collections.Generic; - -namespace Squidex.Domain.Apps.Core.Schemas -{ - public static class Scripts - { - public const string Change = "Change"; - public const string Create = "Create"; - public const string Delete = "Delete"; - public const string Update = "Update"; - - public const string Query = "Query"; - - public static string GetChange(this IReadOnlyDictionary scripts) - { - return scripts?.GetOrDefault(Change); - } - - public static string GetCreate(this IReadOnlyDictionary scripts) - { - return scripts?.GetOrDefault(Create); - } - - public static string GetQuery(this IReadOnlyDictionary scripts) - { - return scripts?.GetOrDefault(Query); - } - - public static string GetUpdate(this IReadOnlyDictionary scripts) - { - return scripts?.GetOrDefault(Update); - } - - public static string GetDelete(this IReadOnlyDictionary scripts) - { - return scripts?.GetOrDefault(Delete); - } - } -} diff --git a/src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizer.cs b/src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizer.cs index cc693745c..cebdfbf99 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizer.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizer.cs @@ -48,9 +48,9 @@ namespace Squidex.Domain.Apps.Core.EventSynchronization yield return E(new SchemaCategoryChanged { Name = target.Category }); } - if (!source.Scripts.EqualsDictionary(target.Scripts)) + if (!source.Scripts.EqualsJson(target.Scripts, serializer)) { - yield return E(new SchemaScriptsConfigured { Scripts = target.Scripts.ToDictionary(x => x.Key, x => x.Value) }); + yield return E(new SchemaScriptsConfigured { Scripts = target.Scripts }); } if (!source.PreviewUrls.EqualsDictionary(target.PreviewUrls)) @@ -115,6 +115,8 @@ namespace Squidex.Domain.Apps.Core.EventSynchronization if (source.ByName.TryGetValue(targetField.Name, out var sourceField)) { + canCreateField = false; + id = sourceField.NamedId(); if (CanUpdate(sourceField, targetField)) @@ -126,14 +128,16 @@ namespace Squidex.Domain.Apps.Core.EventSynchronization } else if (!sourceField.IsLocked && !options.NoFieldRecreation) { + canCreateField = true; + + sourceIds.Remove(id); + sourceNames.Remove(id.Name); + yield return E(new FieldDeleted { FieldId = id }); } - else - { - canCreateField = false; - } } - else if (canCreateField) + + if (canCreateField) { var partitioning = (string)null; @@ -192,11 +196,14 @@ namespace Squidex.Domain.Apps.Core.EventSynchronization } } - var targetNames = target.Ordered.Select(x => x.Name); - - if (sourceNames.Intersect(targetNames).Count() == target.Ordered.Count && !sourceNames.SequenceEqual(targetNames)) + if (sourceNames.Count > 1) { - yield return new SchemaFieldsReordered { FieldIds = sourceIds.Select(x => x.Id).ToList(), ParentFieldId = parentId }; + var targetNames = target.Ordered.Select(x => x.Name); + + if (sourceNames.Intersect(targetNames).Count() == target.Ordered.Count && !sourceNames.SequenceEqual(targetNames)) + { + yield return new SchemaFieldsReordered { FieldIds = sourceIds.Select(x => x.Id).ToList(), ParentFieldId = parentId }; + } } } diff --git a/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs b/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs index c66ce4d39..bc588ebb5 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/Templates/Builders/SchemaBuilder.cs @@ -24,20 +24,39 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates.Builders public static SchemaBuilder Create(string name) { + var schemaName = name.ToKebabCase(); + return new SchemaBuilder(new CreateSchema { - Name = name.ToKebabCase(), - Publish = true, - Properties = new SchemaProperties - { - Label = name - } - }); + Name = schemaName + }).Published().WithLabel(name); + } + + public SchemaBuilder WithLabel(string label) + { + command.Properties = command.Properties ?? new SchemaProperties(); + command.Properties.Label = label; + + return this; + } + + public SchemaBuilder WithScripts(SchemaScripts scripts) + { + command.Scripts = scripts; + + return this; + } + + public SchemaBuilder Published() + { + command.IsPublished = true; + + return this; } public SchemaBuilder Singleton() { - command.Singleton = true; + command.IsSingleton = true; return this; } diff --git a/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs index c684477ff..35576796a 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateBlogCommandMiddleware.cs @@ -11,7 +11,6 @@ using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Templates.Builders; using Squidex.Domain.Apps.Entities.Contents.Commands; -using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -106,19 +105,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates .Disabled() .Label("Slug (Autogenerated)") .Hints("Autogenerated slug that can be used to identity the post.")) + .WithScripts(DefaultScripts.GenerateSlug) .Build(); await publish(schema); - var schemaId = NamedId.Of(schema.SchemaId, schema.Name); - - await publish(new ConfigureScripts - { - SchemaId = schemaId.Id, - Scripts = DefaultScripts.GenerateSlug - }); - - return schemaId; + return NamedId.Of(schema.SchemaId, schema.Name); } private static async Task> CreatePagesSchemaAsync(Func publish) @@ -139,19 +131,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates .Disabled() .Label("Slug (Autogenerated)") .Hints("Autogenerated slug that can be used to identity the page.")) + .WithScripts(DefaultScripts.GenerateSlug) .Build(); await publish(schema); - var schemaId = NamedId.Of(schema.SchemaId, schema.Name); - - await publish(new ConfigureScripts - { - SchemaId = schemaId.Id, - Scripts = DefaultScripts.GenerateSlug - }); - - return schemaId; + return NamedId.Of(schema.SchemaId, schema.Name); } } } \ No newline at end of file diff --git a/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateIdentityCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateIdentityCommandMiddleware.cs index 14927ca2b..7ae11260e 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateIdentityCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateIdentityCommandMiddleware.cs @@ -9,7 +9,6 @@ using System; using System.Threading.Tasks; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Templates.Builders; -using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -229,17 +228,10 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates .AddString("Security Stamp", f => f .Disabled() .Hints("Internal security stamp")) + .WithScripts(DefaultScripts.GenerateUsername) .Build(); await publish(schema); - - var schemaId = NamedId.Of(schema.SchemaId, schema.Name); - - await publish(new ConfigureScripts - { - SchemaId = schemaId.Id, - Scripts = DefaultScripts.GenerateUsername - }); } private static Task CreateApiResourcesSchemaAsync(Func publish) diff --git a/src/Squidex.Domain.Apps.Entities/Apps/Templates/DefaultScripts.cs b/src/Squidex.Domain.Apps.Entities/Apps/Templates/DefaultScripts.cs index ba6df11ab..0144dc10f 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/Templates/DefaultScripts.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/Templates/DefaultScripts.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Collections.Generic; using Squidex.Domain.Apps.Core.Schemas; namespace Squidex.Domain.Apps.Entities.Apps.Templates @@ -34,16 +33,16 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates replace(data);"; - public static readonly Dictionary GenerateSlug = new Dictionary + public static readonly SchemaScripts GenerateSlug = new SchemaScripts { - [Scripts.Create] = ScriptToGenerateSlug, - [Scripts.Update] = ScriptToGenerateSlug + Create = ScriptToGenerateSlug, + Update = ScriptToGenerateSlug }; - public static readonly Dictionary GenerateUsername = new Dictionary + public static readonly SchemaScripts GenerateUsername = new SchemaScripts { - [Scripts.Create] = ScriptToGenerateUsername, - [Scripts.Update] = ScriptToGenerateUsername + Create = ScriptToGenerateUsername, + Update = ScriptToGenerateUsername }; } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs index d09431545..f934c0deb 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs @@ -8,7 +8,6 @@ using System; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Contents; -using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Contents.Commands; @@ -67,7 +66,7 @@ namespace Squidex.Domain.Apps.Entities.Contents GuardContent.CanCreate(ctx.Schema, c); - await ctx.ExecuteScriptAndTransformAsync(Scripts.Create, "Create", c, c.Data); + await ctx.ExecuteScriptAndTransformAsync(s => s.Create, "Create", c, c.Data); await ctx.EnrichAsync(c.Data); if (!c.DoNotValidate) @@ -77,7 +76,7 @@ namespace Squidex.Domain.Apps.Entities.Contents if (c.Publish) { - await ctx.ExecuteScriptAsync(Scripts.Change, "Published", c, c.Data); + await ctx.ExecuteScriptAsync(s => s.Change, "Published", c, c.Data); } Create(c); @@ -141,7 +140,7 @@ namespace Squidex.Domain.Apps.Entities.Contents reason = StatusChange.Restored; } - await ctx.ExecuteScriptAsync(Scripts.Change, reason, c, Snapshot.Data); + await ctx.ExecuteScriptAsync(s => s.Change, reason, c, Snapshot.Data); ChangeStatus(c, reason); } @@ -167,7 +166,7 @@ namespace Squidex.Domain.Apps.Entities.Contents GuardContent.CanDelete(ctx.Schema, c); - await ctx.ExecuteScriptAsync(Scripts.Delete, "Delete", c, Snapshot.Data); + await ctx.ExecuteScriptAsync(s => s.Delete, "Delete", c, Snapshot.Data); Delete(c); }); @@ -209,7 +208,7 @@ namespace Squidex.Domain.Apps.Entities.Contents await ctx.ValidateAsync(c.Data); } - newData = await ctx.ExecuteScriptAndTransformAsync(Scripts.Update, "Update", c, newData, Snapshot.Data); + newData = await ctx.ExecuteScriptAndTransformAsync(s => s.Update, "Update", c, newData, Snapshot.Data); if (isProposal) { diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs index 239cbbf91..9d851ece7 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.EnrichContent; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Domain.Apps.Entities.Apps; @@ -17,7 +18,6 @@ using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.Schemas; -using Squidex.Infrastructure; using Squidex.Infrastructure.Queries; using Squidex.Infrastructure.Tasks; @@ -87,7 +87,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return data.ValidatePartialAsync(ctx, schemaEntity.SchemaDef, appEntity.PartitionResolver(), message); } - public Task ExecuteScriptAndTransformAsync(string script, object operation, ContentCommand command, NamedContentData data, NamedContentData oldData = null) + public Task ExecuteScriptAndTransformAsync(Func script, object operation, ContentCommand command, NamedContentData data, NamedContentData oldData = null) { var ctx = CreateScriptContext(operation, command, data, oldData); @@ -96,7 +96,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return Task.FromResult(result); } - public Task ExecuteScriptAsync(string script, object operation, ContentCommand command, NamedContentData data, NamedContentData oldData = null) + public Task ExecuteScriptAsync(Func script, object operation, ContentCommand command, NamedContentData data, NamedContentData oldData = null) { var ctx = CreateScriptContext(operation, command, data, oldData); @@ -125,9 +125,9 @@ namespace Squidex.Domain.Apps.Entities.Contents return await contentRepository.QueryIdsAsync(appEntity.Id, filterSchemaId, filterNode); } - private string GetScript(string script) + private string GetScript(Func script) { - return schemaEntity.SchemaDef.Scripts.GetOrDefault(script); + return script(schemaEntity.SchemaDef.Scripts); } } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs index af2e3ca91..14570304c 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs @@ -14,7 +14,6 @@ using Microsoft.Extensions.Options; using Microsoft.OData; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.ConvertContent; -using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Entities.Contents.Edm; using Squidex.Domain.Apps.Entities.Contents.Repositories; @@ -159,7 +158,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { var converters = GenerateConverters(context, checkType).ToArray(); - var scriptText = schema.SchemaDef.Scripts.GetQuery(); + var scriptText = schema.SchemaDef.Scripts.Query; var isScripting = !string.IsNullOrWhiteSpace(scriptText); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs index 20358dd65..6c930f903 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs @@ -10,6 +10,7 @@ using System.Linq; using GraphQL.Resolvers; using GraphQL.Types; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; diff --git a/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs index 4b11b746e..a9695f500 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs @@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Entities.Contents if (context.IsCompleted && context.Command is CreateSchema createSchema && - createSchema.Singleton) + createSchema.IsSingleton) { var schemaId = NamedId.Of(createSchema.SchemaId, createSchema.Name); diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureScripts.cs b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureScripts.cs index 7012a91c1..5e9528a2c 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureScripts.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/ConfigureScripts.cs @@ -5,12 +5,12 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Collections.Generic; +using Squidex.Domain.Apps.Core.Schemas; namespace Squidex.Domain.Apps.Entities.Schemas.Commands { public sealed class ConfigureScripts : SchemaCommand { - public Dictionary Scripts { get; set; } + public SchemaScripts Scripts { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs index 22c4b746b..cc882abe4 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs @@ -17,7 +17,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands public string Name { get; set; } - public bool Singleton { get; set; } + public bool IsSingleton { get; set; } public CreateSchema() { @@ -26,7 +26,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands public Schema ToSchema() { - return ToSchema(Name, Singleton); + return ToSchema(Name, IsSingleton); } } } \ No newline at end of file diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UpsertCommand.cs b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UpsertCommand.cs index 0ab6fa7cf..9b9e6bbe9 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UpsertCommand.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/UpsertCommand.cs @@ -14,15 +14,15 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands { public abstract class UpsertCommand : SchemaCommand { - public bool Publish { get; set; } + public bool IsPublished { get; set; } public string Category { get; set; } public SchemaFields Fields { get; set; } - public SchemaProperties Properties { get; set; } + public SchemaScripts Scripts { get; set; } - public Dictionary Scripts { get; set; } + public SchemaProperties Properties { get; set; } public Dictionary PreviewUrls { get; set; } @@ -30,7 +30,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands { var schema = new Schema(name, Properties, isSingleton); - if (Publish) + if (IsPublished) { schema = schema.Publish(); } diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/SchemaExtensions.cs b/src/Squidex.Domain.Apps.Entities/Schemas/SchemaExtensions.cs index d2f82939e..9d9cb5e29 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/SchemaExtensions.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/SchemaExtensions.cs @@ -19,59 +19,19 @@ namespace Squidex.Domain.Apps.Entities.Schemas return StaticNamedId.Of(schema.Id, schema.SchemaDef.Name); } - public static long MaxId(this Schema schema) - { - var id = 0L; - - foreach (var field in schema.Fields) - { - if (field is IArrayField arrayField) - { - foreach (var nestedField in arrayField.Fields) - { - id = Math.Max(id, nestedField.Id); - } - } - - id = Math.Max(id, field.Id); - } - - return id; - } - public static string EscapePartition(this string value) { return value.Replace('-', '_'); } - public static string TypeName(this IField field) - { - return field.Name.ToPascalCase(); - } - public static string TypeName(this ISchemaEntity schema) { - return schema.SchemaDef.Name.ToPascalCase(); - } - - public static string DisplayName(this IField field) - { - return field.RawProperties.Label.WithFallback(field.TypeName()); + return schema.SchemaDef.TypeName(); } public static string DisplayName(this ISchemaEntity schema) { - return schema.SchemaDef.Properties.Label.WithFallback(schema.TypeName()); - } - - public static string TypeName(this Schema schema) - { - return schema.Name.ToPascalCase(); - } - - public static string DisplayName(this Schema schema) - { - return schema.Properties.Label.WithFallback(schema.TypeName()); + return schema.SchemaDef.DisplayName(); } } } diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/SchemaHistoryEventsCreator.cs b/src/Squidex.Domain.Apps.Entities/Schemas/SchemaHistoryEventsCreator.cs index 45fbd966f..2d6b9e484 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/SchemaHistoryEventsCreator.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/SchemaHistoryEventsCreator.cs @@ -19,6 +19,15 @@ namespace Squidex.Domain.Apps.Entities.Schemas public SchemaHistoryEventsCreator(TypeNameRegistry typeNameRegistry) : base(typeNameRegistry) { + AddEventMessage("SchemaCreated", + "created schema {[Name]}."); + + AddEventMessage("ScriptsConfigured", + "configured script of schema {[Name]}."); + + AddEventMessage( + "reordered fields of schema {[Name]}."); + AddEventMessage( "created schema {[Name]}."); @@ -37,6 +46,9 @@ namespace Squidex.Domain.Apps.Entities.Schemas AddEventMessage( "reordered fields of schema {[Name]}."); + AddEventMessage( + "configured script of schema {[Name]}."); + AddEventMessage( "added field {[Field]} to schema {[Name]}."); diff --git a/src/Squidex.Domain.Apps.Events/Schemas/SchemaScriptsConfigured.cs b/src/Squidex.Domain.Apps.Events/Schemas/SchemaScriptsConfigured.cs index 1deeabd55..f0bb9bea9 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/SchemaScriptsConfigured.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/SchemaScriptsConfigured.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Collections.Generic; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Schemas @@ -13,6 +13,6 @@ namespace Squidex.Domain.Apps.Events.Schemas [EventType(nameof(SchemaScriptsConfigured))] public sealed class SchemaScriptsConfigured : SchemaEvent { - public Dictionary Scripts { get; set; } + public SchemaScripts Scripts { get; set; } } } diff --git a/src/Squidex/Areas/Api/Config/Swagger/XmlResponseTypesProcessor.cs b/src/Squidex/Areas/Api/Config/Swagger/XmlResponseTypesProcessor.cs index e2297a41d..6d969c204 100644 --- a/src/Squidex/Areas/Api/Config/Swagger/XmlResponseTypesProcessor.cs +++ b/src/Squidex/Areas/Api/Config/Swagger/XmlResponseTypesProcessor.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using NJsonSchema.Infrastructure; @@ -23,8 +24,6 @@ namespace Squidex.Areas.Api.Config.Swagger public async Task ProcessAsync(OperationProcessorContext context) { - var hasOkResponse = false; - var operation = context.OperationDescription.Operation; var returnsDescription = await context.MethodInfo.GetXmlDocumentationTagAsync("returns") ?? string.Empty; @@ -41,19 +40,11 @@ namespace Squidex.Areas.Api.Config.Swagger } response.Description = match.Groups["Description"].Value; - - if (statusCode == "200" || statusCode == "204") - { - hasOkResponse = true; - } } await AddInternalErrorResponseAsync(context, operation); - if (!hasOkResponse) - { - RemoveOkResponse(operation); - } + CleanupResponses(operation); return true; } @@ -66,11 +57,14 @@ namespace Squidex.Areas.Api.Config.Swagger } } - private static void RemoveOkResponse(SwaggerOperation operation) + private static void CleanupResponses(SwaggerOperation operation) { - if (operation.Responses.TryGetValue("200", out var response) && response.Description?.Contains("=>") == true) + foreach (var (code, response) in operation.Responses.ToList()) { - operation.Responses.Remove("200"); + if (string.IsNullOrWhiteSpace(response.Description) || response.Description?.Contains("=>") == true) + { + operation.Responses.Remove(code); + } } } } diff --git a/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaSwaggerGenerator.cs b/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaSwaggerGenerator.cs index 270cb5e7f..703e77ce3 100644 --- a/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaSwaggerGenerator.cs +++ b/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaSwaggerGenerator.cs @@ -230,7 +230,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Generator }); } - private SwaggerPathItem AddOperation(SwaggerOperationMethod method, string entityName, string path, Action updater) + private SwaggerPathItem AddOperation(string method, string entityName, string path, Action updater) { var operations = document.Paths.GetOrAddNew(path); var operation = new SwaggerOperation(); diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/ConfigureScriptsDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/ConfigurePreviewUrlsDto.cs similarity index 67% rename from src/Squidex/Areas/Api/Controllers/Schemas/Models/ConfigureScriptsDto.cs rename to src/Squidex/Areas/Api/Controllers/Schemas/Models/ConfigurePreviewUrlsDto.cs index 8247b7179..22069636e 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/ConfigureScriptsDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/ConfigurePreviewUrlsDto.cs @@ -1,7 +1,7 @@ // ========================================================================== // Squidex Headless CMS // ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) +// Copyright (c) Squidex UG (haftungsbeschraenkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== @@ -10,11 +10,11 @@ using Squidex.Domain.Apps.Entities.Schemas.Commands; namespace Squidex.Areas.Api.Controllers.Schemas.Models { - public sealed class ConfigureScriptsDto : Dictionary + public sealed class ConfigurePreviewUrlsDto : Dictionary { - public ConfigureScripts ToCommand() + public ConfigurePreviewUrls ToCommand() { - return new ConfigureScripts { Scripts = this }; + return new ConfigurePreviewUrls { PreviewUrls = this }; } } } diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs index a2b8e3299..8f969a4bb 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs @@ -22,7 +22,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// /// Set to true to allow a single content item only. /// - public bool Singleton { get; set; } + public bool IsSingleton { get; set; } public CreateSchema ToCommand() { diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/PreviewUrlsDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/PreviewUrlsDto.cs deleted file mode 100644 index 39c68aef1..000000000 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/PreviewUrlsDto.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Collections.Generic; - -namespace Squidex.Areas.Api.Controllers.Schemas.Models -{ - public sealed class PreviewUrlsDto : Dictionary - { - } -} diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs index 97c9647c8..a6ed2b46b 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs @@ -19,6 +19,8 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models { public sealed class SchemaDetailsDto { + private static readonly Dictionary EmptyPreviewUrls = new Dictionary(); + /// /// The id of the schema. /// @@ -47,34 +49,14 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models public bool IsPublished { get; set; } /// - /// The script that is executed for each query when querying contents. - /// - public string ScriptQuery { get; set; } - - /// - /// The script that is executed when creating a content. - /// - public string ScriptCreate { get; set; } - - /// - /// The script that is executed when updating a content. - /// - public string ScriptUpdate { get; set; } - - /// - /// The script that is executed when deleting a content. - /// - public string ScriptDelete { get; set; } - - /// - /// The script that is executed when changing a content status. + /// The scripts. /// - public string ScriptChange { get; set; } + public SchemaScriptsDto Scripts { get; set; } = new SchemaScriptsDto(); /// /// The preview Urls. /// - public Dictionary PreviewUrls { get; set; } + public Dictionary PreviewUrls { get; set; } = EmptyPreviewUrls; /// /// The list of fields. @@ -86,7 +68,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// The schema properties. /// [Required] - public SchemaPropertiesDto Properties { get; set; } + public SchemaPropertiesDto Properties { get; set; } = new SchemaPropertiesDto(); /// /// The user that has created the schema. @@ -117,12 +99,18 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models public static SchemaDetailsDto FromSchema(ISchemaEntity schema) { - var response = new SchemaDetailsDto { Properties = new SchemaPropertiesDto() }; + var response = new SchemaDetailsDto(); SimpleMapper.Map(schema, response); SimpleMapper.Map(schema.SchemaDef, response); + SimpleMapper.Map(schema.SchemaDef.Scripts, response.Scripts); SimpleMapper.Map(schema.SchemaDef.Properties, response.Properties); + if (schema.SchemaDef.PreviewUrls.Count > 0) + { + response.PreviewUrls = new Dictionary(schema.SchemaDef.PreviewUrls); + } + response.Fields = new List(); foreach (var field in schema.SchemaDef.Fields) diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaScriptsDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaScriptsDto.cs new file mode 100644 index 000000000..3e2fd8a2d --- /dev/null +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaScriptsDto.cs @@ -0,0 +1,48 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Entities.Schemas.Commands; +using Squidex.Infrastructure.Reflection; + +namespace Squidex.Areas.Api.Controllers.Schemas.Models +{ + public sealed class SchemaScriptsDto + { + /// + /// The script that is executed for each query when querying contents. + /// + public string Query { get; set; } + + /// + /// The script that is executed when creating a content. + /// + public string Create { get; set; } + + /// + /// The script that is executed when updating a content. + /// + public string Update { get; set; } + + /// + /// The script that is executed when deleting a content. + /// + public string Delete { get; set; } + + /// + /// The script that is executed when change a content status. + /// + public string Change { get; set; } + + public ConfigureScripts ToCommand() + { + var scripts = SimpleMapper.Map(this, new SchemaScripts()); + + return new ConfigureScripts { Scripts = scripts }; + } + } +} \ No newline at end of file diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/UpsertDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/UpsertDto.cs index 0e199c6cf..8d114940f 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/UpsertDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/UpsertDto.cs @@ -42,7 +42,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// /// Set it to true to autopublish the schema. /// - public bool Publish { get; set; } + public bool IsPublished { get; set; } public static TCommand ToCommand(TDto dto, TCommand command) where TCommand : UpsertCommand where TDto : UpsertDto { diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs b/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs index 00850058e..048607c97 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs @@ -146,7 +146,6 @@ namespace Squidex.Areas.Api.Controllers.Schemas /// [HttpPut] [Route("apps/{app}/schemas/{name}/fields/{id:long}/")] - [ProducesResponseType(typeof(ErrorDto), 409)] [ProducesResponseType(typeof(ErrorDto), 400)] [ApiPermission(Permissions.AppSchemasUpdate)] [ApiCosts(1)] @@ -172,7 +171,6 @@ namespace Squidex.Areas.Api.Controllers.Schemas /// [HttpPut] [Route("apps/{app}/schemas/{name}/fields/{parentId:long}/nested/{id:long}/")] - [ProducesResponseType(typeof(ErrorDto), 409)] [ProducesResponseType(typeof(ErrorDto), 400)] [ApiPermission(Permissions.AppSchemasUpdate)] [ApiCosts(1)] diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs b/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs index b867cdd2e..1da3dd5f3 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs @@ -132,7 +132,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas /// The name of the schema. /// The schema object that needs to updated. /// - /// 204 => Schema has been updated. + /// 204 => Schema updated. /// 400 => Schema properties are not valid. /// 404 => Schema or app not found. /// @@ -154,7 +154,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas /// The name of the schema. /// The schema object that needs to updated. /// - /// 204 => Schema has been updated. + /// 204 => Schema updated. /// 400 => Schema properties are not valid. /// 404 => Schema or app not found. /// @@ -176,7 +176,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas /// The name of the schema. /// The schema object that needs to updated. /// - /// 204 => Schema has been updated. + /// 204 => Schema updated. /// 404 => Schema or app not found. /// [HttpPut] @@ -197,16 +197,16 @@ namespace Squidex.Areas.Api.Controllers.Schemas /// The name of the schema. /// The preview urls for the schema. /// - /// 204 => Schema has been updated. + /// 204 => Schema updated. /// 404 => Schema or app not found. /// [HttpPut] [Route("apps/{app}/schemas/{name}/preview-urls")] [ApiPermission(Permissions.AppSchemasUpdate)] [ApiCosts(1)] - public async Task PutPreviewUrls(string app, string name, [FromBody] PreviewUrlsDto request) + public async Task PutPreviewUrls(string app, string name, [FromBody] ConfigurePreviewUrlsDto request) { - await CommandBus.PublishAsync(new ConfigurePreviewUrls { PreviewUrls = request ?? new PreviewUrlsDto() }); + await CommandBus.PublishAsync(request.ToCommand()); return NoContent(); } @@ -218,7 +218,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas /// The name of the schema. /// The schema scripts object that needs to updated. /// - /// 204 => Schema has been updated. + /// 204 => Schema updated. /// 400 => Schema properties are not valid. /// 404 => Schema or app not found. /// @@ -226,7 +226,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas [Route("apps/{app}/schemas/{name}/scripts/")] [ApiPermission(Permissions.AppSchemasScripts)] [ApiCosts(1)] - public async Task PutSchemaScripts(string app, string name, [FromBody] ConfigureScriptsDto request) + public async Task PutSchemaScripts(string app, string name, [FromBody] SchemaScriptsDto request) { await CommandBus.PublishAsync(request.ToCommand()); diff --git a/src/Squidex/Config/Domain/EntitiesServices.cs b/src/Squidex/Config/Domain/EntitiesServices.cs index 4401d09b8..98641c63f 100644 --- a/src/Squidex/Config/Domain/EntitiesServices.cs +++ b/src/Squidex/Config/Domain/EntitiesServices.cs @@ -251,6 +251,9 @@ namespace Squidex.Config.Domain services.AddTransientAs() .As(); + services.AddTransientAs() + .As(); + services.AddTransientAs() .As(); diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.html b/src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.html index 090907620..74f2705aa 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.html @@ -7,7 +7,7 @@ diff --git a/src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.ts b/src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.ts index a48809b1e..ba545655a 100644 --- a/src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.ts +++ b/src/Squidex/app/features/schemas/pages/schema/schema-scripts-form.component.ts @@ -26,7 +26,7 @@ export class SchemaScriptsFormComponent implements OnInit { @Input() public schema: SchemaDetailsDto; - public selectedField = 'scriptQuery'; + public selectedField = 'query'; public editForm = new EditScriptsForm(this.formBuilder); @@ -37,7 +37,7 @@ export class SchemaScriptsFormComponent implements OnInit { } public ngOnInit() { - this.editForm.load(this.schema); + this.editForm.load(this.schema.scripts); } public complete() { diff --git a/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html b/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html index ac0fd5016..509579d6e 100644 --- a/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html +++ b/src/Squidex/app/features/schemas/pages/schemas/schema-form.component.html @@ -34,11 +34,11 @@