From 3eb794d2b6410a08c84f633623733b285b9115aa Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 26 Jun 2018 17:55:50 +0200 Subject: [PATCH 1/7] Extend schema grain. --- .../Schemas/Commands/CreateSchema.cs | 2 ++ src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs | 2 ++ .../Schemas/State/SchemaState.cs | 5 +++++ src/Squidex.Domain.Apps.Events/Schemas/SchemaCreated.cs | 2 ++ .../Schemas/SchemaGrainTests.cs | 5 +++-- 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs index 923499e79..9c39fa5a9 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/Commands/CreateSchema.cs @@ -22,6 +22,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Commands public SchemaProperties Properties { get; set; } + public bool Singleton { get; set; } + public bool Publish { get; set; } public CreateSchema() diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs b/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs index 335a91e92..7f5ccf51e 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs @@ -25,6 +25,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas bool IsPublished { get; } + bool IsSingleton { get; } + bool IsDeleted { get; } string ScriptQuery { get; } diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs b/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs index 4a787d912..01bd7a7d1 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs @@ -37,6 +37,9 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State [JsonProperty] public bool IsDeleted { get; set; } + [JsonProperty] + public bool IsSingleton { get; set; } + [JsonProperty] public string ScriptQuery { get; set; } @@ -65,6 +68,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State { Name = @event.Name; + IsSingleton = @event.Singleton; + var schema = new Schema(@event.Name); if (@event.Properties != null) diff --git a/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreated.cs b/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreated.cs index 2e7c6ec2b..6f4f24295 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreated.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreated.cs @@ -20,6 +20,8 @@ namespace Squidex.Domain.Apps.Events.Schemas public SchemaProperties Properties { get; set; } + public bool Singleton { get; set; } + public bool Publish { get; set; } } } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs index bf0e83ad7..cd880f849 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs @@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas { var properties = new SchemaProperties(); - var command = new CreateSchema { Name = SchemaName, SchemaId = SchemaId, Properties = properties }; + var command = new CreateSchema { Name = SchemaName, SchemaId = SchemaId, Properties = properties, Singleton = true }; var result = await sut.ExecuteAsync(CreateCommand(command)); @@ -72,10 +72,11 @@ namespace Squidex.Domain.Apps.Entities.Schemas Assert.Equal(SchemaName, sut.Snapshot.Name); Assert.Equal(SchemaName, sut.Snapshot.SchemaDef.Name); + Assert.True(sut.Snapshot.IsSingleton); LastEvents .ShouldHaveSameEvents( - CreateEvent(new SchemaCreated { Name = SchemaName, Properties = properties }) + CreateEvent(new SchemaCreated { Name = SchemaName, Properties = properties, Singleton = true }) ); } From f9f7cede58cff78e575d5ffe457f9955eb648df8 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 26 Jun 2018 17:57:08 +0200 Subject: [PATCH 2/7] Extend api. --- .../Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs | 5 +++++ .../Areas/Api/Controllers/Schemas/Models/SchemaDto.cs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs index b8109375f..1835ecc51 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs @@ -37,6 +37,11 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// public bool Publish { get; set; } + /// + /// Set to true to allow a single content item only. + /// + public bool Singleton { get; set; } + public CreateSchema ToCommand() { var command = new CreateSchema(); diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs index 0c0869ede..54b0fd561 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs @@ -44,6 +44,11 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// public bool IsPublished { get; set; } + /// + /// Indicates if the schema is a singleton. + /// + public bool IsSingleton { get; set; } + /// /// The user that has created the schema. /// From 2a0cdfb91090f43f8c9e04e96ebbfdb3c8f7d567 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 26 Jun 2018 18:46:00 +0200 Subject: [PATCH 3/7] Extended the domain code. --- .../Contents/ContentGrain.cs | 24 +++---- .../Contents/ContentOperationContext.cs | 5 ++ .../Contents/Guards/GuardContent.cs | 23 ++++++- .../Contents/SingletonCommandMiddleware.cs | 36 ++++++++++ .../Contents/Guard/GuardContentTests.cs | 66 ++++++++++++++++--- .../SingletonCommandMiddlewareTests.cs | 60 +++++++++++++++++ 6 files changed, 189 insertions(+), 25 deletions(-) create mode 100644 src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs create mode 100644 tests/Squidex.Domain.Apps.Entities.Tests/Contents/SingletonCommandMiddlewareTests.cs diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs index 000314ccb..755e30a1d 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs @@ -61,17 +61,17 @@ namespace Squidex.Domain.Apps.Entities.Contents case CreateContent createContent: return CreateReturnAsync(createContent, async c => { - GuardContent.CanCreate(c); + var ctx = await CreateContext(c.AppId.Id, c.SchemaId.Id, () => "Failed to create content."); - var operationContext = await CreateContext(c.AppId.Id, c.SchemaId.Id, () => "Failed to create content."); + GuardContent.CanCreate(ctx.Schema, c); - await operationContext.ExecuteScriptAndTransformAsync(x => x.ScriptCreate, "Create", c, c.Data, null); - await operationContext.EnrichAsync(c.Data); - await operationContext.ValidateAsync(c.Data); + await ctx.ExecuteScriptAndTransformAsync(x => x.ScriptCreate, "Create", c, c.Data, null); + await ctx.EnrichAsync(c.Data); + await ctx.ValidateAsync(c.Data); if (c.Publish) { - await operationContext.ExecuteScriptAsync(x => x.ScriptChange, "Published", c, c.Data, null); + await ctx.ExecuteScriptAsync(x => x.ScriptChange, "Published", c, c.Data, null); } Create(c); @@ -100,7 +100,9 @@ namespace Squidex.Domain.Apps.Entities.Contents { try { - GuardContent.CanChangeContentStatus(Snapshot.IsPending, Snapshot.Status, c); + var ctx = await CreateContext(Snapshot.AppId.Id, Snapshot.SchemaId.Id, () => "Failed to change content."); + + GuardContent.CanChangeContentStatus(ctx.Schema, Snapshot.IsPending, Snapshot.Status, c); if (c.DueTime.HasValue) { @@ -114,8 +116,6 @@ namespace Squidex.Domain.Apps.Entities.Contents } else { - var ctx = await CreateContext(Snapshot.AppId.Id, Snapshot.SchemaId.Id, () => "Failed to change content."); - await ctx.ExecuteScriptAsync(x => x.ScriptChange, c.Status, c, Snapshot.Data); ChangeStatus(c); @@ -138,11 +138,11 @@ namespace Squidex.Domain.Apps.Entities.Contents case DeleteContent deleteContent: return UpdateAsync(deleteContent, async c => { - GuardContent.CanDelete(c); + var ctx = await CreateContext(Snapshot.AppId.Id, Snapshot.SchemaId.Id, () => "Failed to delete content."); - var operationContext = await CreateContext(Snapshot.AppId.Id, Snapshot.SchemaId.Id, () => "Failed to delete content."); + GuardContent.CanDelete(ctx.Schema, c); - await operationContext.ExecuteScriptAsync(x => x.ScriptDelete, "Delete", c, Snapshot.Data); + await ctx.ExecuteScriptAsync(x => x.ScriptDelete, "Delete", c, Snapshot.Data); Delete(c); }); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs index 5b1bc9474..97e729321 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs @@ -31,6 +31,11 @@ namespace Squidex.Domain.Apps.Entities.Contents private IAppEntity appEntity; private Func message; + public ISchemaEntity Schema + { + get { return schemaEntity; } + } + public static async Task CreateAsync( Guid appId, Guid schemaId, diff --git a/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs b/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs index 8f5e4d1b8..8c02f6d88 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs @@ -5,16 +5,18 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Contents.Commands; +using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Guards { public static class GuardContent { - public static void CanCreate(CreateContent command) + public static void CanCreate(ISchemaEntity schema, CreateContent command) { Guard.NotNull(command, nameof(command)); @@ -22,6 +24,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guards { ValidateData(command, e); }); + + if (schema.IsSingleton && command.ContentId != Guid.Empty) + { + throw new DomainException("Singleton content cannot be created."); + } } public static void CanUpdate(UpdateContent command) @@ -54,10 +61,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guards } } - public static void CanChangeContentStatus(bool isPending, Status status, ChangeContentStatus command) + public static void CanChangeContentStatus(ISchemaEntity schema, bool isPending, Status status, ChangeContentStatus command) { Guard.NotNull(command, nameof(command)); + if (schema.IsSingleton && command.Status != Status.Published) + { + throw new DomainException("Singleton content archived or unpublished."); + } + Validate.It(() => "Cannot change status.", e => { if (!StatusFlow.Exists(command.Status)) @@ -86,9 +98,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guards }); } - public static void CanDelete(DeleteContent command) + public static void CanDelete(ISchemaEntity schema, DeleteContent command) { Guard.NotNull(command, nameof(command)); + + if (schema.IsSingleton) + { + throw new DomainException("Singleton content cannot be deleted."); + } } private static void ValidateData(ContentDataCommand command, AddValidation e) diff --git a/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs new file mode 100644 index 000000000..2f1547416 --- /dev/null +++ b/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs @@ -0,0 +1,36 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Threading.Tasks; +using Squidex.Domain.Apps.Entities.Contents.Commands; +using Squidex.Domain.Apps.Entities.Schemas.Commands; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Commands; +using Squidex.Infrastructure.Reflection; + +namespace Squidex.Domain.Apps.Entities.Contents +{ + public sealed class SingletonCommandMiddleware : ICommandMiddleware + { + public async Task HandleAsync(CommandContext context, Func next) + { + await next(); + + if (context.IsCompleted && + context.Command is CreateSchema createSchema && + createSchema.Singleton) + { + var schemaId = new NamedId(createSchema.SchemaId, createSchema.Name); + + var command = SimpleMapper.Map(createSchema, new CreateContent { ContentId = Guid.Empty, SchemaId = schemaId, Publish = true }); + + await context.CommandBus.PublishAsync(command); + } + } + } +} diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs index f3a1ed76b..56357383f 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs @@ -5,10 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; +using FakeItEasy; using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Guards; +using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Xunit; @@ -17,6 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard { public class GuardContentTests { + private readonly ISchemaEntity schema = A.Fake(); private readonly Instant dueTimeInPast = SystemClock.Instance.GetCurrentInstant().Minus(Duration.FromHours(1)); [Fact] @@ -24,16 +28,36 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard { var command = new CreateContent(); - ValidationAssert.Throws(() => GuardContent.CanCreate(command), + ValidationAssert.Throws(() => GuardContent.CanCreate(schema, command), new ValidationError("Data is required.", "Data")); } + [Fact] + public void CanCreate_should_throw_exception_if_singleton() + { + A.CallTo(() => schema.IsSingleton).Returns(true); + + var command = new CreateContent { Data = new NamedContentData() }; + + Assert.Throws(() => GuardContent.CanCreate(schema, command)); + } + + [Fact] + public void CanCreate_should_not_throw_exception_if_singleton_and_id_empty() + { + A.CallTo(() => schema.IsSingleton).Returns(true); + + var command = new CreateContent { Data = new NamedContentData(), ContentId = Guid.Empty }; + + GuardContent.CanCreate(schema, command); + } + [Fact] public void CanCreate_should_not_throw_exception_if_data_is_not_null() { var command = new CreateContent { Data = new NamedContentData() }; - GuardContent.CanCreate(command); + GuardContent.CanCreate(schema, command); } [Fact] @@ -75,7 +99,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard { var command = new ChangeContentStatus { Status = (Status)10 }; - ValidationAssert.Throws(() => GuardContent.CanChangeContentStatus(false, Status.Archived, command), + ValidationAssert.Throws(() => GuardContent.CanChangeContentStatus(schema, false, Status.Archived, command), new ValidationError("Status is not valid.", "Status")); } @@ -84,7 +108,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard { var command = new ChangeContentStatus { Status = Status.Published }; - ValidationAssert.Throws(() => GuardContent.CanChangeContentStatus(false, Status.Archived, command), + ValidationAssert.Throws(() => GuardContent.CanChangeContentStatus(schema, false, Status.Archived, command), new ValidationError("Cannot change status from Archived to Published.", "Status")); } @@ -93,7 +117,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard { var command = new ChangeContentStatus { Status = Status.Published, DueTime = dueTimeInPast }; - ValidationAssert.Throws(() => GuardContent.CanChangeContentStatus(false, Status.Draft, command), + ValidationAssert.Throws(() => GuardContent.CanChangeContentStatus(schema, false, Status.Draft, command), new ValidationError("Due time must be in the future.", "DueTime")); } @@ -102,16 +126,28 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard { var command = new ChangeContentStatus { Status = Status.Published }; - ValidationAssert.Throws(() => GuardContent.CanChangeContentStatus(false, Status.Published, command), + ValidationAssert.Throws(() => GuardContent.CanChangeContentStatus(schema, false, Status.Published, command), new ValidationError("Content has no changes to publish.", "Status")); } + [Fact] + public void CanChangeContentStatus_should_throw_exception_if_singleton() + { + A.CallTo(() => schema.IsSingleton).Returns(true); + + var command = new ChangeContentStatus { Status = Status.Draft }; + + Assert.Throws(() => GuardContent.CanChangeContentStatus(schema, false, Status.Published, command)); + } + [Fact] public void CanChangeContentStatus_should_not_throw_exception_if_publishing_with_pending_changes() { + A.CallTo(() => schema.IsSingleton).Returns(true); + var command = new ChangeContentStatus { Status = Status.Published }; - GuardContent.CanChangeContentStatus(true, Status.Published, command); + GuardContent.CanChangeContentStatus(schema, true, Status.Published, command); } [Fact] @@ -119,7 +155,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard { var command = new ChangeContentStatus { Status = Status.Published }; - GuardContent.CanChangeContentStatus(false, Status.Draft, command); + GuardContent.CanChangeContentStatus(schema, false, Status.Draft, command); } [Fact] @@ -139,11 +175,21 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard } [Fact] - public void CanPatch_should_not_throw_exception() + public void CanDelete_should_throw_exception_if_singleton() + { + A.CallTo(() => schema.IsSingleton).Returns(true); + + var command = new DeleteContent(); + + Assert.Throws(() => GuardContent.CanDelete(schema, command)); + } + + [Fact] + public void CanDelete_should_not_throw_exception() { var command = new DeleteContent(); - GuardContent.CanDelete(command); + GuardContent.CanDelete(schema, command); } } } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/SingletonCommandMiddlewareTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/SingletonCommandMiddlewareTests.cs new file mode 100644 index 000000000..27587abd7 --- /dev/null +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/SingletonCommandMiddlewareTests.cs @@ -0,0 +1,60 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Threading.Tasks; +using FakeItEasy; +using Squidex.Domain.Apps.Entities.Contents.Commands; +using Squidex.Domain.Apps.Entities.Schemas.Commands; +using Squidex.Infrastructure.Commands; +using Xunit; + +namespace Squidex.Domain.Apps.Entities.Contents +{ + public sealed class SingletonCommandMiddlewareTests + { + private readonly ICommandBus commandBus = A.Fake(); + private readonly SingletonCommandMiddleware sut = new SingletonCommandMiddleware(); + + [Fact] + public async Task Should_create_content_when_singleton_schema_is_created() + { + var context = + new CommandContext(new CreateSchema { Singleton = true, Name = "my-schema" }, commandBus) + .Complete(); + + await sut.HandleAsync(context); + + A.CallTo(() => commandBus.PublishAsync(A.That.Matches(x => x is CreateContent))) + .MustHaveHappened(); + } + + [Fact] + public async Task Should_not_create_content_when_non_singleton_schema_is_created() + { + var context = + new CommandContext(new CreateSchema { Singleton = false }, commandBus) + .Complete(); + + await sut.HandleAsync(context); + + A.CallTo(() => commandBus.PublishAsync(A.Ignored)) + .MustNotHaveHappened(); + } + + [Fact] + public async Task Should_not_create_content_when_singleton_schema_not_created() + { + var context = + new CommandContext(new CreateSchema { Singleton = true }, commandBus); + + await sut.HandleAsync(context); + + A.CallTo(() => commandBus.PublishAsync(A.Ignored)) + .MustNotHaveHappened(); + } + } +} From 34d278cba1f64a8d5a5fbe9c173ba158a89ee050 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 26 Jun 2018 18:54:33 +0200 Subject: [PATCH 4/7] IsSingleton => Singleton --- .../Contents/Guards/GuardContent.cs | 6 +++--- .../Schemas/ISchemaEntity.cs | 4 ++-- .../Schemas/State/SchemaState.cs | 4 ++-- .../Contents/Guard/GuardContentTests.cs | 10 +++++----- .../Schemas/SchemaGrainTests.cs | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs b/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs index 8c02f6d88..c40c5e629 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs @@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guards ValidateData(command, e); }); - if (schema.IsSingleton && command.ContentId != Guid.Empty) + if (schema.Singleton && command.ContentId != Guid.Empty) { throw new DomainException("Singleton content cannot be created."); } @@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guards { Guard.NotNull(command, nameof(command)); - if (schema.IsSingleton && command.Status != Status.Published) + if (schema.Singleton && command.Status != Status.Published) { throw new DomainException("Singleton content archived or unpublished."); } @@ -102,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guards { Guard.NotNull(command, nameof(command)); - if (schema.IsSingleton) + if (schema.Singleton) { throw new DomainException("Singleton content cannot be deleted."); } diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs b/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs index 7f5ccf51e..58233780d 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs @@ -23,9 +23,9 @@ namespace Squidex.Domain.Apps.Entities.Schemas string Category { get; } - bool IsPublished { get; } + bool Singleton { get; } - bool IsSingleton { get; } + bool IsPublished { get; } bool IsDeleted { get; } diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs b/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs index 01bd7a7d1..070ca131d 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs @@ -38,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State public bool IsDeleted { get; set; } [JsonProperty] - public bool IsSingleton { get; set; } + public bool Singleton { get; set; } [JsonProperty] public string ScriptQuery { get; set; } @@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State { Name = @event.Name; - IsSingleton = @event.Singleton; + Singleton = @event.Singleton; var schema = new Schema(@event.Name); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs index 56357383f..a69db5009 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs @@ -35,7 +35,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanCreate_should_throw_exception_if_singleton() { - A.CallTo(() => schema.IsSingleton).Returns(true); + A.CallTo(() => schema.Singleton).Returns(true); var command = new CreateContent { Data = new NamedContentData() }; @@ -45,7 +45,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanCreate_should_not_throw_exception_if_singleton_and_id_empty() { - A.CallTo(() => schema.IsSingleton).Returns(true); + A.CallTo(() => schema.Singleton).Returns(true); var command = new CreateContent { Data = new NamedContentData(), ContentId = Guid.Empty }; @@ -133,7 +133,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanChangeContentStatus_should_throw_exception_if_singleton() { - A.CallTo(() => schema.IsSingleton).Returns(true); + A.CallTo(() => schema.Singleton).Returns(true); var command = new ChangeContentStatus { Status = Status.Draft }; @@ -143,7 +143,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanChangeContentStatus_should_not_throw_exception_if_publishing_with_pending_changes() { - A.CallTo(() => schema.IsSingleton).Returns(true); + A.CallTo(() => schema.Singleton).Returns(true); var command = new ChangeContentStatus { Status = Status.Published }; @@ -177,7 +177,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanDelete_should_throw_exception_if_singleton() { - A.CallTo(() => schema.IsSingleton).Returns(true); + A.CallTo(() => schema.Singleton).Returns(true); var command = new DeleteContent(); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs index cd880f849..b2f00be97 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs @@ -72,7 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas Assert.Equal(SchemaName, sut.Snapshot.Name); Assert.Equal(SchemaName, sut.Snapshot.SchemaDef.Name); - Assert.True(sut.Snapshot.IsSingleton); + Assert.True(sut.Snapshot.Singleton); LastEvents .ShouldHaveSameEvents( From 1c74592f7ddabe4aa6e34d5509099d50b49e5922 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 26 Jun 2018 19:02:59 +0200 Subject: [PATCH 5/7] Improved namings and updated schema service client. --- .../Contents/Guards/GuardContent.cs | 6 +++--- .../Schemas/ISchemaEntity.cs | 2 +- .../Schemas/State/SchemaState.cs | 4 ++-- .../Controllers/Schemas/Models/CreateSchemaDto.cs | 8 ++++---- .../Api/Controllers/Schemas/Models/SchemaDto.cs | 8 ++++---- .../app/shared/services/schemas.service.spec.ts | 13 ++++++++----- src/Squidex/app/shared/services/schemas.service.ts | 11 ++++++++--- src/Squidex/app/shared/state/contents.forms.spec.ts | 2 +- src/Squidex/app/shared/state/schemas.state.spec.ts | 8 ++++---- .../Contents/Guard/GuardContentTests.cs | 10 +++++----- .../Schemas/SchemaGrainTests.cs | 2 +- 11 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs b/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs index c40c5e629..8c02f6d88 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs @@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guards ValidateData(command, e); }); - if (schema.Singleton && command.ContentId != Guid.Empty) + if (schema.IsSingleton && command.ContentId != Guid.Empty) { throw new DomainException("Singleton content cannot be created."); } @@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guards { Guard.NotNull(command, nameof(command)); - if (schema.Singleton && command.Status != Status.Published) + if (schema.IsSingleton && command.Status != Status.Published) { throw new DomainException("Singleton content archived or unpublished."); } @@ -102,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guards { Guard.NotNull(command, nameof(command)); - if (schema.Singleton) + if (schema.IsSingleton) { throw new DomainException("Singleton content cannot be deleted."); } diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs b/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs index 58233780d..98913f9e3 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/ISchemaEntity.cs @@ -23,7 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas string Category { get; } - bool Singleton { get; } + bool IsSingleton { get; } bool IsPublished { get; } diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs b/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs index 070ca131d..01bd7a7d1 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/State/SchemaState.cs @@ -38,7 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State public bool IsDeleted { get; set; } [JsonProperty] - public bool Singleton { get; set; } + public bool IsSingleton { get; set; } [JsonProperty] public string ScriptQuery { get; set; } @@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.State { Name = @event.Name; - Singleton = @event.Singleton; + IsSingleton = @event.Singleton; var schema = new Schema(@event.Name); diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs index 1835ecc51..922647abc 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/CreateSchemaDto.cs @@ -33,14 +33,14 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models public List Fields { get; set; } /// - /// Set it to true to autopublish the schema. + /// Set to true to allow a single content item only. /// - public bool Publish { get; set; } + public bool Singleton { get; set; } /// - /// Set to true to allow a single content item only. + /// Set it to true to autopublish the schema. /// - public bool Singleton { get; set; } + public bool Publish { get; set; } public CreateSchema ToCommand() { diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs index 54b0fd561..370d6a91d 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs @@ -40,14 +40,14 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models public SchemaPropertiesDto Properties { get; set; } /// - /// Indicates if the schema is published. + /// Indicates if the schema is a singleton. /// - public bool IsPublished { get; set; } + public bool IsSingleton { get; set; } /// - /// Indicates if the schema is a singleton. + /// Indicates if the schema is published. /// - public bool IsSingleton { get; set; } + public bool IsPublished { get; set; } /// /// The user that has created the schema. diff --git a/src/Squidex/app/shared/services/schemas.service.spec.ts b/src/Squidex/app/shared/services/schemas.service.spec.ts index b5d99e774..3b7df6d12 100644 --- a/src/Squidex/app/shared/services/schemas.service.spec.ts +++ b/src/Squidex/app/shared/services/schemas.service.spec.ts @@ -78,6 +78,7 @@ describe('SchemasService', () => { label: 'label1', hints: 'hints1' }, + isSingleton: true, isPublished: true, created: '2016-12-12T10:10', createdBy: 'Created1', @@ -94,6 +95,7 @@ describe('SchemasService', () => { label: 'label2', hints: 'hints2' }, + isSingleton: true, isPublished: true, created: '2016-10-12T10:10', createdBy: 'Created2', @@ -106,11 +108,11 @@ describe('SchemasService', () => { expect(schemas!).toEqual( [ - new SchemaDto('id1', 'name1', 'category1', new SchemaPropertiesDto('label1', 'hints1'), true, + new SchemaDto('id1', 'name1', 'category1', new SchemaPropertiesDto('label1', 'hints1'), true, true, DateTime.parseISO_UTC('2016-12-12T10:10'), 'Created1', DateTime.parseISO_UTC('2017-12-12T10:10'), 'LastModifiedBy1', new Version('11')), - new SchemaDto('id2', 'name2', 'category2', new SchemaPropertiesDto('label2', 'hints2'), true, + new SchemaDto('id2', 'name2', 'category2', new SchemaPropertiesDto('label2', 'hints2'), true, true, DateTime.parseISO_UTC('2016-10-12T10:10'), 'Created2', DateTime.parseISO_UTC('2017-10-12T10:10'), 'LastModifiedBy2', new Version('22')) @@ -135,6 +137,7 @@ describe('SchemasService', () => { id: 'id1', name: 'name1', category: 'category1', + isSingleton: true, isPublished: true, created: '2016-12-12T10:10', createdBy: 'Created1', @@ -290,7 +293,7 @@ describe('SchemasService', () => { }); expect(schema!).toEqual( - new SchemaDetailsDto('id1', 'name1', 'category1', new SchemaPropertiesDto('label1', 'hints1'), true, + new SchemaDetailsDto('id1', 'name1', 'category1', new SchemaPropertiesDto('label1', 'hints1'), true, true, DateTime.parseISO_UTC('2016-12-12T10:10'), 'Created1', DateTime.parseISO_UTC('2017-12-12T10:10'), 'LastModifiedBy1', new Version('2'), @@ -319,7 +322,7 @@ describe('SchemasService', () => { it('should make post request to create schema', inject([SchemasService, HttpTestingController], (schemasService: SchemasService, httpMock: HttpTestingController) => { - const dto = new CreateSchemaDto('name'); + const dto = new CreateSchemaDto('name', undefined, undefined, true); let schema: SchemaDetailsDto; @@ -341,7 +344,7 @@ describe('SchemasService', () => { }); expect(schema!).toEqual( - new SchemaDetailsDto('1', dto.name, '', new SchemaPropertiesDto(), false, now, user, now, user, new Version('2'), [])); + new SchemaDetailsDto('1', dto.name, '', new SchemaPropertiesDto(), true, false, now, user, now, user, new Version('2'), [])); })); it('should make put request to update schema', diff --git a/src/Squidex/app/shared/services/schemas.service.ts b/src/Squidex/app/shared/services/schemas.service.ts index 6d4f3eb5e..90135bd28 100644 --- a/src/Squidex/app/shared/services/schemas.service.ts +++ b/src/Squidex/app/shared/services/schemas.service.ts @@ -34,6 +34,7 @@ export class SchemaDto extends Model { public readonly name: string, public readonly category: string, public readonly properties: SchemaPropertiesDto, + public readonly isSingleton: boolean, public readonly isPublished: boolean, public readonly created: DateTime, public readonly createdBy: string, @@ -53,7 +54,7 @@ export class SchemaDetailsDto extends SchemaDto { public listFields: RootFieldDto[]; public listFieldsEditable: RootFieldDto[]; - constructor(id: string, name: string, category: string, properties: SchemaPropertiesDto, isPublished: boolean, created: DateTime, createdBy: string, lastModified: DateTime, lastModifiedBy: string, version: Version, + constructor(id: string, name: string, category: string, properties: SchemaPropertiesDto, isSingleton: boolean, isPublished: boolean, created: DateTime, createdBy: string, lastModified: DateTime, lastModifiedBy: string, version: Version, public readonly fields: RootFieldDto[], public readonly scriptQuery?: string, public readonly scriptCreate?: string, @@ -61,7 +62,7 @@ export class SchemaDetailsDto extends SchemaDto { public readonly scriptDelete?: string, public readonly scriptChange?: string ) { - super(id, name, category, properties, isPublished, created, createdBy, lastModified, lastModifiedBy, version); + super(id, name, category, properties, isSingleton, isPublished, created, createdBy, lastModified, lastModifiedBy, version); this.onCloned(); } @@ -177,7 +178,8 @@ export class CreateSchemaDto { constructor( public readonly name: string, public readonly fields?: RootFieldDto[], - public readonly properties?: SchemaPropertiesDto + public readonly properties?: SchemaPropertiesDto, + public readonly singleton?: boolean ) { } } @@ -240,6 +242,7 @@ export class SchemasService { item.id, item.name, item.category, properties, + item.isSingleton, item.isPublished, DateTime.parseISO_UTC(item.created), item.createdBy, DateTime.parseISO_UTC(item.lastModified), item.lastModifiedBy, @@ -300,6 +303,7 @@ export class SchemasService { body.name, body.category, properties, + body.isSingleton, body.isPublished, DateTime.parseISO_UTC(body.created), body.createdBy, DateTime.parseISO_UTC(body.lastModified), body.lastModifiedBy, @@ -328,6 +332,7 @@ export class SchemasService { dto.name, '', dto.properties || new SchemaPropertiesDto(), + dto.singleton === true, false, now, user, now, user, diff --git a/src/Squidex/app/shared/state/contents.forms.spec.ts b/src/Squidex/app/shared/state/contents.forms.spec.ts index fbf86b36a..61da6789d 100644 --- a/src/Squidex/app/shared/state/contents.forms.spec.ts +++ b/src/Squidex/app/shared/state/contents.forms.spec.ts @@ -371,7 +371,7 @@ describe('StringField', () => { }); function createSchema(properties: SchemaPropertiesDto, index = 1, fields: RootFieldDto[]) { - return new SchemaDetailsDto('id' + index, 'schema' + index, '', properties, true, null!, null!, null!, null!, null!, fields); + return new SchemaDetailsDto('id' + index, 'schema' + index, '', properties, false, true, null!, null!, null!, null!, null!, fields); } function createField(properties: FieldPropertiesDto, index = 1, partitioning = 'languages') { diff --git a/src/Squidex/app/shared/state/schemas.state.spec.ts b/src/Squidex/app/shared/state/schemas.state.spec.ts index b25f318b6..c02091aac 100644 --- a/src/Squidex/app/shared/state/schemas.state.spec.ts +++ b/src/Squidex/app/shared/state/schemas.state.spec.ts @@ -41,8 +41,8 @@ describe('SchemasState', () => { const newVersion = new Version('2'); const oldSchemas = [ - new SchemaDto('id1', 'name1', 'category1', {}, false, creation, creator, creation, creator, version), - new SchemaDto('id2', 'name2', 'category2', {}, true , creation, creator, creation, creator, version) + new SchemaDto('id1', 'name1', 'category1', {}, false, false, creation, creator, creation, creator, version), + new SchemaDto('id2', 'name2', 'category2', {}, false, true , creation, creator, creation, creator, version) ]; const nested1 = new NestedFieldDto(3, '3', createProperties('Number'), 2); @@ -52,7 +52,7 @@ describe('SchemasState', () => { const field2 = new RootFieldDto(2, '2', createProperties('Array'), 'invariant', true, true, true, [nested1, nested2]); const schema = - new SchemaDetailsDto('id2', 'name2', 'category2', {}, true, + new SchemaDetailsDto('id2', 'name2', 'category2', {}, false, true, creation, creator, creation, creator, version, @@ -284,7 +284,7 @@ describe('SchemasState', () => { it('should add schema to snapshot when created', () => { const request = new CreateSchemaDto('newName'); - const result = new SchemaDetailsDto('id4', 'newName', '', {}, false, modified, modifier, modified, modifier, version, []); + const result = new SchemaDetailsDto('id4', 'newName', '', {}, false, false, modified, modifier, modified, modifier, version, []); schemasService.setup(x => x.postSchema(app, request, modifier, modified)) .returns(() => of(result)); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs index a69db5009..56357383f 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs @@ -35,7 +35,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanCreate_should_throw_exception_if_singleton() { - A.CallTo(() => schema.Singleton).Returns(true); + A.CallTo(() => schema.IsSingleton).Returns(true); var command = new CreateContent { Data = new NamedContentData() }; @@ -45,7 +45,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanCreate_should_not_throw_exception_if_singleton_and_id_empty() { - A.CallTo(() => schema.Singleton).Returns(true); + A.CallTo(() => schema.IsSingleton).Returns(true); var command = new CreateContent { Data = new NamedContentData(), ContentId = Guid.Empty }; @@ -133,7 +133,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanChangeContentStatus_should_throw_exception_if_singleton() { - A.CallTo(() => schema.Singleton).Returns(true); + A.CallTo(() => schema.IsSingleton).Returns(true); var command = new ChangeContentStatus { Status = Status.Draft }; @@ -143,7 +143,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanChangeContentStatus_should_not_throw_exception_if_publishing_with_pending_changes() { - A.CallTo(() => schema.Singleton).Returns(true); + A.CallTo(() => schema.IsSingleton).Returns(true); var command = new ChangeContentStatus { Status = Status.Published }; @@ -177,7 +177,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard [Fact] public void CanDelete_should_throw_exception_if_singleton() { - A.CallTo(() => schema.Singleton).Returns(true); + A.CallTo(() => schema.IsSingleton).Returns(true); var command = new DeleteContent(); diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs index b2f00be97..cd880f849 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaGrainTests.cs @@ -72,7 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas Assert.Equal(SchemaName, sut.Snapshot.Name); Assert.Equal(SchemaName, sut.Snapshot.SchemaDef.Name); - Assert.True(sut.Snapshot.Singleton); + Assert.True(sut.Snapshot.IsSingleton); LastEvents .ShouldHaveSameEvents( From bcc6908dfe5bc5cad7a80634a33e6331726e085e Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 27 Jun 2018 19:39:17 +0200 Subject: [PATCH 6/7] UI finalized and bugfixes in API. --- .../Contents/ContentQueryService.cs | 1 - .../Contents/SingletonCommandMiddleware.cs | 10 +- src/Squidex.Infrastructure/States/Store.cs | 4 +- .../Schemas/Models/SchemaDetailsDto.cs | 5 + src/Squidex/Config/Domain/EntitiesServices.cs | 3 + .../pages/content/content-page.component.html | 82 +++--- .../pages/schemas/schema-form.component.html | 46 ++- .../pages/schemas/schema-form.component.scss | 62 +++++ .../pages/schemas/schema-form.component.ts | 2 +- .../schema-must-exist-published.guard.spec.ts | 9 +- .../schema-must-exist-published.guard.ts | 10 +- .../app/shared/services/schemas.service.ts | 4 +- .../app/shared/state/contents.state.ts | 16 +- src/Squidex/app/shared/state/schemas.forms.ts | 1 + src/Squidex/app/theme/icomoon/demo.html | 34 ++- .../app/theme/icomoon/fonts/icomoon.eot | Bin 24360 -> 24880 bytes .../app/theme/icomoon/fonts/icomoon.svg | 2 + .../app/theme/icomoon/fonts/icomoon.ttf | Bin 24196 -> 24716 bytes .../app/theme/icomoon/fonts/icomoon.woff | Bin 24272 -> 24792 bytes .../theme/icomoon/icons/multiple-content.svg | 95 +++++++ .../theme/icomoon/icons/single-content.svg | 69 +++++ src/Squidex/app/theme/icomoon/selection.json | 261 ++++++++++++------ src/Squidex/app/theme/icomoon/style.css | 16 +- 23 files changed, 576 insertions(+), 156 deletions(-) create mode 100644 src/Squidex/app/theme/icomoon/icons/multiple-content.svg create mode 100644 src/Squidex/app/theme/icomoon/icons/single-content.svg diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs index 5ec1f122e..c404d6476 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs @@ -63,7 +63,6 @@ namespace Squidex.Domain.Apps.Entities.Contents public async Task FindContentAsync(QueryContext context, Guid id, long version = -1) { Guard.NotNull(context, nameof(context)); - Guard.NotEmpty(id, nameof(id)); var schema = await GetSchemaAsync(context); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs index 2f1547416..6dd070600 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs @@ -7,6 +7,7 @@ using System; using System.Threading.Tasks; +using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Infrastructure; @@ -27,9 +28,14 @@ namespace Squidex.Domain.Apps.Entities.Contents { var schemaId = new NamedId(createSchema.SchemaId, createSchema.Name); - var command = SimpleMapper.Map(createSchema, new CreateContent { ContentId = Guid.Empty, SchemaId = schemaId, Publish = true }); + var data = new NamedContentData(); - await context.CommandBus.PublishAsync(command); + var contentId = Guid.Empty; + var content = new CreateContent { Data = data, ContentId = contentId, SchemaId = schemaId, Publish = true }; + + SimpleMapper.Map(context.Command, content); + + await context.CommandBus.PublishAsync(content); } } } diff --git a/src/Squidex.Infrastructure/States/Store.cs b/src/Squidex.Infrastructure/States/Store.cs index 461c443fb..89e162a54 100644 --- a/src/Squidex.Infrastructure/States/Store.cs +++ b/src/Squidex.Infrastructure/States/Store.cs @@ -42,7 +42,7 @@ namespace Squidex.Infrastructure.States public IPersistence WithEventSourcing(Type owner, TKey key, Func, Task> applyEvent) { - Guard.NotDefault(key, nameof(key)); + Guard.NotNull(key, nameof(key)); var snapshotStore = (ISnapshotStore)services.GetService(typeof(ISnapshotStore)); @@ -51,7 +51,7 @@ namespace Squidex.Infrastructure.States private IPersistence CreatePersistence(Type owner, TKey key, PersistenceMode mode, Func applySnapshot, Func, Task> applyEvent) { - Guard.NotDefault(key, nameof(key)); + Guard.NotNull(key, nameof(key)); var snapshotStore = (ISnapshotStore)services.GetService(typeof(ISnapshotStore)); diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs index 850c6f938..c9c3c5909 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDetailsDto.cs @@ -36,6 +36,11 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models /// public string Category { get; set; } + /// + /// Indicates if the schema is a singleton. + /// + public bool IsSingleton { get; set; } + /// /// Indicates if the schema is published. /// diff --git a/src/Squidex/Config/Domain/EntitiesServices.cs b/src/Squidex/Config/Domain/EntitiesServices.cs index ab8132503..140a66cc6 100644 --- a/src/Squidex/Config/Domain/EntitiesServices.cs +++ b/src/Squidex/Config/Domain/EntitiesServices.cs @@ -128,6 +128,9 @@ namespace Squidex.Config.Domain services.AddSingletonAs() .As(); + services.AddSingletonAs() + .As(); + services.AddSingletonAs() .As(); diff --git a/src/Squidex/app/features/content/pages/content/content-page.component.html b/src/Squidex/app/features/content/pages/content/content-page.component.html index d6442b2a9..cdf90089e 100644 --- a/src/Squidex/app/features/content/pages/content/content-page.component.html +++ b/src/Squidex/app/features/content/pages/content/content-page.component.html @@ -3,7 +3,7 @@
- + @@ -32,7 +32,8 @@ + + + + +