diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs index b77d09195..92532ec69 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs @@ -102,10 +102,6 @@ namespace Squidex.Domain.Apps.Entities.Contents if (Snapshot.IsPending && Snapshot.Status == Status.Published && c.Status == Status.Published) { - var ctx = await CreateContext(Snapshot.AppId.Id, Snapshot.SchemaId.Id, () => "Failed to update content."); - - await ctx.ExecuteScriptAndTransformAsync(x => x.ScriptUpdate, "Update", c, Snapshot.DataDraft, Snapshot.Data); - ConfirmChanges(c); } else @@ -170,14 +166,14 @@ namespace Squidex.Domain.Apps.Entities.Contents await ctx.ValidateAsync(c.Data); } + newData = await ctx.ExecuteScriptAndTransformAsync(x => x.ScriptUpdate, "Update", c, newData, Snapshot.Data); + if (isProposal) { ProposeUpdate(c, newData); } else { - newData = await ctx.ExecuteScriptAndTransformAsync(x => x.ScriptUpdate, "Update", c, newData, Snapshot.Data); - Update(c, newData); } } diff --git a/tests/RunCoverage.ps1 b/tests/RunCoverage.ps1 index 27b2b5e1a..aa392b454 100644 --- a/tests/RunCoverage.ps1 +++ b/tests/RunCoverage.ps1 @@ -26,7 +26,7 @@ if ($all -Or $infrastructure) { -register:user ` -target:"C:\Program Files\dotnet\dotnet.exe" ` -targetargs:"test $folderWorking\Squidex.Infrastructure.Tests\Squidex.Infrastructure.Tests.csproj" ` - -filter:"+[Squidex.Infrastructure*]* -[Squidex.Infrastructure*]*CodeGen*" ` + -filter:"+[Squidex.*]* -[Squidex.Infrastructure*]*CodeGen*" ` -skipautoprops ` -output:"$folderWorking\$folderReports\Infrastructure.xml" ` -oldStyle @@ -37,7 +37,7 @@ if ($all -Or $appsCore) { -register:user ` -target:"C:\Program Files\dotnet\dotnet.exe" ` -targetargs:"test $folderWorking\Squidex.Domain.Apps.Core.Tests\Squidex.Domain.Apps.Core.Tests.csproj" ` - -filter:"+[Squidex.Domain.Apps.Core*]*" ` + -filter:"+[Squidex.*]*" ` -skipautoprops ` -output:"$folderWorking\$folderReports\Core.xml" ` -oldStyle @@ -48,7 +48,7 @@ if ($all -Or $appsEntities) { -register:user ` -target:"C:\Program Files\dotnet\dotnet.exe" ` -targetargs:"test $folderWorking\Squidex.Domain.Apps.Entities.Tests\Squidex.Domain.Apps.Entities.Tests.csproj" ` - -filter:"+[Squidex.Domain.Apps.Entities*]* -[Squidex.Domain.Apps.Entities*]*CodeGen*" ` + -filter:"+[Squidex.*]* -[Squidex.Domain.Apps.Entities*]*CodeGen*" ` -skipautoprops ` -output:"$folderWorking\$folderReports\Entities.xml" ` -oldStyle @@ -59,7 +59,7 @@ if ($all -Or $users) { -register:user ` -target:"C:\Program Files\dotnet\dotnet.exe" ` -targetargs:"test $folderWorking\Squidex.Domain.Users.Tests\Squidex.Domain.Users.Tests.csproj" ` - -filter:"+[Squidex.Domain.Users*]*" ` + -filter:"+[Squidex.*]*" ` -skipautoprops ` -output:"$folderWorking\$folderReports\Users.xml" ` -oldStyle diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs index 47ad93198..fde2d505e 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs @@ -109,6 +109,16 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds Assert.Empty(result); } + [Fact] + public void Should_empty_list_from_non_references_field() + { + var sut = new StringField(1, "my-string", Partitioning.Invariant); + + var result = sut.ExtractReferences("invalid").ToArray(); + + Assert.Empty(result); + } + [Fact] public void Should_return_null_from_assets_field_when_removing_references_from_null_array() { diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs index 92fdaf1ea..13acf8402 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs @@ -6,9 +6,11 @@ // ========================================================================== using System; +using System.Security.Claims; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Scripting; using Squidex.Infrastructure; +using Squidex.Infrastructure.Security; using Xunit; namespace Squidex.Domain.Apps.Core.Operations.Scripting @@ -202,5 +204,41 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting Assert.Equal(expected, result); } + + [Fact] + public void Should_transform_content_with_old_content() + { + var content = + new NamedContentData() + .AddField("number0", + new ContentFieldData() + .AddValue("iv", 3.0)); + + var oldContent = + new NamedContentData() + .AddField("number0", + new ContentFieldData() + .AddValue("iv", 5.0)); + + var expected = + new NamedContentData() + .AddField("number0", + new ContentFieldData() + .AddValue("iv", 13.0)); + + var userIdentity = new ClaimsIdentity(); + var userPrincipal = new ClaimsPrincipal(userIdentity); + + userIdentity.AddClaim(new Claim(OpenIdClaims.ClientId, "2")); + + var context = new ScriptContext { Data = content, OldData = oldContent, User = userPrincipal }; + + var result = scriptEngine.ExecuteAndTransform(context, @" + ctx.data.number0.iv = ctx.data.number0.iv + ctx.oldData.number0.iv * parseInt(ctx.user.id, 10); + + replace(ctx.data);"); + + Assert.Equal(expected, result); + } } } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs index 82f09ce1d..4c5e71454 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs @@ -193,13 +193,15 @@ namespace Squidex.Domain.Apps.Entities.Contents result.ShouldBeEquivalent(new ContentDataChangedResult(otherData, 2)); + Assert.True(sut.Snapshot.IsPending); + LastEvents .ShouldHaveSameEvents( CreateContentEvent(new ContentUpdateProposed { Data = otherData }) ); A.CallTo(() => scriptEngine.ExecuteAndTransform(A.Ignored, "")) - .MustNotHaveHappened(); + .MustHaveHappened(); } [Fact] @@ -264,13 +266,15 @@ namespace Squidex.Domain.Apps.Entities.Contents result.ShouldBeEquivalent(new ContentDataChangedResult(otherData, 2)); + Assert.True(sut.Snapshot.IsPending); + LastEvents .ShouldHaveSameEvents( CreateContentEvent(new ContentUpdateProposed { Data = patched }) ); A.CallTo(() => scriptEngine.ExecuteAndTransform(A.Ignored, "")) - .MustNotHaveHappened(); + .MustHaveHappened(); } [Fact] @@ -315,6 +319,30 @@ namespace Squidex.Domain.Apps.Entities.Contents .MustHaveHappened(); } + [Fact] + public async Task ChangedStatus_should_create_proposal_events_and_update_state() + { + var command = new ChangeContentStatus { Status = Status.Published }; + + await ExecuteCreateAsync(); + await ExecutePublishAsync(); + await ExecuteProposeUpdateAsync(); + + var result = await sut.ExecuteAsync(CreateContentCommand(command)); + + result.ShouldBeEquivalent(new EntitySavedResult(3)); + + Assert.False(sut.Snapshot.IsPending); + + LastEvents + .ShouldHaveSameEvents( + CreateContentEvent(new ContentChangesPublished()) + ); + + A.CallTo(() => scriptEngine.Execute(A.Ignored, "")) + .MustNotHaveHappened(); + } + [Fact] public async Task ChangeStatus_should_refresh_properties_and_create_scheduled_events_when_command_has_due_time() { @@ -363,6 +391,27 @@ namespace Squidex.Domain.Apps.Entities.Contents .MustHaveHappened(); } + [Fact] + public async Task DiscardChanges_should_update_properties_and_create_events() + { + var command = new DiscardChanges(); + + await ExecuteCreateAsync(); + await ExecutePublishAsync(); + await ExecuteProposeUpdateAsync(); + + var result = await sut.ExecuteAsync(CreateContentCommand(command)); + + result.ShouldBeEquivalent(new EntitySavedResult(3)); + + Assert.False(sut.Snapshot.IsPending); + + LastEvents + .ShouldHaveSameEvents( + CreateContentEvent(new ContentChangesDiscarded()) + ); + } + private Task ExecuteCreateAsync() { return sut.ExecuteAsync(CreateContentCommand(new CreateContent { Data = data })); @@ -370,7 +419,12 @@ namespace Squidex.Domain.Apps.Entities.Contents private Task ExecuteUpdateAsync() { - return sut.ExecuteAsync(CreateContentCommand(new UpdateContent { Data = data })); + return sut.ExecuteAsync(CreateContentCommand(new UpdateContent { Data = otherData })); + } + + private Task ExecuteProposeUpdateAsync() + { + return sut.ExecuteAsync(CreateContentCommand(new UpdateContent { Data = otherData, AsDraft = true })); } private Task ExecuteDeleteAsync() diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs index fb3f1b21b..197292ce6 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs @@ -99,7 +99,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { A.CallTo(() => appProvider.GetSchemaAsync(appId, schemaId, false)) .Returns(schema); - A.CallTo(() => contentRepository.FindContentAsync(app, schema, null, contentId)) + A.CallTo(() => contentRepository.FindContentAsync(app, schema, A.Ignored, contentId)) .Returns(content); A.CallTo(() => schema.ScriptQuery) diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Actions/ElasticSearchActionTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Actions/ElasticSearchActionTests.cs new file mode 100644 index 000000000..2bad9987c --- /dev/null +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Guards/Actions/ElasticSearchActionTests.cs @@ -0,0 +1,67 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Threading.Tasks; +using Squidex.Domain.Apps.Core.Rules.Actions; +using Xunit; + +namespace Squidex.Domain.Apps.Entities.Rules.Guards.Actions +{ + public class ElasticSearchActionTests + { + [Fact] + public async Task Should_add_error_if_host_is_null() + { + var action = new ElasticSearchAction { Host = null, IndexName = "squidex", IndexType = "squidex" }; + + var errors = await RuleActionValidator.ValidateAsync(action); + + Assert.NotEmpty(errors); + } + + [Fact] + public async Task Should_add_error_if_host_is_relative() + { + var action = new ElasticSearchAction { Host = new Uri("/rel", UriKind.Relative), IndexName = "squidex", IndexType = "squidex" }; + + var errors = await RuleActionValidator.ValidateAsync(action); + + Assert.NotEmpty(errors); + } + + [Fact] + public async Task Should_add_error_if_index_name_is_null() + { + var action = new ElasticSearchAction { Host = new Uri("http://host", UriKind.Absolute), IndexName = null, IndexType = "squidex" }; + + var errors = await RuleActionValidator.ValidateAsync(action); + + Assert.NotEmpty(errors); + } + + [Fact] + public async Task Should_add_error_if_index_type_is_null() + { + var action = new ElasticSearchAction { Host = new Uri("http://host", UriKind.Absolute), IndexName = "squidex", IndexType = null }; + + var errors = await RuleActionValidator.ValidateAsync(action); + + Assert.NotEmpty(errors); + } + + [Fact] + public async Task Should_not_add_error_if_values_are_valid() + { + var action = new ElasticSearchAction { Host = new Uri("http://host", UriKind.Absolute), IndexName = "squidex", IndexType = "squidex" }; + + var errors = await RuleActionValidator.ValidateAsync(action); + + Assert.Empty(errors); + } + } +}