diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs index e2a8bb524..aede3db19 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs @@ -52,19 +52,19 @@ namespace Squidex.Domain.Apps.Entities.Contents return Task.FromResult(Status.Draft); } - public Task CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal user) + public Task CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal? user) { return Task.FromResult(true); } - public Task CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal user) + public Task CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal? user) { var result = Flow.TryGetValue(status, out var step) && step.Transitions.Any(x => x.Status == next); return Task.FromResult(result); } - public Task CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal user) + public Task CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal? user) { var result = status != Status.Archived; @@ -78,7 +78,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return Task.FromResult(result); } - public Task GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal user) + public Task GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal? user) { var result = Flow.TryGetValue(status, out var step) ? step.Transitions : Array.Empty(); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/GuardContent.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/GuardContent.cs index e2f1c3fa3..b18b9e960 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/GuardContent.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/GuardContent.cs @@ -169,7 +169,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards if (command.CheckReferrers) { - var hasReferrer = await contentRepository.HasReferrersAsync(content.AppId.Id, command.ContentId, SearchScope.All); + var hasReferrer = await contentRepository.HasReferrersAsync(content.AppId.Id, content.Id, SearchScope.All); if (hasReferrer) { @@ -186,7 +186,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards } } - private static async Task ValidateCanUpdate(IContentEntity content, IContentWorkflow contentWorkflow, ClaimsPrincipal user) + private static async Task ValidateCanUpdate(IContentEntity content, IContentWorkflow contentWorkflow, ClaimsPrincipal? user) { var status = content.NewStatus ?? content.Status; @@ -198,7 +198,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards public static void CheckPermission(IContentEntity content, ContentCommand command, string permission) { - if (content.CreatedBy?.Equals(command.Actor) == true) + if (Equals(content.CreatedBy, command.Actor) || command.User == null) { return; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs index c132bbf5b..5805e783c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs @@ -38,21 +38,21 @@ namespace Squidex.Domain.Apps.Entities.Contents return workflow.Steps.Select(x => new StatusInfo(x.Key, GetColor(x.Value))).ToArray(); } - public async Task CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal user) + public async Task CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal? user) { var workflow = await GetWorkflowAsync(content.AppId.Id, content.SchemaId.Id); return workflow.TryGetTransition(status, next, out var transition) && IsTrue(transition, content.Data, user); } - public async Task CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal user) + public async Task CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal? user) { var workflow = await GetWorkflowAsync(schema.AppId.Id, schema.Id); return workflow.TryGetTransition(workflow.Initial, Status.Published, out var transition) && IsTrue(transition, data, user); } - public async Task CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal user) + public async Task CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal? user) { var workflow = await GetWorkflowAsync(content.AppId.Id, content.SchemaId.Id); @@ -85,7 +85,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return status; } - public async Task GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal user) + public async Task GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal? user) { var result = new List(); @@ -102,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return result.ToArray(); } - private bool IsTrue(WorkflowCondition condition, ContentData data, ClaimsPrincipal user) + private bool IsTrue(WorkflowCondition condition, ContentData data, ClaimsPrincipal? user) { if (condition?.Roles != null && user != null) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs index 6c87762ac..cdda08e44 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs @@ -16,15 +16,15 @@ namespace Squidex.Domain.Apps.Entities.Contents { Task GetInitialStatusAsync(ISchemaEntity schema); - Task CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal user); + Task CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal? user); - Task CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal user); + Task CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal? user); - Task CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal user); + Task CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal? user); Task GetInfoAsync(IContentEntity content, Status status); - Task GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal user); + Task GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal? user); Task GetAllAsync(ISchemaEntity schema); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/SquidexCommand.cs b/backend/src/Squidex.Domain.Apps.Entities/SquidexCommand.cs index c1c4d484d..f49d3eeae 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/SquidexCommand.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/SquidexCommand.cs @@ -15,7 +15,7 @@ namespace Squidex.Domain.Apps.Entities { public RefToken Actor { get; set; } - public ClaimsPrincipal User { get; set; } + public ClaimsPrincipal? User { get; set; } public bool FromRule { get; set; } diff --git a/backend/src/Squidex.Infrastructure/RefToken.cs b/backend/src/Squidex.Infrastructure/RefToken.cs index 2da062050..9ecf64f10 100644 --- a/backend/src/Squidex.Infrastructure/RefToken.cs +++ b/backend/src/Squidex.Infrastructure/RefToken.cs @@ -54,11 +54,6 @@ namespace Squidex.Infrastructure return $"{Type.ToString().ToLowerInvariant()}:{Identifier}"; } - public override int GetHashCode() - { - return (Type.GetHashCode() * 397) ^ Identifier.GetHashCode(); - } - public static bool TryParse(string? value, [MaybeNullWhen(false)] out RefToken result) { value = value?.Trim(TrimChars); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs index bc54f67c9..ad2a64703 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs @@ -53,8 +53,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject { var result = A.Fake(); - var command = CreateCommand(new MyCommand()); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new MyCommand()); context.Complete(result); @@ -68,8 +69,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject { var file = new NoopAssetFile(); - var command = CreateCommand(new UploadAppImage { AppId = appId, File = file }); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new UploadAppImage { AppId = appId, File = file }); A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._)) .Returns(new ImageInfo(100, 100, false)); @@ -87,8 +89,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject var file = new NoopAssetFile(); - var command = CreateCommand(new UploadAppImage { AppId = appId, File = file }); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new UploadAppImage { AppId = appId, File = file }); A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream)) .Returns(Task.FromResult(null)); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs index 20faa09b9..70d70f61d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs @@ -87,8 +87,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject [Fact] public async Task Should_not_invoke_enricher_for_other_result() { - var command = CreateCommand(new MyCommand()); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new MyCommand()); context.Complete(12); @@ -103,8 +104,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject { var result = new AssetEntity(); - var command = CreateCommand(new MyCommand()); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new MyCommand()); context.Complete(result); @@ -121,8 +123,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject { var result = A.Fake(); - var command = CreateCommand(new MyCommand()); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new MyCommand()); context.Complete(result); @@ -139,8 +142,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject [Fact] public async Task Create_should_create_domain_object() { - var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new CreateAsset { AssetId = assetId, File = file }); await sut.HandleAsync(context); @@ -155,8 +159,11 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject [Fact] public async Task Create_should_calculate_hash() { - var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); - var context = CreateContextForCommand(command); + var command = new CreateAsset { AssetId = assetId, File = file }; + + var context = + CreateCommandContext( + command); await sut.HandleAsync(context); @@ -166,8 +173,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject [Fact] public async Task Create_should_return_duplicate_result_if_file_with_same_hash_found() { - var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new CreateAsset { AssetId = assetId, File = file }); SetupSameHashAsset(file.FileName, file.FileSize, out _); @@ -181,8 +189,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject [Fact] public async Task Create_should_not_return_duplicate_result_if_file_with_same_hash_found_but_duplicate_allowed() { - var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file, Duplicate = true }); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new CreateAsset { AssetId = assetId, File = file, Duplicate = true }); SetupSameHashAsset(file.FileName, file.FileSize, out _); @@ -196,8 +205,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject [Fact] public async Task Create_should_pass_through_duplicate() { - var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new CreateAsset { AssetId = assetId, File = file }); SetupSameHashAsset(file.FileName, file.FileSize, out var duplicate); @@ -213,8 +223,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject [Fact] public async Task Update_should_update_domain_object() { - var command = CreateCommand(new UpdateAsset { AssetId = assetId, File = file }); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new UpdateAsset { AssetId = assetId, File = file }); await ExecuteCreateAsync(); @@ -227,8 +238,11 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject [Fact] public async Task Update_should_calculate_hash() { - var command = CreateCommand(new UpdateAsset { AssetId = assetId, File = file }); - var context = CreateContextForCommand(command); + var command = new UpdateAsset { AssetId = assetId, File = file }; + + var context = + CreateCommandContext( + command); await ExecuteCreateAsync(); @@ -240,8 +254,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject [Fact] public async Task Update_should_enrich_asset() { - var command = CreateCommand(new UpdateAsset { AssetId = assetId, File = file }); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new UpdateAsset { AssetId = assetId, File = file }); await ExecuteCreateAsync(); @@ -255,8 +270,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject [Fact] public async Task AnnotateAsset_should_enrich_asset() { - var command = CreateCommand(new AnnotateAsset { AssetId = assetId, FileName = "newName" }); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new AnnotateAsset { AssetId = assetId, FileName = "newName" }); await ExecuteCreateAsync(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs index 7cf1dca1b..b8cf8f8e9 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs @@ -46,8 +46,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject [Fact] public async Task Should_not_invoke_enricher_for_other_result() { - var command = CreateCommand(new MyCommand()); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new MyCommand()); context.Complete(12); @@ -62,8 +63,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject { var result = new ContentEntity(); - var command = CreateCommand(new MyCommand()); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new MyCommand()); context.Complete(result); @@ -80,8 +82,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject { var result = A.Fake(); - var command = CreateCommand(new MyCommand()); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new MyCommand()); context.Complete(result); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs index 8cbefbc7c..3c222c6da 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs @@ -25,88 +25,86 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards { public class GuardContentTests : IClassFixture { - private readonly IContentWorkflow contentWorkflow = A.Fake(); + private readonly IContentWorkflow workflow = A.Fake(); private readonly IContentRepository contentRepository = A.Fake(); private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); + private readonly ISchemaEntity schema; + private readonly ISchemaEntity singleton; private readonly ClaimsPrincipal user = Mocks.FrontendUser(); private readonly Instant dueTimeInPast = SystemClock.Instance.GetCurrentInstant().Minus(Duration.FromHours(1)); private readonly RefToken actor = RefToken.User("123"); + public GuardContentTests() + { + schema = + Mocks.Schema(appId, schemaId, new Schema(schemaId.Name)); + + singleton = + Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, isSingleton: true)); + } + [Fact] public async Task CanCreate_should_throw_exception_if_data_is_null() { - var schema = CreateSchema(false); - var command = new CreateContent(); - await ValidationAssert.ThrowsAsync(() => GuardContent.CanCreate(command, contentWorkflow, schema), + await ValidationAssert.ThrowsAsync(() => GuardContent.CanCreate(command, workflow, schema), new ValidationError("Data is required.", "Data")); } [Fact] public async Task CanCreate_should_throw_exception_if_singleton() { - var schema = CreateSchema(true); - var command = new CreateContent { Data = new ContentData() }; - await Assert.ThrowsAsync(() => GuardContent.CanCreate(command, contentWorkflow, schema)); + await Assert.ThrowsAsync(() => GuardContent.CanCreate(command, workflow, singleton)); } [Fact] public async Task CanCreate_should_not_throw_exception_if_singleton_and_id_is_schema_id() { - var schema = CreateSchema(true); - var command = new CreateContent { Data = new ContentData(), ContentId = schema.Id }; - await GuardContent.CanCreate(command, contentWorkflow, schema); + await GuardContent.CanCreate(command, workflow, schema); } [Fact] - public async Task CanCreate_should_throw_exception_publish_not_allowed() + public async Task CanCreate_should_throw_exception_if_publishing_not_allowed() { - var schema = CreateSchema(false); - - SetupCanCreatePublish(schema, false); + SetupCanCreatePublish(false); var command = new CreateContent { Data = new ContentData(), Publish = true }; - await Assert.ThrowsAsync(() => GuardContent.CanCreate(command, contentWorkflow, schema)); + await Assert.ThrowsAsync(() => GuardContent.CanCreate(command, workflow, schema)); } [Fact] - public async Task CanCreate_should_not_throw_exception_publishing_allowed() + public async Task CanCreate_should_not_throw_exception_if_publishing_allowed() { - var schema = CreateSchema(false); - - SetupCanCreatePublish(schema, true); + SetupCanCreatePublish(true); var command = new CreateContent { Data = new ContentData(), Publish = true }; - await Assert.ThrowsAsync(() => GuardContent.CanCreate(command, contentWorkflow, schema)); + await Assert.ThrowsAsync(() => GuardContent.CanCreate(command, workflow, schema)); } [Fact] public async Task CanCreate_should_not_throw_exception_if_data_is_not_null() { - var schema = CreateSchema(false); - var command = new CreateContent { Data = new ContentData() }; - await GuardContent.CanCreate(command, contentWorkflow, schema); + await GuardContent.CanCreate(command, workflow, schema); } [Fact] public async Task CanUpdate_should_throw_exception_if_data_is_null() { - SetupCanUpdate(true); - var content = CreateContent(Status.Draft); + var command = CreateCommand(new UpdateContent()); - await ValidationAssert.ThrowsAsync(() => GuardContent.CanUpdate(command, content, contentWorkflow), + await ValidationAssert.ThrowsAsync(() => GuardContent.CanUpdate(command, content, workflow), new ValidationError("Data is required.", "Data")); } @@ -116,9 +114,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards SetupCanUpdate(false); var content = CreateContent(Status.Draft); + var command = CreateCommand(new UpdateContent { Data = new ContentData() }); - await Assert.ThrowsAsync(() => GuardContent.CanUpdate(command, content, contentWorkflow)); + await Assert.ThrowsAsync(() => GuardContent.CanUpdate(command, content, workflow)); } [Fact] @@ -127,9 +126,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards SetupCanUpdate(true); var content = CreateContent(Status.Draft); + var command = CreateCommand(new UpdateContent { Data = new ContentData() }); - await GuardContent.CanUpdate(command, content, contentWorkflow); + await GuardContent.CanUpdate(command, content, workflow); } [Fact] @@ -138,9 +138,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards SetupCanUpdate(true); var content = CreateContent(Status.Draft); + var command = CreateCommand(new PatchContent()); - await ValidationAssert.ThrowsAsync(() => GuardContent.CanPatch(command, content, contentWorkflow), + await ValidationAssert.ThrowsAsync(() => GuardContent.CanPatch(command, content, workflow), new ValidationError("Data is required.", "Data")); } @@ -150,9 +151,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards SetupCanUpdate(false); var content = CreateContent(Status.Draft); + var command = CreateCommand(new PatchContent { Data = new ContentData() }); - await Assert.ThrowsAsync(() => GuardContent.CanPatch(command, content, contentWorkflow)); + await Assert.ThrowsAsync(() => GuardContent.CanPatch(command, content, workflow)); } [Fact] @@ -161,95 +163,91 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards SetupCanUpdate(true); var content = CreateContent(Status.Draft); + var command = CreateCommand(new PatchContent { Data = new ContentData() }); - await GuardContent.CanPatch(command, content, contentWorkflow); + await GuardContent.CanPatch(command, content, workflow); } [Fact] public async Task CanChangeStatus_should_throw_exception_if_singleton() { - var schema = CreateSchema(true); - var content = CreateContent(Status.Published); + var command = CreateCommand(new ChangeContentStatus { Status = Status.Draft }); - await Assert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema)); + await Assert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, workflow, contentRepository, singleton)); } [Fact] public async Task CanChangeStatus_should_throw_exception_if_due_date_in_past() { - var schema = CreateSchema(false); - var content = CreateContent(Status.Draft); + var command = CreateCommand(new ChangeContentStatus { Status = Status.Published, DueTime = dueTimeInPast }); - A.CallTo(() => contentWorkflow.CanMoveToAsync(content, content.Status, command.Status, user)) + A.CallTo(() => workflow.CanMoveToAsync(content, content.Status, command.Status, user)) .Returns(true); - await ValidationAssert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema), + await ValidationAssert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, workflow, contentRepository, schema), new ValidationError("Due time must be in the future.", "DueTime")); } [Fact] public async Task CanChangeStatus_should_throw_exception_if_status_flow_not_valid() { - var schema = CreateSchema(false); - var content = CreateContent(Status.Draft); + var command = CreateCommand(new ChangeContentStatus { Status = Status.Published }); - A.CallTo(() => contentWorkflow.CanMoveToAsync(content, content.Status, command.Status, user)) + A.CallTo(() => workflow.CanMoveToAsync(content, content.Status, command.Status, user)) .Returns(false); - await ValidationAssert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema), + await ValidationAssert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, workflow, contentRepository, schema), new ValidationError("Cannot change status from Draft to Published.", "Status")); } [Fact] public async Task CanChangeStatus_should_throw_exception_if_referenced() { - var schema = CreateSchema(true); - var content = CreateContent(Status.Published); + var command = CreateCommand(new ChangeContentStatus { Status = Status.Draft }); A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, content.Id, SearchScope.Published)) .Returns(true); - await Assert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema)); + await Assert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, workflow, contentRepository, schema)); } [Fact] public async Task CanChangeStatus_should_not_throw_exception_if_singleton_is_published() { - var schema = CreateSchema(true); - var content = CreateDraftContent(Status.Draft); + var command = CreateCommand(new ChangeContentStatus { Status = Status.Published }); - await GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema); + await GuardContent.CanChangeStatus(command, content, workflow, contentRepository, singleton); } [Fact] public async Task CanChangeStatus_should_not_throw_exception_if_status_flow_valid() { - var schema = CreateSchema(false); - var content = CreateContent(Status.Draft); + var command = CreateCommand(new ChangeContentStatus { Status = Status.Published }); - A.CallTo(() => contentWorkflow.CanMoveToAsync(content, content.Status, command.Status, user)) + A.CallTo(() => workflow.CanMoveToAsync(content, content.Status, command.Status, user)) .Returns(true); - await GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema); + await GuardContent.CanChangeStatus(command, content, workflow, contentRepository, schema); } [Fact] public void CreateDraft_should_throw_exception_if_not_published() { var content = CreateContent(Status.Draft); + var command = CreateCommand(new CreateContentDraft()); Assert.Throws(() => GuardContent.CanCreateDraft(command, content)); @@ -259,6 +257,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards public void CreateDraft_should_not_throw_exception() { var content = CreateContent(Status.Published); + var command = CreateCommand(new CreateContentDraft()); GuardContent.CanCreateDraft(command, content); @@ -267,9 +266,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards [Fact] public void CanDeleteDraft_should_throw_exception_if_no_draft_found() { - CreateSchema(false); - var content = CreateContent(Status.Published); + var command = CreateCommand(new DeleteContentDraft()); Assert.Throws(() => GuardContent.CanDeleteDraft(command, content)); @@ -279,6 +277,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards public void CanDeleteDraft_should_not_throw_exception() { var content = CreateDraftContent(Status.Draft); + var command = CreateCommand(new DeleteContentDraft()); GuardContent.CanDeleteDraft(command, content); @@ -287,21 +286,19 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards [Fact] public async Task CanDelete_should_throw_exception_if_singleton() { - var schema = CreateSchema(true); - var content = CreateContent(Status.Published); + var command = CreateCommand(new DeleteContent()); - await Assert.ThrowsAsync(() => GuardContent.CanDelete(command, content, contentRepository, schema)); + await Assert.ThrowsAsync(() => GuardContent.CanDelete(command, content, contentRepository, singleton)); } [Fact] public async Task CanDelete_should_throw_exception_if_referenced() { - var schema = CreateSchema(true); - var content = CreateContent(Status.Published); - var command = CreateCommand(new DeleteContent()); + + var command = CreateCommand(new DeleteContent { CheckReferrers = true }); A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, content.Id, SearchScope.All)) .Returns(true); @@ -312,9 +309,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards [Fact] public async Task CanDelete_should_not_throw_exception() { - var schema = CreateSchema(false); - var content = CreateContent(Status.Published); + var command = CreateCommand(new DeleteContent()); await GuardContent.CanDelete(command, content, contentRepository, schema); @@ -324,21 +320,35 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards public void CheckPermission_should_not_throw_exception_if_content_is_from_current_user() { var content = CreateContent(status: Status.Published); + var command = CreateCommand(new DeleteContent()); GuardContent.CheckPermission(content, command, Permissions.AppContentsDelete); } [Fact] - public void CheckPermission_should_not_throw_exception_if_content_is_from_another_user_but_user_has_permission() + public void CheckPermission_should_not_throw_exception_if_user_is_null() { - var permission = Permissions.ForApp(Permissions.AppContentsDelete, appId.Name, schemaId.Name).Id; + var content = CreateContent(Status.Published); - var otherUser = Mocks.FrontendUser(permission: permission); - var otherActor = RefToken.User("456"); + var commandActor = RefToken.User("456"); + var command = CreateCommand(new DeleteContent { Actor = commandActor }); + command.User = null; + + GuardContent.CheckPermission(content, command, Permissions.AppContentsDelete); + } + + [Fact] + public void CheckPermission_should_not_throw_exception_if_content_is_from_another_user_but_user_has_permission() + { var content = CreateContent(Status.Published); - var command = CreateCommand(new DeleteContent { Actor = otherActor, User = otherUser }); + + var permission = Permissions.ForApp(Permissions.AppContentsDelete, appId.Name, schemaId.Name).Id; + + var commandUser = Mocks.FrontendUser(permission: permission); + var commandActor = RefToken.User("456"); + var command = CreateCommand(new DeleteContent { Actor = commandActor, User = commandUser }); GuardContent.CheckPermission(content, command, Permissions.AppContentsDelete); } @@ -346,31 +356,26 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards [Fact] public void CheckPermission_should_exception_if_content_is_from_another_user_and_user_has_no_permission() { - var otherActor = RefToken.User("456"); - var content = CreateContent(Status.Published); - var command = CreateCommand(new DeleteContent { Actor = otherActor }); + + var commandActor = RefToken.User("456"); + var command = CreateCommand(new DeleteContent { Actor = commandActor }); Assert.Throws(() => GuardContent.CheckPermission(content, command, Permissions.AppContentsDelete)); } private void SetupCanUpdate(bool canUpdate) { - A.CallTo(() => contentWorkflow.CanUpdateAsync(A._, A._, user)) + A.CallTo(() => workflow.CanUpdateAsync(A._, A._, user)) .Returns(canUpdate); } - private void SetupCanCreatePublish(ISchemaEntity schema, bool canCreate) + private void SetupCanCreatePublish(bool canCreate) { - A.CallTo(() => contentWorkflow.CanPublishOnCreateAsync(schema, A._, user)) + A.CallTo(() => workflow.CanPublishOnCreateAsync(schema, A._, user)) .Returns(canCreate); } - private ISchemaEntity CreateSchema(bool isSingleton) - { - return Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, isSingleton: isSingleton)); - } - private T CreateCommand(T command) where T : ContentCommand { if (command.Actor == null) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs index 6c85c7352..c0a67de19 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs @@ -18,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { public class EnrichWithWorkflowsTests { - private readonly IContentWorkflow contentWorkflow = A.Fake(); + private readonly IContentWorkflow workflow = A.Fake(); private readonly Context requestContext; private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); @@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { requestContext = new Context(Mocks.FrontendUser(), Mocks.App(appId)); - sut = new EnrichWithWorkflows(contentWorkflow); + sut = new EnrichWithWorkflows(workflow); } [Fact] @@ -42,7 +42,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries new StatusInfo(Status.Published, StatusColors.Published) }; - A.CallTo(() => contentWorkflow.GetNextAsync(content, content.Status, requestContext.User)) + A.CallTo(() => workflow.GetNextAsync(content, content.Status, requestContext.User)) .Returns(nexts); await sut.EnrichAsync(requestContext, new[] { content }, null!); @@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries Assert.Equal(Status.Published, content.NextStatuses?.Single().Status); - A.CallTo(() => contentWorkflow.GetNextAsync(content, A._, requestContext.User)) + A.CallTo(() => workflow.GetNextAsync(content, A._, requestContext.User)) .MustNotHaveHappened(); } @@ -72,7 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries Assert.Empty(content.NextStatuses); - A.CallTo(() => contentWorkflow.GetNextAsync(content, A._, requestContext.User)) + A.CallTo(() => workflow.GetNextAsync(content, A._, requestContext.User)) .MustNotHaveHappened(); } @@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var content = new ContentEntity { SchemaId = schemaId }; - A.CallTo(() => contentWorkflow.GetInfoAsync(content, content.Status)) + A.CallTo(() => workflow.GetInfoAsync(content, content.Status)) .Returns(new StatusInfo(Status.Published, StatusColors.Published)); await sut.EnrichAsync(requestContext, new[] { content }, null!); @@ -94,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var content = new ContentEntity { SchemaId = schemaId, NewStatus = Status.Archived }; - A.CallTo(() => contentWorkflow.GetInfoAsync(content, content.NewStatus.Value)) + A.CallTo(() => workflow.GetInfoAsync(content, content.NewStatus.Value)) .Returns(new StatusInfo(Status.Published, StatusColors.Archived)); await sut.EnrichAsync(requestContext, new[] { content }, null!); @@ -107,7 +107,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var content = new ContentEntity { SchemaId = schemaId, ScheduleJob = ScheduleJob.Build(Status.Archived, user, default) }; - A.CallTo(() => contentWorkflow.GetInfoAsync(content, content.ScheduleJob.Status)) + A.CallTo(() => workflow.GetInfoAsync(content, content.ScheduleJob.Status)) .Returns(new StatusInfo(Status.Published, StatusColors.Archived)); await sut.EnrichAsync(requestContext, new[] { content }, null!); @@ -120,7 +120,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var content = new ContentEntity { SchemaId = schemaId }; - A.CallTo(() => contentWorkflow.GetInfoAsync(content, content.Status)) + A.CallTo(() => workflow.GetInfoAsync(content, content.Status)) .Returns(Task.FromResult(null!)); var ctx = requestContext.Clone(b => b.WithResolveFlow(false)); @@ -135,7 +135,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries { var content = new ContentEntity { SchemaId = schemaId }; - A.CallTo(() => contentWorkflow.CanUpdateAsync(content, content.Status, requestContext.User)) + A.CallTo(() => workflow.CanUpdateAsync(content, content.Status, requestContext.User)) .Returns(true); var ctx = requestContext.Clone(b => b.WithResolveFlow(false)); @@ -156,7 +156,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries Assert.False(content.CanUpdate); - A.CallTo(() => contentWorkflow.CanUpdateAsync(content, A._, requestContext.User)) + A.CallTo(() => workflow.CanUpdateAsync(content, A._, requestContext.User)) .MustNotHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/GuardRuleTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/GuardRuleTests.cs index 42e458c08..a884eeb15 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/GuardRuleTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/GuardRuleTests.cs @@ -41,15 +41,14 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards [Fact] public async Task CanCreate_should_throw_exception_if_trigger_null() { - var command = new CreateRule + var command = CreateCommand(new CreateRule { - Trigger = null!, Action = new TestAction { Url = validUrl }, - AppId = appId - }; + Trigger = null!, + }); await ValidationAssert.ThrowsAsync(() => GuardRule.CanCreate(command, appProvider), new ValidationError("Trigger is required.", "Trigger")); @@ -58,15 +57,14 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards [Fact] public async Task CanCreate_should_throw_exception_if_action_null() { - var command = new CreateRule + var command = CreateCommand(new CreateRule { Trigger = new ContentChangedTriggerV2 { Schemas = ReadOnlyCollection.Empty() }, Action = null!, - AppId = appId - }; + }); await ValidationAssert.ThrowsAsync(() => GuardRule.CanCreate(command, appProvider), new ValidationError("Action is required.", "Action")); @@ -75,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards [Fact] public async Task CanCreate_should_not_throw_exception_if_trigger_and_action_valid() { - var command = new CreateRule + var command = CreateCommand(new CreateRule { Trigger = new ContentChangedTriggerV2 { @@ -84,9 +82,8 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards Action = new TestAction { Url = validUrl - }, - AppId = appId - }; + } + }); await GuardRule.CanCreate(command, appProvider); } @@ -150,6 +147,13 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards GuardRule.CanDelete(command); } + private CreateRule CreateCommand(CreateRule command) + { + command.AppId = appId; + + return command; + } + private IRuleEntity Rule() { var rule = A.Fake(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleCommandMiddlewareTests.cs index 241a17575..9625a32ce 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleCommandMiddlewareTests.cs @@ -45,8 +45,9 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject [Fact] public async Task Should_not_invoke_enricher_for_other_result() { - var command = CreateCommand(new MyCommand()); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new MyCommand()); context.Complete(12); @@ -61,8 +62,9 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject { var result = new RuleEntity(); - var command = CreateCommand(new MyCommand()); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new MyCommand()); context.Complete(result); @@ -79,8 +81,9 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject { var result = A.Fake(); - var command = CreateCommand(new MyCommand()); - var context = CreateContextForCommand(command); + var context = + CreateCommandContext( + new MyCommand()); context.Complete(result); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs index 268acc0c2..d708c8a54 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs @@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_name_not_valid() { - var command = new CreateSchema { AppId = appId, Name = "INVALID NAME" }; + var command = CreateCommand(new CreateSchema { Name = "INVALID NAME" }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Name is not a valid slug.", "Name")); @@ -45,9 +45,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_field_name_invalid() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -58,7 +57,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards } }, Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Name is not a Javascript property name.", @@ -68,9 +67,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_field_properties_null() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -81,7 +79,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards } }, Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Properties is required.", @@ -91,9 +89,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_field_properties_not_valid() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -104,7 +101,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards } }, Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Max length must be greater or equal to min length.", @@ -115,9 +112,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_field_partitioning_not_valid() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -128,7 +124,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards } }, Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Partitioning is not a valid value.", @@ -138,9 +134,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_fields_contains_duplicate_name() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -157,7 +152,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards } }, Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Field 'field1' has been added twice.", @@ -167,9 +162,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_nested_field_name_invalid() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -188,7 +182,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards } }, Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Name is not a Javascript property name.", @@ -198,9 +192,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_nested_field_properties_null() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -219,7 +212,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards } }, Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Properties is required.", @@ -229,9 +222,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_nested_field_is_array() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -250,7 +242,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards } }, Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Nested field cannot be array fields.", @@ -260,9 +252,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_nested_field_properties_not_valid() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -281,7 +272,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards } }, Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Max length must be greater or equal to min length.", @@ -292,9 +283,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_nested_field_have_duplicate_names() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -318,7 +308,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards } }, Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Field 'nested1' has been added twice.", @@ -328,9 +318,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_ui_field_is_invalid() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -345,7 +334,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards FieldsInLists = new FieldNames("field1"), FieldsInReferences = new FieldNames("field1"), Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("UI field cannot be hidden.", @@ -361,7 +350,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_invalid_lists_field_are_used() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { Fields = new[] { @@ -381,7 +370,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards FieldsInLists = new FieldNames(null!, null!, "field3", "field1", "field1", "field4"), FieldsInReferences = null, Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Field is required.", @@ -399,7 +388,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_invalid_references_field_are_used() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { Fields = new[] { @@ -419,7 +408,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards FieldsInLists = null, FieldsInReferences = new FieldNames(null!, null!, "field3", "field1", "field1", "field4"), Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Field is required.", @@ -437,12 +426,12 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_throw_exception_if_references_contains_meta_field() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { FieldsInLists = null, FieldsInReferences = new FieldNames("meta.id"), Name = "new-schema" - }; + }); ValidationAssert.Throws(() => GuardSchema.CanCreate(command), new ValidationError("Field is not part of the schema.", @@ -452,9 +441,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards [Fact] public void CanCreate_should_not_throw_exception_if_command_is_valid() { - var command = new CreateSchema + var command = CreateCommand(new CreateSchema { - AppId = appId, Fields = new[] { new UpsertSchemaField @@ -494,7 +482,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards FieldsInLists = new FieldNames("field1", "meta.id"), FieldsInReferences = new FieldNames("field1"), Name = "new-schema" - }; + }); GuardSchema.CanCreate(command); } @@ -706,6 +694,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards GuardSchema.CanDelete(command); } + private CreateSchema CreateCommand(CreateSchema command) + { + command.AppId = appId; + + return command; + } + private static StringFieldProperties ValidProperties() { return new StringFieldProperties { MinLength = 10, MaxLength = 20 }; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs index 8855b22b5..d95e9c751 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs @@ -73,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers .Invokes((IEnumerable> events) => LastEvents = events); } - protected CommandContext CreateContextForCommand(TCommand command) where TCommand : SquidexCommand + protected CommandContext CreateCommandContext(TCommand command) where TCommand : SquidexCommand { return new CommandContext(CreateCommand(command), A.Dummy()); }