diff --git a/.composer.json b/.composer.json index 7bb9de59aa4..2d4b9ef0c20 100644 --- a/.composer.json +++ b/.composer.json @@ -29,6 +29,11 @@ "../../bin/phpunit --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/UnitTests.xml Neos.ContentRepository.Core/Tests/Unit", "../../bin/phpunit --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/UnitTests.xml Neos.ContentRepositoryRegistry/Tests/Unit" ], + "test:parallel": [ + "FLOW_CONTEXT=Testing/Behat ../../bin/paratest --debug -v --functional --group parallel --processes 2 --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php", + "FLOW_CONTEXT=Testing/Behat ../../bin/paratest --debug -v --functional --group parallel --processes 2 --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php", + "FLOW_CONTEXT=Testing/Behat ../../bin/paratest --debug -v --functional --group parallel --processes 2 --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php" + ], "test:functional": [ "../../bin/phpunit --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.Core/Tests/Functional" ], @@ -54,7 +59,8 @@ "test": [ "@test:unit", "@test:functional", - "@test:behavioral" + "@test:behavioral", + "@test:parallel" ] }, "autoload": { diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/HierarchyIntegrityIsProvided.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/HierarchyIntegrityIsProvided.feature index 962becc18bd..bb7eeccc08b 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/HierarchyIntegrityIsProvided.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/HierarchyIntegrityIsProvided.feature @@ -20,9 +20,9 @@ Feature: Run integrity violation detection regarding hierarchy relations and nod | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/NodesHaveAtMostOneParentPerSubgraph.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/NodesHaveAtMostOneParentPerSubgraph.feature index eedd68e8ffd..0cb73f49e4b 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/NodesHaveAtMostOneParentPerSubgraph.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/NodesHaveAtMostOneParentPerSubgraph.feature @@ -20,9 +20,9 @@ Feature: Run integrity violation detection regarding parent relations | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature index 577f79c2461..3267be5d085 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature @@ -23,9 +23,9 @@ Feature: Run integrity violation detection regarding reference relations | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -51,7 +51,6 @@ Feature: Run integrity violation detection regarding reference relations Scenario: Detach a reference relation from its source When the command SetNodeReferences is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | sourceOriginDimensionSpacePoint | {"language":"de"} | | sourceNodeAggregateId | "source-nodandaise" | | referenceName | "referenceProperty" | diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionIntegrityIsProvided.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionIntegrityIsProvided.feature index 7412e9ee0cb..0e368b7fc70 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionIntegrityIsProvided.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionIntegrityIsProvided.feature @@ -20,9 +20,9 @@ Feature: Run integrity violation detection regarding restriction relations | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionsArePropagatedRecursively.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionsArePropagatedRecursively.feature index 9253b7ac73a..b5c4e458f2c 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionsArePropagatedRecursively.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/RestrictionsArePropagatedRecursively.feature @@ -20,9 +20,9 @@ Feature: Run integrity violation detection regarding restriction relations | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/SiblingsAreDistinctlySorted.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/SiblingsAreDistinctlySorted.feature index e8c8510392f..75f7032d08c 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/SiblingsAreDistinctlySorted.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/SiblingsAreDistinctlySorted.feature @@ -20,9 +20,9 @@ Feature: Run integrity violation detection regarding sibling sorting | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/TetheredNodesAreNamed.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/TetheredNodesAreNamed.feature index b767c0e392e..3068aaa7edf 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/TetheredNodesAreNamed.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/ProjectionIntegrityViolationDetection/TetheredNodesAreNamed.feature @@ -20,9 +20,9 @@ Feature: Run projection integrity violation detection regarding naming of tether | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/01-CreateRootNodeAggregateWithNode_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/01-CreateRootNodeAggregateWithNode_ConstraintChecks.feature index 1aa76a131e7..b1ff005357c 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/01-CreateRootNodeAggregateWithNode_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/01-CreateRootNodeAggregateWithNode_ConstraintChecks.feature @@ -13,6 +13,9 @@ Feature: Create a root node aggregate 'Neos.ContentRepository.Testing:AbstractRoot': abstract: true 'Neos.ContentRepository.Testing:NonRoot': [] + 'Neos.ContentRepository.Testing:OtherRoot': + superTypes: + 'Neos.ContentRepository:Root': true """ And using identifier "default", I define a content repository And I am in content repository "default" @@ -24,21 +27,31 @@ Feature: Create a root node aggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date - Scenario: Try to create a root node aggregate in a content stream that currently does not exist: + Scenario: Try to create a root node aggregate in a workspace that currently does not exist: When the command CreateRootNodeAggregateWithNode is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "i-do-not-exist" | + | workspaceName | "i-do-not-exist" | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository:Root" | Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" + Scenario: Try to create a root node aggregate in a closed content stream: + When the command CloseContentStream is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + And the command CreateRootNodeAggregateWithNode is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:OtherRoot" | + Then the last command should have thrown an exception of type "ContentStreamIsClosed" + Scenario: Try to create a root node aggregate in a content stream where it is already present: When the command CreateRootNodeAggregateWithNode is executed with payload and exceptions are caught: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/02-CreateRootNodeAggregateWithNode_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/02-CreateRootNodeAggregateWithNode_WithoutDimensions.feature index 324f7c6d0f0..9f86bc72a56 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/02-CreateRootNodeAggregateWithNode_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/02-CreateRootNodeAggregateWithNode_WithoutDimensions.feature @@ -25,7 +25,7 @@ Feature: Create a root node aggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Scenario: Create the initial root node aggregate using valid payload without dimensions When the command CreateRootNodeAggregateWithNode is executed with payload: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/03-CreateRootNodeAggregateWithNodeAndTetheredChildren_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/03-CreateRootNodeAggregateWithNodeAndTetheredChildren_WithoutDimensions.feature index 7678cbc51e4..43ee5bb29b9 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/03-CreateRootNodeAggregateWithNodeAndTetheredChildren_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/03-CreateRootNodeAggregateWithNodeAndTetheredChildren_WithoutDimensions.feature @@ -38,8 +38,7 @@ Feature: Create a root node aggregate with tethered children | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" - And I am in dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And I am user identified by "initiating-user-identifier" Scenario: Create root node with tethered children @@ -134,7 +133,7 @@ Feature: Create a root node aggregate with tethered children | Key | Value | | text | "my sub sub default" | - When I am in content stream "cs-identifier" and dimension space point [] + And I am in the active content stream of workspace "live" and dimension space point {} And I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no parent node And I expect this node to have the following child nodes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/04-CreateRootNodeAggregateWithNodeAndTetheredChildren_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/04-CreateRootNodeAggregateWithNodeAndTetheredChildren_WithDimensions.feature index cf15c9682e6..6380b4c0bee 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/04-CreateRootNodeAggregateWithNodeAndTetheredChildren_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/04-CreateRootNodeAggregateWithNodeAndTetheredChildren_WithDimensions.feature @@ -40,7 +40,7 @@ Feature: Create a root node aggregate with tethered children | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" And I am user identified by "initiating-user-identifier" Scenario: Create root node with tethered children @@ -173,7 +173,7 @@ Feature: Create a root node aggregate with tethered children | Key | Value | | text | "my sub sub default" | - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} And I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no parent node And I expect this node to have the following child nodes: @@ -202,7 +202,7 @@ Feature: Create a root node aggregate with tethered children And I expect this node to have no references And I expect this node to not be referenced - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no parent node And I expect this node to have the following child nodes: @@ -232,7 +232,7 @@ Feature: Create a root node aggregate with tethered children And I expect this node to not be referenced - When I am in content stream "cs-identifier" and dimension space point {"language": "en"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "en"} And I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no parent node And I expect this node to have the following child nodes: @@ -262,7 +262,7 @@ Feature: Create a root node aggregate with tethered children And I expect this node to not be referenced - When I am in content stream "cs-identifier" and dimension space point {"language": "en_US"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "en_US"} And I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no parent node And I expect this node to have the following child nodes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/05-CreateRootNodeAggregateWithNode_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/05-CreateRootNodeAggregateWithNode_WithDimensions.feature index 4770ce6aead..af98e698f3f 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/05-CreateRootNodeAggregateWithNode_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/01-RootNodeCreation/05-CreateRootNodeAggregateWithNode_WithDimensions.feature @@ -26,7 +26,7 @@ Feature: Create a root node aggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Scenario: Create the initial root node aggregate using valid payload with dimensions When the command CreateRootNodeAggregateWithNode is executed with payload: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/01-CreateNodeAggregateWithNode_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/01-CreateNodeAggregateWithNode_ConstraintChecks.feature index 18d2a8d135b..ed9ffe003e4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/01-CreateNodeAggregateWithNode_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/01-CreateNodeAggregateWithNode_ConstraintChecks.feature @@ -38,18 +38,17 @@ Feature: Create node aggregate with node | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" - And I am in dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date - Scenario: Try to create a node aggregate in a content stream that currently does not exist: + Scenario: Try to create a node aggregate in a workspace that currently does not exist: When the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "non-existent-cs-identifier" | + | workspaceName | "non-existent" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Node" | | parentNodeAggregateId | "lady-eleonode-rootford" | @@ -57,7 +56,20 @@ Feature: Create node aggregate with node Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" - Scenario: Try to create a node aggregate in a content stream where it is already present: + Scenario: Try to create a node aggregate in a workspace whose content stream is closed: + When the command CloseContentStream is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + And the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | nodeTypeName | "Neos.ContentRepository.Testing:Node" | + | parentNodeAggregateId | "lady-eleonode-rootford" | + | nodeName | "document" | + + Then the last command should have thrown an exception of type "ContentStreamIsClosed" + + Scenario: Try to create a node aggregate in a workspace where it is already present: When the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/02-CreateNodeAggregateWithNode_ConstraintChecks_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/02-CreateNodeAggregateWithNode_ConstraintChecks_WithDimensions.feature index 67583dec79f..66512883875 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/02-CreateNodeAggregateWithNode_ConstraintChecks_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/02-CreateNodeAggregateWithNode_ConstraintChecks_WithDimensions.feature @@ -40,7 +40,7 @@ Feature: Create node aggregate with node | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" And I am in dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature index bd56ce51ff7..b162ee69a6e 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/03-CreateNodeAggregateWithNode_WithoutDimensions.feature @@ -30,7 +30,7 @@ Feature: Create node aggregate with node | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" And I am in dimension space point {} And I am user identified by "initiating-user-identifier" And the command CreateRootNodeAggregateWithNode is executed with payload: @@ -149,7 +149,7 @@ Feature: Create node aggregate with node | Key | Value | | defaultText | "my default" | - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect the subgraph projection to consist of exactly 4 nodes And I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no parent node @@ -201,7 +201,7 @@ Feature: Create node aggregate with node | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" And I am in dimension space point {} And I am user identified by "initiating-user-identifier" And the command CreateRootNodeAggregateWithNode is executed with payload: @@ -242,7 +242,7 @@ Feature: Create node aggregate with node | succeedingNodeAggregateId | "sir-david-nodenborough" | When the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And I expect node aggregate identifier "sir-nodeward-nodington-iii" and node path "esquire" to lead to node cs-identifier;sir-nodeward-nodington-iii;{} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no child nodes @@ -286,7 +286,7 @@ Feature: Create node aggregate with node | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" And I am in dimension space point {} And I am user identified by "initiating-user-identifier" And the command CreateRootNodeAggregateWithNode is executed with payload: @@ -408,7 +408,7 @@ Feature: Create node aggregate with node | Key | Value | | text | "my sub sub default" | - When I am in content stream "cs-identifier" and dimension space point [] + When I am in the active content stream of workspace "live" and dimension space point [] And I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no parent node And I expect this node to have the following child nodes: @@ -470,7 +470,7 @@ Feature: Create node aggregate with node | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" And I am in dimension space point {} And I am user identified by "initiating-user-identifier" And the command CreateRootNodeAggregateWithNode is executed with payload: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/04-CreateNodeAggregateWithNode_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/04-CreateNodeAggregateWithNode_WithDimensions.feature index 272af25581c..4cc710e9add 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/04-CreateNodeAggregateWithNode_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/04-CreateNodeAggregateWithNode_WithDimensions.feature @@ -30,7 +30,7 @@ Feature: Create node aggregate with node | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/05-CreateNodeAggregateWithNode_ComplexDefaultAndInitialProperties.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/05-CreateNodeAggregateWithNode_ComplexDefaultAndInitialProperties.feature index 99bd1294925..22f043d0590 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/05-CreateNodeAggregateWithNode_ComplexDefaultAndInitialProperties.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/05-CreateNodeAggregateWithNode_ComplexDefaultAndInitialProperties.feature @@ -55,7 +55,7 @@ Feature: Create a node aggregate with complex default values | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" And I am in dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/06-CreateNodeAggregateWithNode_NodeTypeConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/06-CreateNodeAggregateWithNode_NodeTypeConstraintChecks.feature index edf96859d07..49a1f36fe45 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/06-CreateNodeAggregateWithNode_NodeTypeConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/02-NodeCreation/06-CreateNodeAggregateWithNode_NodeTypeConstraintChecks.feature @@ -32,6 +32,7 @@ Feature: Create node aggregate with node """ And using identifier "default", I define a content repository And I am in content repository "default" + And I am in workspace "live" And I am user identified by "initiating-user-identifier" And the command CreateRootWorkspace is executed with payload: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/01-CreateNodeVariant_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/01-CreateNodeVariant_ConstraintChecks.feature index 701ef17114d..d4d2be10e79 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/01-CreateNodeVariant_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/01-CreateNodeVariant_ConstraintChecks.feature @@ -26,7 +26,7 @@ Feature: Create node variant | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + And I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -41,15 +41,26 @@ Feature: Create node variant # Node /document/child | nody-mc-nodeface | child | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | {} | - Scenario: Try to create a variant in a content stream that does not exist yet + Scenario: Try to create a variant in a workspace that does not exist When the command CreateNodeVariant is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "i-do-not-exist-yet" | + | workspaceName | "i-do-not-exist-yet" | | nodeAggregateId | "sir-david-nodenborough" | | sourceOrigin | {"market":"CH", "language":"gsw"} | | targetOrigin | {"market":"DE", "language":"de"} | Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" + Scenario: Try to create a variant in a workspace that does not exist + When the command CloseContentStream is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + And the command CreateNodeVariant is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | sourceOrigin | {"market":"CH", "language":"gsw"} | + | targetOrigin | {"market":"DE", "language":"de"} | + Then the last command should have thrown an exception of type "ContentStreamIsClosed" + Scenario: Try to create a variant in a node aggregate that currently does not exist When the command CreateNodeVariant is executed with payload and exceptions are caught: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/02-CreateNodeSpecializationVariant.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/02-CreateNodeSpecializationVariant.feature index a092c8da646..2427efbaa0d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/02-CreateNodeSpecializationVariant.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/02-CreateNodeSpecializationVariant.feature @@ -31,7 +31,7 @@ Feature: Create node specialization | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + And I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -48,7 +48,7 @@ Feature: Create node specialization | nody-mc-nodeface | child-document | sir-david-nodenborough | Neos.ContentRepository.Testing:LeafDocument | {} | Scenario: check the tree state before the specialization - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} And the subtree for node aggregate "sir-david-nodenborough" with node types "" and 2 levels deep should be: | Level | nodeAggregateId | | 0 | sir-david-nodenborough | @@ -92,7 +92,7 @@ Feature: Create node specialization When the graph projection is fully up to date - When I am in content stream "cs-identifier" + When I am in the active content stream of workspace "live" Then I expect the node aggregate "lady-eleonode-rootford" to exist And I expect this node aggregate to occupy dimension space points [{}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] @@ -123,41 +123,41 @@ Feature: Create node specialization And I expect a node identified by cs-identifier;nodimer-tetherton;{"market":"CH", "language":"gsw"} to exist in the content graph And I expect a node identified by cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} to exist in the content graph - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"CH", "language":"gsw"} And I expect this node to have the following child nodes: @@ -215,7 +215,7 @@ Feature: Create node specialization And I expect a node identified by cs-identifier;nodimer-tetherton;{"market":"DE", "language":"de"} to exist in the content graph And I expect a node identified by cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} to exist in the content graph - When I am in content stream "cs-identifier" + When I am in the active content stream of workspace "live" Then I expect the node aggregate "lady-eleonode-rootford" to exist And I expect this node aggregate to occupy dimension space points [{}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] @@ -236,42 +236,42 @@ Feature: Create node specialization And I expect this node aggregate to occupy dimension space points [{"market":"DE", "language":"en"}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"de"} @@ -351,7 +351,7 @@ Feature: Create node specialization And I expect a node identified by cs-identifier;nodimer-tetherton;{"market":"CH", "language":"en"} to exist in the content graph And I expect a node identified by cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} to exist in the content graph - When I am in content stream "cs-identifier" + When I am in the active content stream of workspace "live" Then I expect the node aggregate "lady-eleonode-rootford" to exist And I expect this node aggregate to occupy dimension space points [{}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] @@ -372,42 +372,42 @@ Feature: Create node specialization And I expect this node aggregate to occupy dimension space points [{"market":"DE", "language":"en"}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"CH", "language":"en"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"CH", "language":"en"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"CH", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"CH", "language":"de"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"CH", "language":"de"} And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to node cs-identifier;nodimer-tetherton;{"market":"CH", "language":"de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"CH", "language":"de"} And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to node cs-identifier;nodewyn-tetherton;{"market":"CH", "language":"de"} @@ -431,9 +431,9 @@ Feature: Create node specialization | sourceOrigin | {"market":"DE", "language":"en"} | | targetOrigin | {"market":"DE", "language":"gsw"} | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + And I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"de"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"gsw"} diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/03-CreateNodeGeneralizationVariant.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/03-CreateNodeGeneralizationVariant.feature index cf81e99de4e..5ce8b4c93b9 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/03-CreateNodeGeneralizationVariant.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/03-CreateNodeGeneralizationVariant.feature @@ -31,7 +31,7 @@ Feature: Create node generalization | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + And I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -97,7 +97,7 @@ Feature: Create node generalization And I expect a node identified by cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} to exist in the content graph And I expect a node identified by cs-identifier;nody-mc-nodeface;{"market":"CH", "language":"gsw"} to exist in the content graph - When I am in content stream "cs-identifier" + When I am in the active content stream of workspace "live" Then I expect the node aggregate "lady-eleonode-rootford" to exist And I expect this node aggregate to occupy dimension space points [{}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] @@ -118,7 +118,7 @@ Feature: Create node generalization And I expect this node aggregate to occupy dimension space points [{"market":"CH", "language":"gsw"}] And I expect this node aggregate to cover dimension space points [{"market":"CH", "language":"gsw"}] - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -128,7 +128,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -138,7 +138,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -148,7 +148,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -158,7 +158,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -168,7 +168,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"CH", "language":"gsw"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -220,7 +220,7 @@ Feature: Create node generalization And I expect a node identified by cs-identifier;nodimer-tetherton;{"market":"DE", "language":"gsw"} to exist in the content graph And I expect a node identified by cs-identifier;nody-mc-nodeface;{"market":"CH", "language":"gsw"} to exist in the content graph - When I am in content stream "cs-identifier" + When I am in the active content stream of workspace "live" Then I expect the node aggregate "lady-eleonode-rootford" to exist And I expect this node aggregate to occupy dimension space points [{}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] @@ -241,21 +241,21 @@ Feature: Create node generalization And I expect this node aggregate to occupy dimension space points [{"market":"CH", "language":"gsw"}] And I expect this node aggregate to cover dimension space points [{"market":"CH", "language":"gsw"}] - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to no node And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to no node And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to no node And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to no node And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to no node And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to no node And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"gsw"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -265,21 +265,21 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to no node And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to no node And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to no node And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to no node And I expect node aggregate identifier "nodewyn-tetherton" and node path "document/tethered-node" to lead to no node And I expect node aggregate identifier "nodimer-tetherton" and node path "document/tethered-node/tethered-leaf" to lead to no node And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"CH", "language":"gsw"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -348,7 +348,7 @@ Feature: Create node generalization And I expect a node identified by cs-identifier;nodimer-tetherton;{"market":"DE", "language":"en"} to exist in the content graph And I expect a node identified by cs-identifier;nody-mc-nodeface;{"market":"CH", "language":"gsw"} to exist in the content graph - When I am in content stream "cs-identifier" + When I am in the active content stream of workspace "live" Then I expect the node aggregate "lady-eleonode-rootford" to exist And I expect this node aggregate to occupy dimension space points [{}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] @@ -369,7 +369,7 @@ Feature: Create node generalization And I expect this node aggregate to occupy dimension space points [{"market":"CH", "language":"gsw"}] And I expect this node aggregate to cover dimension space points [{"market":"CH", "language":"gsw"}] - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -379,7 +379,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"de"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -389,7 +389,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"de"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -399,7 +399,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -409,7 +409,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"de"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -419,7 +419,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"CH", "language":"gsw"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -488,7 +488,7 @@ Feature: Create node generalization And I expect a node identified by cs-identifier;nodimer-tetherton;{"market":"DE", "language":"de"} to exist in the content graph And I expect a node identified by cs-identifier;nody-mc-nodeface;{"market":"CH", "language":"gsw"} to exist in the content graph - When I am in content stream "cs-identifier" + When I am in the active content stream of workspace "live" Then I expect the node aggregate "lady-eleonode-rootford" to exist And I expect this node aggregate to occupy dimension space points [{}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] @@ -509,7 +509,7 @@ Feature: Create node generalization And I expect this node aggregate to occupy dimension space points [{"market":"CH", "language":"gsw"}] And I expect this node aggregate to cover dimension space points [{"market":"CH", "language":"gsw"}] - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -519,7 +519,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"de"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -529,7 +529,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"de"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -539,7 +539,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -549,7 +549,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"de"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -559,7 +559,7 @@ Feature: Create node generalization And I expect this node to be a child of node cs-identifier;nodewyn-tetherton;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"CH", "language":"gsw"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/04-CreateNodePeerVariant.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/04-CreateNodePeerVariant.feature index d34578b9f84..92856d1573c 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/04-CreateNodePeerVariant.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/03-NodeVariation/04-CreateNodePeerVariant.feature @@ -31,7 +31,7 @@ Feature: Create node peer variant | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + And I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -97,7 +97,7 @@ Feature: Create node peer variant And I expect a node identified by cs-identifier;nodesis-prime;{"market":"CH", "language":"fr"} to exist in the content graph And I expect a node identified by cs-identifier;nodesis-mediocre;{"market":"CH", "language":"fr"} to exist in the content graph - When I am in content stream "cs-identifier" + When I am in the active content stream of workspace "live" Then I expect the node aggregate "lady-eleonode-rootford" to exist And I expect this node aggregate to occupy dimension space points [{}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"DE", "language":"fr"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"},{"market":"CH", "language":"fr"}] @@ -134,7 +134,7 @@ Feature: Create node peer variant And I expect this node aggregate to occupy dimension space points [{"market":"CH", "language":"fr"}] And I expect this node aggregate to cover dimension space points [{"market":"CH", "language":"fr"}] - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -145,7 +145,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to no node And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -156,7 +156,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to no node And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -167,7 +167,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to no node And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"fr"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"fr"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to no node And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node @@ -178,7 +178,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to no node And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -189,7 +189,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to no node And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -200,7 +200,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to no node And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -211,7 +211,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to no node And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"fr"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"fr"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"CH", "language":"fr"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node @@ -300,7 +300,7 @@ Feature: Create node peer variant And I expect a node identified by cs-identifier;nodesis-mediocre;{"market":"DE", "language":"de"} to exist in the content graph And I expect a node identified by cs-identifier;nodesis-mediocre;{"market":"DE", "language":"en"} to exist in the content graph - When I am in content stream "cs-identifier" + When I am in the active content stream of workspace "live" Then I expect the node aggregate "lady-eleonode-rootford" to exist And I expect this node aggregate to occupy dimension space points [{}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"DE", "language":"fr"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"},{"market":"CH", "language":"fr"}] @@ -337,7 +337,7 @@ Feature: Create node peer variant And I expect this node aggregate to occupy dimension space points [{"market":"CH", "language":"fr"},{"market":"DE", "language":"de"},{"market":"DE", "language":"en"}] And I expect this node aggregate to cover dimension space points [{"market":"CH", "language":"fr"},{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -348,7 +348,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to node cs-identifier;nodesis-prime;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -359,7 +359,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to node cs-identifier;nodesis-prime;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"de"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -370,7 +370,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to node cs-identifier;nodesis-prime;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"de"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"fr"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"fr"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to no node And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node @@ -381,7 +381,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to no node And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -392,7 +392,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to node cs-identifier;nodesis-prime;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -403,7 +403,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to node cs-identifier;nodesis-prime;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"de"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} @@ -415,7 +415,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to node cs-identifier;nodesis-prime;{"market":"DE", "language":"de"} And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"de"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"fr"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"fr"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to no node And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node @@ -504,7 +504,7 @@ Feature: Create node peer variant And I expect a node identified by cs-identifier;nodesis-mediocre;{"market":"DE", "language":"en"} to exist in the content graph And I expect a node identified by cs-identifier;nodesis-mediocre;{"market":"DE", "language":"de"} to exist in the content graph - When I am in content stream "cs-identifier" + When I am in the active content stream of workspace "live" Then I expect the node aggregate "lady-eleonode-rootford" to exist And I expect this node aggregate to occupy dimension space points [{}] And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"DE", "language":"fr"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"},{"market":"CH", "language":"fr"}] @@ -541,7 +541,7 @@ Feature: Create node peer variant And I expect this node aggregate to occupy dimension space points [{"market":"CH", "language":"fr"},{"market":"DE", "language":"de"},{"market":"DE", "language":"en"}] And I expect this node aggregate to cover dimension space points [{"market":"CH", "language":"fr"},{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -559,7 +559,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;nodesis-prime;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -578,7 +578,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"de"} And I expect this node to be a child of node cs-identifier;nodesis-prime;{"market":"DE", "language":"de"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -596,7 +596,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"de"} And I expect this node to be a child of node cs-identifier;nodesis-prime;{"market":"DE", "language":"de"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"fr"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"fr"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to no node And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node @@ -607,7 +607,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-prime" and node path "peer-document/tethered-document" to lead to no node And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"en"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -625,7 +625,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;nodesis-prime;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"de"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -644,7 +644,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"de"} And I expect this node to be a child of node cs-identifier;nodesis-prime;{"market":"DE", "language":"de"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} @@ -662,7 +662,7 @@ Feature: Create node peer variant And I expect node aggregate identifier "nodesis-mediocre" and node path "peer-document/tethered-document/tethered" to lead to node cs-identifier;nodesis-mediocre;{"market":"DE", "language":"de"} And I expect this node to be a child of node cs-identifier;nodesis-prime;{"market":"DE", "language":"de"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"fr"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"fr"} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to no node And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to no node @@ -736,7 +736,7 @@ Feature: Create node peer variant And I expect a node identified by cs-identifier;nodesis-prime;{"market":"CH", "language":"fr"} to exist in the content graph And I expect a node identified by cs-identifier;nodesis-mediocre;{"market":"CH", "language":"fr"} to exist in the content graph - When I am in content stream "cs-identifier" + When I am in the active content stream of workspace "live" # only nodenborough and mc-nodeface are affected @@ -749,42 +749,42 @@ Feature: Create node peer variant And I expect this node aggregate to cover dimension space points [{"market":"DE", "language":"en"},{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"DE", "language":"fr"},{"market":"CH", "language":"en"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"},{"market":"CH", "language":"fr"}] - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"de"} Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"gsw"} Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"fr"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"fr"} Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"fr"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"fr"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"fr"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"en"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"en"} Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"de"} Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"en"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"market":"DE", "language":"en"} - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"fr"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"fr"} Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{"market":"CH", "language":"fr"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE", "language":"fr"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"market":"CH", "language":"fr"} diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/01-SetNodeProperties_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/01-SetNodeProperties_ConstraintChecks.feature index cae1505f4c6..2ac617f4d44 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/01-SetNodeProperties_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/01-SetNodeProperties_ConstraintChecks.feature @@ -26,7 +26,7 @@ Feature: Set node properties: Constraint checks | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -41,12 +41,23 @@ Feature: Set node properties: Constraint checks Scenario: Try to set properties in a content stream that does not exist yet When the command SetNodeProperties is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "i-do-not-exist-yet" | + | workspaceName | "i-do-not-exist-yet" | | nodeAggregateId | "nody-mc-nodeface" | | originDimensionSpacePoint | {"language":"de"} | | propertyValues | {"text":"New text"} | Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" + Scenario: Try to set properties in a workspace whose content stream is closed + When the command CloseContentStream is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + When the command SetNodeProperties is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {"language":"de"} | + | propertyValues | {"text":"New text"} | + Then the last command should have thrown an exception of type "ContentStreamIsClosed" + Scenario: Try to set properties on a node aggregate that currently does not exist When the command SetNodeProperties is executed with payload and exceptions are caught: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/02-SetNodeProperties.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/02-SetNodeProperties.feature index 0edc545ef4e..a4309cb9ba8 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/02-SetNodeProperties.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/02-SetNodeProperties.feature @@ -64,7 +64,7 @@ Feature: Set properties | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"mul"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"mul"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/03-SetNodeProperties_PropertyScopes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/03-SetNodeProperties_PropertyScopes.feature index a4af16d7c13..866f822ac9a 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/03-SetNodeProperties_PropertyScopes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/04-NodeModification/03-SetNodeProperties_PropertyScopes.feature @@ -37,7 +37,7 @@ Feature: Set node properties with different scopes | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"mul"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"mul"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/01-SetNodeReferences_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/01-SetNodeReferences_ConstraintChecks.feature index 837684537cd..c38adfdb27c 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/01-SetNodeReferences_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/01-SetNodeReferences_ConstraintChecks.feature @@ -42,7 +42,7 @@ Feature: Constraint checks on SetNodeReferences | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -54,11 +54,22 @@ Feature: Constraint checks on SetNodeReferences | anthony-destinode | Neos.ContentRepository.Testing:ReferencedNode | lady-eleonode-rootford | | berta-destinode | Neos.ContentRepository.Testing:ReferencedNode | lady-eleonode-rootford | + Scenario: Try to reference nodes in a workspace whose content stream is closed + When the command CloseContentStream is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + When the command SetNodeReferences is executed with payload and exceptions are caught: + | Key | Value | + | sourceNodeAggregateId | "source-nodandaise" | + | referenceName | "referenceProperty" | + | references | [{"target":"anthony-destinode"}] | + Then the last command should have thrown an exception of type "ContentStreamIsClosed" + # checks for contentStreamId Scenario: Try to reference nodes in a non-existent content stream When the command SetNodeReferences is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "i-do-not-exist" | + | workspaceName | "i-do-not-exist" | | sourceNodeAggregateId | "source-nodandaise" | | referenceName | "referenceProperty" | | references | [{"target":"anthony-destinode"}] | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/02-SetNodeReferences_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/02-SetNodeReferences_WithoutDimensions.feature index a89cc2a8bf0..af2ac4fbb23 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/02-SetNodeReferences_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/02-SetNodeReferences_WithoutDimensions.feature @@ -50,7 +50,7 @@ Feature: Node References without Dimensions | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/03-SetNodeReferences_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/03-SetNodeReferences_WithDimensions.feature index ce9a9f8f4f6..466f0e67602 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/03-SetNodeReferences_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/03-SetNodeReferences_WithDimensions.feature @@ -30,7 +30,7 @@ Feature: Node References with Dimensions | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -49,7 +49,7 @@ Feature: Node References with Dimensions | references | [{"target": "anthony-destinode"}] | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "de"} And I expect this node to have the following references: | Name | Node | Properties | @@ -59,7 +59,7 @@ Feature: Node References with Dimensions | Name | Node | Properties | | referenceProperty | cs-identifier;source-nodandaise;{"language": "de"} | null | - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "ch"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "de"} And I expect this node to have the following references: | Name | Node | Properties | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/04-SetNodeReferences_PropertyScopes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/04-SetNodeReferences_PropertyScopes.feature index b5be6986e06..0fc81b875af 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/04-SetNodeReferences_PropertyScopes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/04-SetNodeReferences_PropertyScopes.feature @@ -44,7 +44,7 @@ Feature: Set node properties with different scopes | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"mul"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"mul"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -128,7 +128,7 @@ Feature: Set node properties with different scopes | references | [{"target": "anthony-destinode"}] | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "mul"} And I expect this node to have the following references: | Name | Node | Properties | @@ -141,7 +141,7 @@ Feature: Set node properties with different scopes | nodeAggregateScopedReference | cs-identifier;source-nodandaise;{"language": "mul"} | null | | nodeAggregateScopedReferences | cs-identifier;source-nodandaise;{"language": "mul"} | null | - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "de"} And I expect this node to have the following references: | Name | Node | Properties | @@ -165,7 +165,7 @@ Feature: Set node properties with different scopes | unscopedReference | cs-identifier;source-nodandaise;{"language": "de"} | null | | unscopedReferences | cs-identifier;source-nodandaise;{"language": "de"} | null | - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "gsw"} And I expect this node to have the following references: | Name | Node | Properties | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/05-NodeVariation_After_NodeReferencing.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/05-NodeVariation_After_NodeReferencing.feature index ae2e995690a..35bfb620617 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/05-NodeVariation_After_NodeReferencing.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/05-NodeReferencing/05-NodeVariation_After_NodeReferencing.feature @@ -30,7 +30,7 @@ Feature: Node References with Dimensions | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -57,7 +57,7 @@ Feature: Node References with Dimensions And the graph projection is fully up to date # after specialization, the reference must still exist on the specialized node - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "ch"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "ch"} And I expect this node to have the following references: | Name | Node | Properties | @@ -68,7 +68,7 @@ Feature: Node References with Dimensions | referenceProperty | cs-identifier;source-nodandaise;{"language": "ch"} | null | # the reference must also exist on the non-touched nodes - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "de"} And I expect this node to have the following references: | Name | Node | Properties | @@ -89,7 +89,7 @@ Feature: Node References with Dimensions And the graph projection is fully up to date # reference to self (modified 2 lines above) - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "ch"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "ch"} And I expect this node to have the following references: | Name | Node | Properties | @@ -99,7 +99,7 @@ Feature: Node References with Dimensions | referenceProperty | cs-identifier;source-nodandaise;{"language": "ch"} | null | # unmodified on the untouched nodes - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "de"} And I expect this node to have the following references: | Name | Node | Properties | @@ -127,7 +127,7 @@ Feature: Node References with Dimensions # on the specialization, the reference exists. - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "ch"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "ch"} And I expect this node to have the following references: | Name | Node | Properties | @@ -138,7 +138,7 @@ Feature: Node References with Dimensions | referenceProperty | cs-identifier;source-nodandaise;{"language": "ch"} | null | # on the other nodes, the reference does not exist. - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "de"} And I expect this node to have no references @@ -170,7 +170,7 @@ Feature: Node References with Dimensions And the graph projection is fully up to date # after creating a peer, the reference must still exist on the peer node - When I am in content stream "cs-identifier" and dimension space point {"language": "en"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "en"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "en"} And I expect this node to have the following references: | Name | Node | Properties | @@ -181,7 +181,7 @@ Feature: Node References with Dimensions | referenceProperty | cs-identifier;source-nodandaise;{"language": "en"} | null | # the reference must also exist on the non-touched nodes - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "de"} And I expect this node to have the following references: | Name | Node | Properties | @@ -191,7 +191,7 @@ Feature: Node References with Dimensions | Name | Node | Properties | | referenceProperty | cs-identifier;source-nodandaise;{"language": "de"} | null | - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "ch"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "de"} And I expect this node to have the following references: | Name | Node | Properties | @@ -212,7 +212,7 @@ Feature: Node References with Dimensions And the graph projection is fully up to date # reference to self (modified 2 lines above) - When I am in content stream "cs-identifier" and dimension space point {"language": "en"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "en"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "en"} And I expect this node to have the following references: | Name | Node | Properties | @@ -222,7 +222,7 @@ Feature: Node References with Dimensions | referenceProperty | cs-identifier;source-nodandaise;{"language": "en"} | null | # unmodified on the untouched nodes - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "de"} And I expect this node to have the following references: | Name | Node | Properties | @@ -232,7 +232,7 @@ Feature: Node References with Dimensions | Name | Node | Properties | | referenceProperty | cs-identifier;source-nodandaise;{"language": "de"} | null | - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "ch"} Then I expect node aggregate identifier "source-nodandaise" to lead to node cs-identifier;source-nodandaise;{"language": "de"} And I expect this node to have the following references: | Name | Node | Properties | @@ -269,7 +269,7 @@ Feature: Node References with Dimensions And the graph projection is fully up to date # after generalizing, the reference must still exist on the generalized node - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "ch-only" to lead to node cs-identifier;ch-only;{"language": "de"} Then I expect this node to have the following references: | Name | Node | Properties | @@ -280,7 +280,7 @@ Feature: Node References with Dimensions | referenceProperty | cs-identifier;ch-only;{"language": "de"} | null | # the reference must also exist on the non-touched node - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "ch"} Then I expect node aggregate identifier "ch-only" to lead to node cs-identifier;ch-only;{"language": "ch"} Then I expect this node to have the following references: | Name | Node | Properties | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/01-DisableNodeAggregate_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/01-DisableNodeAggregate_ConstraintChecks.feature index c1362e74535..d41691053ff 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/01-DisableNodeAggregate_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/01-DisableNodeAggregate_ConstraintChecks.feature @@ -23,7 +23,7 @@ Feature: Constraint checks on node aggregate disabling | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -36,11 +36,21 @@ Feature: Constraint checks on node aggregate disabling Scenario: Try to disable a node aggregate in a non-existing content stream When the command DisableNodeAggregate is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "i-do-not-exist" | + | workspaceName | "i-do-not-exist" | | nodeAggregateId | "sir-david-nodenborough" | | nodeVariantSelectionStrategy | "allVariants" | Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" + Scenario: Try to disable a node aggregate in a workspace whose content stream is closed + When the command CloseContentStream is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + When the command DisableNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | nodeVariantSelectionStrategy | "allVariants" | + Then the last command should have thrown an exception of type "ContentStreamIsClosed" + Scenario: Try to disable a non-existing node aggregate When the command DisableNodeAggregate is executed with payload and exceptions are caught: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/02-DisableNodeAggregate_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/02-DisableNodeAggregate_WithoutDimensions.feature index 9f8d73c1cf0..bd52248617d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/02-DisableNodeAggregate_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/02-DisableNodeAggregate_WithoutDimensions.feature @@ -24,7 +24,7 @@ Feature: Disable a node aggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -57,7 +57,7 @@ Feature: Disable a node aggregate | affectedDimensionSpacePoints | [[]] | When the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Then I expect the graph projection to consist of exactly 5 nodes And I expect a node identified by cs-identifier;lady-eleonode-rootford;{} to exist in the content graph And I expect a node identified by cs-identifier;preceding-nodenborough;{} to exist in the content graph @@ -68,7 +68,7 @@ Feature: Disable a node aggregate And I expect the node aggregate "sir-david-nodenborough" to exist And I expect this node aggregate to disable dimension space points [{}] - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "withoutRestrictions" Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have the following child nodes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/03-DisableNodeAggregate_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/03-DisableNodeAggregate_WithDimensions.feature index 9ab8ece1340..29d50add32f 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/03-DisableNodeAggregate_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/03-DisableNodeAggregate_WithDimensions.feature @@ -26,7 +26,7 @@ Feature: Disable a node aggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"mul"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"mul"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -67,7 +67,7 @@ Feature: Disable a node aggregate | affectedDimensionSpacePoints | [{"language":"de"}, {"language":"ltz"}, {"language":"gsw"}] | When the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Then I expect the graph projection to consist of exactly 6 nodes And I expect a node identified by cs-identifier;lady-eleonode-rootford;{} to exist in the content graph And I expect a node identified by cs-identifier;preceding-nodenborough;{"language":"mul"} to exist in the content graph @@ -318,7 +318,7 @@ Feature: Disable a node aggregate | affectedDimensionSpacePoints | [{"language":"ltz"}, {"language":"mul"}, {"language":"de"}, {"language":"en"}, {"language":"gsw"}] | When the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Then I expect the graph projection to consist of exactly 6 nodes And I expect a node identified by cs-identifier;lady-eleonode-rootford;{} to exist in the content graph And I expect a node identified by cs-identifier;preceding-nodenborough;{"language":"mul"} to exist in the content graph diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/04-EnableNodeAggregate_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/04-EnableNodeAggregate_ConstraintChecks.feature index 124c1de977b..44b5734afd4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/04-EnableNodeAggregate_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/04-EnableNodeAggregate_ConstraintChecks.feature @@ -23,7 +23,7 @@ Feature: Enable a node aggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -36,7 +36,7 @@ Feature: Enable a node aggregate Scenario: Try to enable a node aggregate in a non-existing content stream When the command EnableNodeAggregate is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "i-do-not-exist" | + | workspaceName | "i-do-not-exist" | | nodeAggregateId | "sir-david-nodenborough" | | nodeVariantSelectionStrategy | "allVariants" | Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/05-EnableNodeAggregate_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/05-EnableNodeAggregate_WithoutDimensions.feature index 1a53bc1d35b..2cb99fedc0b 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/05-EnableNodeAggregate_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/05-EnableNodeAggregate_WithoutDimensions.feature @@ -24,7 +24,7 @@ Feature: Enable a node aggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -63,7 +63,7 @@ Feature: Enable a node aggregate | affectedDimensionSpacePoints | [[]] | When the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Then I expect the graph projection to consist of exactly 5 nodes And I expect a node identified by cs-identifier;lady-eleonode-rootford;{} to exist in the content graph And I expect a node identified by cs-identifier;preceding-nodenborough;{} to exist in the content graph @@ -74,7 +74,7 @@ Feature: Enable a node aggregate And I expect the node aggregate "sir-david-nodenborough" to exist And I expect this node aggregate to disable dimension space points [] - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have the following child nodes: @@ -144,14 +144,14 @@ Feature: Enable a node aggregate | affectedDimensionSpacePoints | [[]] | When the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Then I expect the node aggregate "sir-david-nodenborough" to exist And I expect this node aggregate to disable dimension space points [] And I expect the node aggregate "nody-mc-nodeface" to exist And I expect this node aggregate to disable dimension space points [{}] - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have the following child nodes: @@ -221,14 +221,14 @@ Feature: Enable a node aggregate | affectedDimensionSpacePoints | [[]] | When the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Then I expect the node aggregate "sir-david-nodenborough" to exist And I expect this node aggregate to disable dimension space points [{}] And I expect the node aggregate "nody-mc-nodeface" to exist And I expect this node aggregate to disable dimension space points [] - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have the following child nodes: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/06-EnableNodeAggregate_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/06-EnableNodeAggregate_WithDimensions.feature index eef0ffed0ed..7e2a1641fc4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/06-EnableNodeAggregate_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/06-EnableNodeAggregate_WithDimensions.feature @@ -26,7 +26,7 @@ Feature: Enable a node aggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"mul"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"mul"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -81,7 +81,7 @@ Feature: Enable a node aggregate | affectedDimensionSpacePoints | [{"language":"de"},{"language":"ltz"},{"language":"gsw"}] | When the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Then I expect the graph projection to consist of exactly 7 nodes And I expect a node identified by cs-identifier;lady-eleonode-rootford;{} to exist in the content graph And I expect a node identified by cs-identifier;preceding-nodenborough;{"language":"mul"} to exist in the content graph @@ -376,7 +376,7 @@ Feature: Enable a node aggregate | affectedDimensionSpacePoints | [{"language":"mul"},{"language":"de"},{"language":"en"},{"language":"gsw"},{"language":"ltz"}] | When the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Then I expect the graph projection to consist of exactly 7 nodes And I expect a node identified by cs-identifier;lady-eleonode-rootford;{} to exist in the content graph And I expect a node identified by cs-identifier;preceding-nodenborough;{"language":"mul"} to exist in the content graph @@ -704,7 +704,7 @@ Feature: Enable a node aggregate | nodeVariantSelectionStrategy | "allVariants" | When the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Then I expect the node aggregate "the-great-nodini" to exist And I expect this node aggregate to disable dimension space points [] diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/07-CreateNodeAggregateWithNodeWithDisabledAncestor_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/07-CreateNodeAggregateWithNodeWithDisabledAncestor_WithoutDimensions.feature index 5a897f510bc..1d236a45a38 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/07-CreateNodeAggregateWithNodeWithDisabledAncestor_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/07-CreateNodeAggregateWithNodeWithDisabledAncestor_WithoutDimensions.feature @@ -22,7 +22,7 @@ Feature: Creation of nodes underneath disabled nodes | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/08-CreateNodeAggregateWithNodeWithDisabledAncestor_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/08-CreateNodeAggregateWithNodeWithDisabledAncestor_WithDimensions.feature index 2db08431ae7..48ca1fa841d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/08-CreateNodeAggregateWithNodeWithDisabledAncestor_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/08-CreateNodeAggregateWithNodeWithDisabledAncestor_WithDimensions.feature @@ -24,7 +24,7 @@ Feature: Creation of nodes underneath disabled nodes | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"mul"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"mul"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/09-CreateNodeVariantOfDisabledNode.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/09-CreateNodeVariantOfDisabledNode.feature index e419bb7d363..cd58c9d668a 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/09-CreateNodeVariantOfDisabledNode.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/06-NodeDisabling/09-CreateNodeVariantOfDisabledNode.feature @@ -22,7 +22,7 @@ Feature: Variation of hidden nodes | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"mul"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"mul"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/01-RemoveNodeAggregate_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/01-RemoveNodeAggregate_ConstraintChecks.feature index 53561be51c4..bc0798286f2 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/01-RemoveNodeAggregate_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/01-RemoveNodeAggregate_ConstraintChecks.feature @@ -27,7 +27,7 @@ Feature: Remove NodeAggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -40,12 +40,23 @@ Feature: Remove NodeAggregate Scenario: Try to remove a node aggregate in a non-existing content stream When the command RemoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "i-do-not-exist" | + | workspaceName | "i-do-not-exist" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {"language":"de"} | | nodeVariantSelectionStrategy | "allVariants" | Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" + Scenario: Try to remove a node aggregate in a workspace whose content stream is closed + When the command CloseContentStream is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + When the command RemoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"language":"de"} | + | nodeVariantSelectionStrategy | "allVariants" | + Then the last command should have thrown an exception of type "ContentStreamIsClosed" + Scenario: Try to remove a non-existing node aggregate When the command RemoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/02-RemoveNodeAggregate_WithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/02-RemoveNodeAggregate_WithoutDimensions.feature index 093aa669a7a..96d5fdbf148 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/02-RemoveNodeAggregate_WithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/02-RemoveNodeAggregate_WithoutDimensions.feature @@ -24,7 +24,7 @@ Feature: Remove NodeAggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/03-RemoveNodeAggregate_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/03-RemoveNodeAggregate_WithDimensions.feature index 1186753cc69..584cb7eabb1 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/03-RemoveNodeAggregate_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/03-RemoveNodeAggregate_WithDimensions.feature @@ -26,7 +26,7 @@ Feature: Remove NodeAggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"en"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"en"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/04-VariantRecreation.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/04-VariantRecreation.feature new file mode 100644 index 00000000000..81027a506e7 --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/07-NodeRemoval/04-VariantRecreation.feature @@ -0,0 +1,102 @@ +@contentrepository @adapters=DoctrineDBAL,Postgres +Feature: Recreate a node variant + + As a user of the CR I want to be able to recreate a variant after I deleted and published it + See https://github.com/neos/neos-development-collection/issues/4583 + + Background: + Given using the following content dimensions: + | Identifier | Values | Generalizations | + | language | en, de, fr, gsw | gsw->de->en | + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:Tethered': [] + 'Neos.ContentRepository.Testing:TetheredDocument': + childNodes: + tethered: + type: 'Neos.ContentRepository.Testing:Tethered' + 'Neos.ContentRepository.Testing:Document': + childNodes: + tethered-document: + type: 'Neos.ContentRepository.Testing:TetheredDocument' + 'Neos.ContentRepository.Testing:DocumentWithoutTetheredChildren': [] + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And I am user identified by "initiating-user-identifier" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + + And I am in the active content stream of workspace "live" and dimension space point {"language":"en"} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the graph projection is fully up to date + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | originDimensionSpacePoint | nodeName | parentNodeAggregateId | nodeTypeName | tetheredDescendantNodeAggregateIds | + | sir-david-nodenborough | {"language":"en"} | document | lady-eleonode-rootford | Neos.ContentRepository.Testing:Document | {"tethered-document": "nodimus-prime", "tethered-document/tethered": "nodimus-mediocre"} | + | nody-mc-nodeface | {"language":"en"} | grandchild-document | nodimus-prime | Neos.ContentRepository.Testing:DocumentWithoutTetheredChildren | {} | + + And the command CreateWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | baseWorkspaceName | "live" | + | newContentStreamId | "user-cs-id" | + And the graph projection is fully up to date + + Scenario: Create specialization variant of node, publish, delete it and recreate it + When the command CreateNodeVariant is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | nodeAggregateId | "sir-david-nodenborough" | + | sourceOrigin | {"language":"en"} | + | targetOrigin | {"language":"de"} | + And the graph projection is fully up to date + When the command CreateNodeVariant is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | nodeAggregateId | "nody-mc-nodeface" | + | sourceOrigin | {"language":"en"} | + | targetOrigin | {"language":"de"} | + And the graph projection is fully up to date + And the command PublishWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | newContentStreamId | "new-user-cs-id" | + And the graph projection is fully up to date + + And the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"language":"de"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + And the command CreateNodeVariant is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | nodeAggregateId | "sir-david-nodenborough" | + | sourceOrigin | {"language":"en"} | + | targetOrigin | {"language":"de"} | + And the graph projection is fully up to date + When the command CreateNodeVariant is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | nodeAggregateId | "nody-mc-nodeface" | + | sourceOrigin | {"language":"en"} | + | targetOrigin | {"language":"de"} | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "user-ws" and dimension space point {"language": "de"} + Then I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node new-user-cs-id;sir-david-nodenborough;{"language": "de"} + Then I expect node aggregate identifier "nodimus-prime" and node path "document/tethered-document" to lead to node new-user-cs-id;nodimus-prime;{"language": "de"} + Then I expect node aggregate identifier "nodimus-mediocre" and node path "document/tethered-document/tethered" to lead to node new-user-cs-id;nodimus-mediocre;{"language": "de"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "document/tethered-document/grandchild-document" to lead to node new-user-cs-id;nody-mc-nodeface;{"language": "de"} + diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature index 053d191525e..5dd2d441fa8 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature @@ -7,10 +7,10 @@ Feature: Move node to a new parent / within the current parent before a sibling These are the base test cases for the NodeAggregateCommandHandler to block invalid commands Content Structure: - - lady-eleonode-rootford (Neos.ContentRepository:Root) - - sir-david-nodenborough (Neos.ContentRepository.Testing:DocumentWithTetheredChildNode) - - "tethered" nodewyn-tetherton (Neos.ContentRepository.Testing:Content) - - sir-nodeward-nodington-iii (Neos.ContentRepository.Testing:Document) + - lady-eleonode-rootford (Neos.ContentRepository:Root) + - sir-david-nodenborough (Neos.ContentRepository.Testing:DocumentWithTetheredChildNode) + - "tethered" nodewyn-tetherton (Neos.ContentRepository.Testing:Content) + - sir-nodeward-nodington-iii (Neos.ContentRepository.Testing:Document) Background: Given using the following content dimensions: @@ -37,63 +37,73 @@ Feature: Move node to a new parent / within the current parent before a sibling And using identifier "default", I define a content repository And I am in content repository "default" And the command CreateRootWorkspace is executed with payload: - | Key | Value | - | workspaceName | "live" | - | workspaceTitle | "Live" | - | workspaceDescription | "The live workspace" | - | newContentStreamId | "cs-identifier" | + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" And the graph projection is fully up to date And the command CreateRootNodeAggregateWithNode is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "lady-eleonode-rootford" | - | nodeTypeName | "Neos.ContentRepository:Root" | + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | nodeTypeName | "Neos.ContentRepository.Testing:DocumentWithTetheredChildNode" | - | originDimensionSpacePoint | {"market":"DE", "language":"de"} | - | coveredDimensionSpacePoints | [{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "document" | - | nodeAggregateClassification | "regular" | + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "sir-david-nodenborough" | + | nodeTypeName | "Neos.ContentRepository.Testing:DocumentWithTetheredChildNode" | + | originDimensionSpacePoint | {"market":"DE", "language":"de"} | + | coveredDimensionSpacePoints | [{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] | + | parentNodeAggregateId | "lady-eleonode-rootford" | + | nodeName | "document" | + | nodeAggregateClassification | "regular" | And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nodewyn-tetherton" | - | nodeTypeName | "Neos.ContentRepository.Testing:Content" | - | originDimensionSpacePoint | {"market":"DE", "language":"de"} | - | coveredDimensionSpacePoints | [{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "tethered" | - | nodeAggregateClassification | "tethered" | + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nodewyn-tetherton" | + | nodeTypeName | "Neos.ContentRepository.Testing:Content" | + | originDimensionSpacePoint | {"market":"DE", "language":"de"} | + | coveredDimensionSpacePoints | [{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] | + | parentNodeAggregateId | "sir-david-nodenborough" | + | nodeName | "tethered" | + | nodeAggregateClassification | "tethered" | And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"market":"DE", "language":"de"} | - | coveredDimensionSpacePoints | [{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "esquire" | - | nodeAggregateClassification | "regular" | + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | nodeTypeName | "Neos.ContentRepository.Testing:Document" | + | originDimensionSpacePoint | {"market":"DE", "language":"de"} | + | coveredDimensionSpacePoints | [{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] | + | parentNodeAggregateId | "sir-david-nodenborough" | + | nodeName | "esquire" | + | nodeAggregateClassification | "regular" | And the graph projection is fully up to date - Scenario: Try to move a node in a non-existing content stream: + Scenario: Try to move a node in a non-existing workspace: When the command MoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "non-existing" | - | nodeAggregateId | "sir-david-nodenborough" | + | workspaceName | "non-existing" | + | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {"market": "DE", "language": "de"} | | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" + Scenario: Try to move a node in a workspace whose content stream is closed: + When the command CloseContentStream is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | dimensionSpacePoint | {"market": "DE", "language": "de"} | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "ContentStreamIsClosed" + Scenario: Try to move a node of a non-existing node aggregate: When the command MoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "i-do-not-exist" | + | nodeAggregateId | "i-do-not-exist" | | dimensionSpacePoint | {"market": "DE", "language": "de"} | | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" @@ -101,8 +111,7 @@ Feature: Move node to a new parent / within the current parent before a sibling Scenario: Try to move a node of a root node aggregate: When the command MoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "lady-eleonode-rootford" | + | nodeAggregateId | "lady-eleonode-rootford" | | dimensionSpacePoint | {"market":"DE", "language":"de"} | | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeAggregateIsRoot" @@ -110,8 +119,7 @@ Feature: Move node to a new parent / within the current parent before a sibling Scenario: Try to move a node of a tethered node aggregate: When the command MoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nodewyn-tetherton" | + | nodeAggregateId | "nodewyn-tetherton" | | dimensionSpacePoint | {"market": "DE", "language": "de"} | | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeAggregateIsTethered" @@ -119,8 +127,7 @@ Feature: Move node to a new parent / within the current parent before a sibling Scenario: Try to move a node in a non-existing dimension space point: When the command MoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | + | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {"market": "nope", "language": "neither"} | | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "DimensionSpacePointNotFound" @@ -128,137 +135,128 @@ Feature: Move node to a new parent / within the current parent before a sibling Scenario: Try to move a node in a dimension space point the aggregate does not cover When the command MoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | + | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {"market": "DE", "language": "fr"} | | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeAggregateDoesCurrentlyNotCoverDimensionSpacePoint" Scenario: Try to move existing node to a non-existing parent When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "sir-david-nodenborough" | - | newParentNodeAggregateId | "non-existing-parent-identifier" | - | relationDistributionStrategy | "scatter" | + | Key | Value | + | dimensionSpacePoint | {"market": "DE", "language": "de"} | + | nodeAggregateId | "sir-david-nodenborough" | + | newParentNodeAggregateId | "non-existing-parent-identifier" | + | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" Scenario: Try to move a node to a parent that already has a child node of the same name Given the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"market": "DE", "language": "de"} | - | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "document" | - | nodeAggregateClassification | "regular" | + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:Document" | + | originDimensionSpacePoint | {"market": "DE", "language": "de"} | + | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | + | parentNodeAggregateId | "sir-david-nodenborough" | + | nodeName | "document" | + | nodeAggregateClassification | "regular" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "nody-mc-nodeface" | - | newParentNodeAggregateId | "lady-eleonode-rootford" | - | relationDistributionStrategy | "scatter" | + | Key | Value | + | dimensionSpacePoint | {"market": "DE", "language": "de"} | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "lady-eleonode-rootford" | + | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" Scenario: Move a node that has no name Given the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"market": "DE", "language": "de"} | - | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeAggregateClassification | "regular" | + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:Document" | + | originDimensionSpacePoint | {"market": "DE", "language": "de"} | + | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | + | parentNodeAggregateId | "sir-david-nodenborough" | + | nodeAggregateClassification | "regular" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "nody-mc-nodeface" | - | newParentNodeAggregateId | "lady-eleonode-rootford" | - | relationDistributionStrategy | "scatter" | + | Key | Value | + | dimensionSpacePoint | {"market": "DE", "language": "de"} | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "lady-eleonode-rootford" | + | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"market": "DE", "language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"market": "DE", "language": "de"} And I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE","language":"de"} Scenario: Try to move a node to a parent whose node type does not allow child nodes of the node's type Given the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"market": "DE", "language": "de"} | - | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "other-document" | - | nodeAggregateClassification | "regular" | + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:Document" | + | originDimensionSpacePoint | {"market": "DE", "language": "de"} | + | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | + | parentNodeAggregateId | "lady-eleonode-rootford" | + | nodeName | "other-document" | + | nodeAggregateClassification | "regular" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "nody-mc-nodeface" | - | newParentNodeAggregateId | "nodewyn-tetherton" | - | relationDistributionStrategy | "scatter" | + | Key | Value | + | dimensionSpacePoint | {"market": "DE", "language": "de"} | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "nodewyn-tetherton" | + | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeConstraintException" Scenario: Try to move a node to a parent whose parent's node type does not allow grand child nodes of the node's type Given the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Content" | - | originDimensionSpacePoint | {"market": "DE", "language": "de"} | - | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "content" | - | nodeAggregateClassification | "regular" | + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:Content" | + | originDimensionSpacePoint | {"market": "DE", "language": "de"} | + | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | + | parentNodeAggregateId | "lady-eleonode-rootford" | + | nodeName | "content" | + | nodeAggregateClassification | "regular" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "nody-mc-nodeface" | - | newParentNodeAggregateId | "nodewyn-tetherton" | - | relationDistributionStrategy | "scatter" | + | Key | Value | + | dimensionSpacePoint | {"market": "DE", "language": "de"} | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "nodewyn-tetherton" | + | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeConstraintException" Scenario: Try to move existing node to a non-existing succeeding sibling When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | + | Key | Value | + | dimensionSpacePoint | {"market": "DE", "language": "de"} | | nodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | "i-do-not-exist" | - | relationDistributionStrategy | "scatter" | + | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" Scenario: Try to move existing node to a non-existing preceding sibling When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | + | Key | Value | + | dimensionSpacePoint | {"market": "DE", "language": "de"} | | nodeAggregateId | "sir-david-nodenborough" | | newPrecedingSiblingNodeAggregateId | "i-do-not-exist" | - | relationDistributionStrategy | "scatter" | + | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" Scenario: Try to move a node to one of its children When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "sir-david-nodenborough" | - | newParentNodeAggregateId | "nodewyn-tetherton" | - | relationDistributionStrategy | "scatter" | + | Key | Value | + | dimensionSpacePoint | {"market": "DE", "language": "de"} | + | nodeAggregateId | "sir-david-nodenborough" | + | newParentNodeAggregateId | "nodewyn-tetherton" | + | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeAggregateIsDescendant" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature index aa8c3df065b..eee4aed8bc4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature @@ -29,9 +29,9 @@ Feature: Move a node aggregate considering disable state but without content dim | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -79,14 +79,13 @@ Feature: Move a node aggregate considering disable state but without content dim Scenario: Move a node disabled by one of its ancestors to a new parent that is enabled Given the event NodeAggregateWasDisabled was published with payload: | Key | Value | - | contentStreamId | "cs-identifier" | + | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | affectedDimensionSpacePoints | [{}] | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | @@ -95,7 +94,7 @@ Feature: Move a node aggregate considering disable state but without content dim # node aggregate occupation and coverage is not relevant without dimensions and thus not tested - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" And I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/child-document" to lead to node cs-identifier;nody-mc-nodeface;{} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{} @@ -110,13 +109,12 @@ Feature: Move a node aggregate considering disable state but without content dim When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/child-document" to lead to no node @@ -131,13 +129,12 @@ Feature: Move a node aggregate considering disable state but without content dim When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/document" to lead to no node @@ -158,13 +155,12 @@ Feature: Move a node aggregate considering disable state but without content dim When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/child-document" to lead to no node @@ -183,13 +179,12 @@ Feature: Move a node aggregate considering disable state but without content dim When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/document" to lead to no node @@ -203,13 +198,12 @@ Feature: Move a node aggregate considering disable state but without content dim When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/document" to lead to no node @@ -228,13 +222,12 @@ Feature: Move a node aggregate considering disable state but without content dim When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/document" to lead to no node @@ -254,13 +247,12 @@ Feature: Move a node aggregate considering disable state but without content dim When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "nodimus-prime" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/child-document" to lead to no node @@ -279,13 +271,12 @@ Feature: Move a node aggregate considering disable state but without content dim When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "nodimus-prime" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/esquire-child/document" to lead to no node @@ -304,13 +295,12 @@ Feature: Move a node aggregate considering disable state but without content dim When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "nodimus-prime" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/esquire-child/document" to lead to no node @@ -325,13 +315,12 @@ Feature: Move a node aggregate considering disable state but without content dim When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "nodimus-prime" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/esquire-child/document" to lead to no node diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateWithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateWithoutDimensions.feature index c1dfb1bb4bc..048a6738ceb 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateWithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateWithoutDimensions.feature @@ -24,9 +24,9 @@ Feature: Move a node without content dimensions | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -64,7 +64,6 @@ Feature: Move a node without content dimensions Scenario: Move a node to the end of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -79,7 +78,7 @@ Feature: Move a node without content dimensions # node aggregate occupation and coverage is not relevant without dimensions and thus not tested - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-nodeward-nodington-iii" and node path "esquire" to lead to node cs-identifier;sir-nodeward-nodington-iii;{} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no preceding siblings @@ -100,7 +99,6 @@ Feature: Move a node without content dimensions Scenario: Move a node before one of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-nodeward-nodington-iii" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -115,7 +113,7 @@ Feature: Move a node without content dimensions # node aggregate occupation and coverage is not relevant without dimensions and thus not tested - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-nodeward-nodington-iii" and node path "esquire" to lead to node cs-identifier;sir-nodeward-nodington-iii;{} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no preceding siblings @@ -147,7 +145,6 @@ Feature: Move a node without content dimensions And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | @@ -169,7 +166,7 @@ Feature: Move a node without content dimensions # node aggregate occupation and coverage is not relevant without dimensions and thus not tested - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} And I expect node aggregate identifier "sir-nodeward-nodington-iii" and node path "esquire" to lead to node cs-identifier;sir-nodeward-nodington-iii;{} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no preceding siblings @@ -194,7 +191,6 @@ Feature: Move a node without content dimensions Scenario: Move a node to a new parent and before one of its children When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "lady-eleonode-rootford" | @@ -215,7 +211,7 @@ Feature: Move a node without content dimensions # node aggregate occupation and coverage is not relevant without dimensions and thus not tested - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no preceding siblings diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NewParent_Dimensions.feature index 2719cbd9eb6..e2791f32b28 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NewParent_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NewParent_Dimensions.feature @@ -25,9 +25,9 @@ Feature: Move a node with content dimensions | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -105,14 +105,13 @@ Feature: Move a node with content dimensions Scenario: Move a complete node aggregate to a new parent before the first of its new siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have no preceding siblings @@ -133,7 +132,6 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | "sir-david-nodenborough" | @@ -141,7 +139,7 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have no preceding siblings @@ -151,7 +149,7 @@ Feature: Move a node with content dimensions | cs-identifier;berta-destinode;{"language": "mul"} | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have no preceding siblings @@ -163,14 +161,13 @@ Feature: Move a node with content dimensions Scenario: Move a complete node aggregate to a new parent before one of its new siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | "berta-destinode" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -192,14 +189,13 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | "berta-destinode" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -210,7 +206,7 @@ Feature: Move a node with content dimensions | cs-identifier;berta-destinode;{"language": "mul"} | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -231,14 +227,13 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newPrecedingSiblingNodeAggregateId | "berta-destinode" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -249,7 +244,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -269,14 +264,13 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -286,7 +280,7 @@ Feature: Move a node with content dimensions | cs-identifier;anthony-destinode;{"language": "mul"} | And I expect this node to have no succeeding siblings - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -298,7 +292,6 @@ Feature: Move a node with content dimensions Scenario: Move a single node in a node aggregate to a new parent after the last of its new siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "de"} | | newParentNodeAggregateId | "sir-david-nodenborough" | @@ -306,13 +299,13 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"language": "mul"} And I expect this node to have no preceding siblings And I expect this node to have no succeeding siblings - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -325,7 +318,6 @@ Feature: Move a node with content dimensions Scenario: Move a node and its specializations in a node aggregate to a new parent after the last of its new siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "de"} | | newParentNodeAggregateId | "sir-david-nodenborough" | @@ -333,13 +325,13 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"language": "mul"} And I expect this node to have no preceding siblings And I expect this node to have no succeeding siblings - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -349,7 +341,7 @@ Feature: Move a node with content dimensions | cs-identifier;anthony-destinode;{"language": "mul"} | And I expect this node to have no succeeding siblings - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -362,7 +354,6 @@ Feature: Move a node with content dimensions Scenario: Move a complete node aggregate to a new parent between siblings with different parents in other variants Given the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "berta-destinode" | | dimensionSpacePoint | {"language": "gsw"} | | newParentNodeAggregateId | "lady-abigail-nodenborough" | @@ -372,7 +363,6 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | "sir-david-nodenborough" | @@ -381,7 +371,7 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -393,7 +383,7 @@ Feature: Move a node with content dimensions | cs-identifier;carl-destinode;{"language": "mul"} | # An explicitly given parent node aggregate identifier should overrule given sibling identifiers - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -406,7 +396,6 @@ Feature: Move a node with content dimensions Scenario: Move a complete node aggregate between siblings with different parents in other variants (without explicit new parent) Given the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "berta-destinode" | | dimensionSpacePoint | {"language": "gsw"} | | newParentNodeAggregateId | "lady-abigail-nodenborough" | @@ -416,7 +405,6 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newPrecedingSiblingNodeAggregateId | "anthony-destinode" | @@ -424,7 +412,7 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -435,7 +423,7 @@ Feature: Move a node with content dimensions | cs-identifier;berta-destinode;{"language": "mul"} | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "document2/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;lady-abigail-nodenborough;{"language": "mul"} And I expect this node to have no preceding siblings diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature index 95e2549cd30..fa4d0a3467f 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature @@ -25,9 +25,9 @@ Feature: Move a node with content dimensions | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -95,14 +95,13 @@ Feature: Move a node with content dimensions Scenario: Move a complete node aggregate before the first of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | null | | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have no preceding siblings @@ -123,7 +122,6 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | null | @@ -131,7 +129,7 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have no preceding siblings @@ -141,7 +139,7 @@ Feature: Move a node with content dimensions | cs-identifier;berta-destinode;{"language": "mul"} | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have no preceding siblings @@ -153,14 +151,13 @@ Feature: Move a node with content dimensions Scenario: Move a complete node aggregate before another of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | null | | newSucceedingSiblingNodeAggregateId | "berta-destinode" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -182,14 +179,13 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | null | | newSucceedingSiblingNodeAggregateId | "berta-destinode" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -200,7 +196,7 @@ Feature: Move a node with content dimensions | cs-identifier;berta-destinode;{"language": "mul"} | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -221,14 +217,13 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | null | | newPrecedingSiblingNodeAggregateId | "berta-destinode" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -239,7 +234,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -259,14 +254,13 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | null | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -276,7 +270,7 @@ Feature: Move a node with content dimensions | cs-identifier;anthony-destinode;{"language": "mul"} | And I expect this node to have no succeeding siblings - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -288,14 +282,13 @@ Feature: Move a node with content dimensions Scenario: Move a single node before the first of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have no preceding siblings @@ -305,7 +298,7 @@ Feature: Move a node with content dimensions | cs-identifier;berta-destinode;{"language": "mul"} | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -319,14 +312,13 @@ Feature: Move a node with content dimensions Scenario: Move a single node between two of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | newSucceedingSiblingNodeAggregateId | "berta-destinode" | | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -337,7 +329,7 @@ Feature: Move a node with content dimensions | cs-identifier;berta-destinode;{"language": "mul"} | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -351,13 +343,12 @@ Feature: Move a node with content dimensions Scenario: Move a single node to the end of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "mul"} | | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -367,7 +358,7 @@ Feature: Move a node with content dimensions | cs-identifier;anthony-destinode;{"language": "mul"} | And I expect this node to have no succeeding siblings - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -381,14 +372,13 @@ Feature: Move a node with content dimensions Scenario: Move a node and its specializations before the first of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "de"} | | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -399,7 +389,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have no preceding siblings @@ -409,7 +399,7 @@ Feature: Move a node with content dimensions | cs-identifier;berta-destinode;{"language": "mul"} | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have no preceding siblings @@ -422,14 +412,13 @@ Feature: Move a node with content dimensions Scenario: Move a node and its specializations between two of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "de"} | | newSucceedingSiblingNodeAggregateId | "berta-destinode" | | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -440,7 +429,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -451,7 +440,7 @@ Feature: Move a node with content dimensions | cs-identifier;berta-destinode;{"language": "mul"} | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -465,13 +454,12 @@ Feature: Move a node with content dimensions Scenario: Move a node and its specializations to the end of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"language": "de"} | | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date - When I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -482,7 +470,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;carl-destinode;{"language": "mul"} | - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -492,7 +480,7 @@ Feature: Move a node with content dimensions | cs-identifier;anthony-destinode;{"language": "mul"} | And I expect this node to have no succeeding siblings - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} And I expect this node to have the following preceding siblings: @@ -503,7 +491,7 @@ Feature: Move a node with content dimensions And I expect this node to have no succeeding siblings Scenario: Trigger position update in DBAL graph - Given I am in content stream "cs-identifier" and dimension space point {"language": "mul"} + Given I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} # distance i to x: 128 Given the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamClosing/01-CloseContentStream_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamClosing/01-CloseContentStream_ConstraintChecks.feature new file mode 100644 index 00000000000..d991eb4fd5b --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamClosing/01-CloseContentStream_ConstraintChecks.feature @@ -0,0 +1,31 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Constraint check test cases for closing content streams + + Background: + Given using no content dimensions + And using the following node types: + """yaml + Neos.ContentRepository:Root: {} + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + + Scenario: Try to close a non-existing content stream: + And the command CloseContentStream is executed with payload and exceptions are caught: + | Key | Value | + | contentStreamId | "i-do-not-exist" | + Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" + + Scenario: Try to close a content stream that is already closed: + When the command CloseContentStream is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + And the command CloseContentStream is executed with payload and exceptions are caught: + | Key | Value | + | contentStreamId | "cs-identifier" | + Then the last command should have thrown an exception of type "ContentStreamIsClosed" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/01-ForkContentStream_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/01-ForkContentStream_ConstraintChecks.feature new file mode 100644 index 00000000000..8d25d71e03a --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/01-ForkContentStream_ConstraintChecks.feature @@ -0,0 +1,59 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: ForkContentStream Without Dimensions + + We have only one node underneath the root node: /foo. + LIVE Content Stream ID: cs-identifier + We fork the live content stream as ID user-cs-identifier + and then we commit a modification in the LIVE content stream. + We then expect the *forked* content stream to contain the *original* value; and the *live* content stream must contain the changed value. + + Background: + Given using no content dimensions + And using the following node types: + """yaml + Neos.ContentRepository:Root: {} + 'Neos.ContentRepository.Testing:Content': + properties: + text: + type: string + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the event NodeAggregateWithNodeWasCreated was published with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:Content" | + | originDimensionSpacePoint | {} | + | coveredDimensionSpacePoints | [{}] | + | parentNodeAggregateId | "lady-eleonode-rootford" | + | nodeName | "child" | + | nodeAggregateClassification | "regular" | + And the event NodePropertiesWereSet was published with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | affectedDimensionSpacePoints | [{}] | + | propertyValues | {"text": {"value": "original value", "type": "string"}} | + | propertiesToUnset | {} | + + Scenario: Try to fork a content stream that is closed: + When the command CloseContentStream is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + When the command ForkContentStream is executed with payload and exceptions are caught: + | Key | Value | + | contentStreamId | "user-cs-identifier" | + | sourceContentStreamId | "cs-identifier" | + Then the last command should have thrown an exception of type "ContentStreamIsClosed" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/ForkContentStreamWithDisabledNodesWithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/ForkContentStreamWithDisabledNodesWithoutDimensions.feature index 568fa934935..dcc5fad2036 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/ForkContentStreamWithDisabledNodesWithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/ForkContentStreamWithDisabledNodesWithoutDimensions.feature @@ -23,9 +23,9 @@ Feature: On forking a content stream, hidden nodes should be correctly copied as | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -51,7 +51,6 @@ Feature: On forking a content stream, hidden nodes should be correctly copied as And the graph projection is fully up to date And the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "the-great-nodini" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/ForkContentStreamWithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/ForkContentStreamWithoutDimensions.feature index c586200c69a..e7b8197080c 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/ForkContentStreamWithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/ForkContentStreamWithoutDimensions.feature @@ -24,9 +24,9 @@ Feature: ForkContentStream Without Dimensions | workspaceName | "live" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/NodeReferencesOnForkContentStream.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/NodeReferencesOnForkContentStream.feature index e16bb97b991..fab5bbeab88 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/NodeReferencesOnForkContentStream.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ContentStreamForking/NodeReferencesOnForkContentStream.feature @@ -29,7 +29,7 @@ Feature: On forking a content stream, node references should be copied as well. | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddDimensionShineThrough.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddDimensionShineThrough.feature index 2c1b41dcd60..b8e3d750c59 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddDimensionShineThrough.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddDimensionShineThrough.feature @@ -38,16 +38,15 @@ Feature: Add Dimension Specialization | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {"language": "de"} | @@ -73,13 +72,14 @@ Feature: Add Dimension Specialization to: { language: 'ch' } """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" + And I am in dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} And I expect this node to be of type "Neos.ContentRepository.Testing:Document" And I expect this node to have the following properties: | Key | Value | | text | "hello" | - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in dimension space point {"language": "ch"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to no node @@ -103,9 +103,10 @@ Feature: Add Dimension Specialization # finally, we MODIFY the node and ensure that the modification is visible in both DSPs (as otherwise the shine through would not have worked # as expected) + # migration-cs is the actual name of the temporary workspace + And I am in workspace "migration-cs" And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "migration-cs" | | nodeAggregateId | "sir-david-nodenborough" | | originDimensionSpacePoint | {"language": "de"} | | propertyValues | {"text": "changed"} | @@ -123,12 +124,12 @@ Feature: Add Dimension Specialization | text | "changed" | # the original content stream was untouched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} And I expect this node to have the following properties: | Key | Value | | text | "hello" | - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "ch"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to no node When I run integrity violation detection @@ -138,14 +139,13 @@ Feature: Add Dimension Specialization When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {"language": "de"} | | nodeVariantSelectionStrategy | "allVariants" | And the graph projection is fully up to date # ensure the node is disabled - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to no node When VisibilityConstraints are set to "withoutRestrictions" Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} @@ -195,7 +195,6 @@ Feature: Add Dimension Specialization # we create a node in CH When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | sourceOrigin | {"language":"de"} | | targetOrigin | {"language":"en"} | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddNewProperty_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddNewProperty_NoDimensions.feature index 8bf55a12488..1bb02934429 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddNewProperty_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/AddNewProperty_NoDimensions.feature @@ -23,6 +23,7 @@ Feature: Add New Property | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | contentStreamId | "cs-identifier" | @@ -77,7 +78,7 @@ Feature: Add New Property type: 'DateTime' """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to have the following properties: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/ChangePropertyValue_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/ChangePropertyValue_Dimensions.feature index f094e12c200..bd52c8d1d2b 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/ChangePropertyValue_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/ChangePropertyValue_Dimensions.feature @@ -29,16 +29,15 @@ Feature: Change Property Value across dimensions; and test DimensionSpacePoints | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document (in "de") When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {"language": "de"} | @@ -49,7 +48,6 @@ Feature: Change Property Value across dimensions; and test DimensionSpacePoints # Node /document (in "en") When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | sourceOrigin | {"language":"de"} | | targetOrigin | {"language":"en"} | @@ -81,19 +79,19 @@ Feature: Change Property Value across dimensions; and test DimensionSpacePoints # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} And I expect this node to have the following properties: | Key | Value | | text | "Original text" | - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "ch"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} And I expect this node to have the following properties: | Key | Value | | text | "Original text" | - When I am in content stream "cs-identifier" and dimension space point {"language": "en"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "en"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "en"} And I expect this node to have the following properties: | Key | Value | @@ -123,7 +121,6 @@ Feature: Change Property Value across dimensions; and test DimensionSpacePoints # Node /document (in "ch") When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | sourceOrigin | {"language":"de"} | | targetOrigin | {"language":"ch"} | @@ -170,7 +167,6 @@ Feature: Change Property Value across dimensions; and test DimensionSpacePoints # Node /document (in "ch") When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | sourceOrigin | {"language":"de"} | | targetOrigin | {"language":"ch"} | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/ChangePropertyValue_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/ChangePropertyValue_NoDimensions.feature index db580202967..2c3ae2d9969 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/ChangePropertyValue_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/ChangePropertyValue_NoDimensions.feature @@ -24,16 +24,15 @@ Feature: Change Property | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -60,7 +59,7 @@ Feature: Change Property newSerializedValue: 'fixed value' """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to have the following properties: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_NodeName_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_NodeName_NoDimensions.feature index 51e75cc63c8..0958d6cf1f4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_NodeName_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_NodeName_NoDimensions.feature @@ -23,17 +23,16 @@ Feature: Filter - Node Name | workspaceTitle | "Live" | | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" And the graph projection is fully up to date And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /name1 When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "na-name1" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | nodeName | "name1" | @@ -45,7 +44,6 @@ Feature: Filter - Node Name # Node /name2 When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "na-name2" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | nodeName | "name2" | @@ -57,7 +55,6 @@ Feature: Filter - Node Name # no node name When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "na-without-name" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -84,7 +81,7 @@ Feature: Filter - Node Name newSerializedValue: 'fixed value' """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "na-name1" to lead to node cs-identifier;na-name1;{} And I expect this node to have the following properties: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_PropertyNotEmpty_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_PropertyNotEmpty_NoDimensions.feature index 479188d9260..103e8290d27 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_PropertyNotEmpty_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_PropertyNotEmpty_NoDimensions.feature @@ -24,16 +24,15 @@ Feature: Filter - Property not empty | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /name1 (has text value set) When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "na-name1" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | nodeName | "name1" | @@ -45,7 +44,6 @@ Feature: Filter - Property not empty # Node /name2 (has text value empty) When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "na-name2" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | nodeName | "name2" | @@ -57,7 +55,6 @@ Feature: Filter - Property not empty # no node name (has text value not set) When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "na-null-value" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -68,7 +65,6 @@ Feature: Filter - Property not empty # no node name (has text value not set, and null will be ignored as unset) When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "na-no-text" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -95,7 +91,7 @@ Feature: Filter - Property not empty newSerializedValue: 'fixed value' """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "na-name1" to lead to node cs-identifier;na-name1;{} And I expect this node to have the following properties: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_PropertyValue_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_PropertyValue_NoDimensions.feature index 83a02d64615..b3e314fab70 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_PropertyValue_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/Filter_PropertyValue_NoDimensions.feature @@ -23,17 +23,16 @@ Feature: Filter - Property Value | workspaceTitle | "Live" | | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" And the graph projection is fully up to date And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /name1 (has text value set) When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "na-name1" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | nodeName | "name1" | @@ -45,7 +44,6 @@ Feature: Filter - Property Value # Node /name2 (has text value2) When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "na-name2" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | nodeName | "name2" | @@ -57,7 +55,6 @@ Feature: Filter - Property Value # no node name (has text value not set, and null will be ignored as unset) When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "na-null-value" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -68,7 +65,6 @@ Feature: Filter - Property Value # no node name (has text value not set) When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "na-no-text" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -96,7 +92,7 @@ Feature: Filter - Property Value newSerializedValue: 'fixed value' """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "na-name1" to lead to node cs-identifier;na-name1;{} And I expect this node to have the following properties: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/MoveDimensionSpacePoint.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/MoveDimensionSpacePoint.feature index 73512873b28..c3a56b5605b 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/MoveDimensionSpacePoint.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/MoveDimensionSpacePoint.feature @@ -35,17 +35,16 @@ Feature: Move dimension space point | workspaceTitle | "Live" | | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" And the graph projection is fully up to date And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {"language": "de"} | @@ -91,14 +90,13 @@ Feature: Move dimension space point When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {"language": "de"} | | nodeVariantSelectionStrategy | "allVariants" | And the graph projection is fully up to date # ensure the node is disabled - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to no node When VisibilityConstraints are set to "withoutRestrictions" Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} @@ -122,7 +120,7 @@ Feature: Move dimension space point """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to no node When VisibilityConstraints are set to "withoutRestrictions" Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_Dimensions.feature index 3b433612102..b4394b7679f 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_Dimensions.feature @@ -30,16 +30,15 @@ Feature: Adjust node types with a node migration | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {"language": "de"} | @@ -76,11 +75,11 @@ Feature: Adjust node types with a node migration newType: 'Neos.ContentRepository.Testing:OtherDocument' """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} And I expect this node to be of type "Neos.ContentRepository.Testing:Document" # ... also in the fallback dimension - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "ch"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} And I expect this node to be of type "Neos.ContentRepository.Testing:Document" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_NoDimensions.feature index 511099385b9..afd94e15f65 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/NodeTypeAdjustment_NoDimensions.feature @@ -28,16 +28,15 @@ Feature: Adjust node types with a node migration | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -74,7 +73,7 @@ Feature: Adjust node types with a node migration newType: 'Neos.ContentRepository.Testing:OtherDocument' """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to be of type "Neos.ContentRepository.Testing:Document" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RemoveNodes_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RemoveNodes_Dimensions.feature index 7c07c7fe455..9498e574b49 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RemoveNodes_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RemoveNodes_Dimensions.feature @@ -27,16 +27,15 @@ Feature: Remove Nodes | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document (in "de") When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {"language": "de"} | @@ -47,7 +46,6 @@ Feature: Remove Nodes # Node /document (in "en") When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | sourceOrigin | {"language":"de"} | | targetOrigin | {"language":"en"} | @@ -74,13 +72,13 @@ Feature: Remove Nodes type: 'RemoveNode' """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "en"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "en"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "en"} # the node was removed inside the new content stream, but only in de and gsw (virtual specialization) @@ -120,13 +118,13 @@ Feature: Remove Nodes """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "en"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "en"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "en"} # the node was removed inside the new content stream, but only in de and gsw, since it is a specialization @@ -190,13 +188,13 @@ Feature: Remove Nodes """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "en"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "en"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "en"} # the node was removed inside the new content stream, but only in gsw @@ -231,13 +229,13 @@ Feature: Remove Nodes """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "en"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "en"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "en"} # the node was removed inside the new content stream, but only in gsw @@ -277,13 +275,13 @@ Feature: Remove Nodes """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "en"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "en"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "en"} # the node was removed inside the new content stream, but only in gsw @@ -315,13 +313,13 @@ Feature: Remove Nodes """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "de"} - When I am in content stream "cs-identifier" and dimension space point {"language": "en"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "en"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language": "en"} # the node was removed inside the new content stream, but only in gsw diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RemoveProperty_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RemoveProperty_NoDimensions.feature index 814dd9e5f2d..399bcf84a1d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RemoveProperty_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RemoveProperty_NoDimensions.feature @@ -24,16 +24,15 @@ Feature: Remove Property | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -59,7 +58,7 @@ Feature: Remove Property property: 'text' """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to have the following properties: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RenameNodeAggregate_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RenameNodeAggregate_Dimensions.feature index 0dbe9995e01..2842fc39a2d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RenameNodeAggregate_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RenameNodeAggregate_Dimensions.feature @@ -27,16 +27,15 @@ Feature: Rename Node Aggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document (in "de") When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | nodeName | "foo" | @@ -48,7 +47,6 @@ Feature: Rename Node Aggregate # Node /document (in "en") When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | sourceOrigin | {"language":"de"} | | targetOrigin | {"language":"en"} | @@ -74,10 +72,10 @@ Feature: Rename Node Aggregate # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {"language": "de"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} Then I expect the node "sir-david-nodenborough" to have the name "foo" - When I am in content stream "cs-identifier" and dimension space point {"language": "ch"} + When I am in the active content stream of workspace "live" and dimension space point {"language": "ch"} Then I expect the node "sir-david-nodenborough" to have the name "foo" # the node was changed inside the new content stream, across all dimensions diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RenameProperty_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RenameProperty_NoDimensions.feature index bfba5f15260..b63569bd20f 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RenameProperty_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/RenameProperty_NoDimensions.feature @@ -24,16 +24,15 @@ Feature: Rename Property | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -73,7 +72,7 @@ Feature: Rename Property to: 'newText' """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to have the following properties: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/StripTagsOnProperty_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/StripTagsOnProperty_NoDimensions.feature index d075f010fc1..987cbc19287 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/StripTagsOnProperty_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/EventSourced/Migration/StripTagsOnProperty_NoDimensions.feature @@ -24,16 +24,15 @@ Feature: Strip Tags on Property | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -59,7 +58,7 @@ Feature: Strip Tags on Property property: 'text' """ # the original content stream has not been touched - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to have the following properties: | Key | Value | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeCopying/CopyNode_NoDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeCopying/CopyNode_NoDimensions.feature index 5699d8fb4f4..ce6239b603a 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeCopying/CopyNode_NoDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeCopying/CopyNode_NoDimensions.feature @@ -16,9 +16,9 @@ Feature: Copy nodes (without dimensions) | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -54,7 +54,7 @@ Feature: Copy nodes (without dimensions) And the graph projection is fully up to date Scenario: Copy - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} # node to copy (currentNode): "sir-nodeward-nodington-iii" Then I expect node aggregate identifier "sir-nodeward-nodington-iii" to lead to node cs-identifier;sir-nodeward-nodington-iii;{} When the command CopyNodesRecursively is executed, copying the current node aggregate with payload: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePropertyConversion/NodePropertyConversion.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePropertyConversion/NodePropertyConversion.feature index e112c758be8..77aa2b318ad 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePropertyConversion/NodePropertyConversion.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePropertyConversion/NodePropertyConversion.feature @@ -17,9 +17,9 @@ Feature: Node Property Conversion | workspaceName | "live" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date @@ -27,7 +27,6 @@ Feature: Node Property Conversion Scenario: DateTime objects at Node Creation When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:Content" | | originDimensionSpacePoint | {} | @@ -45,7 +44,6 @@ Feature: Node Property Conversion Scenario: DateTime objects at Node Property Updating When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:Content" | | originDimensionSpacePoint | {} | @@ -55,7 +53,6 @@ Feature: Node Property Conversion When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | originDimensionSpacePoint | {} | | propertyValues | {"dateProperty": "Date:1997-07-19T19:20:30+05:00"} | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature index 16d55fe52d5..f6355585dc0 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateAfterDisabling.feature @@ -24,7 +24,7 @@ Feature: Disable a node aggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -58,7 +58,6 @@ Feature: Disable a node aggregate When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -66,7 +65,7 @@ Feature: Disable a node aggregate | nodeName | "child-document" | When the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Then I expect the graph projection to consist of exactly 5 nodes And I expect a node identified by cs-identifier;lady-eleonode-rootford;{} to exist in the content graph And I expect a node identified by cs-identifier;preceding-nodenborough;{} to exist in the content graph @@ -77,7 +76,7 @@ Feature: Disable a node aggregate And I expect the node aggregate "sir-david-nodenborough" to exist And I expect this node aggregate to disable dimension space points [] - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} And VisibilityConstraints are set to "frontend" Then the subtree for node aggregate "lady-eleonode-rootford" with node types "" and 2 levels deep should be: | Level | nodeAggregateId | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature index 92b49ded40a..9f44a74c9c0 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRemoval/RemoveNodeAggregateWithDimensions.feature @@ -20,9 +20,9 @@ Feature: Remove NodeAggregate | workspaceDescription | "The live workspace" | | newContentStreamId | "live-cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "live-cs-identifier" | | nodeAggregateId | "lady-eleonode-nodesworth" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date @@ -30,10 +30,8 @@ Feature: Remove NodeAggregate # Node /document And the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "live-cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language":"de"} | | parentNodeAggregateId | "lady-eleonode-nodesworth" | | nodeName | "document" | And the graph projection is fully up to date @@ -41,16 +39,13 @@ Feature: Remove NodeAggregate # Node /document/child-document And the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "live-cs-identifier" | | nodeAggregateId | "nodimus-prime" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language":"de"} | | parentNodeAggregateId | "nody-mc-nodeface" | | nodeName | "child-document" | And the graph projection is fully up to date And the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "live-cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | sourceOrigin | {"language":"de"} | | targetOrigin | {"language":"gsw"} | @@ -62,7 +57,6 @@ Feature: Remove NodeAggregate Scenario: In LIVE workspace, removing a NodeAggregate removes all nodes completely When the command RemoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "live-cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | nodeVariantSelectionStrategy | "allVariants" | | coveredDimensionSpacePoint | {"language":"de"} | @@ -81,15 +75,17 @@ Feature: Remove NodeAggregate Scenario: In USER workspace, removing a NodeAggregate removes all nodes completely; leaving the live workspace untouched - When the command "ForkContentStream" is executed with payload: - | Key | Value | - | contentStreamId | "user-cs-identifier" | - | sourceContentStreamId | "live-cs-identifier" | + # Create user workspace + When the command CreateWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | baseWorkspaceName | "live" | + | newContentStreamId | "user-cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "user-test" When the command RemoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | nodeVariantSelectionStrategy | "allVariants" | | coveredDimensionSpacePoint | {"language":"de"} | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/01_ChangeNodeAggregateName_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/01_ChangeNodeAggregateName_ConstraintChecks.feature index 613c3bb4213..542dbc3fb26 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/01_ChangeNodeAggregateName_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/01_ChangeNodeAggregateName_ConstraintChecks.feature @@ -24,7 +24,7 @@ Feature: Change node name | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | @@ -36,10 +36,10 @@ Feature: Change node name | sir-david-nodenborough | null | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | {} | {"tethered": "nodewyn-tetherton"} | | nody-mc-nodeface | occupied | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | {} | {} | - Scenario: Try to rename a node aggregate in a non-existing content stream + Scenario: Try to rename a node aggregate in a non-existing workspace When the command ChangeNodeAggregateName is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "i-do-not-exist" | + | workspaceName | "i-do-not-exist" | | nodeAggregateId | "sir-david-nodenborough" | | newNodeName | "new-name" | Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/ChangeNodeAggregateName.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/ChangeNodeAggregateName.feature index c4bf71b0d0a..e1760070c4e 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/ChangeNodeAggregateName.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRenaming/ChangeNodeAggregateName.feature @@ -12,69 +12,69 @@ Feature: Change node name And using identifier "default", I define a content repository And I am in content repository "default" And the command CreateRootWorkspace is executed with payload: - | Key | Value | - | workspaceName | "live" | - | workspaceTitle | "Live" | - | workspaceDescription | "The live workspace" | - | newContentStreamId | "cs-identifier" | + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "lady-eleonode-rootford" | - | nodeTypeName | "Neos.ContentRepository:Root" | + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | Scenario: Change node name of content node Given the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Content" | - | originDimensionSpacePoint | {} | - | coveredDimensionSpacePoints | [{}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "dog" | - | nodeAggregateClassification | "regular" | + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:Content" | + | originDimensionSpacePoint | {} | + | coveredDimensionSpacePoints | [{}] | + | parentNodeAggregateId | "lady-eleonode-rootford" | + | nodeName | "dog" | + | nodeAggregateClassification | "regular" | And the graph projection is fully up to date When the command "ChangeNodeAggregateName" is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | newNodeName | "cat" | + | Key | Value | + | workspaceName | "live" | + | nodeAggregateId | "nody-mc-nodeface" | + | newNodeName | "cat" | Then I expect exactly 4 events to be published on stream with prefix "ContentStream:cs-identifier" And event at index 3 is of type "NodeAggregateNameWasChanged" with payload: - | Key | Expected | + | Key | Expected | | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | - | newNodeName | "cat" | + | newNodeName | "cat" | Scenario: Change node name actually updates projection Given the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Content" | - | originDimensionSpacePoint | {} | - | coveredDimensionSpacePoints | [{}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "dog" | - | nodeAggregateClassification | "regular" | + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:Content" | + | originDimensionSpacePoint | {} | + | coveredDimensionSpacePoints | [{}] | + | parentNodeAggregateId | "lady-eleonode-rootford" | + | nodeName | "dog" | + | nodeAggregateClassification | "regular" | And the graph projection is fully up to date # we read the node initially, to ensure it is filled in the cache (to check whether cache clearing actually works) - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} Then I expect this node to have the following child nodes: | Name | NodeDiscriminator | | dog | cs-identifier;nody-mc-nodeface;{} | When the command "ChangeNodeAggregateName" is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | newNodeName | "cat" | + | Key | Value | + | workspaceName | "live" | + | nodeAggregateId | "nody-mc-nodeface" | + | newNodeName | "cat" | And the graph projection is fully up to date Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_BasicErrorCases.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_BasicErrorCases.feature index 0f459aa04b1..597ab0036b9 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_BasicErrorCases.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_BasicErrorCases.feature @@ -44,125 +44,112 @@ Feature: Change node aggregate type - basic error cases And using identifier "default", I define a content repository And I am in content repository "default" And the command CreateRootWorkspace is executed with payload: - | Key | Value | - | workspaceName | "live" | - | workspaceTitle | "Live" | - | workspaceDescription | "The live workspace" | - | newContentStreamId | "cs-identifier" | + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "lady-eleonode-rootford" | - | nodeTypeName | "Neos.ContentRepository:Root" | + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | + | Key | Value | | nodeAggregateId | "sir-david-nodenborough" | - | nodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | - | originDimensionSpacePoint | {"language":"de"} | + | nodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "parent" | - | initialPropertyValues | {} | + | nodeName | "parent" | + | initialPropertyValues | {} | And the graph projection is fully up to date Scenario: Try to change the node aggregate type on a non-existing content stream When the command ChangeNodeAggregateType was published with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "non-existing" | - | nodeAggregateId | "sir-david-nodenborough" | - | newNodeTypeName | "Neos.ContentRepository.Testing:ChildOfNodeTypeA" | - | strategy | "happypath" | + | Key | Value | + | workspaceName | "non-existing" | + | nodeAggregateId | "sir-david-nodenborough" | + | newNodeTypeName | "Neos.ContentRepository.Testing:ChildOfNodeTypeA" | + | strategy | "happypath" | Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" Scenario: Try to change the type on a non-existing node aggregate When the command ChangeNodeAggregateType was published with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | newNodeTypeName | "Neos.ContentRepository.Testing:ChildOfNodeTypeA" | - | strategy | "happypath" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | newNodeTypeName | "Neos.ContentRepository.Testing:ChildOfNodeTypeA" | + | strategy | "happypath" | Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" Scenario: Try to change a node aggregate to a non existing type When the command ChangeNodeAggregateType was published with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | newNodeTypeName | "Neos.ContentRepository.Testing:Undefined" | - | strategy | "happypath" | + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | newNodeTypeName | "Neos.ContentRepository.Testing:Undefined" | + | strategy | "happypath" | Then the last command should have thrown an exception of type "NodeTypeNotFound" Scenario: Try to change to a node type disallowed by the parent node When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | + | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:NodeTypeA" | - | originDimensionSpacePoint | {"language":"de"} | + | nodeTypeName | "Neos.ContentRepository.Testing:NodeTypeA" | | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "parent" | - | initialPropertyValues | {} | + | nodeName | "parent" | + | initialPropertyValues | {} | And the graph projection is fully up to date When the command ChangeNodeAggregateType was published with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | newNodeTypeName | "Neos.ContentRepository.Testing:NodeTypeB" | - | strategy | "happypath" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | newNodeTypeName | "Neos.ContentRepository.Testing:NodeTypeB" | + | strategy | "happypath" | Then the last command should have thrown an exception of type "NodeConstraintException" Scenario: Try to change to a node type that is not allowed by the grand parent aggregate inside an autocreated parent aggregate When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | + | Key | Value | | nodeAggregateId | "parent2-na" | - | nodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | - | originDimensionSpacePoint | {"language":"de"} | + | nodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "parent2" | - | initialPropertyValues | {} | + | nodeName | "parent2" | + | initialPropertyValues | {} | | tetheredDescendantNodeAggregateIds | {"autocreated": "autocreated-child"} | And the graph projection is fully up to date When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:NodeTypeA" | - | originDimensionSpacePoint | {"language":"de"} | - | parentNodeAggregateId | "autocreated-child" | - | initialPropertyValues | {} | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:NodeTypeA" | + | originDimensionSpacePoint | {"language":"de"} | + | parentNodeAggregateId | "autocreated-child" | + | initialPropertyValues | {} | And the graph projection is fully up to date When the command ChangeNodeAggregateType was published with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | newNodeTypeName | "Neos.ContentRepository.Testing:NodeTypeB" | - | strategy | "happypath" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | newNodeTypeName | "Neos.ContentRepository.Testing:NodeTypeB" | + | strategy | "happypath" | Then the last command should have thrown an exception of type "NodeConstraintException" Scenario: Try to change the node type of an auto created child node to anything other than defined: When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | + | Key | Value | | nodeAggregateId | "parent2-na" | - | nodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | - | originDimensionSpacePoint | {"language":"de"} | + | nodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | + | originDimensionSpacePoint | {"language":"de"} | | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "parent2" | - | initialPropertyValues | {} | + | nodeName | "parent2" | + | initialPropertyValues | {} | | tetheredDescendantNodeAggregateIds | {"autocreated": "nody-mc-nodeface"} | And the graph projection is fully up to date When the command ChangeNodeAggregateType was published with payload and exceptions are caught: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | newNodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | - | strategy | "happypath" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | newNodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | + | strategy | "happypath" | Then the last command should have thrown an exception of type "NodeConstraintException" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_DeleteStrategy.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_DeleteStrategy.feature index a7045ab3946..c2bfccea819 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_DeleteStrategy.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_DeleteStrategy.feature @@ -66,16 +66,15 @@ Feature: Change node aggregate type - behavior of DELETE strategy | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | | originDimensionSpacePoint | {"language":"de"} | @@ -88,7 +87,6 @@ Feature: Change node aggregate type - behavior of DELETE strategy Scenario: Try to change to a node type that disallows already present children with the delete conflict resolution strategy When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:NodeTypeA" | | originDimensionSpacePoint | {"language":"de"} | @@ -97,26 +95,24 @@ Feature: Change node aggregate type - behavior of DELETE strategy When the command ChangeNodeAggregateType was published with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | newNodeTypeName | "Neos.ContentRepository.Testing:ParentNodeTypeB" | | strategy | "delete" | And the graph projection is fully up to date # the type has changed - When I am in content stream "cs-identifier" and dimension space point {"language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"language":"de"} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{"language":"de"} And I expect this node to be of type "Neos.ContentRepository.Testing:ParentNodeTypeB" # the child nodes have been removed Then I expect node aggregate identifier "nody-mc-nodeface" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language":"gsw"} Then I expect node aggregate identifier "nody-mc-nodeface" to lead to no node Scenario: Try to change to a node type that disallows already present grandchildren with the delete conflict resolution strategy When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "parent2-na" | | nodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | | originDimensionSpacePoint | {"language":"de"} | @@ -127,7 +123,6 @@ Feature: Change node aggregate type - behavior of DELETE strategy When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:NodeTypeA" | | originDimensionSpacePoint | {"language":"de"} | @@ -137,33 +132,31 @@ Feature: Change node aggregate type - behavior of DELETE strategy When the command ChangeNodeAggregateType was published with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "parent2-na" | | newNodeTypeName | "Neos.ContentRepository.Testing:ParentNodeTypeB" | | strategy | "delete" | And the graph projection is fully up to date # the type has changed - When I am in content stream "cs-identifier" and dimension space point {"language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"language":"de"} Then I expect node aggregate identifier "parent2-na" to lead to node cs-identifier;parent2-na;{"language":"de"} And I expect this node to be of type "Neos.ContentRepository.Testing:ParentNodeTypeB" # the child nodes still exist - When I am in content stream "cs-identifier" and dimension space point {"language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"language":"de"} Then I expect node aggregate identifier "autocreated-child" to lead to node cs-identifier;autocreated-child;{"language":"de"} - When I am in content stream "cs-identifier" and dimension space point {"language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language":"gsw"} Then I expect node aggregate identifier "autocreated-child" to lead to node cs-identifier;autocreated-child;{"language":"de"} # the grandchild nodes have been removed Then I expect node aggregate identifier "nody-mc-nodeface" to lead to no node - When I am in content stream "cs-identifier" and dimension space point {"language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language":"gsw"} Then I expect node aggregate identifier "nody-mc-nodeface" to lead to no node Scenario: Change node type successfully When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nodea-identifier-de" | | nodeTypeName | "Neos.ContentRepository.Testing:NodeTypeA" | | originDimensionSpacePoint | {"language":"de"} | @@ -174,7 +167,6 @@ Feature: Change node aggregate type - behavior of DELETE strategy When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nodea-identifier-de" | | sourceOrigin | {"language":"de"} | | targetOrigin | {"language":"gsw"} | @@ -182,7 +174,6 @@ Feature: Change node aggregate type - behavior of DELETE strategy When the command ChangeNodeAggregateType was published with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nodea-identifier-de" | | newNodeTypeName | "Neos.ContentRepository.Testing:NodeTypeB" | | strategy | "delete" | @@ -190,11 +181,11 @@ Feature: Change node aggregate type - behavior of DELETE strategy And the graph projection is fully up to date # the type has changed - When I am in content stream "cs-identifier" and dimension space point {"language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"language":"de"} Then I expect node aggregate identifier "nodea-identifier-de" to lead to node cs-identifier;nodea-identifier-de;{"language":"de"} And I expect this node to be of type "Neos.ContentRepository.Testing:NodeTypeB" - When I am in content stream "cs-identifier" and dimension space point {"language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language":"gsw"} Then I expect node aggregate identifier "nodea-identifier-de" to lead to node cs-identifier;nodea-identifier-de;{"language":"gsw"} And I expect this node to be of type "Neos.ContentRepository.Testing:NodeTypeB" And I expect this node to have the following child nodes: @@ -205,7 +196,6 @@ Feature: Change node aggregate type - behavior of DELETE strategy Scenario: When changing node type, a non-allowed tethered node should stay (Tethered nodes are not taken into account when checking constraints) When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nodea-identifier-de" | | nodeTypeName | "Neos.ContentRepository.Testing:NodeTypeA" | | originDimensionSpacePoint | {"language":"de"} | @@ -216,7 +206,6 @@ Feature: Change node aggregate type - behavior of DELETE strategy When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nodea-identifier-de" | | sourceOrigin | {"language":"de"} | | targetOrigin | {"language":"gsw"} | @@ -224,7 +213,6 @@ Feature: Change node aggregate type - behavior of DELETE strategy When the command ChangeNodeAggregateType was published with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nodea-identifier-de" | | newNodeTypeName | "Neos.ContentRepository.Testing:NodeTypeB" | | strategy | "delete" | @@ -232,7 +220,7 @@ Feature: Change node aggregate type - behavior of DELETE strategy And the graph projection is fully up to date # the type has changed - When I am in content stream "cs-identifier" and dimension space point {"language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"language":"de"} Then I expect node aggregate identifier "nodea-identifier-de" to lead to node cs-identifier;nodea-identifier-de;{"language":"de"} And I expect this node to be of type "Neos.ContentRepository.Testing:NodeTypeB" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_HappyPathStrategy.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_HappyPathStrategy.feature index b50ac899fff..712826df8c3 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_HappyPathStrategy.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeRetyping/ChangeNodeAggregateType_HappyPathStrategy.feature @@ -59,6 +59,7 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | contentStreamId | "cs-identifier" | @@ -68,7 +69,6 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | | originDimensionSpacePoint | {"language":"de"} | @@ -81,7 +81,6 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy Scenario: Try to change to a node type that disallows already present children with the HAPPYPATH conflict resolution strategy When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:NodeTypeA" | | originDimensionSpacePoint | {"language":"de"} | @@ -90,7 +89,6 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy When the command ChangeNodeAggregateType was published with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | newNodeTypeName | "Neos.ContentRepository.Testing:ParentNodeTypeB" | | strategy | "happypath" | @@ -99,7 +97,6 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy Scenario: Try to change to a node type that disallows already present grandchildren with the HAPPYPATH conflict resolution strategy When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "parent2-na" | | nodeTypeName | "Neos.ContentRepository.Testing:ParentNodeType" | | originDimensionSpacePoint | {"language":"de"} | @@ -110,7 +107,6 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:NodeTypeA" | | originDimensionSpacePoint | {"language":"de"} | @@ -120,7 +116,6 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy When the command ChangeNodeAggregateType was published with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "parent2-na" | | newNodeTypeName | "Neos.ContentRepository.Testing:ParentNodeTypeB" | | strategy | "happypath" | @@ -129,7 +124,6 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy Scenario: Change node type successfully When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nodea-identifier-de" | | nodeTypeName | "Neos.ContentRepository.Testing:NodeTypeA" | | originDimensionSpacePoint | {"language":"de"} | @@ -140,7 +134,6 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nodea-identifier-de" | | sourceOrigin | {"language":"de"} | | targetOrigin | {"language":"gsw"} | @@ -148,7 +141,6 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy When the command ChangeNodeAggregateType was published with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nodea-identifier-de" | | newNodeTypeName | "Neos.ContentRepository.Testing:NodeTypeB" | | strategy | "happypath" | @@ -156,11 +148,11 @@ Feature: Change node aggregate type - behavior of HAPPYPATH strategy And the graph projection is fully up to date # the type has changed - When I am in content stream "cs-identifier" and dimension space point {"language":"de"} + When I am in the active content stream of workspace "live" and dimension space point {"language":"de"} Then I expect node aggregate identifier "nodea-identifier-de" to lead to node cs-identifier;nodea-identifier-de;{"language":"de"} And I expect this node to be of type "Neos.ContentRepository.Testing:NodeTypeB" - When I am in content stream "cs-identifier" and dimension space point {"language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"language":"gsw"} Then I expect node aggregate identifier "nodea-identifier-de" to lead to node cs-identifier;nodea-identifier-de;{"language":"gsw"} And I expect this node to be of type "Neos.ContentRepository.Testing:NodeTypeB" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/AncestorNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/AncestorNodes.feature index 1d1d8898a10..db876fac357 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/AncestorNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/AncestorNodes.feature @@ -51,7 +51,7 @@ Feature: Find and count nodes using the findAncestorNodes and countAncestorNodes | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ChildNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ChildNodes.feature index 2eec1f078db..7c582591e06 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ChildNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ChildNodes.feature @@ -65,7 +65,7 @@ Feature: Find and count nodes using the findChildNodes and countChildNodes queri | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ClosestNode.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ClosestNode.feature index 1ebdad8ef2d..c5816b0d300 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ClosestNode.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/ClosestNode.feature @@ -51,7 +51,7 @@ Feature: Find nodes using the findClosestNode query | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/CountNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/CountNodes.feature index 9bf7a88015f..33d104675a4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/CountNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/CountNodes.feature @@ -53,7 +53,7 @@ Feature: Find nodes using the countNodes query | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/DescendantNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/DescendantNodes.feature index 8d69cecb89a..8e10cf0989c 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/DescendantNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/DescendantNodes.feature @@ -65,7 +65,7 @@ Feature: Find and count nodes using the findDescendantNodes and countDescendantN | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeById.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeById.feature index 86070abf48c..784145ebdd4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeById.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeById.feature @@ -63,7 +63,7 @@ Feature: Find nodes using the findNodeById query | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPath.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPath.feature index 22ca151cffa..e729b32d65e 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPath.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPath.feature @@ -66,7 +66,7 @@ Feature: Find nodes using the findNodeByPath query | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPathAsNodeName.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPathAsNodeName.feature index 9125fd17850..dd4a723f80d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPathAsNodeName.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindNodeByPathAsNodeName.feature @@ -63,7 +63,7 @@ Feature: Find nodes using the findNodeByPath query with node name as path argume | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindParentNode.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindParentNode.feature index bcae519c37d..e4e40665c0c 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindParentNode.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindParentNode.feature @@ -63,7 +63,7 @@ Feature: Find nodes using the findParentNodes query | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindRootNodeByType.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindRootNodeByType.feature index 8ae3fb196f8..c56e42a84a0 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindRootNodeByType.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindRootNodeByType.feature @@ -24,7 +24,7 @@ Feature: Find root nodes by type | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindSubtree.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindSubtree.feature index 5014f8c7c79..f65d2abd4ce 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindSubtree.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/FindSubtree.feature @@ -53,7 +53,7 @@ Feature: Find nodes using the findSubtree query | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/References.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/References.feature index d6befee25cf..3b4589e8a42 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/References.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/References.feature @@ -73,7 +73,7 @@ Feature: Find and count references and their target nodes using the findReferenc | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/RetrieveNodePath.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/RetrieveNodePath.feature index 8fd2e37cf40..d4bf8631090 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/RetrieveNodePath.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/RetrieveNodePath.feature @@ -54,7 +54,7 @@ Feature: Find nodes using the retrieveNodePath query | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/SiblingNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/SiblingNodes.feature index d3d40abfec4..ea4e1dda130 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/SiblingNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/SiblingNodes.feature @@ -63,7 +63,7 @@ Feature: Find sibling nodes using the findPrecedingSiblingNodes and findSucceedi | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/Timestamps.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/Timestamps.feature index ddb1b31533e..abf1450618a 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/Timestamps.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodeTraversal/Timestamps.feature @@ -74,7 +74,7 @@ Feature: Behavior of Node timestamp properties "created", "originalCreated", "la | newContentStreamId | "cs-user" | | workspaceOwner | "some-user" | And the graph projection is fully up to date - And I am in content stream "cs-user" and dimension space point {"language":"de"} + And I am in the active content stream of workspace "user-test" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | @@ -98,7 +98,7 @@ Feature: Behavior of Node timestamp properties "created", "originalCreated", "la When the current date and time is "2023-03-16T13:00:00+01:00" And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-user" | + | workspaceName | "user-test" | | originDimensionSpacePoint | {"language": "ch"} | | nodeAggregateId | "a" | | propertyValues | {"text": "Changed"} | @@ -117,7 +117,7 @@ Feature: Behavior of Node timestamp properties "created", "originalCreated", "la When the current date and time is "2023-03-16T13:00:00+01:00" And the command "ChangeNodeAggregateName" is executed with payload: | Key | Value | - | contentStreamId | "cs-user" | + | workspaceName | "user-test" | | nodeAggregateId | "a" | | newNodeName | "a-renamed" | And the graph projection is fully up to date @@ -135,7 +135,7 @@ Feature: Behavior of Node timestamp properties "created", "originalCreated", "la When the current date and time is "2023-03-16T13:00:00+01:00" And the command SetNodeReferences is executed with payload: | Key | Value | - | contentStreamId | "cs-user" | + | workspaceName | "user-test" | | sourceOriginDimensionSpacePoint | {"language": "ch"} | | sourceNodeAggregateId | "a" | | referenceName | "ref" | @@ -161,7 +161,7 @@ Feature: Behavior of Node timestamp properties "created", "originalCreated", "la When the current date and time is "2023-03-16T13:00:00+01:00" And the command ChangeNodeAggregateType was published with payload: | Key | Value | - | contentStreamId | "cs-user" | + | workspaceName | "user-test" | | nodeAggregateId | "a" | | newNodeTypeName | "Neos.ContentRepository.Testing:SpecialPage" | | strategy | "happypath" | @@ -217,7 +217,7 @@ Feature: Behavior of Node timestamp properties "created", "originalCreated", "la When the current date and time is "2023-03-16T13:00:00+01:00" And the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-user" | + | workspaceName | "user-test" | | dimensionSpacePoint | {"language": "ch"} | | relationDistributionStrategy | "gatherSpecializations" | | nodeAggregateId | "a" | @@ -253,7 +253,7 @@ Feature: Behavior of Node timestamp properties "created", "originalCreated", "la When the current date and time is "2023-03-16T13:00:00+01:00" And the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-user" | + | workspaceName | "user-test" | | coveredDimensionSpacePoint | {"language": "ch"} | | nodeAggregateId | "a" | | nodeVariantSelectionStrategy | "allSpecializations" | @@ -272,7 +272,7 @@ Feature: Behavior of Node timestamp properties "created", "originalCreated", "la When the current date and time is "2023-03-16T14:00:00+01:00" And the command EnableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-user" | + | workspaceName | "user-test" | | coveredDimensionSpacePoint | {"language": "ch"} | | nodeAggregateId | "a" | | nodeVariantSelectionStrategy | "allSpecializations" | @@ -292,7 +292,7 @@ Feature: Behavior of Node timestamp properties "created", "originalCreated", "la When the current date and time is "2023-03-16T13:00:00+01:00" And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-user" | + | workspaceName | "user-test" | | nodeAggregateId | "a" | | propertyValues | {"text": "Changed"} | And I execute the findNodeById query for node aggregate id "non-existing" I expect no node to be returned diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesCoverTheirOrigin.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesCoverTheirOrigin.feature index 77d4575b33f..f7c96024ca4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesCoverTheirOrigin.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesCoverTheirOrigin.feature @@ -20,9 +20,9 @@ Feature: Run projection integrity violation detection to find nodes that do not | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregateIdentifiersAreUniquePerSubgraph.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregateIdentifiersAreUniquePerSubgraph.feature index 49fcc92aa44..cb0fa7092c4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregateIdentifiersAreUniquePerSubgraph.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregateIdentifiersAreUniquePerSubgraph.feature @@ -20,9 +20,9 @@ Feature: Create two nodes with the same node aggregate identifier in the same su | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyClassifiedPerContentStream.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyClassifiedPerContentStream.feature index 8328134f806..79752e4371e 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyClassifiedPerContentStream.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyClassifiedPerContentStream.feature @@ -20,9 +20,9 @@ Feature: Run projection integrity violation detection regarding node aggregate c | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyTypedPerContentStream.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyTypedPerContentStream.feature index 3695cb2c013..5ddfd4d3e0a 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyTypedPerContentStream.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/NodeAggregatesAreConsistentlyTypedPerContentStream.feature @@ -22,9 +22,9 @@ Feature: Run projection integrity violation detection regarding node aggregate t | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature index fac33f3cf85..f8101ef42c1 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/ReferenceIntegrityIsProvided.feature @@ -20,9 +20,9 @@ Feature: Run integrity violation detection regarding reference relations | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language":"de"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/RootNodeAggregateDimensionUpdates/UpdateRootNodeAggregateDimensions_WithDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/RootNodeAggregateDimensionUpdates/UpdateRootNodeAggregateDimensions_WithDimensions.feature index f2e7eb542a4..3382f6122a5 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/RootNodeAggregateDimensionUpdates/UpdateRootNodeAggregateDimensions_WithDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/RootNodeAggregateDimensionUpdates/UpdateRootNodeAggregateDimensions_WithDimensions.feature @@ -20,7 +20,7 @@ Feature: Update Root Node aggregate dimensions | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature index 23dcda99640..b059a1cf922 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DimensionMismatch.feature @@ -25,9 +25,9 @@ Feature: Dimension mismatch | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language": "en"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date @@ -36,7 +36,6 @@ Feature: Dimension mismatch # Node /document When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {"language": "en"} | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DisallowedChildNode.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DisallowedChildNode.feature index 5789bb46c7a..d662515984e 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DisallowedChildNode.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DisallowedChildNode.feature @@ -31,9 +31,9 @@ Feature: Remove disallowed Child Nodes and grandchild nodes | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | # Node /document @@ -85,7 +85,7 @@ Feature: Remove disallowed Child Nodes and grandchild nodes When I adjust the node structure for node type "Neos.ContentRepository.Testing:Document" Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:Document" - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} And I expect node aggregate identifier "sir-david-nodenborough" to lead to no node @@ -120,9 +120,10 @@ Feature: Remove disallowed Child Nodes and grandchild nodes | workspaceTitle | "Live" | | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | # Node /document @@ -183,6 +184,6 @@ Feature: Remove disallowed Child Nodes and grandchild nodes When I adjust the node structure for node type "Neos.ContentRepository.Testing:SubDocument" Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:SubDocument" - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} And I expect node aggregate identifier "subdoc" to lead to no node diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DisallowedChildNodesAndTetheredNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DisallowedChildNodesAndTetheredNodes.feature index 9dc7063bf5d..9b819a633ee 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DisallowedChildNodesAndTetheredNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/DisallowedChildNodesAndTetheredNodes.feature @@ -31,7 +31,7 @@ Feature: Remove disallowed Child Nodes and grandchild nodes | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature index 75e391be4a6..ce752a421b1 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/Properties.feature @@ -25,16 +25,15 @@ Feature: Properties | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date # Node /document When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -42,7 +41,6 @@ Feature: Properties And the graph projection is fully up to date Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:Document" - When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to have the following properties: | Key | Value | @@ -59,7 +57,7 @@ Feature: Properties When I adjust the node structure for node type "Neos.ContentRepository.Testing:Document" Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:Document" - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to have no properties @@ -81,7 +79,7 @@ Feature: Properties When I adjust the node structure for node type "Neos.ContentRepository.Testing:Document" Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:Document" - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to have the following properties: | Key | Value | @@ -102,7 +100,6 @@ Feature: Properties """ And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | originDimensionSpacePoint | {} | | propertyValues | {"otherProp": ""} | @@ -134,6 +131,6 @@ Feature: Properties When I adjust the node structure for node type "Neos.ContentRepository.Testing:Document" Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:Document" - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to have no properties diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodes.feature index 6b8aa2ea3cd..cdc5e01843f 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodes.feature @@ -37,6 +37,7 @@ Feature: Tethered Nodes integrity violations | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | contentStreamId | "cs-identifier" | @@ -203,7 +204,7 @@ Feature: Tethered Nodes integrity violations Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:Document" When I adjust the node structure for node type "Neos.ContentRepository:Root" Then I expect no needed structure adjustments for type "Neos.ContentRepository:Root" - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} Then I expect node aggregate identifier "nodewyn-tetherton" to lead to no node Then I expect node aggregate identifier "nodimer-tetherton" to lead to no node And I expect path "tethered-node" to lead to no node diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature index 5e6a7a3615f..72bc102776d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/TetheredNodesReordering.feature @@ -26,15 +26,14 @@ Feature: Tethered Nodes Reordering Structure changes | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + When I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date And the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | originDimensionSpacePoint | {} | @@ -45,7 +44,6 @@ Feature: Tethered Nodes Reordering Structure changes Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:Document" - When I am in the active content stream of workspace "live" and dimension space point {} And I get the node at path "document/tethered-node" And I expect this node to have no preceding siblings And I expect this node to have the following succeeding siblings: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/UnknownNodeType.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/UnknownNodeType.feature index 4d0578ccf21..6bcb3ca90ff 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/UnknownNodeType.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/StructureAdjustment/UnknownNodeType.feature @@ -18,9 +18,9 @@ Feature: Unknown node types | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | # Node /document @@ -47,6 +47,6 @@ Feature: Unknown node types When I adjust the node structure for node type "Neos.ContentRepository.Testing:Document" Then I expect no needed structure adjustments for type "Neos.ContentRepository.Testing:Document" - When I am in content stream "cs-identifier" and dimension space point {"market":"CH", "language":"gsw"} + When I am in the active content stream of workspace "live" and dimension space point {"market":"CH", "language":"gsw"} And I expect node aggregate identifier "sir-david-nodenborough" to lead to no node diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W10-IndividualNodeDiscarding/01-ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W10-IndividualNodeDiscarding/01-ConstraintChecks.feature new file mode 100644 index 00000000000..271e9440ced --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W10-IndividualNodeDiscarding/01-ConstraintChecks.feature @@ -0,0 +1,88 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Workspace discarding - complex chained functionality + + Background: + Given using the following content dimensions: + | Identifier | Values | Generalizations | + | language | ltz, de, en, fr | ltz->de->en | + + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:ContentCollection': + constraints: + nodeTypes: + 'Neos.ContentRepository.Testing:Content': true + + 'Neos.ContentRepository.Testing:Document': + childNodes: + tethered: + type: 'Neos.ContentRepository.Testing:ContentCollection' + + 'Neos.ContentRepository.Testing:Content': + properties: + text: + type: string + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language": "de"} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | + | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | document | {"tethered": "nodewyn-tetherton"} | + | nody-mc-nodeface | Neos.ContentRepository.Testing:Content | nodewyn-tetherton | grandchild | {} | + + And the command CreateWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | baseWorkspaceName | "live" | + | newContentStreamId | "user-cs-id" | + And the graph projection is fully up to date + + Scenario: Vary to generalization, then delete the origin and discard parts of the result so that an exception is thrown. Ensure that the workspace recovers from this + When the command CreateNodeVariant is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | nodeAggregateId | "sir-david-nodenborough" | + | sourceOrigin | {"language": "de"} | + | targetOrigin | {"language": "en"} | + And the graph projection is fully up to date + And the command CreateNodeVariant is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | nodeAggregateId | "nody-mc-nodeface" | + | sourceOrigin | {"language": "de"} | + | targetOrigin | {"language": "en"} | + And the graph projection is fully up to date + + And the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"language": "en"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command DiscardIndividualNodesFromWorkspace is executed with payload and exceptions are caught: + | Key | Value | + | workspaceName | "user-ws" | + | nodesToDiscard | [{"workspaceName": "user-ws", "dimensionSpacePoint": {"language": "en"}, "nodeAggregateId": "sir-david-nodenborough"}, {"workspaceName": "user-ws", "dimensionSpacePoint": {"language": "en"}, "nodeAggregateId": "sir-david-nodenborough"}] | + | newContentStreamId | "user-cs-id-rebased" | + Then the last command should have thrown an exception of type "NodeAggregateDoesCurrentlyNotCoverDimensionSpacePoint" + + When the command DiscardWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | newContentStreamId | "user-cs-id-yet-again-rebased" | + And the graph projection is fully up to date + When I am in the active content stream of workspace "user-ws" and dimension space point {"language": "de"} + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-id-yet-again-rebased;nody-mc-nodeface;{"language": "de"} diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W10-IndividualNodeDiscarding/02-BasicFeatures.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W10-IndividualNodeDiscarding/02-BasicFeatures.feature new file mode 100644 index 00000000000..7698343042a --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W10-IndividualNodeDiscarding/02-BasicFeatures.feature @@ -0,0 +1,191 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Discard individual nodes (basics) + + Publishing an individual node works + Node structure is as follows: + - rn-identifier (root node) + -- sir-david-nodenborough (name=text1) <== modifications! + --- nody-mc-nodeface (name=text2) <== modifications! + -- sir-nodeward-nodington-iii (name=image) <== modifications! + + + Background: + Given using no content dimensions + And using the following node types: + """yaml + Neos.ContentRepository:Root: {} + 'Neos.ContentRepository.Testing:Content': + properties: + text: + type: string + 'Neos.ContentRepository.Testing:Image': + properties: + image: + type: string + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the event NodeAggregateWithNodeWasCreated was published with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "sir-david-nodenborough" | + | nodeTypeName | "Neos.ContentRepository.Testing:Content" | + | originDimensionSpacePoint | {} | + | coveredDimensionSpacePoints | [{}] | + | parentNodeAggregateId | "lady-eleonode-rootford" | + | initialPropertyValues | {"text": {"type": "string", "value": "Initial t1"}} | + | nodeAggregateClassification | "regular" | + And the event NodeAggregateWithNodeWasCreated was published with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:Content" | + | originDimensionSpacePoint | {} | + | coveredDimensionSpacePoints | [{}] | + | parentNodeAggregateId | "sir-david-nodenborough" | + | initialPropertyValues | {"text": {"type": "string", "value": "Initial t2"}} | + | nodeAggregateClassification | "regular" | + And the event NodeAggregateWithNodeWasCreated was published with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | nodeTypeName | "Neos.ContentRepository.Testing:Image" | + | originDimensionSpacePoint | {} | + | coveredDimensionSpacePoints | [{}] | + | parentNodeAggregateId | "lady-eleonode-rootford" | + | initialPropertyValues | {"image": {"type": "string", "value": "Initial image"}} | + | nodeAggregateClassification | "regular" | + And the graph projection is fully up to date + + # Create user workspace + And the command CreateWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | baseWorkspaceName | "live" | + | newContentStreamId | "user-cs-identifier" | + And the graph projection is fully up to date + # modify nodes in user WS + And the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodeAggregateId | "sir-david-nodenborough" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified t1"} | + And the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified t2"} | + And the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | originDimensionSpacePoint | {} | + | propertyValues | {"image": "Modified image"} | + And the graph projection is fully up to date + + ################ + # DISCARDING + ################ + Scenario: It is possible to discard a single node; and only the others are live. + # discard "sir-nodeward-nodington-iii" only + When the command DiscardIndividualNodesFromWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodesToDiscard | [{"workspaceName": "user-test", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | + | newContentStreamId | "user-cs-identifier-new" | + + And the graph projection is fully up to date + + When I am in the active content stream of workspace "user-test" and dimension space point {} + Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node user-cs-identifier-new;sir-david-nodenborough;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Modified t1" | + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier-new;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Modified t2" | + Then I expect node aggregate identifier "sir-nodeward-nodington-iii" to lead to node user-cs-identifier-new;sir-nodeward-nodington-iii;{} + And I expect this node to have the following properties: + | Key | Value | + | image | "Initial image" | + + Scenario: It is possible to discard no node + When the command DiscardIndividualNodesFromWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodesToDiscard | [] | + | newContentStreamId | "user-cs-identifier-new" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "user-test" and dimension space point {} + Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node user-cs-identifier-new;sir-david-nodenborough;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Modified t1" | + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier-new;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Modified t2" | + Then I expect node aggregate identifier "sir-nodeward-nodington-iii" to lead to node user-cs-identifier-new;sir-nodeward-nodington-iii;{} + And I expect this node to have the following properties: + | Key | Value | + | image | "Modified image" | + + Scenario: It is possible to discard all nodes + When the command DiscardIndividualNodesFromWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodesToDiscard | [{"workspaceName": "user-test", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-david-nodenborough"}, {"workspaceName": "user-test", "dimensionSpacePoint": {}, "nodeAggregateId": "nody-mc-nodeface"}, {"workspaceName": "user-test", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | + | newContentStreamId | "user-cs-identifier-new" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "user-test" and dimension space point {} + Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node user-cs-identifier-new;sir-david-nodenborough;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Initial t1" | + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier-new;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Initial t2" | + Then I expect node aggregate identifier "sir-nodeward-nodington-iii" to lead to node user-cs-identifier-new;sir-nodeward-nodington-iii;{} + And I expect this node to have the following properties: + | Key | Value | + | image | "Initial image" | + + Scenario: When discarding a node, the live workspace does not change. + # discard "sir-nodeward-nodington-iii" + When the command DiscardIndividualNodesFromWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodesToDiscard | [{"workspaceName": "user-test", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | + And the graph projection is fully up to date + + # live WS does not change because of a discard + When I am in the active content stream of workspace "live" and dimension space point {} + Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Initial t1" | + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Initial t2" | + Then I expect node aggregate identifier "sir-nodeward-nodington-iii" to lead to node cs-identifier;sir-nodeward-nodington-iii;{} + And I expect this node to have the following properties: + | Key | Value | + | image | "Initial image" | + diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/RebasingAutoCreatedNodesWorks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W6-WorkspaceRebasing/02-RebasingWithAutoCreatedNodes.feature similarity index 95% rename from Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/RebasingAutoCreatedNodesWorks.feature rename to Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W6-WorkspaceRebasing/02-RebasingWithAutoCreatedNodes.feature index 6b00171dd3d..cd071f56e12 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/RebasingAutoCreatedNodesWorks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W6-WorkspaceRebasing/02-RebasingWithAutoCreatedNodes.feature @@ -33,10 +33,10 @@ Feature: Rebasing auto-created nodes works | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the graph projection is fully up to date And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date @@ -52,7 +52,7 @@ Feature: Rebasing auto-created nodes works # USER workspace: create a new node with auto-created child nodes When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:Content" | | nodeName | "mcnodeface" | @@ -67,7 +67,7 @@ Feature: Rebasing auto-created nodes works # - then, for the auto-created child node, set a property. When the command "SetSerializedNodeProperties" is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | $this->currentNodeAggregateId | | originDimensionSpacePoint | {} | | propertyValues | {"text": {"value":"Modified","type":"string"}} | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W7-WorkspacePublication/02-PublishWorkspace.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W7-WorkspacePublication/02-PublishWorkspace.feature new file mode 100644 index 00000000000..ce52bbcb253 --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W7-WorkspacePublication/02-PublishWorkspace.feature @@ -0,0 +1,198 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Workspace based content publishing + + This is an END TO END test; testing all layers of the related functionality step by step together + + Basic fixture setup is: + - root workspace with a single "root" node inside; and an additional child node. + - then, a nested workspace is created based on the "root" node + + Background: + Given using no content dimensions + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:Content': + properties: + text: + type: string + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | + | nody-mc-nodeface | Neos.ContentRepository.Testing:Content | lady-eleonode-rootford | child | + + And the command SetNodeProperties is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Original"} | + # we need to ensure that the projections are up to date now; otherwise a content stream is forked with an out- + # of-date base version. This means the content stream can never be merged back, but must always be rebased. + And the graph projection is fully up to date + And the command CreateWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | baseWorkspaceName | "live" | + | newContentStreamId | "user-cs-identifier" | + | workspaceOwner | "owner-identifier" | + And the graph projection is fully up to date + + Scenario: Basic events are emitted + # LIVE workspace + Then I expect exactly 4 events to be published on stream "ContentStream:cs-identifier" + And event at index 0 is of type "ContentStreamWasCreated" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + + # Event 1 is the root Node Created event (we can skip this here, it is tested somewhere else); Event 2 is the SetProperty + Then I expect exactly 1 event to be published on stream "Workspace:live" + And event at index 0 is of type "RootWorkspaceWasCreated" with payload: + | Key | Expected | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The workspace \"live\"" | + | newContentStreamId | "cs-identifier" | + + # USER workspace + Then I expect exactly 1 event to be published on stream "ContentStream:user-cs-identifier" + And event at index 0 is of type "ContentStreamWasForked" with payload: + | Key | Expected | + | newContentStreamId | "user-cs-identifier" | + | sourceContentStreamId | "cs-identifier" | + + Then I expect exactly 1 event to be published on stream "Workspace:user-test" + And event at index 0 is of type "WorkspaceWasCreated" with payload: + | Key | Expected | + | workspaceName | "user-test" | + | baseWorkspaceName | "live" | + | workspaceTitle | "User-test" | + | workspaceDescription | "The workspace \"user-test\"" | + | newContentStreamId | "user-cs-identifier" | + | workspaceOwner | "owner-identifier" | + + Scenario: modify the property in the nested workspace and publish afterwards works + When the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified"} | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {} + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Original" | + + When I am in the active content stream of workspace "user-test" and dimension space point {} + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Modified" | + + # PUBLISHING + When the command PublishWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {} + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Modified" | + + Scenario: modify the property in the nested workspace, do modification in live workspace; publish afterwards will not work because rebase is missing; then rebase and publish + + When the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified in user workspace"} | + And the graph projection is fully up to date + And the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "live" | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified in live workspace"} | + And the graph projection is fully up to date + + # PUBLISHING without rebase: error + When the command PublishWorkspace is executed with payload and exceptions are caught: + | Key | Value | + | workspaceName | "user-test" | + + Then the last command should have thrown an exception of type "BaseWorkspaceHasBeenModifiedInTheMeantime" + + # REBASING + Publishing: works now (TODO soft constraint check for old value) + When the command RebaseWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | rebasedContentStreamId | "rebased-cs-id" | + And the graph projection is fully up to date + + And the command PublishWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {} + + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Modified in user workspace" | + + Scenario: modify the property in the nested workspace, publish, modify again and publish again (e.g. a workspace can be re-used after publishing for other changes) + + When the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified"} | + + And the graph projection is fully up to date + + # PUBLISHING + And the command PublishWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + And the graph projection is fully up to date + When I am in the active content stream of workspace "live" and dimension space point {} + + When the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "live" | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified anew"} | + + And the graph projection is fully up to date + + # PUBLISHING + And the command PublishWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {} + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Modified anew" | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/01-ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/01-ConstraintChecks.feature new file mode 100644 index 00000000000..90504e16e75 --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/01-ConstraintChecks.feature @@ -0,0 +1,80 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Workspace publication - complex chained functionality + + Background: + Given using the following content dimensions: + | Identifier | Values | Generalizations | + | language | ltz, de, en, fr | ltz->de->en | + + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:ContentCollection': + constraints: + nodeTypes: + 'Neos.ContentRepository.Testing:Content': true + + 'Neos.ContentRepository.Testing:Document': + childNodes: + tethered: + type: 'Neos.ContentRepository.Testing:ContentCollection' + + 'Neos.ContentRepository.Testing:Content': + properties: + text: + type: string + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"language": "de"} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | + | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | document | {"tethered": "nodewyn-tetherton"} | + | nody-mc-nodeface | Neos.ContentRepository.Testing:Content | nodewyn-tetherton | grandchild | {} | + + And the command CreateWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | baseWorkspaceName | "live" | + | newContentStreamId | "user-cs-id" | + And the graph projection is fully up to date + + Scenario: Vary to generalization, then publish only the child node so that an exception is thrown. Ensure that the workspace recovers from this + When the command CreateNodeVariant is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | nodeAggregateId | "sir-david-nodenborough" | + | sourceOrigin | {"language": "de"} | + | targetOrigin | {"language": "en"} | + And the graph projection is fully up to date + And the command CreateNodeVariant is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | nodeAggregateId | "nody-mc-nodeface" | + | sourceOrigin | {"language": "de"} | + | targetOrigin | {"language": "en"} | + And the graph projection is fully up to date + + When the command PublishIndividualNodesFromWorkspace is executed with payload and exceptions are caught: + | Key | Value | + | workspaceName | "user-ws" | + | nodesToPublish | [{"workspaceName": "user-ws", "dimensionSpacePoint": {"language": "en"}, "nodeAggregateId": "nody-mc-nodeface"}] | + | newContentStreamId | "user-cs-id-rebased" | + Then the last command should have thrown an exception of type "NodeAggregateDoesCurrentlyNotCoverDimensionSpacePoint" + + When the command PublishWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-ws" | + | newContentStreamId | "user-cs-id-yet-again-rebased" | + And the graph projection is fully up to date + When I am in the active content stream of workspace "user-ws" and dimension space point {"language": "de"} + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-id-yet-again-rebased;nody-mc-nodeface;{"language": "de"} diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/IndividualNodePublication.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/02-BasicFeatures.feature similarity index 70% rename from Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/IndividualNodePublication.feature rename to Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/02-BasicFeatures.feature index d6bfa11b1a2..d7605cc24b9 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/IndividualNodePublication.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/02-BasicFeatures.feature @@ -22,11 +22,13 @@ Feature: Individual node publication | workspaceName | "live" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | + | workspaceName | "live" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | + And the graph projection is fully up to date # Create user workspace And the command CreateWorkspace is executed with payload: @@ -41,22 +43,24 @@ Feature: Individual node publication ################ Scenario: It is possible to publish a single node; and only this one is live. # create nodes in user WS - Given I am in content stream "user-cs-identifier" and dimension space point {} + Given I am in workspace "user-test" + And I am in the active content stream of workspace "user-test" + And I am in dimension space point {} And the following CreateNodeAggregateWithNode commands are executed: - | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | - | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | document | {} | + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | + | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | document | {} | And I remember NodeAggregateId of node "sir-david-nodenborough"s child "child2" as "child2Id" And the following CreateNodeAggregateWithNode commands are executed: - | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | - | nody-mc-nodeface | Neos.ContentRepository.Testing:Content | $child2Id | nody | {} | + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | + | nody-mc-nodeface | Neos.ContentRepository.Testing:Content | $child2Id | nody | {} | When the command PublishIndividualNodesFromWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - | nodesToPublish | [{"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-david-nodenborough"}] | - | contentStreamIdForRemainingPart | "user-cs-identifier-remaining" | + | Key | Value | + | nodesToPublish | [{"workspaceName": "user-test", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-david-nodenborough"}] | + | contentStreamIdForRemainingPart | "user-cs-identifier-remaining" | + | contentStreamIdForMatchingPart | "user-cs-identifier-matching" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" + And I am in the active content stream of workspace "live" Then I expect a node identified by cs-identifier;sir-david-nodenborough;{} to exist in the content graph diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/PublishAndDiscardIndividualNodes.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/03-MoreBasicFeatures.feature similarity index 62% rename from Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/PublishAndDiscardIndividualNodes.feature rename to Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/03-MoreBasicFeatures.feature index 416b80ffb97..cd22380f14c 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/PublishAndDiscardIndividualNodes.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/03-MoreBasicFeatures.feature @@ -1,5 +1,5 @@ @contentrepository @adapters=DoctrineDBAL -Feature: Publishing and discard individual nodes (basics) +Feature: Publishing individual nodes (basics) Publishing an individual node works Node structure is as follows: @@ -30,9 +30,9 @@ Feature: Publishing and discard individual nodes (basics) | workspaceName | "live" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -77,19 +77,19 @@ Feature: Publishing and discard individual nodes (basics) # modify nodes in user WS And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "sir-david-nodenborough" | | originDimensionSpacePoint | {} | | propertyValues | {"text": "Modified t1"} | And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "nody-mc-nodeface" | | originDimensionSpacePoint | {} | | propertyValues | {"text": "Modified t2"} | And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "sir-nodeward-nodington-iii" | | originDimensionSpacePoint | {} | | propertyValues | {"image": "Modified image"} | @@ -103,8 +103,9 @@ Feature: Publishing and discard individual nodes (basics) When the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user-test" | - | nodesToPublish | [{"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | + | nodesToPublish | [{"workspaceName": "user-test", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | | contentStreamIdForRemainingPart | "user-cs-identifier-remaining" | + | contentStreamIdForMatchingPart | "user-cs-identifier-matching" | And the graph projection is fully up to date When I am in the active content stream of workspace "live" and dimension space point {} @@ -175,7 +176,7 @@ Feature: Publishing and discard individual nodes (basics) When the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user-test" | - | nodesToPublish | [{"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-david-nodenborough"}, {"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "nody-mc-nodeface"}, {"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | + | nodesToPublish | [{"workspaceName": "user-test", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-david-nodenborough"}, {"workspaceName": "user-test", "dimensionSpacePoint": {}, "nodeAggregateId": "nody-mc-nodeface"}, {"workspaceName": "user-test", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | | contentStreamIdForRemainingPart | "user-cs-identifier-remaining" | And the graph projection is fully up to date @@ -206,99 +207,3 @@ Feature: Publishing and discard individual nodes (basics) And I expect this node to have the following properties: | Key | Value | | image | "Modified image" | - - - ################ - # DISCARDING - ################ - Scenario: It is possible to discard a single node; and only the others are live. - # discard "sir-nodeward-nodington-iii" only - When the command DiscardIndividualNodesFromWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - | nodesToDiscard | [{"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | - | newContentStreamId | "user-cs-identifier-new" | - - And the graph projection is fully up to date - - When I am in the active content stream of workspace "user-test" and dimension space point {} - Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node user-cs-identifier-new;sir-david-nodenborough;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Modified t1" | - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier-new;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Modified t2" | - Then I expect node aggregate identifier "sir-nodeward-nodington-iii" to lead to node user-cs-identifier-new;sir-nodeward-nodington-iii;{} - And I expect this node to have the following properties: - | Key | Value | - | image | "Initial image" | - - Scenario: It is possible to discard no node - When the command DiscardIndividualNodesFromWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - | nodesToDiscard | [] | - | newContentStreamId | "user-cs-identifier-new" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "user-test" and dimension space point {} - Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node user-cs-identifier-new;sir-david-nodenborough;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Modified t1" | - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier-new;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Modified t2" | - Then I expect node aggregate identifier "sir-nodeward-nodington-iii" to lead to node user-cs-identifier-new;sir-nodeward-nodington-iii;{} - And I expect this node to have the following properties: - | Key | Value | - | image | "Modified image" | - - Scenario: It is possible to discard all nodes - When the command DiscardIndividualNodesFromWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - | nodesToDiscard | [{"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-david-nodenborough"}, {"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "nody-mc-nodeface"}, {"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | - | newContentStreamId | "user-cs-identifier-new" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "user-test" and dimension space point {} - Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node user-cs-identifier-new;sir-david-nodenborough;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Initial t1" | - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier-new;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Initial t2" | - Then I expect node aggregate identifier "sir-nodeward-nodington-iii" to lead to node user-cs-identifier-new;sir-nodeward-nodington-iii;{} - And I expect this node to have the following properties: - | Key | Value | - | image | "Initial image" | - - Scenario: When discarding a node, the live workspace does not change. - # discard "sir-nodeward-nodington-iii" - When the command DiscardIndividualNodesFromWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - | nodesToDiscard | [{"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | - And the graph projection is fully up to date - - # live WS does not change because of a discard - When I am in the active content stream of workspace "live" and dimension space point {} - Then I expect node aggregate identifier "sir-david-nodenborough" to lead to node cs-identifier;sir-david-nodenborough;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Initial t1" | - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Initial t2" | - Then I expect node aggregate identifier "sir-nodeward-nodington-iii" to lead to node cs-identifier;sir-nodeward-nodington-iii;{} - And I expect this node to have the following properties: - | Key | Value | - | image | "Initial image" | - diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/AllCommandsAreImplemented.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/04-AllFeaturePublication.feature similarity index 93% rename from Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/AllCommandsAreImplemented.feature rename to Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/04-AllFeaturePublication.feature index 6cab17a2920..dfdb72c5b5f 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/AllCommandsAreImplemented.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/04-AllFeaturePublication.feature @@ -39,9 +39,9 @@ Feature: Publishing hide/show scenario of nodes | workspaceName | "live" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -83,17 +83,16 @@ Feature: Publishing hide/show scenario of nodes | baseWorkspaceName | "live" | | newContentStreamId | "user-cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "user-test" # SETUP: hide two nodes in USER workspace Given the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | And the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | | nodeAggregateId | "sir-nodeward-nodington-iii" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -102,7 +101,9 @@ Feature: Publishing hide/show scenario of nodes When the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user-test" | - | nodesToPublish | [{"nodeAggregateId": "sir-david-nodenborough", "contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}}] | + | nodesToPublish | [{"nodeAggregateId": "sir-david-nodenborough", "workspaceName": "user-test", "dimensionSpacePoint": {}}] | + | contentStreamIdForRemainingPart | "remaining-cs-id" | + | contentStreamIdForMatchingPart | "matching-cs-id" | And the graph projection is fully up to date When I am in the active content stream of workspace "live" and dimension space point {} @@ -110,7 +111,7 @@ Feature: Publishing hide/show scenario of nodes And I expect node aggregate identifier "nody-mc-nodeface" to lead to no node And I expect node aggregate identifier "sir-nodeward-nodington-iii" to lead to node cs-identifier;sir-nodeward-nodington-iii;{} - When I am in the active content stream of workspace "user-test" and dimension space point {} + When I am in content stream "remaining-cs-id" and dimension space point {} Then I expect node aggregate identifier "sir-david-nodenborough" to lead to no node And I expect node aggregate identifier "nody-mc-nodeface" to lead to no node And I expect node aggregate identifier "sir-nodeward-nodington-iii" to lead to no node @@ -119,13 +120,11 @@ Feature: Publishing hide/show scenario of nodes # BEFORE: ensure two nodes are hidden in live (and user WS) Given the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | Given the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-nodeward-nodington-iii" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -139,16 +138,16 @@ Feature: Publishing hide/show scenario of nodes | newContentStreamId | "user-cs-identifier" | And the graph projection is fully up to date - # SETUP: show two nodes in USER workspace + # SETUP: enable two nodes in USER workspace Given the command EnableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | Given the command EnableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "sir-nodeward-nodington-iii" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -157,7 +156,7 @@ Feature: Publishing hide/show scenario of nodes When the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user-test" | - | nodesToPublish | [{"nodeAggregateId": "sir-david-nodenborough", "contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}}] | + | nodesToPublish | [{"nodeAggregateId": "sir-david-nodenborough", "workspaceName": "user-test", "dimensionSpacePoint": {}}] | | contentStreamIdForRemainingPart | "user-cs-identifier-modified" | And the graph projection is fully up to date @@ -225,14 +224,14 @@ Feature: Publishing hide/show scenario of nodes # SETUP: remove two nodes in USER workspace When the command RemoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | When the command RemoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "sir-nodeward-nodington-iii" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -241,7 +240,8 @@ Feature: Publishing hide/show scenario of nodes When the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user-test" | - | nodesToPublish | [{"nodeAggregateId": "sir-david-nodenborough", "contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}}] | + | nodesToPublish | [{"nodeAggregateId": "sir-david-nodenborough", "workspaceName": "user-test", "dimensionSpacePoint": {}}] | + | contentStreamIdForRemainingPart | "user-cs-identifier-modified" | And the graph projection is fully up to date When I am in the active content stream of workspace "live" and dimension space point {} @@ -266,13 +266,13 @@ Feature: Publishing hide/show scenario of nodes # SETUP: remove two nodes in USER workspace When the command RemoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | When the command RemoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "sir-nodeward-nodington-iii" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -281,7 +281,7 @@ Feature: Publishing hide/show scenario of nodes When the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user-test" | - | nodesToPublish | [{"nodeAggregateId": "sir-david-nodenborough", "contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}}] | + | nodesToPublish | [{"nodeAggregateId": "sir-david-nodenborough", "workspaceName": "user-test", "dimensionSpacePoint": {}}] | And the graph projection is fully up to date When I am in the active content stream of workspace "live" and dimension space point {} @@ -306,14 +306,14 @@ Feature: Publishing hide/show scenario of nodes # SETUP: set two node references in USER workspace When the command SetNodeReferences is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | sourceNodeAggregateId | "sir-david-nodenborough" | | sourceOriginDimensionSpacePoint | {} | | referenceName | "referenceProperty" | | references | [{"target":"sir-nodeward-nodington-iii"}] | And the command SetNodeReferences is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | sourceNodeAggregateId | "nody-mc-nodeface" | | sourceOriginDimensionSpacePoint | {} | | referenceName | "referenceProperty" | @@ -323,7 +323,7 @@ Feature: Publishing hide/show scenario of nodes When the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user-test" | - | nodesToPublish | [{"nodeAggregateId": "sir-david-nodenborough", "contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}}] | + | nodesToPublish | [{"nodeAggregateId": "sir-david-nodenborough", "workspaceName": "user-test", "dimensionSpacePoint": {}}] | | contentStreamIdForRemainingPart | "user-cs-identifier-modified" | And the graph projection is fully up to date @@ -366,7 +366,7 @@ Feature: Publishing hide/show scenario of nodes # SETUP: set two new nodes in USER workspace When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "new1-agg" | | nodeTypeName | "Neos.ContentRepository.Testing:Content" | | originDimensionSpacePoint | {} | @@ -374,7 +374,7 @@ Feature: Publishing hide/show scenario of nodes | nodeName | "foo" | When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "new2-agg" | | nodeTypeName | "Neos.ContentRepository.Testing:Content" | | originDimensionSpacePoint | {} | @@ -385,7 +385,7 @@ Feature: Publishing hide/show scenario of nodes When the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user-test" | - | nodesToPublish | [{"nodeAggregateId": "new1-agg", "contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}}] | + | nodesToPublish | [{"nodeAggregateId": "new1-agg", "workspaceName": "user-test", "dimensionSpacePoint": {}}] | | contentStreamIdForRemainingPart | "user-cs-identifier-modified" | And the graph projection is fully up to date diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/PublishMovedNodesWithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/05-PublishMovedNodesWithoutDimensions.feature similarity index 93% rename from Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/PublishMovedNodesWithoutDimensions.feature rename to Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/05-PublishMovedNodesWithoutDimensions.feature index bf99d43aceb..9b2018d0cb1 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/NodePublishing/PublishMovedNodesWithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W8-IndividualNodePublication/05-PublishMovedNodesWithoutDimensions.feature @@ -23,9 +23,9 @@ Feature: Publishing moved nodes without dimensions | workspaceName | "live" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -70,7 +70,7 @@ Feature: Publishing moved nodes without dimensions Scenario: Publish the move of a node to the end of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user" | | dimensionSpacePoint | {} | | nodeAggregateId | "sir-david-nodenborough" | | newParentNodeAggregateId | null | @@ -78,7 +78,7 @@ Feature: Publishing moved nodes without dimensions And the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user" | - | nodesToPublish | [{"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-david-nodenborough"}] | + | nodesToPublish | [{"workspaceName": "user", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-david-nodenborough"}] | And the graph projection is fully up to date Then I expect the graph projection to consist of exactly 4 nodes @@ -89,7 +89,7 @@ Feature: Publishing moved nodes without dimensions # node aggregate occupation and coverage is not relevant without dimensions and thus not tested - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-nodeward-nodington-iii" and node path "esquire" to lead to node cs-identifier;sir-nodeward-nodington-iii;{} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no preceding siblings @@ -110,7 +110,7 @@ Feature: Publishing moved nodes without dimensions Scenario: Publish the move of a node before one of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user" | | nodeAggregateId | "sir-nodeward-nodington-iii" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -118,7 +118,7 @@ Feature: Publishing moved nodes without dimensions And the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user" | - | nodesToPublish | [{"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | + | nodesToPublish | [{"workspaceName": "user", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-nodeward-nodington-iii"}] | And the graph projection is fully up to date Then I expect the graph projection to consist of exactly 4 nodes @@ -129,7 +129,7 @@ Feature: Publishing moved nodes without dimensions # node aggregate occupation and coverage is not relevant without dimensions and thus not tested - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} Then I expect node aggregate identifier "sir-nodeward-nodington-iii" and node path "esquire" to lead to node cs-identifier;sir-nodeward-nodington-iii;{} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no preceding siblings @@ -161,14 +161,14 @@ Feature: Publishing moved nodes without dimensions And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user" | | nodeAggregateId | "sir-david-nodenborough" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | And the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user" | - | nodesToPublish | [{"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-david-nodenborough"}] | + | nodesToPublish | [{"workspaceName": "user", "dimensionSpacePoint": {}, "nodeAggregateId": "sir-david-nodenborough"}] | And the graph projection is fully up to date Then I expect the graph projection to consist of exactly 5 nodes @@ -180,7 +180,7 @@ Feature: Publishing moved nodes without dimensions # node aggregate occupation and coverage is not relevant without dimensions and thus not tested - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} And I expect node aggregate identifier "sir-nodeward-nodington-iii" and node path "esquire" to lead to node cs-identifier;sir-nodeward-nodington-iii;{} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no preceding siblings @@ -205,7 +205,7 @@ Feature: Publishing moved nodes without dimensions Scenario: Publish the move of a node to a new parent and before one of its children When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "lady-eleonode-rootford" | @@ -213,7 +213,7 @@ Feature: Publishing moved nodes without dimensions And the command PublishIndividualNodesFromWorkspace is executed with payload: | Key | Value | | workspaceName | "user" | - | nodesToPublish | [{"contentStreamId": "user-cs-identifier", "dimensionSpacePoint": {}, "nodeAggregateId": "nody-mc-nodeface"}] | + | nodesToPublish | [{"workspaceName": "user", "dimensionSpacePoint": {}, "nodeAggregateId": "nody-mc-nodeface"}] | When the graph projection is fully up to date Then I expect the graph projection to consist of exactly 4 nodes @@ -224,7 +224,7 @@ Feature: Publishing moved nodes without dimensions # node aggregate occupation and coverage is not relevant without dimensions and thus not tested - When I am in content stream "cs-identifier" and dimension space point {} + When I am in the active content stream of workspace "live" and dimension space point {} And I expect node aggregate identifier "sir-david-nodenborough" and node path "document" to lead to node cs-identifier;sir-david-nodenborough;{} And I expect this node to be a child of node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have no preceding siblings diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W9-WorkspaceDiscarding/02-DiscardWorkspace.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W9-WorkspaceDiscarding/02-DiscardWorkspace.feature new file mode 100644 index 00000000000..e2095bab136 --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/W9-WorkspaceDiscarding/02-DiscardWorkspace.feature @@ -0,0 +1,163 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Workspace discarding - basic functionality + + This is an END TO END test; testing all layers of the related functionality step by step together + + Basic fixture setup is: + - root workspace with a single "root" node inside; and an additional child node. + - then, a nested workspace is created based on the "root" node + + Background: + Given using no content dimensions + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:Content': + properties: + text: + type: string + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | + | nody-mc-nodeface | Neos.ContentRepository.Testing:Content | lady-eleonode-rootford | child | + + And the command SetNodeProperties is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Original"} | + # we need to ensure that the projections are up to date now; otherwise a content stream is forked with an out- + # of-date base version. This means the content stream can never be merged back, but must always be rebased. + And the graph projection is fully up to date + And the command CreateWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | baseWorkspaceName | "live" | + | newContentStreamId | "user-cs-identifier" | + | workspaceOwner | "owner-identifier" | + And the graph projection is fully up to date + + Scenario: Discarding a full workspace works + When the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified"} | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "user-test" and dimension space point {} + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Modified" | + + # Discarding + When the command DiscardWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | newContentStreamId | "user-cs-identifier-modified" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "user-test" and dimension space point {} + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier-modified;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Original" | + + Scenario: Discarding a full workspace shows the most up-to-date base workspace when the base WS was modified in the meantime + When the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified"} | + And the graph projection is fully up to date + + And the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "live" | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified in live workspace"} | + And the graph projection is fully up to date + + # Discarding + When the command DiscardWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-test" | + | newContentStreamId | "user-cs-identifier-modified" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "user-test" and dimension space point {} + Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier-modified;nody-mc-nodeface;{} + And I expect this node to have the following properties: + | Key | Value | + | text | "Modified in live workspace" | + + Scenario: Conflicting changes lead to OUTDATED_CONFLICT which can be recovered from via discard + + When the command CreateWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-ws-one" | + | baseWorkspaceName | "live" | + | newContentStreamId | "user-cs-one" | + | workspaceOwner | "owner-identifier" | + And the graph projection is fully up to date + And the command CreateWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-ws-two" | + | baseWorkspaceName | "live" | + | newContentStreamId | "user-cs-two" | + | workspaceOwner | "owner-identifier" | + And the graph projection is fully up to date + + When the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | workspaceName | "user-ws-one" | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeVariantSelectionStrategy | "allVariants" | + | coveredDimensionSpacePoint | {} | + And the graph projection is fully up to date + + When the command SetNodeProperties is executed with payload: + | Key | Value | + | workspaceName | "user-ws-two" | + | nodeAggregateId | "nody-mc-nodeface" | + | originDimensionSpacePoint | {} | + | propertyValues | {"text": "Modified"} | + And the graph projection is fully up to date + + And the command PublishWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-ws-one" | + And the graph projection is fully up to date + + Then workspace user-ws-two has status OUTDATED + + When the command RebaseWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-ws-two" | + | rebasedContentStreamId | "user-cs-two-rebased" | + + Then workspace user-ws-two has status OUTDATED_CONFLICT + + When the command DiscardWorkspace is executed with payload: + | Key | Value | + | workspaceName | "user-ws-two" | + | newContentStreamId | "user-cs-two-discarded" | + And the graph projection is fully up to date + + Then workspace user-ws-two has status OUTDATED diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/WorkspaceBasedContentPublishing.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/WorkspaceBasedContentPublishing.feature deleted file mode 100644 index c7bc3d1531d..00000000000 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/WorkspacePublishing/WorkspaceBasedContentPublishing.feature +++ /dev/null @@ -1,322 +0,0 @@ -@contentrepository @adapters=DoctrineDBAL -Feature: Workspace based content publishing - - This is an END TO END test; testing all layers of the related functionality step by step together - - Basic fixture setup is: - - root workspace with a single "root" node inside; and an additional child node. - - then, a nested workspace is created based on the "root" node - - Background: - Given using no content dimensions - And using the following node types: - """yaml - 'Neos.ContentRepository.Testing:Content': - properties: - text: - type: string - """ - And using identifier "default", I define a content repository - And I am in content repository "default" - And the command CreateRootWorkspace is executed with payload: - | Key | Value | - | workspaceName | "live" | - | newContentStreamId | "cs-identifier" | - And the graph projection is fully up to date - And the command CreateRootNodeAggregateWithNode is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "lady-eleonode-rootford" | - | nodeTypeName | "Neos.ContentRepository:Root" | - - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Content" | - | originDimensionSpacePoint | {} | - | coveredDimensionSpacePoints | [{}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "child" | - | nodeAggregateClassification | "regular" | - - And the graph projection is fully up to date - - And the command SetNodeProperties is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | originDimensionSpacePoint | {} | - | propertyValues | {"text": "Original"} | - # we need to ensure that the projections are up to date now; otherwise a content stream is forked with an out- - # of-date base version. This means the content stream can never be merged back, but must always be rebased. - And the graph projection is fully up to date - And the command CreateWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - | baseWorkspaceName | "live" | - | newContentStreamId | "user-cs-identifier" | - | workspaceOwner | "owner-identifier" | - And the graph projection is fully up to date - - Scenario: Basic events are emitted - # LIVE workspace - Then I expect exactly 4 events to be published on stream "ContentStream:cs-identifier" - And event at index 0 is of type "ContentStreamWasCreated" with payload: - | Key | Expected | - | contentStreamId | "cs-identifier" | - - # Event 1 is the root Node Created event (we can skip this here, it is tested somewhere else); Event 2 is the SetProperty - Then I expect exactly 1 event to be published on stream "Workspace:live" - And event at index 0 is of type "RootWorkspaceWasCreated" with payload: - | Key | Expected | - | workspaceName | "live" | - | workspaceTitle | "Live" | - | workspaceDescription | "The workspace \"live\"" | - | newContentStreamId | "cs-identifier" | - - # USER workspace - Then I expect exactly 1 event to be published on stream "ContentStream:user-cs-identifier" - And event at index 0 is of type "ContentStreamWasForked" with payload: - | Key | Expected | - | newContentStreamId | "user-cs-identifier" | - | sourceContentStreamId | "cs-identifier" | - - Then I expect exactly 1 event to be published on stream "Workspace:user-test" - And event at index 0 is of type "WorkspaceWasCreated" with payload: - | Key | Expected | - | workspaceName | "user-test" | - | baseWorkspaceName | "live" | - | workspaceTitle | "User-test" | - | workspaceDescription | "The workspace \"user-test\"" | - | newContentStreamId | "user-cs-identifier" | - | workspaceOwner | "owner-identifier" | - - Scenario: modify the property in the nested workspace and publish afterwards works - When the command SetNodeProperties is executed with payload: - | Key | Value | - | contentStreamId | "user-cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | originDimensionSpacePoint | {} | - | propertyValues | {"text": "Modified"} | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {} - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Original" | - - When I am in the active content stream of workspace "user-test" and dimension space point {} - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Modified" | - - # PUBLISHING - When the command PublishWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {} - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Modified" | - - Scenario: modify the property in the nested workspace, do modification in live workspace; publish afterwards will not work because rebase is missing; then rebase and publish - - When the command SetNodeProperties is executed with payload: - | Key | Value | - | contentStreamId | "user-cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | originDimensionSpacePoint | {} | - | propertyValues | {"text": "Modified in user workspace"} | - And the graph projection is fully up to date - And the command SetNodeProperties is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | originDimensionSpacePoint | {} | - | propertyValues | {"text": "Modified in live workspace"} | - And the graph projection is fully up to date - - # PUBLISHING without rebase: error - When the command PublishWorkspace is executed with payload and exceptions are caught: - | Key | Value | - | workspaceName | "user-test" | - - Then the last command should have thrown an exception of type "BaseWorkspaceHasBeenModifiedInTheMeantime" - - # REBASING + Publishing: works now (TODO soft constraint check for old value) - When the command RebaseWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - And the graph projection is fully up to date - - And the command PublishWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {} - - When I am in the active content stream of workspace "live" and dimension space point {} - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Modified in user workspace" | - - Scenario: modify the property in the nested workspace, publish, modify again and publish again (e.g. a workspace can be re-used after publishing for other changes) - - When the command SetNodeProperties is executed with payload: - | Key | Value | - | contentStreamId | "user-cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | originDimensionSpacePoint | {} | - | propertyValues | {"text": "Modified"} | - - And the graph projection is fully up to date - - # PUBLISHING - And the command PublishWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {} - - When the command SetNodeProperties is executed with payload: - | Key | Value | - | contentStreamId | $this->contentStreamId | - | nodeAggregateId | "nody-mc-nodeface" | - | originDimensionSpacePoint | {} | - | propertyValues | {"text": "Modified anew"} | - - And the graph projection is fully up to date - - # PUBLISHING - And the command PublishWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {} - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Modified anew" | - - Scenario: Discarding a full workspace works - When the command SetNodeProperties is executed with payload: - | Key | Value | - | contentStreamId | "user-cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | originDimensionSpacePoint | {} | - | propertyValues | {"text": "Modified"} | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "user-test" and dimension space point {} - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Modified" | - - # Discarding - When the command DiscardWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - | newContentStreamId | "user-cs-identifier-modified" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "user-test" and dimension space point {} - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier-modified;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Original" | - - Scenario: Discarding a full workspace shows the most up-to-date base workspace when the base WS was modified in the meantime - When the command SetNodeProperties is executed with payload: - | Key | Value | - | contentStreamId | "user-cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | originDimensionSpacePoint | {} | - | propertyValues | {"text": "Modified"} | - And the graph projection is fully up to date - - And the command SetNodeProperties is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | originDimensionSpacePoint | {} | - | propertyValues | {"text": "Modified in live workspace"} | - And the graph projection is fully up to date - - # Discarding - When the command DiscardWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-test" | - | newContentStreamId | "user-cs-identifier-modified" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "user-test" and dimension space point {} - Then I expect node aggregate identifier "nody-mc-nodeface" to lead to node user-cs-identifier-modified;nody-mc-nodeface;{} - And I expect this node to have the following properties: - | Key | Value | - | text | "Modified in live workspace" | - - Scenario: Conflicting changes lead to OUTDATED_CONFLICT which can be recovered from via discard - - When the command CreateWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-ws-one" | - | baseWorkspaceName | "live" | - | newContentStreamId | "user-cs-one" | - | workspaceOwner | "owner-identifier" | - And the graph projection is fully up to date - And the command CreateWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-ws-two" | - | baseWorkspaceName | "live" | - | newContentStreamId | "user-cs-two" | - | workspaceOwner | "owner-identifier" | - And the graph projection is fully up to date - - When the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeVariantSelectionStrategy | "allVariants" | - | coveredDimensionSpacePoint | {} | - | contentStreamId | "user-cs-one" | - And the graph projection is fully up to date - - When the command SetNodeProperties is executed with payload: - | Key | Value | - | contentStreamId | "user-cs-two" | - | nodeAggregateId | "nody-mc-nodeface" | - | originDimensionSpacePoint | {} | - | propertyValues | {"text": "Modified"} | - And the graph projection is fully up to date - - And the command PublishWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-ws-one" | - And the graph projection is fully up to date - - Then workspace user-ws-two has status OUTDATED - - When the command RebaseWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-ws-two" | - | rebasedContentStreamId | "user-cs-two-rebased" | - - Then workspace user-ws-two has status OUTDATED_CONFLICT - - When the command DiscardWorkspace is executed with payload: - | Key | Value | - | workspaceName | "user-ws-two" | - | newContentStreamId | "user-cs-two-discarded" | - And the graph projection is fully up to date - - Then workspace user-ws-two has status OUTDATED - diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/NodeOperationsOnMultipleWorkspaces.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/NodeOperationsOnMultipleWorkspaces.feature index fb90bd09ae5..7e26a903218 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/NodeOperationsOnMultipleWorkspaces.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/NodeOperationsOnMultipleWorkspaces.feature @@ -17,9 +17,9 @@ Feature: Single Node operations on multiple workspaces/content streams; e.g. cop | workspaceName | "live" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -45,7 +45,6 @@ Feature: Single Node operations on multiple workspaces/content streams; e.g. cop And the graph projection is fully up to date And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | originDimensionSpacePoint | {} | | propertyValues | {"text": "Original"} | @@ -60,7 +59,7 @@ Feature: Single Node operations on multiple workspaces/content streams; e.g. cop Scenario: Set property of a node Given the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "user-cs-identifier" | + | workspaceName | "user-test" | | nodeAggregateId | "nody-mc-nodeface" | | originDimensionSpacePoint | {} | | propertyValues | {"text": "Changed"} | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/PruneContentStreams.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/PruneContentStreams.feature index d4dc4aa0924..92dc9d8e919 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/PruneContentStreams.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/PruneContentStreams.feature @@ -14,9 +14,9 @@ Feature: If content streams are not in use anymore by the workspace, they can be | workspaceName | "live" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "root-node" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date @@ -124,4 +124,4 @@ Feature: If content streams are not in use anymore by the workspace, they can be And I prune removed content streams from the event stream # the events should still exist - Then I expect exactly 2 events to be published on stream "ContentStream:review-cs-identifier" + Then I expect exactly 3 events to be published on stream "ContentStream:review-cs-identifier" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/SingleNodeOperationsOnLiveWorkspace.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/SingleNodeOperationsOnLiveWorkspace.feature index c323f850774..1d68654f937 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/SingleNodeOperationsOnLiveWorkspace.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/Workspaces/SingleNodeOperationsOnLiveWorkspace.feature @@ -19,9 +19,9 @@ Feature: Single Node operations on live workspace | workspaceName | "live" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -39,7 +39,6 @@ Feature: Single Node operations on live workspace Scenario: Set property of a node Given the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | originDimensionSpacePoint | {} | | propertyValues | {"text": "Hello"} | @@ -47,7 +46,6 @@ Feature: Single Node operations on live workspace Then I expect exactly 4 events to be published on stream with prefix "ContentStream:cs-identifier" And event at index 3 is of type "NodePropertiesWereSet" with payload: | Key | Expected | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | originDimensionSpacePoint | [] | | propertyValues.text.value | "Hello" | @@ -62,7 +60,6 @@ Feature: Single Node operations on live workspace Scenario: Error on invalid dimension space point Given the command SetNodeProperties is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | originDimensionSpacePoint | {"not": "existing"} | | propertyValues | {"text": "Hello"} | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php b/Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php new file mode 100644 index 00000000000..f6683a671e0 --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php @@ -0,0 +1,262 @@ + [ + 'Neos.ContentRepository:Root' => [], + 'Neos.ContentRepository.Testing:Document' => [ + 'properties' => [ + 'title' => [ + 'type' => 'string' + ] + ] + ] + ], + new DefaultNodeLabelGeneratorFactory() + ); + $this->contentRepositoryRegistry = $this->objectManager->get(ContentRepositoryRegistry::class); + + if (is_file(self::SETUP_IS_RUNNING_FLAG_PATH)) { + $this->awaitFileRemoval(self::SETUP_IS_RUNNING_FLAG_PATH, 60000); // 60s for CR setup + } + if (is_file(self::SETUP_IS_DONE_FLAG_PATH)) { + $this->contentRepository = $this->contentRepositoryRegistry + ->get(ContentRepositoryId::fromString('default')); + return; + } + touch(self::SETUP_IS_RUNNING_FLAG_PATH); + + $contentRepository = $this->setUpContentRepository(ContentRepositoryId::fromString('default')); + + $origin = OriginDimensionSpacePoint::createWithoutDimensions(); + $contentRepository->handle(CreateRootWorkspace::create( + WorkspaceName::forLive(), + new WorkspaceTitle('Live'), + new WorkspaceDescription('The live workspace'), + ContentStreamId::fromString('live-cs-id') + ))->block(); + $contentRepository->handle(CreateRootNodeAggregateWithNode::create( + WorkspaceName::forLive(), + NodeAggregateId::fromString('lady-eleonode-rootford'), + NodeTypeName::fromString(NodeTypeName::ROOT_NODE_TYPE_NAME) + ))->block(); + $contentRepository->handle(CreateNodeAggregateWithNode::create( + WorkspaceName::forLive(), + NodeAggregateId::fromString('nody-mc-nodeface'), + NodeTypeName::fromString('Neos.ContentRepository.Testing:Document'), + $origin, + NodeAggregateId::fromString('lady-eleonode-rootford'), + initialPropertyValues: PropertyValuesToWrite::fromArray([ + 'title' => 'title' + ]) + ))->block(); + $contentRepository->handle(CreateWorkspace::create( + WorkspaceName::fromString('user-test'), + WorkspaceName::forLive(), + new WorkspaceTitle('User'), + new WorkspaceDescription('The user workspace'), + ContentStreamId::fromString('user-cs-id') + ))->block(); + for ($i = 0; $i <= 1000; $i++) { + $contentRepository->handle(CreateNodeAggregateWithNode::create( + WorkspaceName::forLive(), + NodeAggregateId::fromString('nody-mc-nodeface-' . $i), + NodeTypeName::fromString('Neos.ContentRepository.Testing:Document'), + $origin, + NodeAggregateId::fromString('lady-eleonode-rootford'), + initialPropertyValues: PropertyValuesToWrite::fromArray([ + 'title' => 'title' + ]) + ))->block(); + // give the database lock some time to recover + usleep(5000); + } + $this->contentRepository = $contentRepository; + + touch(self::SETUP_IS_DONE_FLAG_PATH); + unlink(self::SETUP_IS_RUNNING_FLAG_PATH); + } + + /** + * @test + * @group parallel + */ + public function whileAWorkspaceIsBeingRebased(): void + { + touch(self::REBASE_IS_RUNNING_FLAG_PATH); + $workspaceName = WorkspaceName::fromString('user-test'); + $exception = null; + try { + $this->contentRepository->handle(RebaseWorkspace::create( + $workspaceName, + )->withRebasedContentStreamId(ContentStreamId::fromString('user-test-rebased')))->block(); + } catch (\RuntimeException $runtimeException) { + $exception = $runtimeException; + } + unlink(self::REBASE_IS_RUNNING_FLAG_PATH); + Assert::assertNull($exception); + } + + /** + * @test + * @group parallel + */ + public function thenConcurrentCommandsLeadToAnException(): void + { + $this->awaitFile(self::REBASE_IS_RUNNING_FLAG_PATH); + // give the CR some time to close the content stream + usleep(10000); + $origin = OriginDimensionSpacePoint::createWithoutDimensions(); + $exceptionIsThrownAsExpected = false; + $actualException = 'none'; + try { + $this->contentRepository->handle(SetNodeProperties::create( + WorkspaceName::fromString('user-test'), + NodeAggregateId::fromString('nody-mc-nodeface'), + $origin, + PropertyValuesToWrite::fromArray([ + 'title' => 'title47b' + ]) + ))->block(); + } catch (\Exception $thrownException) { + $exceptionIsThrownAsExpected + = $thrownException instanceof ContentStreamIsClosed || $thrownException instanceof ConcurrencyException; + $actualException = get_class($thrownException); + } + + unlink(self::SETUP_IS_DONE_FLAG_PATH); + Assert::assertTrue($exceptionIsThrownAsExpected, 'Expected exception of type ' . ContentStreamIsClosed::class + . ' or ' . ConcurrencyException::class . ', ' . $actualException . ' thrown' + ); + } + + private function awaitFile(string $filename): void + { + $waiting = 0; + while (!is_file($filename)) { + usleep(1000); + $waiting++; + clearstatcache(true, $filename); + if ($waiting > 60000) { + throw new \Exception('timeout while waiting on file ' . $filename); + } + } + } + + private function awaitFileRemoval(string $filename, int $maximumCycles = 2000): void + { + $waiting = 0; + while (is_file($filename)) { + usleep(10000); + $waiting++; + clearstatcache(true, $filename); + if ($waiting > $maximumCycles) { + throw new \Exception('timeout while waiting on removal of file ' . $filename); + } + } + } + + protected function getObject(string $className): object + { + return $this->objectManager->get($className); + } + + protected function getContentRepositoryService( + ContentRepositoryServiceFactoryInterface $factory + ): ContentRepositoryServiceInterface { + return $this->contentRepositoryRegistry->buildService( + $this->currentContentRepository->id, + $factory + ); + } + + protected function createContentRepository( + ContentRepositoryId $contentRepositoryId + ): ContentRepository { + $this->contentRepositoryRegistry->resetFactoryInstance($contentRepositoryId); + $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); + GherkinTableNodeBasedContentDimensionSourceFactory::reset(); + GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + + return $contentRepository; + } +} diff --git a/Neos.ContentRepository.Core/Classes/EventStore/EventNormalizer.php b/Neos.ContentRepository.Core/Classes/EventStore/EventNormalizer.php index 38528096279..9a821b57018 100644 --- a/Neos.ContentRepository.Core/Classes/EventStore/EventNormalizer.php +++ b/Neos.ContentRepository.Core/Classes/EventStore/EventNormalizer.php @@ -5,7 +5,9 @@ namespace Neos\ContentRepository\Core\EventStore; use Neos\ContentRepository\Core\ContentRepository; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Event\ContentStreamWasReopened; use Neos\ContentRepository\Core\Feature\ContentStreamCreation\Event\ContentStreamWasCreated; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Event\ContentStreamWasClosed; use Neos\ContentRepository\Core\Feature\ContentStreamForking\Event\ContentStreamWasForked; use Neos\ContentRepository\Core\Feature\ContentStreamRemoval\Event\ContentStreamWasRemoved; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Event\DimensionShineThroughWasAdded; @@ -67,8 +69,10 @@ final class EventNormalizer public function __construct() { $supportedEventClassNames = [ + ContentStreamWasClosed::class, ContentStreamWasCreated::class, ContentStreamWasForked::class, + ContentStreamWasReopened::class, ContentStreamWasRemoved::class, DimensionShineThroughWasAdded::class, DimensionSpacePointWasMoved::class, diff --git a/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php b/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php index ddb45de2859..85a97d011c7 100644 --- a/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php +++ b/Neos.ContentRepository.Core/Classes/Factory/ContentRepositoryFactory.php @@ -137,7 +137,7 @@ private function buildCommandBus(): CommandBus new WorkspaceCommandHandler( $this->buildEventPersister(), $this->projectionFactoryDependencies->eventStore, - $this->projectionFactoryDependencies->eventNormalizer + $this->projectionFactoryDependencies->eventNormalizer, ), new NodeAggregateCommandHandler( $this->projectionFactoryDependencies->nodeTypeManager, diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php index 1e969b531ad..d1b8c877fe7 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php @@ -19,6 +19,8 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; use Neos\ContentRepository\Core\DimensionSpace\Exception\DimensionSpacePointNotFound; use Neos\ContentRepository\Core\NodeType\ConstraintCheck; +use Neos\ContentRepository\Core\Projection\ContentStream\ContentStreamFinder; +use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamIsClosed; use Neos\ContentRepository\Core\SharedModel\Exception\RootNodeAggregateDoesNotExist; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet; use Neos\ContentRepository\Core\SharedModel\Exception\DimensionSpacePointIsNotYetOccupied; @@ -55,6 +57,9 @@ use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamState; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; +use Neos\EventStore\Model\EventStream\ExpectedVersion; /** * @internal implementation details of command handlers @@ -66,19 +71,28 @@ abstract protected function getNodeTypeManager(): NodeTypeManager; abstract protected function getAllowedDimensionSubspace(): DimensionSpacePointSet; /** - * @param ContentStreamId $contentStreamId * @throws ContentStreamDoesNotExistYet */ - protected function requireContentStreamToExist( - ContentStreamId $contentStreamId, + protected function requireContentStream( + WorkspaceName $workspaceName, ContentRepository $contentRepository - ): void { - if (!$contentRepository->getContentStreamFinder()->hasContentStream($contentStreamId)) { + ): ContentStreamId { + $contentStreamId = ContentStreamIdOverride::$contentStreamIdToUse + ?: $contentRepository->getWorkspaceFinder()->findOneByName($workspaceName)?->currentContentStreamId; + if (!$contentStreamId || !$contentRepository->getContentStreamFinder()->hasContentStream($contentStreamId)) { throw new ContentStreamDoesNotExistYet( - 'Content stream "' . $contentStreamId->value . '" does not exist yet.', + 'Content stream "' . $contentStreamId?->value . '" does not exist yet.', 1521386692 ); } + if ($contentRepository->getContentStreamFinder()->findStateForContentStream($contentStreamId) === ContentStreamState::STATE_CLOSED) { + throw new ContentStreamIsClosed( + 'Content stream "' . $contentStreamId->value . '" is closed.', + 1710260081 + ); + } + + return $contentStreamId; } /** @@ -664,4 +678,15 @@ protected function validateReferenceProperties( } } } + + protected function getExpectedVersionOfContentStream( + ContentStreamId $contentStreamId, + ContentRepository $contentRepository + ): ExpectedVersion { + return ExpectedVersion::fromVersion( + $contentRepository->getContentStreamFinder() + ->findVersionForContentStream($contentStreamId) + ->unwrap() + ); + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/ContentStreamIdOverride.php b/Neos.ContentRepository.Core/Classes/Feature/Common/ContentStreamIdOverride.php new file mode 100644 index 00000000000..434ca8e2c63 --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/ContentStreamIdOverride.php @@ -0,0 +1,36 @@ +jsonSerialize(); - if (!isset($commandPayload['contentStreamId'])) { + if (!isset($commandPayload['contentStreamId']) && !isset($commandPayload['workspaceName'])) { throw new \RuntimeException(sprintf( - 'TODO: Command %s does not have a property "contentStreamId" (which is required).', + 'TODO: Command %s does not have a property "contentStreamId" or "workspaceName" (which is required).', get_class($command) )); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherContentStreamsInterface.php b/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php similarity index 78% rename from Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherContentStreamsInterface.php rename to Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php index 0636ae5fc72..ecba09c7d60 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherContentStreamsInterface.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/RebasableToOtherWorkspaceInterface.php @@ -16,6 +16,7 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * This interface is implemented by **commands** which can be rebased to other Content Streams. This is basically all @@ -25,9 +26,12 @@ * * @internal used internally for the rebasing mechanism of content streams */ -interface RebasableToOtherContentStreamsInterface +interface RebasableToOtherWorkspaceInterface { - public function createCopyForContentStream(ContentStreamId $target): CommandInterface; + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): CommandInterface; /** * called during deserialization from metadata diff --git a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Command/CloseContentStream.php b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Command/CloseContentStream.php new file mode 100644 index 00000000000..f0143c9d3fe --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Command/CloseContentStream.php @@ -0,0 +1,51 @@ + $array + * @internal only used for testcases + */ + public static function fromArray(array $array): self + { + return new self( + ContentStreamId::fromString($array['contentStreamId']), + ); + } +} diff --git a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Command/ReopenContentStream.php b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Command/ReopenContentStream.php new file mode 100644 index 00000000000..7f7fab54218 --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Command/ReopenContentStream.php @@ -0,0 +1,61 @@ + $array + * @internal only used for testcases + */ + public static function fromArray(array $array): self + { + return new self( + ContentStreamId::fromString($array['contentStreamId']), + ContentStreamState::from($array['previousState']), + ); + } +} diff --git a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Event/ContentStreamWasClosed.php b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Event/ContentStreamWasClosed.php new file mode 100644 index 00000000000..434c96b1682 --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Event/ContentStreamWasClosed.php @@ -0,0 +1,43 @@ + $this->contentStreamId, + ]; + } +} diff --git a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Event/ContentStreamWasReopened.php b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Event/ContentStreamWasReopened.php new file mode 100644 index 00000000000..bd772de5f6a --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamClosing/Event/ContentStreamWasReopened.php @@ -0,0 +1,47 @@ + $this->contentStreamId, + 'previousState' => $this->previousState, + ]; + } +} diff --git a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCommandHandler.php index 51634eac3ba..6fc061d841d 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCommandHandler.php @@ -19,12 +19,21 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\EventStore\Events; use Neos\ContentRepository\Core\EventStore\EventsToPublish; +use Neos\ContentRepository\Core\Feature\Common\ConstraintChecks; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Command\ReopenContentStream; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Event\ContentStreamWasReopened; use Neos\ContentRepository\Core\Feature\ContentStreamCreation\Command\CreateContentStream; use Neos\ContentRepository\Core\Feature\ContentStreamCreation\Event\ContentStreamWasCreated; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Command\CloseContentStream; use Neos\ContentRepository\Core\Feature\ContentStreamForking\Command\ForkContentStream; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Event\ContentStreamWasClosed; use Neos\ContentRepository\Core\Feature\ContentStreamForking\Event\ContentStreamWasForked; use Neos\ContentRepository\Core\Feature\ContentStreamRemoval\Command\RemoveContentStream; use Neos\ContentRepository\Core\Feature\ContentStreamRemoval\Event\ContentStreamWasRemoved; +use Neos\ContentRepository\Core\Projection\ContentStream\ContentStreamFinder; +use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamIsClosed; +use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamIsNotClosed; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamState; use Neos\EventStore\Model\EventStream\ExpectedVersion; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamAlreadyExists; @@ -44,11 +53,13 @@ public function canHandle(CommandInterface $command): bool public function handle(CommandInterface $command, ContentRepository $contentRepository): EventsToPublish { - /** @phpstan-ignore-next-line */ return match ($command::class) { CreateContentStream::class => $this->handleCreateContentStream($command, $contentRepository), + CloseContentStream::class => $this->handleCloseContentStream($command, $contentRepository), + ReopenContentStream::class => $this->handleReopenContentStream($command, $contentRepository), ForkContentStream::class => $this->handleForkContentStream($command, $contentRepository), RemoveContentStream::class => $this->handleRemoveContentStream($command, $contentRepository), + default => throw new \DomainException('Cannot handle commands of class ' . get_class($command), 1710408206), }; } @@ -74,6 +85,47 @@ private function handleCreateContentStream( ); } + private function handleCloseContentStream( + CloseContentStream $command, + ContentRepository $contentRepository + ): EventsToPublish { + $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($command->contentStreamId, $contentRepository); + $this->requireContentStreamToNotBeClosed($command->contentStreamId, $contentRepository); + $streamName = ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId)->getEventStreamName(); + + return new EventsToPublish( + $streamName, + Events::with( + new ContentStreamWasClosed( + $command->contentStreamId, + ), + ), + $expectedVersion + ); + } + + private function handleReopenContentStream( + ReopenContentStream $command, + ContentRepository $contentRepository + ): EventsToPublish { + $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($command->contentStreamId, $contentRepository); + $this->requireContentStreamToBeClosed($command->contentStreamId, $contentRepository); + $streamName = ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId)->getEventStreamName(); + + return new EventsToPublish( + $streamName, + Events::with( + new ContentStreamWasReopened( + $command->contentStreamId, + $command->previousState, + ), + ), + $expectedVersion + ); + } + /** * @throws ContentStreamAlreadyExists * @throws ContentStreamDoesNotExistYet @@ -83,6 +135,7 @@ private function handleForkContentStream( ContentRepository $contentRepository ): EventsToPublish { $this->requireContentStreamToExist($command->sourceContentStreamId, $contentRepository); + $this->requireContentStreamToNotBeClosed($command->sourceContentStreamId, $contentRepository); $this->requireContentStreamToNotExistYet($command->newContentStreamId, $contentRepository); $sourceContentStreamVersion = $contentRepository->getContentStreamFinder() @@ -110,6 +163,7 @@ private function handleRemoveContentStream( ContentRepository $contentRepository ): EventsToPublish { $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($command->contentStreamId, $contentRepository); $streamName = ContentStreamEventStreamName::fromContentStreamId( $command->contentStreamId @@ -122,7 +176,7 @@ private function handleRemoveContentStream( $command->contentStreamId, ), ), - ExpectedVersion::ANY() + $expectedVersion ); } @@ -157,4 +211,39 @@ protected function requireContentStreamToExist( ); } } + + protected function requireContentStreamToNotBeClosed( + ContentStreamId $contentStreamId, + ContentRepository $contentRepository + ): void { + if ($contentRepository->getContentStreamFinder()->findStateForContentStream($contentStreamId) === ContentStreamState::STATE_CLOSED) { + throw new ContentStreamIsClosed( + 'Content stream "' . $contentStreamId->value . '" is closed.', + 1710260081 + ); + } + } + + protected function requireContentStreamToBeClosed( + ContentStreamId $contentStreamId, + ContentRepository $contentRepository + ): void { + if ($contentRepository->getContentStreamFinder()->findStateForContentStream($contentStreamId) !== ContentStreamState::STATE_CLOSED) { + throw new ContentStreamIsNotClosed( + 'Content stream "' . $contentStreamId->value . '" is not closed.', + 1710405911 + ); + } + } + + protected function getExpectedVersionOfContentStream( + ContentStreamId $contentStreamId, + ContentRepository $contentRepository + ): ExpectedVersion { + return ExpectedVersion::fromVersion( + $contentRepository->getContentStreamFinder() + ->findVersionForContentStream($contentStreamId) + ->unwrap() + ); + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCreation/Command/CreateContentStream.php b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCreation/Command/CreateContentStream.php index aeeee0aba79..e3ef05736df 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCreation/Command/CreateContentStream.php +++ b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamCreation/Command/CreateContentStream.php @@ -23,13 +23,13 @@ * * @api commands are the write-API of the ContentRepository */ -final class CreateContentStream implements CommandInterface +final readonly class CreateContentStream implements CommandInterface { /** * @param ContentStreamId $contentStreamId The id of the content stream to create */ private function __construct( - public readonly ContentStreamId $contentStreamId, + public ContentStreamId $contentStreamId, ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamForking/Command/ForkContentStream.php b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamForking/Command/ForkContentStream.php index d8d104a26ff..d049c6a01d3 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamForking/Command/ForkContentStream.php +++ b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamForking/Command/ForkContentStream.php @@ -22,15 +22,15 @@ * * @api commands are the write-API of the ContentRepository */ -final class ForkContentStream implements CommandInterface +final readonly class ForkContentStream implements CommandInterface { /** * @param ContentStreamId $newContentStreamId The id of the new content stream * @param ContentStreamId $sourceContentStreamId The id of the content stream to fork */ private function __construct( - public readonly ContentStreamId $newContentStreamId, - public readonly ContentStreamId $sourceContentStreamId, + public ContentStreamId $newContentStreamId, + public ContentStreamId $sourceContentStreamId, ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamRemoval/Command/RemoveContentStream.php b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamRemoval/Command/RemoveContentStream.php index 42f8c179600..45b2512c34e 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/ContentStreamRemoval/Command/RemoveContentStream.php +++ b/Neos.ContentRepository.Core/Classes/Feature/ContentStreamRemoval/Command/RemoveContentStream.php @@ -22,13 +22,13 @@ * * @api commands are the write-API of the ContentRepository */ -final class RemoveContentStream implements CommandInterface +final readonly class RemoveContentStream implements CommandInterface { /** * @param ContentStreamId $contentStreamId The id of the content stream to remove */ private function __construct( - public readonly ContentStreamId $contentStreamId, + public ContentStreamId $contentStreamId, ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php index 78097c5cdbe..fad58e92820 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php +++ b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/AddDimensionShineThrough.php @@ -16,8 +16,9 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Add a Dimension Space Point Shine-Through; @@ -32,20 +33,22 @@ * * @api commands are the write-API of the ContentRepository */ -final class AddDimensionShineThrough implements +final readonly class AddDimensionShineThrough implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The id of the content stream to perform the operation in + * @param ContentStreamId $contentStreamId The id of the content stream to perform the operation in. + * This content stream is specifically created for this operation and thus not prone to conflicts, + * thus we don't need the workspace name * @param DimensionSpacePoint $source source dimension space point * @param DimensionSpacePoint $target target dimension space point */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly DimensionSpacePoint $source, - public readonly DimensionSpacePoint $target + public ContentStreamId $contentStreamId, + public DimensionSpacePoint $source, + public DimensionSpacePoint $target ) { } @@ -71,24 +74,20 @@ public static function fromArray(array $array): self ); } - /** - * @return array - */ - public function jsonSerialize(): array - { - return [ - 'contentStreamId' => $this->contentStreamId, - 'source' => $this->source, - 'target' => $this->target, - ]; - } - - public function createCopyForContentStream(ContentStreamId $target): self + public function createCopyForWorkspace(WorkspaceName $targetWorkspaceName, ContentStreamId $targetContentStreamId): self { return new self( - $target, + $targetContentStreamId, $this->source, $this->target ); } + + /** + * @return array + */ + public function jsonSerialize(): array + { + return get_object_vars($this); + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php index 1cad2b90c64..0efcb7e929c 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php +++ b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Command/MoveDimensionSpacePoint.php @@ -16,8 +16,9 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Move a dimension space point to a new location; basically moving all content to the new dimension space point. @@ -28,20 +29,22 @@ * * @api commands are the write-API of the ContentRepository */ -final class MoveDimensionSpacePoint implements +final readonly class MoveDimensionSpacePoint implements \JsonSerializable, CommandInterface, - RebasableToOtherContentStreamsInterface + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The id of the content stream to perform the operation in + * @param ContentStreamId $contentStreamId The id of the content stream to perform the operation in. + * This content stream is specifically created for this operation and thus not prone to conflicts, + * thus we don't need the workspace name * @param DimensionSpacePoint $source source dimension space point * @param DimensionSpacePoint $target target dimension space point */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly DimensionSpacePoint $source, - public readonly DimensionSpacePoint $target + public ContentStreamId $contentStreamId, + public DimensionSpacePoint $source, + public DimensionSpacePoint $target ) { } @@ -67,24 +70,22 @@ public static function fromArray(array $array): self ); } + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { + return new self( + $targetContentStreamId, + $this->source, + $this->target + ); + } + /** * @return array */ public function jsonSerialize(): array { - return [ - 'contentStreamId' => $this->contentStreamId, - 'source' => $this->source, - 'target' => $this->target, - ]; - } - - public function createCopyForContentStream(ContentStreamId $target): self - { - return new self( - $target, - $this->source, - $this->target - ); + return get_object_vars($this); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php index a6296468248..0dff29c8909 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/DimensionSpaceCommandHandler.php @@ -29,23 +29,23 @@ use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Command\MoveDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Event\DimensionShineThroughWasAdded; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Event\DimensionSpacePointWasMoved; +use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Exception\DimensionSpacePointAlreadyExists; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphInterface; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\EventStore\Model\EventStream\ExpectedVersion; /** - * ContentStreamCommandHandler - * * @internal from userland, you'll use ContentRepository::handle to dispatch commands */ -final class DimensionSpaceCommandHandler implements CommandHandlerInterface +final readonly class DimensionSpaceCommandHandler implements CommandHandlerInterface { public function __construct( - private readonly ContentDimensionZookeeper $contentDimensionZookeeper, - private readonly InterDimensionalVariationGraph $interDimensionalVariationGraph, + private ContentDimensionZookeeper $contentDimensionZookeeper, + private InterDimensionalVariationGraph $interDimensionalVariationGraph, ) { } @@ -67,6 +67,7 @@ private function handleMoveDimensionSpacePoint( MoveDimensionSpacePoint $command, ContentRepository $contentRepository ): EventsToPublish { + $this->requireContentStream($command->contentStreamId, $contentRepository); $streamName = ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId) ->getEventStreamName(); @@ -94,6 +95,7 @@ private function handleAddDimensionShineThrough( AddDimensionShineThrough $command, ContentRepository $contentRepository ): EventsToPublish { + $this->requireContentStream($command->contentStreamId, $contentRepository); $streamName = ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId) ->getEventStreamName(); @@ -162,4 +164,38 @@ private function requireDimensionSpacePointToBeSpecialization( throw DimensionSpacePointIsNoSpecialization::butWasSupposedToBe($target, $source); } } + + /** + * @throws ContentStreamDoesNotExistYet + */ + protected function requireContentStreamForWorkspaceName( + WorkspaceName $workspaceName, + ContentRepository $contentRepository + ): ContentStreamId { + $contentStreamId = $contentRepository->getWorkspaceFinder()->findOneByName($workspaceName) + ?->currentContentStreamId; + if (!$contentStreamId || !$contentRepository->getContentStreamFinder()->hasContentStream($contentStreamId)) { + throw new ContentStreamDoesNotExistYet( + 'Content stream "' . $contentStreamId?->value . '" does not exist yet.', + 1521386692 + ); + } + + return $contentStreamId; + } + + /** + * @throws ContentStreamDoesNotExistYet + */ + protected function requireContentStream( + ContentStreamId $contentStreamId, + ContentRepository $contentRepository + ): void { + if (!$contentRepository->getContentStreamFinder()->hasContentStream($contentStreamId)) { + throw new ContentStreamDoesNotExistYet( + 'Content stream "' . $contentStreamId->value . '" does not exist yet.', + 1521386692 + ); + } + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Event/DimensionShineThroughWasAdded.php b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Event/DimensionShineThroughWasAdded.php index dbf2a9d76d0..3a20d9aea47 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Event/DimensionShineThroughWasAdded.php +++ b/Neos.ContentRepository.Core/Classes/Feature/DimensionSpaceAdjustment/Event/DimensionShineThroughWasAdded.php @@ -32,12 +32,12 @@ * * @api events are the persistence-API of the content repository */ -final class DimensionShineThroughWasAdded implements EventInterface, PublishableToOtherContentStreamsInterface +final readonly class DimensionShineThroughWasAdded implements EventInterface, PublishableToOtherContentStreamsInterface { public function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly DimensionSpacePoint $source, - public readonly DimensionSpacePoint $target + public ContentStreamId $contentStreamId, + public DimensionSpacePoint $source, + public DimensionSpacePoint $target ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php index fe125c03c8d..0a113a2f087 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNode.php @@ -22,7 +22,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Creates a new node aggregate with a new node. @@ -32,10 +32,10 @@ * * @api commands are the write-API of the ContentRepository */ -final class CreateNodeAggregateWithNode implements CommandInterface +final readonly class CreateNodeAggregateWithNode implements CommandInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the create operation is to be performed * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to create * @param NodeTypeName $nodeTypeName Name of the node type of the new node * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. @@ -46,20 +46,20 @@ final class CreateNodeAggregateWithNode implements CommandInterface * @param NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds Predefined aggregate ids of tethered child nodes per path. For any tethered node that has no matching entry in this set, the node aggregate id is generated randomly. Since tethered nodes may have tethered child nodes themselves, this works for multiple levels ({@see self::withTetheredDescendantNodeAggregateIds()}) */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId, - public readonly NodeTypeName $nodeTypeName, - public readonly OriginDimensionSpacePoint $originDimensionSpacePoint, - public readonly NodeAggregateId $parentNodeAggregateId, - public readonly PropertyValuesToWrite $initialPropertyValues, - public readonly ?NodeAggregateId $succeedingSiblingNodeAggregateId, - public readonly ?NodeName $nodeName, - public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds, + public WorkspaceName $workspaceName, + public NodeAggregateId $nodeAggregateId, + public NodeTypeName $nodeTypeName, + public OriginDimensionSpacePoint $originDimensionSpacePoint, + public NodeAggregateId $parentNodeAggregateId, + public PropertyValuesToWrite $initialPropertyValues, + public ?NodeAggregateId $succeedingSiblingNodeAggregateId, + public ?NodeName $nodeName, + public NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds, ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the create operation is to be performed * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to create * @param NodeTypeName $nodeTypeName Name of the node type of the new node * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. @@ -68,15 +68,15 @@ private function __construct( * @param NodeName|null $nodeName The node's optional name. Set if there is a meaningful relation to its parent that should be named. * @param PropertyValuesToWrite|null $initialPropertyValues The node's initial property values. Will be merged over the node type's default property values */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateId $parentNodeAggregateId, ?NodeAggregateId $succeedingSiblingNodeAggregateId = null, ?NodeName $nodeName = null, ?PropertyValuesToWrite $initialPropertyValues = null): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateId $parentNodeAggregateId, ?NodeAggregateId $succeedingSiblingNodeAggregateId = null, ?NodeName $nodeName = null, ?PropertyValuesToWrite $initialPropertyValues = null): self { - return new self($contentStreamId, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, $parentNodeAggregateId, $initialPropertyValues ?: PropertyValuesToWrite::createEmpty(), $succeedingSiblingNodeAggregateId, $nodeName, NodeAggregateIdsByNodePaths::createEmpty()); + return new self($workspaceName, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, $parentNodeAggregateId, $initialPropertyValues ?: PropertyValuesToWrite::createEmpty(), $succeedingSiblingNodeAggregateId, $nodeName, NodeAggregateIdsByNodePaths::createEmpty()); } public function withInitialPropertyValues(PropertyValuesToWrite $newInitialPropertyValues): self { return new self( - $this->contentStreamId, + $this->workspaceName, $this->nodeAggregateId, $this->nodeTypeName, $this->originDimensionSpacePoint, @@ -119,7 +119,7 @@ public function withInitialPropertyValues(PropertyValuesToWrite $newInitialPrope public function withTetheredDescendantNodeAggregateIds(NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds): self { return new self( - $this->contentStreamId, + $this->workspaceName, $this->nodeAggregateId, $this->nodeTypeName, $this->originDimensionSpacePoint, diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php index dadbd5f3e15..c034138a44e 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/Command/CreateNodeAggregateWithNodeAndSerializedProperties.php @@ -17,7 +17,7 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\NodeCreation\Dto\NodeAggregateIdsByNodePaths; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; @@ -25,6 +25,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * The properties of {@see CreateNodeAggregateWithNode} are directly serialized; and then this command @@ -32,14 +33,14 @@ * * @internal implementation detail, use {@see CreateNodeAggregateWithNode} instead. */ -final class CreateNodeAggregateWithNodeAndSerializedProperties implements +final readonly class CreateNodeAggregateWithNodeAndSerializedProperties implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface, - MatchableWithNodeIdToPublishOrDiscardInterface + MatchableWithNodeIdToPublishOrDiscardInterface, + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the create operation is to be performed * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to create * @param NodeTypeName $nodeTypeName Name of the node type of the new node * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. @@ -50,20 +51,20 @@ final class CreateNodeAggregateWithNodeAndSerializedProperties implements * @param NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds Predefined aggregate ids of tethered child nodes per path. For any tethered node that has no matching entry in this set, the node aggregate id is generated randomly. Since tethered nodes may have tethered child nodes themselves, this works for multiple levels ({@see self::withTetheredDescendantNodeAggregateIds()}) */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId, - public readonly NodeTypeName $nodeTypeName, - public readonly OriginDimensionSpacePoint $originDimensionSpacePoint, - public readonly NodeAggregateId $parentNodeAggregateId, - public readonly SerializedPropertyValues $initialPropertyValues, - public readonly ?NodeAggregateId $succeedingSiblingNodeAggregateId, - public readonly ?NodeName $nodeName, - public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds + public WorkspaceName $workspaceName, + public NodeAggregateId $nodeAggregateId, + public NodeTypeName $nodeTypeName, + public OriginDimensionSpacePoint $originDimensionSpacePoint, + public NodeAggregateId $parentNodeAggregateId, + public SerializedPropertyValues $initialPropertyValues, + public ?NodeAggregateId $succeedingSiblingNodeAggregateId, + public ?NodeName $nodeName, + public NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the create operation is to be performed * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to create * @param NodeTypeName $nodeTypeName Name of the node type of the new node * @param OriginDimensionSpacePoint $originDimensionSpacePoint Origin of the new node in the dimension space. Will also be used to calculate a set of dimension points where the new node will cover from the configured specializations. @@ -72,9 +73,9 @@ private function __construct( * @param NodeName|null $nodeName The node's optional name. Set if there is a meaningful relation to its parent that should be named. * @param SerializedPropertyValues|null $initialPropertyValues The node's initial property values (serialized). Will be merged over the node type's default property values */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateId $parentNodeAggregateId, NodeAggregateId $succeedingSiblingNodeAggregateId = null, NodeName $nodeName = null, SerializedPropertyValues $initialPropertyValues = null): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName, OriginDimensionSpacePoint $originDimensionSpacePoint, NodeAggregateId $parentNodeAggregateId, NodeAggregateId $succeedingSiblingNodeAggregateId = null, NodeName $nodeName = null, SerializedPropertyValues $initialPropertyValues = null): self { - return new self($contentStreamId, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, $parentNodeAggregateId, $initialPropertyValues ?? SerializedPropertyValues::createEmpty(), $succeedingSiblingNodeAggregateId, $nodeName, NodeAggregateIdsByNodePaths::createEmpty()); + return new self($workspaceName, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, $parentNodeAggregateId, $initialPropertyValues ?? SerializedPropertyValues::createEmpty(), $succeedingSiblingNodeAggregateId, $nodeName, NodeAggregateIdsByNodePaths::createEmpty()); } /** @@ -83,7 +84,7 @@ public static function create(ContentStreamId $contentStreamId, NodeAggregateId public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeAggregateId::fromString($array['nodeAggregateId']), NodeTypeName::fromString($array['nodeTypeName']), OriginDimensionSpacePoint::fromArray($array['originDimensionSpacePoint']), @@ -114,7 +115,7 @@ public function withTetheredDescendantNodeAggregateIds( NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds ): self { return new self( - $this->contentStreamId, + $this->workspaceName, $this->nodeAggregateId, $this->nodeTypeName, $this->originDimensionSpacePoint, @@ -134,10 +135,21 @@ public function jsonSerialize(): array return get_object_vars($this); } - public function createCopyForContentStream(ContentStreamId $target): self + public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { + return ( + $this->workspaceName === $nodeIdToPublish->workspaceName + && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) + && $this->originDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint) + ); + } + + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { return new self( - $target, + $targetWorkspaceName, $this->nodeAggregateId, $this->nodeTypeName, $this->originDimensionSpacePoint, @@ -148,13 +160,4 @@ public function createCopyForContentStream(ContentStreamId $target): self $this->tetheredDescendantNodeAggregateIds ); } - - public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool - { - return ( - $this->contentStreamId === $nodeIdToPublish->contentStreamId - && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) - && $this->originDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint) - ); - } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/NodeCreation.php b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/NodeCreation.php index 2609c3b41ae..84afd869e5c 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/NodeCreation.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeCreation/NodeCreation.php @@ -41,6 +41,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Node\PropertyName; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\EventStore\Model\EventStream\ExpectedVersion; /** @@ -72,7 +73,7 @@ private function handleCreateNodeAggregateWithNode( $this->validateProperties($command->initialPropertyValues, $command->nodeTypeName); $lowLevelCommand = CreateNodeAggregateWithNodeAndSerializedProperties::create( - $command->contentStreamId, + $command->workspaceName, $command->nodeAggregateId, $command->nodeTypeName, $command->originDimensionSpacePoint, @@ -128,7 +129,8 @@ private function handleCreateNodeAggregateWithNodeAndSerializedProperties( CreateNodeAggregateWithNodeAndSerializedProperties $command, ContentRepository $contentRepository ): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $this->requireDimensionSpacePointToExist($command->originDimensionSpacePoint->toDimensionSpacePoint()); $nodeType = $this->requireNodeType($command->nodeTypeName); $this->requireNodeTypeToNotBeAbstract($nodeType); @@ -137,7 +139,7 @@ private function handleCreateNodeAggregateWithNodeAndSerializedProperties( $this->requireTetheredDescendantNodeTypesToNotBeOfTypeRoot($nodeType); if ($this->areAncestorNodeTypeConstraintChecksEnabled()) { $this->requireConstraintsImposedByAncestorsAreMet( - $command->contentStreamId, + $contentStreamId, $nodeType, $command->nodeName, [$command->parentNodeAggregateId], @@ -145,18 +147,18 @@ private function handleCreateNodeAggregateWithNodeAndSerializedProperties( ); } $this->requireProjectedNodeAggregateToNotExist( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); $parentNodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->parentNodeAggregateId, $contentRepository ); if ($command->succeedingSiblingNodeAggregateId) { $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->succeedingSiblingNodeAggregateId, $contentRepository ); @@ -173,7 +175,7 @@ private function handleCreateNodeAggregateWithNodeAndSerializedProperties( ); if ($command->nodeName) { $this->requireNodeNameToBeUnoccupied( - $command->contentStreamId, + $contentStreamId, $command->nodeName, $command->parentNodeAggregateId, $command->originDimensionSpacePoint, @@ -193,7 +195,7 @@ private function handleCreateNodeAggregateWithNodeAndSerializedProperties( $descendantNodeAggregateIds->getNodeAggregateIds() as $descendantNodeAggregateId ) { $this->requireProjectedNodeAggregateToNotExist( - $command->contentStreamId, + $contentStreamId, $descendantNodeAggregateId, $contentRepository ); @@ -205,6 +207,7 @@ private function handleCreateNodeAggregateWithNodeAndSerializedProperties( $events = [ $this->createRegularWithNode( $command, + $contentStreamId, $coveredDimensionSpacePoints, $initialPropertyValues ) @@ -212,6 +215,7 @@ private function handleCreateNodeAggregateWithNodeAndSerializedProperties( array_push($events, ...iterator_to_array($this->handleTetheredChildNodes( $command, + $contentStreamId, $nodeType, $coveredDimensionSpacePoints, $command->nodeAggregateId, @@ -221,20 +225,21 @@ private function handleCreateNodeAggregateWithNodeAndSerializedProperties( ))); return new EventsToPublish( - ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId) + ContentStreamEventStreamName::fromContentStreamId($contentStreamId) ->getEventStreamName(), NodeAggregateEventPublisher::enrichWithCommand($command, Events::fromArray($events)), - ExpectedVersion::ANY() + $expectedVersion ); } private function createRegularWithNode( CreateNodeAggregateWithNodeAndSerializedProperties $command, + ContentStreamId $contentStreamId, DimensionSpacePointSet $coveredDimensionSpacePoints, SerializedPropertyValues $initialPropertyValues ): NodeAggregateWithNodeWasCreated { return new NodeAggregateWithNodeWasCreated( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $command->nodeTypeName, $command->originDimensionSpacePoint, @@ -253,6 +258,7 @@ private function createRegularWithNode( */ private function handleTetheredChildNodes( CreateNodeAggregateWithNodeAndSerializedProperties $command, + ContentStreamId $contentStreamId, NodeType $nodeType, DimensionSpacePointSet $coveredDimensionSpacePoints, NodeAggregateId $parentNodeAggregateId, @@ -271,9 +277,9 @@ private function handleTetheredChildNodes( ?? NodeAggregateId::create(); $initialPropertyValues = SerializedPropertyValues::defaultFromNodeType($childNodeType, $this->getPropertyConverter()); - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); $events[] = $this->createTetheredWithNode( $command, + $contentStreamId, $childNodeAggregateId, $childNodeType->name, $coveredDimensionSpacePoints, @@ -284,6 +290,7 @@ private function handleTetheredChildNodes( array_push($events, ...iterator_to_array($this->handleTetheredChildNodes( $command, + $contentStreamId, $childNodeType, $coveredDimensionSpacePoints, $childNodeAggregateId, @@ -298,6 +305,7 @@ private function handleTetheredChildNodes( private function createTetheredWithNode( CreateNodeAggregateWithNodeAndSerializedProperties $command, + ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName, DimensionSpacePointSet $coveredDimensionSpacePoints, @@ -307,7 +315,7 @@ private function createTetheredWithNode( NodeAggregateId $precedingNodeAggregateId = null ): NodeAggregateWithNodeWasCreated { return new NodeAggregateWithNodeWasCreated( - $command->contentStreamId, + $contentStreamId, $nodeAggregateId, $nodeTypeName, $command->originDimensionSpacePoint, diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php b/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php index 1d65963c489..290aa189569 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/DisableNodeAggregate.php @@ -17,46 +17,47 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Disable the given node aggregate in the given content stream in a dimension space point using a given strategy * * @api commands are the write-API of the ContentRepository */ -final class DisableNodeAggregate implements +final readonly class DisableNodeAggregate implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface, - MatchableWithNodeIdToPublishOrDiscardInterface + MatchableWithNodeIdToPublishOrDiscardInterface, + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the disable operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the disable operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to disable * @param DimensionSpacePoint $coveredDimensionSpacePoint The covered dimension space point of the node aggregate in which the user intends to disable it * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be disabled */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId, - public readonly DimensionSpacePoint $coveredDimensionSpacePoint, - public readonly NodeVariantSelectionStrategy $nodeVariantSelectionStrategy, + public WorkspaceName $workspaceName, + public NodeAggregateId $nodeAggregateId, + public DimensionSpacePoint $coveredDimensionSpacePoint, + public NodeVariantSelectionStrategy $nodeVariantSelectionStrategy, ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the disable operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the disable operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to disable * @param DimensionSpacePoint $coveredDimensionSpacePoint The covered dimension space point of the node aggregate in which the user intends to disable it * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be disabled */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, DimensionSpacePoint $coveredDimensionSpacePoint, NodeVariantSelectionStrategy $nodeVariantSelectionStrategy): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, DimensionSpacePoint $coveredDimensionSpacePoint, NodeVariantSelectionStrategy $nodeVariantSelectionStrategy): self { - return new self($contentStreamId, $nodeAggregateId, $coveredDimensionSpacePoint, $nodeVariantSelectionStrategy); + return new self($workspaceName, $nodeAggregateId, $coveredDimensionSpacePoint, $nodeVariantSelectionStrategy); } /** @@ -65,7 +66,7 @@ public static function create(ContentStreamId $contentStreamId, NodeAggregateId public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeAggregateId::fromString($array['nodeAggregateId']), DimensionSpacePoint::fromArray($array['coveredDimensionSpacePoint']), NodeVariantSelectionStrategy::from($array['nodeVariantSelectionStrategy']), @@ -80,22 +81,24 @@ public function jsonSerialize(): array return get_object_vars($this); } - public function createCopyForContentStream(ContentStreamId $target): self - { - return new self( - $target, - $this->nodeAggregateId, - $this->coveredDimensionSpacePoint, - $this->nodeVariantSelectionStrategy, - ); - } - public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { return ( - $this->contentStreamId === $nodeIdToPublish->contentStreamId + $this->workspaceName === $nodeIdToPublish->workspaceName && $this->coveredDimensionSpacePoint === $nodeIdToPublish->dimensionSpacePoint && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) ); } + + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { + return new self( + $targetWorkspaceName, + $this->nodeAggregateId, + $this->coveredDimensionSpacePoint, + $this->nodeVariantSelectionStrategy + ); + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php b/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php index 5bce9711699..3e92115a9bb 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/Command/EnableNodeAggregate.php @@ -17,46 +17,47 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Enable the given node aggregate in the given content stream in a dimension space point using a given strategy * * @api commands are the write-API of the ContentRepository */ -final class EnableNodeAggregate implements +final readonly class EnableNodeAggregate implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface, - MatchableWithNodeIdToPublishOrDiscardInterface + MatchableWithNodeIdToPublishOrDiscardInterface, + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the enable operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the enable operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to enable * @param DimensionSpacePoint $coveredDimensionSpacePoint The covered dimension space point of the node aggregate in which the user intends to enable it * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be enabled */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId, - public readonly DimensionSpacePoint $coveredDimensionSpacePoint, - public readonly NodeVariantSelectionStrategy $nodeVariantSelectionStrategy, + public WorkspaceName $workspaceName, + public NodeAggregateId $nodeAggregateId, + public DimensionSpacePoint $coveredDimensionSpacePoint, + public NodeVariantSelectionStrategy $nodeVariantSelectionStrategy, ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the enable operation is to be performed + * @param WorkspaceName $workspaceName The content stream in which the enable operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to enable * @param DimensionSpacePoint $coveredDimensionSpacePoint The covered dimension space point of the node aggregate in which the user intends to enable it * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be enabled */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, DimensionSpacePoint $coveredDimensionSpacePoint, NodeVariantSelectionStrategy $nodeVariantSelectionStrategy): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, DimensionSpacePoint $coveredDimensionSpacePoint, NodeVariantSelectionStrategy $nodeVariantSelectionStrategy): self { - return new self($contentStreamId, $nodeAggregateId, $coveredDimensionSpacePoint, $nodeVariantSelectionStrategy); + return new self($workspaceName, $nodeAggregateId, $coveredDimensionSpacePoint, $nodeVariantSelectionStrategy); } /** @@ -65,7 +66,7 @@ public static function create(ContentStreamId $contentStreamId, NodeAggregateId public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeAggregateId::fromString($array['nodeAggregateId']), DimensionSpacePoint::fromArray($array['coveredDimensionSpacePoint']), NodeVariantSelectionStrategy::from($array['nodeVariantSelectionStrategy']), @@ -80,22 +81,24 @@ public function jsonSerialize(): array return get_object_vars($this); } - public function createCopyForContentStream(ContentStreamId $target): self - { - return new self( - $target, - $this->nodeAggregateId, - $this->coveredDimensionSpacePoint, - $this->nodeVariantSelectionStrategy, - ); - } - public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { return ( - $this->contentStreamId === $nodeIdToPublish->contentStreamId + $this->workspaceName === $nodeIdToPublish->workspaceName && $this->coveredDimensionSpacePoint === $nodeIdToPublish->dimensionSpacePoint && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) ); } + + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { + return new self( + $targetWorkspaceName, + $this->nodeAggregateId, + $this->coveredDimensionSpacePoint, + $this->nodeVariantSelectionStrategy + ); + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/NodeDisabling.php b/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/NodeDisabling.php index ea4f647c33b..84bcfccd4ea 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/NodeDisabling.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeDisabling/NodeDisabling.php @@ -38,7 +38,6 @@ trait NodeDisabling abstract protected function getInterDimensionalVariationGraph(): DimensionSpace\InterDimensionalVariationGraph; /** - * @param DisableNodeAggregate $command * @return EventsToPublish * @throws ContentStreamDoesNotExistYet * @throws DimensionSpacePointNotFound @@ -49,10 +48,11 @@ private function handleDisableNodeAggregate( DisableNodeAggregate $command, ContentRepository $contentRepository ): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $this->requireDimensionSpacePointToExist($command->coveredDimensionSpacePoint); $nodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); @@ -75,20 +75,20 @@ private function handleDisableNodeAggregate( $events = Events::with( new NodeAggregateWasDisabled( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $affectedDimensionSpacePoints, ), ); return new EventsToPublish( - ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId) + ContentStreamEventStreamName::fromContentStreamId($contentStreamId) ->getEventStreamName(), NodeAggregateEventPublisher::enrichWithCommand( $command, $events ), - ExpectedVersion::ANY() + $expectedVersion ); } @@ -103,10 +103,11 @@ public function handleEnableNodeAggregate( EnableNodeAggregate $command, ContentRepository $contentRepository ): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $this->requireDimensionSpacePointToExist($command->coveredDimensionSpacePoint); $nodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); @@ -129,16 +130,16 @@ public function handleEnableNodeAggregate( $events = Events::with( new NodeAggregateWasEnabled( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $affectedDimensionSpacePoints, ) ); return new EventsToPublish( - ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId)->getEventStreamName(), + ContentStreamEventStreamName::fromContentStreamId($contentStreamId)->getEventStreamName(), NodeAggregateEventPublisher::enrichWithCommand($command, $events), - ExpectedVersion::ANY() + $expectedVersion ); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php index 6fbefbce937..168ce91065b 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/Command/CopyNodesRecursively.php @@ -17,7 +17,7 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\NodeDuplication\Dto\NodeAggregateIdMapping; use Neos\ContentRepository\Core\Feature\NodeDuplication\Dto\NodeSubtreeSnapshot; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; @@ -26,6 +26,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * CopyNodesRecursively command @@ -36,14 +37,14 @@ * * @api commands are the write-API of the ContentRepository */ -final class CopyNodesRecursively implements +final readonly class CopyNodesRecursively implements CommandInterface, \JsonSerializable, MatchableWithNodeIdToPublishOrDiscardInterface, - RebasableToOtherContentStreamsInterface + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The id of the content stream this command is to be handled in + * @param WorkspaceName $workspaceName The name of the workspace this command is to be handled in * @param NodeSubtreeSnapshot $nodeTreeToInsert The snapshot of nodes to copy {@see CopyNodesRecursively::createFromSubgraphAndStartNode()} * @param OriginDimensionSpacePoint $targetDimensionSpacePoint the dimension space point which is the target of the copy * @param NodeAggregateId $targetParentNodeAggregateId Node aggregate id of the target node's parent. If not given, the node will be added as the parent's first child @@ -52,18 +53,18 @@ final class CopyNodesRecursively implements * @param NodeAggregateIdMapping $nodeAggregateIdMapping An assignment of "old" to "new" NodeAggregateIds ({@see NodeAggregateIdMapping}) */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeSubtreeSnapshot $nodeTreeToInsert, - public readonly OriginDimensionSpacePoint $targetDimensionSpacePoint, - public readonly NodeAggregateId $targetParentNodeAggregateId, - public readonly ?NodeAggregateId $targetSucceedingSiblingNodeAggregateId, - public readonly ?NodeName $targetNodeName, - public readonly NodeAggregateIdMapping $nodeAggregateIdMapping + public WorkspaceName $workspaceName, + public NodeSubtreeSnapshot $nodeTreeToInsert, + public OriginDimensionSpacePoint $targetDimensionSpacePoint, + public NodeAggregateId $targetParentNodeAggregateId, + public ?NodeAggregateId $targetSucceedingSiblingNodeAggregateId, + public ?NodeName $targetNodeName, + public NodeAggregateIdMapping $nodeAggregateIdMapping ) { } /** - * @param ContentStreamId $contentStreamId The id of the content stream this command is to be handled in + * @param WorkspaceName $workspaceName The name of the workspace this command is to be handled in * @param NodeSubtreeSnapshot $nodeTreeToInsert The snapshot of nodes to copy {@see CopyNodesRecursively::createFromSubgraphAndStartNode()} * @param OriginDimensionSpacePoint $targetDimensionSpacePoint the dimension space point which is the target of the copy * @param NodeAggregateId $targetParentNodeAggregateId Node aggregate id of the target node's parent. If not given, the node will be added as the parent's first child @@ -71,9 +72,9 @@ private function __construct( * @param NodeName|null $targetNodeName the root node name of the root-inserted-node * @param NodeAggregateIdMapping $nodeAggregateIdMapping An assignment of "old" to "new" NodeAggregateIds ({@see NodeAggregateIdMapping}) */ - public static function create(ContentStreamId $contentStreamId, NodeSubtreeSnapshot $nodeTreeToInsert, OriginDimensionSpacePoint $targetDimensionSpacePoint, NodeAggregateId $targetParentNodeAggregateId, ?NodeAggregateId $targetSucceedingSiblingNodeAggregateId, ?NodeName $targetNodeName, NodeAggregateIdMapping $nodeAggregateIdMapping): self + public static function create(WorkspaceName $workspaceName, NodeSubtreeSnapshot $nodeTreeToInsert, OriginDimensionSpacePoint $targetDimensionSpacePoint, NodeAggregateId $targetParentNodeAggregateId, ?NodeAggregateId $targetSucceedingSiblingNodeAggregateId, ?NodeName $targetNodeName, NodeAggregateIdMapping $nodeAggregateIdMapping): self { - return new self($contentStreamId, $nodeTreeToInsert, $targetDimensionSpacePoint, $targetParentNodeAggregateId, $targetSucceedingSiblingNodeAggregateId, $targetNodeName, $nodeAggregateIdMapping); + return new self($workspaceName, $nodeTreeToInsert, $targetDimensionSpacePoint, $targetParentNodeAggregateId, $targetSucceedingSiblingNodeAggregateId, $targetNodeName, $nodeAggregateIdMapping); } /** @@ -81,6 +82,7 @@ public static function create(ContentStreamId $contentStreamId, NodeSubtreeSnaps */ public static function createFromSubgraphAndStartNode( ContentSubgraphInterface $subgraph, + WorkspaceName $workspaceName, Node $startNode, OriginDimensionSpacePoint $dimensionSpacePoint, NodeAggregateId $targetParentNodeAggregateId, @@ -90,7 +92,7 @@ public static function createFromSubgraphAndStartNode( $nodeSubtreeSnapshot = NodeSubtreeSnapshot::fromSubgraphAndStartNode($subgraph, $startNode); return new self( - $startNode->subgraphIdentity->contentStreamId, + $workspaceName, $nodeSubtreeSnapshot, $dimensionSpacePoint, $targetParentNodeAggregateId, @@ -106,7 +108,7 @@ public static function createFromSubgraphAndStartNode( public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeSubtreeSnapshot::fromArray($array['nodeTreeToInsert']), OriginDimensionSpacePoint::fromArray($array['targetDimensionSpacePoint']), NodeAggregateId::fromString($array['targetParentNodeAggregateId']), @@ -133,36 +135,38 @@ public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool ); return ( !is_null($targetNodeAggregateId) - && $this->contentStreamId === $nodeIdToPublish->contentStreamId + && $this->workspaceName === $nodeIdToPublish->workspaceName && $this->targetDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint) && $targetNodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) ); } - public function createCopyForContentStream(ContentStreamId $target): self - { + public function withNodeAggregateIdMapping( + NodeAggregateIdMapping $nodeAggregateIdMapping + ): self { return new self( - $target, + $this->workspaceName, $this->nodeTreeToInsert, $this->targetDimensionSpacePoint, $this->targetParentNodeAggregateId, $this->targetSucceedingSiblingNodeAggregateId, $this->targetNodeName, - $this->nodeAggregateIdMapping + $nodeAggregateIdMapping ); } - public function withNodeAggregateIdMapping( - NodeAggregateIdMapping $nodeAggregateIdMapping + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId ): self { return new self( - $this->contentStreamId, + $targetWorkspaceName, $this->nodeTreeToInsert, $this->targetDimensionSpacePoint, $this->targetParentNodeAggregateId, $this->targetSucceedingSiblingNodeAggregateId, $this->targetNodeName, - $nodeAggregateIdMapping + $this->nodeAggregateIdMapping ); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php index 635c78d9db7..8c3d2fb2498 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeDuplication/NodeDuplicationCommandHandler.php @@ -82,7 +82,8 @@ private function handleCopyNodesRecursively( ContentRepository $contentRepository ): EventsToPublish { // Basic constraints (Content Stream / Dimension Space Point / Node Type of to-be-inserted root node) - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $this->requireDimensionSpacePointToExist( $command->targetDimensionSpacePoint->toDimensionSpacePoint() ); @@ -93,7 +94,7 @@ private function handleCopyNodesRecursively( // NOTE: we only check this for the *root* node of the to-be-inserted structure; and not for its // children (as we want to create the structure as-is; assuming it was already valid beforehand). $this->requireConstraintsImposedByAncestorsAreMet( - $command->contentStreamId, + $contentStreamId, $nodeType, $command->targetNodeName, [$command->targetParentNodeAggregateId], @@ -102,20 +103,20 @@ private function handleCopyNodesRecursively( // Constraint: The new nodeAggregateIds are not allowed to exist yet. $this->requireNewNodeAggregateIdsToNotExist( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateIdMapping, $contentRepository ); // Constraint: the parent node must exist in the command's DimensionSpacePoint as well $parentNodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->targetParentNodeAggregateId, $contentRepository ); if ($command->targetSucceedingSiblingNodeAggregateId) { $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->targetSucceedingSiblingNodeAggregateId, $contentRepository ); @@ -137,7 +138,7 @@ private function handleCopyNodesRecursively( // Constraint: The node name must be free in all these dimension space points if ($command->targetNodeName) { $this->requireNodeNameToBeUnoccupied( - $command->contentStreamId, + $contentStreamId, $command->targetNodeName, $command->targetParentNodeAggregateId, $command->targetDimensionSpacePoint, @@ -149,7 +150,7 @@ private function handleCopyNodesRecursively( // Now, we can start creating the recursive structure. $events = []; $this->createEventsForNodeToInsert( - $command->contentStreamId, + $contentStreamId, $command->targetDimensionSpacePoint, $coveredDimensionSpacePoints, $command->targetParentNodeAggregateId, @@ -162,13 +163,13 @@ private function handleCopyNodesRecursively( return new EventsToPublish( ContentStreamEventStreamName::fromContentStreamId( - $command->contentStreamId + $contentStreamId )->getEventStreamName(), NodeAggregateEventPublisher::enrichWithCommand( $command, Events::fromArray($events) ), - ExpectedVersion::ANY() + $expectedVersion ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetNodeProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetNodeProperties.php index 2c2f9538e6b..e2a3d63f587 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetNodeProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetNodeProperties.php @@ -18,7 +18,7 @@ use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Add property values for a given node. @@ -34,30 +34,30 @@ * * @api commands are the write-API of the ContentRepository */ -final class SetNodeProperties implements CommandInterface +final readonly class SetNodeProperties implements CommandInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the set properties operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the set properties operation is to be performed * @param NodeAggregateId $nodeAggregateId The id of the node aggregate to set the properties for * @param OriginDimensionSpacePoint $originDimensionSpacePoint The dimension space point the properties should be changed in * @param PropertyValuesToWrite $propertyValues Names and (unserialized) values of properties to set, or unset if the value is null */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId, - public readonly OriginDimensionSpacePoint $originDimensionSpacePoint, - public readonly PropertyValuesToWrite $propertyValues, + public WorkspaceName $workspaceName, + public NodeAggregateId $nodeAggregateId, + public OriginDimensionSpacePoint $originDimensionSpacePoint, + public PropertyValuesToWrite $propertyValues, ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the set properties operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the set properties operation is to be performed * @param NodeAggregateId $nodeAggregateId The id of the node aggregate to set the properties for * @param OriginDimensionSpacePoint $originDimensionSpacePoint The dimension space point the properties should be changed in * @param PropertyValuesToWrite $propertyValues Names and (unserialized) values of properties to set, or unset if the value is null */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, OriginDimensionSpacePoint $originDimensionSpacePoint, PropertyValuesToWrite $propertyValues): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, OriginDimensionSpacePoint $originDimensionSpacePoint, PropertyValuesToWrite $propertyValues): self { - return new self($contentStreamId, $nodeAggregateId, $originDimensionSpacePoint, $propertyValues); + return new self($workspaceName, $nodeAggregateId, $originDimensionSpacePoint, $propertyValues); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php index 498c13014e2..0af47ea210d 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/Command/SetSerializedNodeProperties.php @@ -1,7 +1,7 @@ nodeAggregateId, - $this->originDimensionSpacePoint, - $this->propertyValues, - $this->propertiesToUnset - ); - } - public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { return ( - $this->contentStreamId === $nodeIdToPublish->contentStreamId + $this->workspaceName === $nodeIdToPublish->workspaceName && $this->originDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint) && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) ); } + + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { + return new self( + $targetWorkspaceName, + $this->nodeAggregateId, + $this->originDimensionSpacePoint, + $this->propertyValues, + $this->propertiesToUnset, + ); + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/NodeModification.php b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/NodeModification.php index 7b6b34854b9..91511f5e62c 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeModification/NodeModification.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeModification/NodeModification.php @@ -49,10 +49,10 @@ private function handleSetNodeProperties( SetNodeProperties $command, ContentRepository $contentRepository ): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); $this->requireDimensionSpacePointToExist($command->originDimensionSpacePoint->toDimensionSpacePoint()); $nodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); @@ -62,7 +62,7 @@ private function handleSetNodeProperties( $this->validateProperties($command->propertyValues, $nodeTypeName); $lowLevelCommand = SetSerializedNodeProperties::create( - $command->contentStreamId, + $command->workspaceName, $command->nodeAggregateId, $command->originDimensionSpacePoint, $this->getPropertyConverter()->serializePropertyValues( @@ -79,9 +79,11 @@ private function handleSetSerializedNodeProperties( SetSerializedNodeProperties $command, ContentRepository $contentRepository ): EventsToPublish { + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); // Check if node exists $nodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); @@ -97,7 +99,7 @@ private function handleSetSerializedNodeProperties( ); foreach ($affectedOrigins as $affectedOrigin) { $events[] = new NodePropertiesWereSet( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $affectedOrigin, $nodeAggregate->getCoverageByOccupant($affectedOrigin), @@ -116,7 +118,7 @@ private function handleSetSerializedNodeProperties( ); foreach ($affectedOrigins as $affectedOrigin) { $events[] = new NodePropertiesWereSet( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $affectedOrigin, $nodeAggregate->getCoverageByOccupant($affectedOrigin), @@ -129,13 +131,13 @@ private function handleSetSerializedNodeProperties( $events = $this->mergeSplitEvents($events); return new EventsToPublish( - ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId) + ContentStreamEventStreamName::fromContentStreamId($contentStreamId) ->getEventStreamName(), NodeAggregateEventPublisher::enrichWithCommand( $command, Events::fromArray($events) ), - ExpectedVersion::ANY() + $expectedVersion ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php index cddcae970d7..292df2ba356 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Command/MoveNodeAggregate.php @@ -17,11 +17,12 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\NodeMove\Dto\RelationDistributionStrategy; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * The "Move node aggregate" command @@ -41,14 +42,14 @@ * * @api commands are the write-API of the ContentRepository */ -final class MoveNodeAggregate implements +final readonly class MoveNodeAggregate implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface, - MatchableWithNodeIdToPublishOrDiscardInterface + MatchableWithNodeIdToPublishOrDiscardInterface, + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the move operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the move operation is to be performed * @param DimensionSpacePoint $dimensionSpacePoint This is one of the *covered* dimension space points of the node aggregate and not necessarily one of the occupied ones. This allows us to move virtual specializations only when using the scatter strategy * @param NodeAggregateId $nodeAggregateId The id of the node aggregate to move * @param RelationDistributionStrategy $relationDistributionStrategy The relation distribution strategy to be used ({@see RelationDistributionStrategy}) @@ -57,18 +58,18 @@ final class MoveNodeAggregate implements * @param NodeAggregateId|null $newSucceedingSiblingNodeAggregateId The id of the new succeeding sibling node aggregate. If given, it is attempted to insert the moved nodes right before nodes of this aggregate. In dimension space points this aggregate does not cover, the preceding sibling is tried to be used instead */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly DimensionSpacePoint $dimensionSpacePoint, - public readonly NodeAggregateId $nodeAggregateId, - public readonly RelationDistributionStrategy $relationDistributionStrategy, - public readonly ?NodeAggregateId $newParentNodeAggregateId, - public readonly ?NodeAggregateId $newPrecedingSiblingNodeAggregateId, - public readonly ?NodeAggregateId $newSucceedingSiblingNodeAggregateId, + public WorkspaceName $workspaceName, + public DimensionSpacePoint $dimensionSpacePoint, + public NodeAggregateId $nodeAggregateId, + public RelationDistributionStrategy $relationDistributionStrategy, + public ?NodeAggregateId $newParentNodeAggregateId, + public ?NodeAggregateId $newPrecedingSiblingNodeAggregateId, + public ?NodeAggregateId $newSucceedingSiblingNodeAggregateId, ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the move operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the move operation is to be performed * @param DimensionSpacePoint $dimensionSpacePoint This is one of the *covered* dimension space points of the node aggregate and not necessarily one of the occupied ones. This allows us to move virtual specializations only when using the scatter strategy * @param NodeAggregateId $nodeAggregateId The id of the node aggregate to move * @param RelationDistributionStrategy $relationDistributionStrategy The relation distribution strategy to be used ({@see RelationDistributionStrategy}) @@ -76,9 +77,9 @@ private function __construct( * @param NodeAggregateId|null $newPrecedingSiblingNodeAggregateId The id of the new preceding sibling node aggregate. If given and no successor found, it is attempted to insert the moved nodes right after nodes of this aggregate. In dimension space points this aggregate does not cover, other siblings, in order of proximity, are tried to be used instead * @param NodeAggregateId|null $newSucceedingSiblingNodeAggregateId The id of the new succeeding sibling node aggregate. If given, it is attempted to insert the moved nodes right before nodes of this aggregate. In dimension space points this aggregate does not cover, the preceding sibling is tried to be used instead */ - public static function create(ContentStreamId $contentStreamId, DimensionSpacePoint $dimensionSpacePoint, NodeAggregateId $nodeAggregateId, RelationDistributionStrategy $relationDistributionStrategy, ?NodeAggregateId $newParentNodeAggregateId = null, ?NodeAggregateId $newPrecedingSiblingNodeAggregateId = null, ?NodeAggregateId $newSucceedingSiblingNodeAggregateId = null): self + public static function create(WorkspaceName $workspaceName, DimensionSpacePoint $dimensionSpacePoint, NodeAggregateId $nodeAggregateId, RelationDistributionStrategy $relationDistributionStrategy, ?NodeAggregateId $newParentNodeAggregateId = null, ?NodeAggregateId $newPrecedingSiblingNodeAggregateId = null, ?NodeAggregateId $newSucceedingSiblingNodeAggregateId = null): self { - return new self($contentStreamId, $dimensionSpacePoint, $nodeAggregateId, $relationDistributionStrategy, $newParentNodeAggregateId, $newPrecedingSiblingNodeAggregateId, $newSucceedingSiblingNodeAggregateId); + return new self($workspaceName, $dimensionSpacePoint, $nodeAggregateId, $relationDistributionStrategy, $newParentNodeAggregateId, $newPrecedingSiblingNodeAggregateId, $newSucceedingSiblingNodeAggregateId); } /** @@ -87,7 +88,7 @@ public static function create(ContentStreamId $contentStreamId, DimensionSpacePo public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), DimensionSpacePoint::fromArray($array['dimensionSpacePoint']), NodeAggregateId::fromString($array['nodeAggregateId']), RelationDistributionStrategy::fromString($array['relationDistributionStrategy']), @@ -111,23 +112,25 @@ public function jsonSerialize(): array return get_object_vars($this); } - public function createCopyForContentStream(ContentStreamId $target): self + public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { + return $this->workspaceName === $nodeIdToPublish->workspaceName + && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) + && $this->dimensionSpacePoint === $nodeIdToPublish->dimensionSpacePoint; + } + + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { return new self( - $target, + $targetWorkspaceName, $this->dimensionSpacePoint, $this->nodeAggregateId, $this->relationDistributionStrategy, $this->newParentNodeAggregateId, $this->newPrecedingSiblingNodeAggregateId, - $this->newSucceedingSiblingNodeAggregateId, + $this->newSucceedingSiblingNodeAggregateId ); } - - public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool - { - return $this->contentStreamId === $nodeIdToPublish->contentStreamId - && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) - && $this->dimensionSpacePoint === $nodeIdToPublish->dimensionSpacePoint; - } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php index c8a2792c31d..7dd6afde4cd 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php @@ -64,7 +64,6 @@ abstract protected function requireProjectedNodeAggregate( ): NodeAggregate; /** - * @param MoveNodeAggregate $command * @return EventsToPublish * @throws ContentStreamDoesNotExistYet * @throws NodeAggregatesTypeIsAmbiguous @@ -76,10 +75,11 @@ private function handleMoveNodeAggregate( MoveNodeAggregate $command, ContentRepository $contentRepository ): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $this->requireDimensionSpacePointToExist($command->dimensionSpacePoint); $nodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); @@ -95,7 +95,7 @@ private function handleMoveNodeAggregate( if ($command->newParentNodeAggregateId) { $this->requireConstraintsImposedByAncestorsAreMet( - $command->contentStreamId, + $contentStreamId, $this->requireNodeType($nodeAggregate->nodeTypeName), $nodeAggregate->nodeName, [$command->newParentNodeAggregateId], @@ -103,7 +103,7 @@ private function handleMoveNodeAggregate( ); $this->requireNodeNameToBeUncovered( - $command->contentStreamId, + $contentStreamId, $nodeAggregate->nodeName, $command->newParentNodeAggregateId, $affectedDimensionSpacePoints, @@ -111,7 +111,7 @@ private function handleMoveNodeAggregate( ); $newParentNodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->newParentNodeAggregateId, $contentRepository ); @@ -122,7 +122,7 @@ private function handleMoveNodeAggregate( ); $this->requireNodeAggregateToNotBeDescendant( - $command->contentStreamId, + $contentStreamId, $newParentNodeAggregate, $nodeAggregate, $contentRepository @@ -131,14 +131,14 @@ private function handleMoveNodeAggregate( if ($command->newPrecedingSiblingNodeAggregateId) { $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->newPrecedingSiblingNodeAggregateId, $contentRepository ); } if ($command->newSucceedingSiblingNodeAggregateId) { $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->newSucceedingSiblingNodeAggregateId, $contentRepository ); @@ -150,7 +150,7 @@ private function handleMoveNodeAggregate( $originNodeMoveMappings[] = new OriginNodeMoveMapping( $movedNodeOrigin, $this->resolveCoverageNodeMoveMappings( - $command->contentStreamId, + $contentStreamId, $nodeAggregate, $command->newParentNodeAggregateId, $command->newPrecedingSiblingNodeAggregateId, @@ -164,14 +164,14 @@ private function handleMoveNodeAggregate( $events = Events::with( new NodeAggregateWasMoved( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, OriginNodeMoveMappings::create(...$originNodeMoveMappings) ) ); $contentStreamEventStreamName = ContentStreamEventStreamName::fromContentStreamId( - $command->contentStreamId + $contentStreamId ); return new EventsToPublish( @@ -180,7 +180,7 @@ private function handleMoveNodeAggregate( $command, $events ), - ExpectedVersion::ANY() + $expectedVersion ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php index 3842a5b9d71..4e893eff1a1 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetNodeReferences.php @@ -9,7 +9,7 @@ use Neos\ContentRepository\Core\Feature\NodeReferencing\Dto\NodeReferencesToWrite; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\ReferenceName; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Create a named reference from source to one or multiple destination nodes. @@ -21,33 +21,33 @@ * * @api commands are the write-API of the ContentRepository */ -final class SetNodeReferences implements CommandInterface +final readonly class SetNodeReferences implements CommandInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the create operation is to be performed * @param NodeAggregateId $sourceNodeAggregateId The identifier of the node aggregate to set references * @param OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint The dimension space for which the references should be set * @param ReferenceName $referenceName Name of the reference to set * @param NodeReferencesToWrite $references Unserialized reference(s) to set */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $sourceNodeAggregateId, - public readonly OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, - public readonly ReferenceName $referenceName, - public readonly NodeReferencesToWrite $references, + public WorkspaceName $workspaceName, + public NodeAggregateId $sourceNodeAggregateId, + public OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, + public ReferenceName $referenceName, + public NodeReferencesToWrite $references, ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the create operation is to be performed * @param NodeAggregateId $sourceNodeAggregateId The identifier of the node aggregate to set references * @param OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint The dimension space for which the references should be set * @param ReferenceName $referenceName Name of the reference to set * @param NodeReferencesToWrite $references Unserialized reference(s) to set */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $sourceNodeAggregateId, OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, ReferenceName $referenceName, NodeReferencesToWrite $references): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $sourceNodeAggregateId, OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, ReferenceName $referenceName, NodeReferencesToWrite $references): self { - return new self($contentStreamId, $sourceNodeAggregateId, $sourceOriginDimensionSpacePoint, $referenceName, $references); + return new self($workspaceName, $sourceNodeAggregateId, $sourceOriginDimensionSpacePoint, $referenceName, $references); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php index 355281c63cb..b63266e8ada 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/Command/SetSerializedNodeReferences.php @@ -17,12 +17,13 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\NodeReferencing\Dto\SerializedNodeReferences; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\ReferenceName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Set property values for a given node. @@ -31,38 +32,38 @@ * * @internal implementation detail, use {@see SetNodeReferences} instead. */ -final class SetSerializedNodeReferences implements +final readonly class SetSerializedNodeReferences implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface, - MatchableWithNodeIdToPublishOrDiscardInterface + MatchableWithNodeIdToPublishOrDiscardInterface, + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the create operation is to be performed * @param NodeAggregateId $sourceNodeAggregateId The identifier of the node aggregate to set references * @param OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint The dimension space for which the references should be set * @param ReferenceName $referenceName Name of the reference to set * @param SerializedNodeReferences $references Serialized reference(s) to set */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $sourceNodeAggregateId, - public readonly OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, - public readonly ReferenceName $referenceName, - public readonly SerializedNodeReferences $references, + public WorkspaceName $workspaceName, + public NodeAggregateId $sourceNodeAggregateId, + public OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, + public ReferenceName $referenceName, + public SerializedNodeReferences $references, ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the create operation is to be performed * @param NodeAggregateId $sourceNodeAggregateId The identifier of the node aggregate to set references * @param OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint The dimension space for which the references should be set * @param ReferenceName $referenceName Name of the reference to set * @param SerializedNodeReferences $references Serialized reference(s) to set */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $sourceNodeAggregateId, OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, ReferenceName $referenceName, SerializedNodeReferences $references): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $sourceNodeAggregateId, OriginDimensionSpacePoint $sourceOriginDimensionSpacePoint, ReferenceName $referenceName, SerializedNodeReferences $references): self { - return new self($contentStreamId, $sourceNodeAggregateId, $sourceOriginDimensionSpacePoint, $referenceName, $references); + return new self($workspaceName, $sourceNodeAggregateId, $sourceOriginDimensionSpacePoint, $referenceName, $references); } /** @@ -71,7 +72,7 @@ public static function create(ContentStreamId $contentStreamId, NodeAggregateId public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeAggregateId::fromString($array['sourceNodeAggregateId']), OriginDimensionSpacePoint::fromArray($array['sourceOriginDimensionSpacePoint']), ReferenceName::fromString($array['referenceName']), @@ -88,23 +89,25 @@ public function jsonSerialize(): array return get_object_vars($this); } - public function createCopyForContentStream(ContentStreamId $target): self + public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { + return ( + $this->workspaceName === $nodeIdToPublish->workspaceName + && $this->sourceOriginDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint) + && $this->sourceNodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) + ); + } + + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { return new self( - $target, + $targetWorkspaceName, $this->sourceNodeAggregateId, $this->sourceOriginDimensionSpacePoint, $this->referenceName, $this->references, ); } - - public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool - { - return ( - $this->contentStreamId === $nodeIdToPublish->contentStreamId - && $this->sourceOriginDimensionSpacePoint->equals($nodeIdToPublish->dimensionSpacePoint) - && $this->sourceNodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) - ); - } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/NodeReferencing.php b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/NodeReferencing.php index e74797f6989..064f7fa3c9b 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/NodeReferencing.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeReferencing/NodeReferencing.php @@ -50,10 +50,10 @@ private function handleSetNodeReferences( SetNodeReferences $command, ContentRepository $contentRepository ): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); $this->requireDimensionSpacePointToExist($command->sourceOriginDimensionSpacePoint->toDimensionSpacePoint()); $sourceNodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->sourceNodeAggregateId, $contentRepository ); @@ -71,7 +71,7 @@ private function handleSetNodeReferences( } $lowLevelCommand = SetSerializedNodeReferences::create( - $command->contentStreamId, + $command->workspaceName, $command->sourceNodeAggregateId, $command->sourceOriginDimensionSpacePoint, $command->referenceName, @@ -100,12 +100,13 @@ private function handleSetSerializedNodeReferences( SetSerializedNodeReferences $command, ContentRepository $contentRepository ): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $this->requireDimensionSpacePointToExist( $command->sourceOriginDimensionSpacePoint->toDimensionSpacePoint() ); $sourceNodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->sourceNodeAggregateId, $contentRepository ); @@ -119,7 +120,7 @@ private function handleSetSerializedNodeReferences( foreach ($command->references as $reference) { assert($reference instanceof SerializedNodeReference); $destinationNodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $reference->targetNodeAggregateId, $contentRepository ); @@ -147,7 +148,7 @@ private function handleSetSerializedNodeReferences( $events = Events::with( new NodeReferencesWereSet( - $command->contentStreamId, + $contentStreamId, $command->sourceNodeAggregateId, $affectedOrigins, $command->referenceName, @@ -156,13 +157,13 @@ private function handleSetSerializedNodeReferences( ); return new EventsToPublish( - ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId) + ContentStreamEventStreamName::fromContentStreamId($contentStreamId) ->getEventStreamName(), NodeAggregateEventPublisher::enrichWithCommand( $command, $events ), - ExpectedVersion::ANY() + $expectedVersion ); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php b/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php index 6c3836dc81c..c7cae2ee036 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/Command/RemoveNodeAggregate.php @@ -17,46 +17,47 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * @api commands are the write-API of the ContentRepository */ -final class RemoveNodeAggregate implements +final readonly class RemoveNodeAggregate implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface, - MatchableWithNodeIdToPublishOrDiscardInterface + MatchableWithNodeIdToPublishOrDiscardInterface, + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the remove operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the remove operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to remove * @param DimensionSpacePoint $coveredDimensionSpacePoint One of the dimension space points covered by the node aggregate in which the user intends to remove it * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be removed * @param NodeAggregateId|null $removalAttachmentPoint Internal. It stores the document node id of the removed node, as that is what the UI needs later on for the change display. {@see self::withRemovalAttachmentPoint()} */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId, - public readonly DimensionSpacePoint $coveredDimensionSpacePoint, - public readonly NodeVariantSelectionStrategy $nodeVariantSelectionStrategy, - public readonly ?NodeAggregateId $removalAttachmentPoint + public WorkspaceName $workspaceName, + public NodeAggregateId $nodeAggregateId, + public DimensionSpacePoint $coveredDimensionSpacePoint, + public NodeVariantSelectionStrategy $nodeVariantSelectionStrategy, + public ?NodeAggregateId $removalAttachmentPoint ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the remove operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the remove operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to remove * @param DimensionSpacePoint $coveredDimensionSpacePoint One of the dimension space points covered by the node aggregate in which the user intends to remove it * @param NodeVariantSelectionStrategy $nodeVariantSelectionStrategy The strategy the user chose to determine which specialization variants will also be removed */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, DimensionSpacePoint $coveredDimensionSpacePoint, NodeVariantSelectionStrategy $nodeVariantSelectionStrategy): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, DimensionSpacePoint $coveredDimensionSpacePoint, NodeVariantSelectionStrategy $nodeVariantSelectionStrategy): self { - return new self($contentStreamId, $nodeAggregateId, $coveredDimensionSpacePoint, $nodeVariantSelectionStrategy, null); + return new self($workspaceName, $nodeAggregateId, $coveredDimensionSpacePoint, $nodeVariantSelectionStrategy, null); } /** @@ -65,7 +66,7 @@ public static function create(ContentStreamId $contentStreamId, NodeAggregateId public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeAggregateId::fromString($array['nodeAggregateId']), DimensionSpacePoint::fromArray($array['coveredDimensionSpacePoint']), NodeVariantSelectionStrategy::from($array['nodeVariantSelectionStrategy']), @@ -89,7 +90,7 @@ public static function fromArray(array $array): self */ public function withRemovalAttachmentPoint(NodeAggregateId $removalAttachmentPoint): self { - return new self($this->contentStreamId, $this->nodeAggregateId, $this->coveredDimensionSpacePoint, $this->nodeVariantSelectionStrategy, $removalAttachmentPoint); + return new self($this->workspaceName, $this->nodeAggregateId, $this->coveredDimensionSpacePoint, $this->nodeVariantSelectionStrategy, $removalAttachmentPoint); } /** @@ -100,23 +101,25 @@ public function jsonSerialize(): array return get_object_vars($this); } - public function createCopyForContentStream(ContentStreamId $target): self - { - return new self( - $target, - $this->nodeAggregateId, - $this->coveredDimensionSpacePoint, - $this->nodeVariantSelectionStrategy, - $this->removalAttachmentPoint - ); - } - public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { return ( - $this->contentStreamId === $nodeIdToPublish->contentStreamId + $this->workspaceName === $nodeIdToPublish->workspaceName && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) && $this->coveredDimensionSpacePoint === $nodeIdToPublish->dimensionSpacePoint ); } + + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { + return new self( + $targetWorkspaceName, + $this->nodeAggregateId, + $this->coveredDimensionSpacePoint, + $this->nodeVariantSelectionStrategy, + $this->removalAttachmentPoint, + ); + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/NodeRemoval.php b/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/NodeRemoval.php index 9ea43b119cc..30a1f9a5650 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/NodeRemoval.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeRemoval/NodeRemoval.php @@ -50,9 +50,10 @@ private function handleRemoveNodeAggregate( RemoveNodeAggregate $command, ContentRepository $contentRepository ): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $nodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); @@ -64,7 +65,7 @@ private function handleRemoveNodeAggregate( ); if ($command->removalAttachmentPoint instanceof NodeAggregateId) { $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->removalAttachmentPoint, $contentRepository ); @@ -72,7 +73,7 @@ private function handleRemoveNodeAggregate( $events = Events::with( new NodeAggregateWasRemoved( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $command->nodeVariantSelectionStrategy->resolveAffectedOriginDimensionSpacePoints( $nodeAggregate->getOccupationByCovered($command->coveredDimensionSpacePoint), @@ -89,13 +90,13 @@ private function handleRemoveNodeAggregate( ); return new EventsToPublish( - ContentStreamEventStreamName::fromContentStreamId($command->contentStreamId) + ContentStreamEventStreamName::fromContentStreamId($contentStreamId) ->getEventStreamName(), NodeAggregateEventPublisher::enrichWithCommand( $command, $events ), - ExpectedVersion::ANY() + $expectedVersion ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php b/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php index a0839e3c880..3ae6d3903ed 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/Command/ChangeNodeAggregateName.php @@ -16,11 +16,12 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * All variants in a NodeAggregate have the same NodeName - and this can be changed here. @@ -29,32 +30,32 @@ * * @api commands are the write-API of the ContentRepository */ -final class ChangeNodeAggregateName implements +final readonly class ChangeNodeAggregateName implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface, - MatchableWithNodeIdToPublishOrDiscardInterface + MatchableWithNodeIdToPublishOrDiscardInterface, + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to rename * @param NodeName $newNodeName The new name of the node aggregate */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId, - public readonly NodeName $newNodeName, + public WorkspaceName $workspaceName, + public NodeAggregateId $nodeAggregateId, + public NodeName $newNodeName, ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the node aggregate to rename * @param NodeName $newNodeName The new name of the node aggregate */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeName $newNodeName): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, NodeName $newNodeName): self { - return new self($contentStreamId, $nodeAggregateId, $newNodeName); + return new self($workspaceName, $nodeAggregateId, $newNodeName); } /** @@ -63,7 +64,7 @@ public static function create(ContentStreamId $contentStreamId, NodeAggregateId public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeAggregateId::fromString($array['nodeAggregateId']), NodeName::fromString($array['newNodeName']), ); @@ -77,20 +78,22 @@ public function jsonSerialize(): array return get_object_vars($this); } - public function createCopyForContentStream(ContentStreamId $target): self - { - return new ChangeNodeAggregateName( - $target, - $this->nodeAggregateId, - $this->newNodeName, - ); - } - public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { return ( - $this->contentStreamId->equals($nodeIdToPublish->contentStreamId) + $this->workspaceName->equals($nodeIdToPublish->workspaceName) && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) ); } + + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { + return new self( + $targetWorkspaceName, + $this->nodeAggregateId, + $this->newNodeName, + ); + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/NodeRenaming.php b/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/NodeRenaming.php index f38e032ce57..ac2f8787e5f 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/NodeRenaming.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeRenaming/NodeRenaming.php @@ -33,18 +33,19 @@ trait NodeRenaming private function handleChangeNodeAggregateName(ChangeNodeAggregateName $command, ContentRepository $contentRepository): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $nodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); $this->requireNodeAggregateToNotBeRoot($nodeAggregate, 'and Root Node Aggregates cannot be renamed'); $this->requireNodeAggregateToBeUntethered($nodeAggregate); - foreach ($contentRepository->getContentGraph()->findParentNodeAggregates($command->contentStreamId, $command->nodeAggregateId) as $parentNodeAggregate) { + foreach ($contentRepository->getContentGraph()->findParentNodeAggregates($contentStreamId, $command->nodeAggregateId) as $parentNodeAggregate) { foreach ($parentNodeAggregate->occupiedDimensionSpacePoints as $occupiedParentDimensionSpacePoint) { $this->requireNodeNameToBeUnoccupied( - $command->contentStreamId, + $contentStreamId, $command->newNodeName, $parentNodeAggregate->nodeAggregateId, $occupiedParentDimensionSpacePoint, @@ -56,21 +57,19 @@ private function handleChangeNodeAggregateName(ChangeNodeAggregateName $command, $events = Events::with( new NodeAggregateNameWasChanged( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $command->newNodeName, ), ); return new EventsToPublish( - ContentStreamEventStreamName::fromContentStreamId( - $command->contentStreamId - )->getEventStreamName(), + ContentStreamEventStreamName::fromContentStreamId($contentStreamId)->getEventStreamName(), NodeAggregateEventPublisher::enrichWithCommand( $command, $events ), - ExpectedVersion::ANY() + $expectedVersion ); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php b/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php index d4cd304a9f4..10ab4664c6f 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/Command/ChangeNodeAggregateType.php @@ -14,54 +14,51 @@ namespace Neos\ContentRepository\Core\Feature\NodeTypeChange\Command; -/** @codingStandardsIgnoreStart */ - use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\NodeCreation\Dto\NodeAggregateIdsByNodePaths; use Neos\ContentRepository\Core\Feature\NodeTypeChange\Dto\NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; - -/** @codingStandardsIgnoreEnd */ +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * @api commands are the write-API of the ContentRepository */ -final class ChangeNodeAggregateType implements +final readonly class ChangeNodeAggregateType implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface, - MatchableWithNodeIdToPublishOrDiscardInterface + MatchableWithNodeIdToPublishOrDiscardInterface, + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the operation is to be performed * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to change * @param NodeTypeName $newNodeTypeName Name of the new node type * @param NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy $strategy Strategy for conflicts on affected child nodes ({@see NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy}) * @param NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds Predefined aggregate ids of any tethered child nodes for the new node type per path. For any tethered node that has no matching entry in this set, the node aggregate id is generated randomly. Since tethered nodes may have tethered child nodes themselves, this works for multiple levels ({@see self::withTetheredDescendantNodeAggregateIds()}) */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId, - public readonly NodeTypeName $newNodeTypeName, - public readonly NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy $strategy, - public readonly NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds, + public WorkspaceName $workspaceName, + public NodeAggregateId $nodeAggregateId, + public NodeTypeName $newNodeTypeName, + public NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy $strategy, + public NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds, ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the operation is to be performed * @param NodeAggregateId $nodeAggregateId The unique identifier of the node aggregate to change * @param NodeTypeName $newNodeTypeName Name of the new node type * @param NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy $strategy Strategy for conflicts on affected child nodes ({@see NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy}) */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $newNodeTypeName, NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy $strategy): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, NodeTypeName $newNodeTypeName, NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy $strategy): self { - return new self($contentStreamId, $nodeAggregateId, $newNodeTypeName, $strategy, NodeAggregateIdsByNodePaths::createEmpty()); + return new self($workspaceName, $nodeAggregateId, $newNodeTypeName, $strategy, NodeAggregateIdsByNodePaths::createEmpty()); } /** @@ -70,7 +67,7 @@ public static function create(ContentStreamId $contentStreamId, NodeAggregateId public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeAggregateId::fromString($array['nodeAggregateId']), NodeTypeName::fromString($array['newNodeTypeName']), NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy::from($array['strategy']), @@ -80,28 +77,12 @@ public static function fromArray(array $array): self ); } - public function getNodeAggregateId(): NodeAggregateId - { - return $this->nodeAggregateId; - } - public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { - return $this->contentStreamId === $nodeIdToPublish->contentStreamId + return $this->workspaceName === $nodeIdToPublish->workspaceName && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId); } - public function createCopyForContentStream(ContentStreamId $target): self - { - return new self( - $target, - $this->nodeAggregateId, - $this->newNodeTypeName, - $this->strategy, - $this->tetheredDescendantNodeAggregateIds - ); - } - /** * @return array */ @@ -119,11 +100,24 @@ public function jsonSerialize(): array public function withTetheredDescendantNodeAggregateIds(NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds): self { return new self( - $this->contentStreamId, + $this->workspaceName, $this->nodeAggregateId, $this->newNodeTypeName, $this->strategy, $tetheredDescendantNodeAggregateIds ); } + + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { + return new self( + $targetWorkspaceName, + $this->nodeAggregateId, + $this->newNodeTypeName, + $this->strategy, + $this->tetheredDescendantNodeAggregateIds + ); + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php b/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php index 09f97b8a12c..cffac2fce5e 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeTypeChange/NodeTypeChange.php @@ -112,10 +112,11 @@ private function handleChangeNodeAggregateType( * Constraint checks **************/ // existence of content stream, node type and node aggregate - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $newNodeType = $this->requireNodeType($command->newNodeTypeName); $nodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); @@ -133,7 +134,7 @@ private function handleChangeNodeAggregateType( foreach ($parentNodeAggregates as $parentNodeAggregate) { assert($parentNodeAggregate instanceof NodeAggregate); $this->requireConstraintsImposedByAncestorsAreMet( - $command->contentStreamId, + $contentStreamId, $newNodeType, $nodeAggregate->nodeName, [$parentNodeAggregate->nodeAggregateId], @@ -165,7 +166,7 @@ private function handleChangeNodeAggregateType( **************/ $events = [ new NodeAggregateTypeWasChanged( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $command->newNodeTypeName ), @@ -218,14 +219,12 @@ private function handleChangeNodeAggregateType( } return new EventsToPublish( - ContentStreamEventStreamName::fromContentStreamId( - $command->contentStreamId - )->getEventStreamName(), + ContentStreamEventStreamName::fromContentStreamId($contentStreamId)->getEventStreamName(), NodeAggregateEventPublisher::enrichWithCommand( $command, Events::fromArray($events), ), - ExpectedVersion::ANY() + $expectedVersion ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php b/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php index d9660530e07..959600afca1 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/Command/CreateNodeVariant.php @@ -17,10 +17,11 @@ use Neos\ContentRepository\Core\CommandHandler\CommandInterface; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdToPublishOrDiscard; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Create a variant of a node in a content stream @@ -29,35 +30,35 @@ * * @api commands are the write-API of the ContentRepository */ -final class CreateNodeVariant implements +final readonly class CreateNodeVariant implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface, - MatchableWithNodeIdToPublishOrDiscardInterface + MatchableWithNodeIdToPublishOrDiscardInterface, + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the create operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the affected node aggregate * @param OriginDimensionSpacePoint $sourceOrigin Dimension Space Point from which the node is to be copied from * @param OriginDimensionSpacePoint $targetOrigin Dimension Space Point to which the node is to be copied to */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId, - public readonly OriginDimensionSpacePoint $sourceOrigin, - public readonly OriginDimensionSpacePoint $targetOrigin, + public WorkspaceName $workspaceName, + public NodeAggregateId $nodeAggregateId, + public OriginDimensionSpacePoint $sourceOrigin, + public OriginDimensionSpacePoint $targetOrigin, ) { } /** - * @param ContentStreamId $contentStreamId The content stream in which the create operation is to be performed + * @param WorkspaceName $workspaceName The workspace in which the create operation is to be performed * @param NodeAggregateId $nodeAggregateId The identifier of the affected node aggregate * @param OriginDimensionSpacePoint $sourceOrigin Dimension Space Point from which the node is to be copied from * @param OriginDimensionSpacePoint $targetOrigin Dimension Space Point to which the node is to be copied to */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, OriginDimensionSpacePoint $sourceOrigin, OriginDimensionSpacePoint $targetOrigin): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, OriginDimensionSpacePoint $sourceOrigin, OriginDimensionSpacePoint $targetOrigin): self { - return new self($contentStreamId, $nodeAggregateId, $sourceOrigin, $targetOrigin); + return new self($workspaceName, $nodeAggregateId, $sourceOrigin, $targetOrigin); } /** @@ -66,7 +67,7 @@ public static function create(ContentStreamId $contentStreamId, NodeAggregateId public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeAggregateId::fromString($array['nodeAggregateId']), OriginDimensionSpacePoint::fromArray($array['sourceOrigin']), OriginDimensionSpacePoint::fromArray($array['targetOrigin']), @@ -83,15 +84,17 @@ public function jsonSerialize(): array public function matchesNodeId(NodeIdToPublishOrDiscard $nodeIdToPublish): bool { - return $this->contentStreamId->equals($nodeIdToPublish->contentStreamId) + return $this->workspaceName->equals($nodeIdToPublish->workspaceName) && $this->nodeAggregateId->equals($nodeIdToPublish->nodeAggregateId) && $this->targetOrigin->equals($nodeIdToPublish->dimensionSpacePoint); } - public function createCopyForContentStream(ContentStreamId $target): CommandInterface - { + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { return new self( - $target, + $targetWorkspaceName, $this->nodeAggregateId, $this->sourceOrigin, $this->targetOrigin, diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/NodeVariation.php b/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/NodeVariation.php index dbed5b970aa..6ae6688e7e3 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/NodeVariation.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeVariation/NodeVariation.php @@ -51,9 +51,10 @@ private function handleCreateNodeVariant( CreateNodeVariant $command, ContentRepository $contentRepository ): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $nodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); @@ -66,7 +67,7 @@ private function handleCreateNodeVariant( $this->requireNodeAggregateToOccupyDimensionSpacePoint($nodeAggregate, $command->sourceOrigin); $this->requireNodeAggregateToNotOccupyDimensionSpacePoint($nodeAggregate, $command->targetOrigin); $parentNodeAggregate = $this->requireProjectedParentNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $command->sourceOrigin, $contentRepository @@ -77,7 +78,7 @@ private function handleCreateNodeVariant( ); $events = $this->createEventsForVariations( - $command->contentStreamId, + $contentStreamId, $command->sourceOrigin, $command->targetOrigin, $nodeAggregate, @@ -85,14 +86,12 @@ private function handleCreateNodeVariant( ); return new EventsToPublish( - ContentStreamEventStreamName::fromContentStreamId( - $command->contentStreamId - )->getEventStreamName(), + ContentStreamEventStreamName::fromContentStreamId($contentStreamId)->getEventStreamName(), NodeAggregateEventPublisher::enrichWithCommand( $command, $events ), - ExpectedVersion::ANY() + $expectedVersion ); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php b/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php index ec9b7f83096..ff2ba724c0a 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php +++ b/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/Command/CreateRootNodeAggregateWithNode.php @@ -15,11 +15,12 @@ namespace Neos\ContentRepository\Core\Feature\RootNodeCreation\Command; use Neos\ContentRepository\Core\CommandHandler\CommandInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\NodeCreation\Dto\NodeAggregateIdsByNodePaths; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Create root node aggregate with node command @@ -32,16 +33,16 @@ final readonly class CreateRootNodeAggregateWithNode implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The content stream in which the root node should be created in + * @param WorkspaceName $workspaceName The workspace in which the root node should be created in * @param NodeAggregateId $nodeAggregateId The id of the root node aggregate to create * @param NodeTypeName $nodeTypeName Name of type of the new node to create * @param NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds Predefined aggregate ids of tethered child nodes per path. For any tethered node that has no matching entry in this set, the node aggregate id is generated randomly. Since tethered nodes may have tethered child nodes themselves, this works for multiple levels ({@see self::withTetheredDescendantNodeAggregateIds()}) */ private function __construct( - public ContentStreamId $contentStreamId, + public WorkspaceName $workspaceName, public NodeAggregateId $nodeAggregateId, public NodeTypeName $nodeTypeName, public NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds, @@ -49,14 +50,14 @@ private function __construct( } /** - * @param ContentStreamId $contentStreamId The content stream in which the root node should be created in + * @param WorkspaceName $workspaceName The workspace in which the root node should be created in * @param NodeAggregateId $nodeAggregateId The id of the root node aggregate to create * @param NodeTypeName $nodeTypeName Name of type of the new node to create */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName): self { return new self( - $contentStreamId, + $workspaceName, $nodeAggregateId, $nodeTypeName, NodeAggregateIdsByNodePaths::createEmpty() @@ -94,7 +95,7 @@ public static function create(ContentStreamId $contentStreamId, NodeAggregateId public function withTetheredDescendantNodeAggregateIds(NodeAggregateIdsByNodePaths $tetheredDescendantNodeAggregateIds): self { return new self( - $this->contentStreamId, + $this->workspaceName, $this->nodeAggregateId, $this->nodeTypeName, $tetheredDescendantNodeAggregateIds, @@ -107,7 +108,7 @@ public function withTetheredDescendantNodeAggregateIds(NodeAggregateIdsByNodePat public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeAggregateId::fromString($array['nodeAggregateId']), NodeTypeName::fromString($array['nodeTypeName']), isset($array['tetheredDescendantNodeAggregateIds']) @@ -124,10 +125,12 @@ public function jsonSerialize(): array return get_object_vars($this); } - public function createCopyForContentStream(ContentStreamId $target): self - { + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { return new self( - $target, + $targetWorkspaceName, $this->nodeAggregateId, $this->nodeTypeName, $this->tetheredDescendantNodeAggregateIds diff --git a/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php b/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php index 5e1498731f3..5d8597c827b 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php +++ b/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/Command/UpdateRootNodeAggregateDimensions.php @@ -15,9 +15,10 @@ namespace Neos\ContentRepository\Core\Feature\RootNodeCreation\Command; use Neos\ContentRepository\Core\CommandHandler\CommandInterface; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * change visibility of the root node aggregate. A root node aggregate must be visible in all @@ -26,28 +27,28 @@ * * @api commands are the write-API of the ContentRepository */ -final class UpdateRootNodeAggregateDimensions implements +final readonly class UpdateRootNodeAggregateDimensions implements CommandInterface, \JsonSerializable, - RebasableToOtherContentStreamsInterface + RebasableToOtherWorkspaceInterface { /** - * @param ContentStreamId $contentStreamId The content stream which the dimensions should be updated in + * @param WorkspaceName $workspaceName The workspace which the dimensions should be updated in * @param NodeAggregateId $nodeAggregateId The id of the node aggregate that should be updated */ private function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId, + public WorkspaceName $workspaceName, + public NodeAggregateId $nodeAggregateId, ) { } /** - * @param ContentStreamId $contentStreamId The content stream which the dimensions should be updated in + * @param WorkspaceName $workspaceName The workspace which the dimensions should be updated in * @param NodeAggregateId $nodeAggregateId The id of the node aggregate that should be updated */ - public static function create(ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId): self + public static function create(WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId): self { - return new self($contentStreamId, $nodeAggregateId); + return new self($workspaceName, $nodeAggregateId); } /** @@ -56,7 +57,7 @@ public static function create(ContentStreamId $contentStreamId, NodeAggregateId public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeAggregateId::fromString($array['nodeAggregateId']) ); } @@ -69,10 +70,12 @@ public function jsonSerialize(): array return get_object_vars($this); } - public function createCopyForContentStream(ContentStreamId $target): self - { + public function createCopyForWorkspace( + WorkspaceName $targetWorkspaceName, + ContentStreamId $targetContentStreamId + ): self { return new self( - $target, + $targetWorkspaceName, $this->nodeAggregateId, ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/RootNodeHandling.php b/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/RootNodeHandling.php index 1c5a2dbc6ae..0772c5c7731 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/RootNodeHandling.php +++ b/Neos.ContentRepository.Core/Classes/Feature/RootNodeCreation/RootNodeHandling.php @@ -41,6 +41,7 @@ use Neos\ContentRepository\Core\Feature\Common\NodeAggregateEventPublisher; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\EventStore\Model\EventStream\ExpectedVersion; /** @@ -69,9 +70,10 @@ private function handleCreateRootNodeAggregateWithNode( CreateRootNodeAggregateWithNode $command, ContentRepository $contentRepository ): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $this->requireProjectedNodeAggregateToNotExist( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); @@ -80,7 +82,7 @@ private function handleCreateRootNodeAggregateWithNode( $this->requireNodeTypeToBeOfTypeRoot($nodeType); $this->requireRootNodeTypeToBeUnoccupied( $nodeType->name, - $command->contentStreamId, + $contentStreamId, $contentRepository ); @@ -95,13 +97,14 @@ private function handleCreateRootNodeAggregateWithNode( $events = [ $this->createRootWithNode( $command, + $contentStreamId, $this->getAllowedDimensionSubspace() ) ]; foreach ($this->getInterDimensionalVariationGraph()->getRootGeneralizations() as $rootGeneralization) { array_push($events, ...iterator_to_array($this->handleTetheredRootChildNodes( - $command, + $contentStreamId, $nodeType, OriginDimensionSpacePoint::fromDimensionSpacePoint($rootGeneralization), $this->getInterDimensionalVariationGraph()->getSpecializationSet($rootGeneralization, true), @@ -112,25 +115,24 @@ private function handleCreateRootNodeAggregateWithNode( ))); } - $contentStreamEventStream = ContentStreamEventStreamName::fromContentStreamId( - $command->contentStreamId - ); + $contentStreamEventStream = ContentStreamEventStreamName::fromContentStreamId($contentStreamId); return new EventsToPublish( $contentStreamEventStream->getEventStreamName(), NodeAggregateEventPublisher::enrichWithCommand( $command, Events::fromArray($events) ), - ExpectedVersion::ANY() + $expectedVersion ); } private function createRootWithNode( CreateRootNodeAggregateWithNode $command, + ContentStreamId $contentStreamId, DimensionSpacePointSet $coveredDimensionSpacePoints ): RootNodeAggregateWithNodeWasCreated { return new RootNodeAggregateWithNodeWasCreated( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $command->nodeTypeName, $coveredDimensionSpacePoints, @@ -146,9 +148,10 @@ private function handleUpdateRootNodeAggregateDimensions( UpdateRootNodeAggregateDimensions $command, ContentRepository $contentRepository ): EventsToPublish { - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); + $contentStreamId = $this->requireContentStream($command->workspaceName, $contentRepository); + $expectedVersion = $this->getExpectedVersionOfContentStream($contentStreamId, $contentRepository); $nodeAggregate = $this->requireProjectedNodeAggregate( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $contentRepository ); @@ -158,14 +161,14 @@ private function handleUpdateRootNodeAggregateDimensions( $events = Events::with( new RootNodeAggregateDimensionsWereUpdated( - $command->contentStreamId, + $contentStreamId, $command->nodeAggregateId, $this->getAllowedDimensionSubspace() ) ); $contentStreamEventStream = ContentStreamEventStreamName::fromContentStreamId( - $command->contentStreamId + $contentStreamId ); return new EventsToPublish( $contentStreamEventStream->getEventStreamName(), @@ -173,7 +176,7 @@ private function handleUpdateRootNodeAggregateDimensions( $command, $events ), - ExpectedVersion::ANY() + $expectedVersion ); } @@ -182,7 +185,7 @@ private function handleUpdateRootNodeAggregateDimensions( * @throws NodeTypeNotFoundException */ private function handleTetheredRootChildNodes( - CreateRootNodeAggregateWithNode $command, + ContentStreamId $contentStreamId, NodeType $nodeType, OriginDimensionSpacePoint $originDimensionSpacePoint, DimensionSpacePointSet $coveredDimensionSpacePoints, @@ -202,9 +205,8 @@ private function handleTetheredRootChildNodes( ?? NodeAggregateId::create(); $initialPropertyValues = SerializedPropertyValues::defaultFromNodeType($childNodeType, $this->getPropertyConverter()); - $this->requireContentStreamToExist($command->contentStreamId, $contentRepository); $events[] = $this->createTetheredWithNodeForRoot( - $command, + $contentStreamId, $childNodeAggregateId, $childNodeType->name, $originDimensionSpacePoint, @@ -215,7 +217,7 @@ private function handleTetheredRootChildNodes( ); array_push($events, ...iterator_to_array($this->handleTetheredRootChildNodes( - $command, + $contentStreamId, $childNodeType, $originDimensionSpacePoint, $coveredDimensionSpacePoints, @@ -230,7 +232,7 @@ private function handleTetheredRootChildNodes( } private function createTetheredWithNodeForRoot( - CreateRootNodeAggregateWithNode $command, + ContentStreamId $contentStreamId, NodeAggregateId $nodeAggregateId, NodeTypeName $nodeTypeName, OriginDimensionSpacePoint $originDimensionSpacePoint, @@ -241,7 +243,7 @@ private function createTetheredWithNodeForRoot( NodeAggregateId $precedingNodeAggregateId = null ): NodeAggregateWithNodeWasCreated { return new NodeAggregateWithNodeWasCreated( - $command->contentStreamId, + $contentStreamId, $nodeAggregateId, $nodeTypeName, $originDimensionSpacePoint, diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php index 4d144cdad7b..f631052e700 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCommandHandler.php @@ -23,6 +23,9 @@ use Neos\ContentRepository\Core\EventStore\EventPersister; use Neos\ContentRepository\Core\EventStore\Events; use Neos\ContentRepository\Core\EventStore\EventsToPublish; +use Neos\ContentRepository\Core\Feature\Common\ContentStreamIdOverride; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Command\CloseContentStream; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Command\ReopenContentStream; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto\NodeIdsToPublishOrDiscard; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\DiscardIndividualNodesFromWorkspace; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\DiscardWorkspace; @@ -34,7 +37,7 @@ use Neos\ContentRepository\Core\Feature\ContentStreamRemoval\Command\RemoveContentStream; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamAlreadyExists; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet; -use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherContentStreamsInterface; +use Neos\ContentRepository\Core\Feature\Common\RebasableToOtherWorkspaceInterface; use Neos\ContentRepository\Core\Feature\Common\PublishableToOtherContentStreamsInterface; use Neos\ContentRepository\Core\Feature\Common\MatchableWithNodeIdToPublishOrDiscardInterface; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateRootWorkspace; @@ -78,12 +81,12 @@ /** * @internal from userland, you'll use ContentRepository::handle to dispatch commands */ -final class WorkspaceCommandHandler implements CommandHandlerInterface +final readonly class WorkspaceCommandHandler implements CommandHandlerInterface { public function __construct( - private readonly EventPersister $eventPersister, - private readonly EventStoreInterface $eventStore, - private readonly EventNormalizer $eventNormalizer, + private EventPersister $eventPersister, + private EventStoreInterface $eventStore, + private EventNormalizer $eventNormalizer, ) { } @@ -248,10 +251,9 @@ private function handlePublishWorkspace( )?->block(); // After publishing a workspace, we need to again fork from Base. - $newContentStream = ContentStreamId::create(); $contentRepository->handle( ForkContentStream::create( - $newContentStream, + $command->newContentStreamId, $baseWorkspace->currentContentStreamId, ) )->block(); @@ -261,7 +263,7 @@ private function handlePublishWorkspace( new WorkspaceWasPublished( $command->workspaceName, $baseWorkspace->workspaceName, - $newContentStream, + $command->newContentStreamId, $workspace->currentContentStreamId, ) ); @@ -281,26 +283,24 @@ private function publishContentStream( ContentStreamId $contentStreamId, ContentStreamId $baseContentStreamId, ): ?CommandResult { - $contentStreamName = ContentStreamEventStreamName::fromContentStreamId($contentStreamId); $baseWorkspaceContentStreamName = ContentStreamEventStreamName::fromContentStreamId( $baseContentStreamId ); // TODO: please check the code below in-depth. it does: - // - copy all events from the "user" content stream which implement "PublishableToOtherContentStreamsInterface" + // - copy all events from the "user" content stream which implement @see{}"PublishableToOtherContentStreamsInterface" // - extract the initial ContentStreamWasForked event, // to read the version of the source content stream when the fork occurred // - ensure that no other changes have been done in the meantime in the base content stream - $streamName = $contentStreamName->getEventStreamName(); - + $workspaceContentStream = iterator_to_array($this->eventStore->load( + ContentStreamEventStreamName::fromContentStreamId($contentStreamId)->getEventStreamName() + )); /** @var array $workspaceContentStream */ - $workspaceContentStream = iterator_to_array($this->eventStore->load($streamName)); $events = []; $contentStreamWasForkedEvent = null; foreach ($workspaceContentStream as $eventEnvelope) { - assert($eventEnvelope instanceof EventEnvelope); $event = $this->eventNormalizer->denormalize($eventEnvelope->event); if ($event instanceof ContentStreamWasForked) { @@ -359,75 +359,77 @@ private function handleRebaseWorkspace( $workspace = $this->requireWorkspace($command->workspaceName, $contentRepository); $baseWorkspace = $this->requireBaseWorkspace($workspace, $contentRepository); - // TODO: please check the code below in-depth. it does: + // 0) close old content stream + $contentRepository->handle( + CloseContentStream::create( + $workspace->currentContentStreamId, + ) + )->block(); + // - fork a new content stream - // - extract the commands from the to-be-rebased content stream; and applies them on the new content stream - $rebasedContentStream = $command->rebasedContentStreamId; + $rebasedContentStreamId = $command->rebasedContentStreamId; $contentRepository->handle( ForkContentStream::create( - $rebasedContentStream, + $command->rebasedContentStreamId, $baseWorkspace->currentContentStreamId, ) )->block(); + $workspaceStreamName = WorkspaceEventStreamName::fromWorkspaceName($command->workspaceName)->getEventStreamName(); $workspaceContentStreamName = ContentStreamEventStreamName::fromContentStreamId( $workspace->currentContentStreamId ); + // - extract the commands from the to-be-rebased content stream; and applies them on the new content stream $originalCommands = $this->extractCommandsFromContentStreamMetadata($workspaceContentStreamName); $rebaseStatistics = new WorkspaceRebaseStatistics(); - foreach ($originalCommands as $i => $originalCommand) { - if (!($originalCommand instanceof RebasableToOtherContentStreamsInterface)) { - throw new \RuntimeException( - 'ERROR: The command ' . get_class($originalCommand) - . ' does not implement RebasableToOtherContentStreamsInterface; but it should!' - ); - } - - // try to apply the command on the rebased content stream - $commandToRebase = $originalCommand->createCopyForContentStream($rebasedContentStream); - try { - $contentRepository->handle($commandToRebase)->block(); - // if we came this far, we know the command was applied successfully. - $rebaseStatistics->commandRebaseSuccess(); - } catch (\Exception $e) { - $fullCommandListSoFar = ''; - for ($a = 0; $a <= $i; $a++) { - $fullCommandListSoFar .= "\n - " . get_class($originalCommands[$a]); - - if ($originalCommands[$a] instanceof \JsonSerializable) { - $fullCommandListSoFar .= ' ' . json_encode($originalCommands[$a]); + $this->withContentStreamIdToUse( + $command->rebasedContentStreamId, + function () use ($originalCommands, $contentRepository, $rebaseStatistics, $workspaceContentStreamName, $baseWorkspace): void { + foreach ($originalCommands as $i => $originalCommand) { + // We no longer need to adjust commands as the workspace stays the same + try { + $contentRepository->handle($originalCommand)->block(); + // if we came this far, we know the command was applied successfully. + $rebaseStatistics->commandRebaseSuccess(); + } catch (\Exception $e) { + $fullCommandListSoFar = ''; + for ($a = 0; $a <= $i; $a++) { + $fullCommandListSoFar .= "\n - " . get_class($originalCommands[$a]); + + if ($originalCommands[$a] instanceof \JsonSerializable) { + $fullCommandListSoFar .= ' ' . json_encode($originalCommands[$a]); + } + } + + $rebaseStatistics->commandRebaseError(sprintf( + "The content stream %s cannot be rebased. Error with command %d (%s)" + . " - see nested exception for details.\n\n The base workspace %s is at content stream %s." + . "\n The full list of commands applied so far is: %s", + $workspaceContentStreamName->value, + $i, + get_class($originalCommand), + $baseWorkspace->workspaceName->value, + $baseWorkspace->currentContentStreamId->value, + $fullCommandListSoFar + ), $e); } } - - $rebaseStatistics->commandRebaseError(sprintf( - "The content stream %s cannot be rebased. Error with command %d (%s)" - . " - see nested exception for details.\n\n The base workspace %s is at content stream %s." - . "\n The full list of commands applied so far is: %s", - $workspaceContentStreamName->value, - $i, - get_class($commandToRebase), - $baseWorkspace->workspaceName->value, - $baseWorkspace->currentContentStreamId->value, - $fullCommandListSoFar - ), $e); } - } - - $streamName = WorkspaceEventStreamName::fromWorkspaceName($command->workspaceName)->getEventStreamName(); + ); // if we got so far without an Exception, we can switch the Workspace's active Content stream. if (!$rebaseStatistics->hasErrors()) { $events = Events::with( new WorkspaceWasRebased( $command->workspaceName, - $rebasedContentStream, + $rebasedContentStreamId, $workspace->currentContentStreamId, ), ); return new EventsToPublish( - $streamName, + $workspaceStreamName, $events, ExpectedVersion::ANY() ); @@ -437,14 +439,14 @@ private function handleRebaseWorkspace( $event = Events::with( new WorkspaceRebaseFailed( $command->workspaceName, - $rebasedContentStream, + $rebasedContentStreamId, $workspace->currentContentStreamId, $rebaseStatistics->getErrors() ) ); return new EventsToPublish( - $streamName, + $workspaceStreamName, $event, ExpectedVersion::ANY() ); @@ -452,7 +454,7 @@ private function handleRebaseWorkspace( } /** - * @return array + * @return array */ private function extractCommandsFromContentStreamMetadata( ContentStreamEventStreamName $workspaceContentStreamName, @@ -474,7 +476,7 @@ private function extractCommandsFromContentStreamMetadata( ), 1547815341); } /** - * The "fromArray" might be declared via {@see RebasableToOtherContentStreamsInterface::fromArray()} + * The "fromArray" might be declared via {@see RebasableToOtherWorkspaceInterface::fromArray()} * or any other command can just implement it. */ $commands[] = $commandToRebaseClass::fromArray($commandToRebasePayload); @@ -499,107 +501,124 @@ private function handlePublishIndividualNodesFromWorkspace( ContentRepository $contentRepository, ): EventsToPublish { $workspace = $this->requireWorkspace($command->workspaceName, $contentRepository); + $oldWorkspaceContentStreamId = $workspace->currentContentStreamId; + $oldWorkspaceContentStreamIdState = $contentRepository->getContentStreamFinder()->findStateForContentStream($oldWorkspaceContentStreamId); + if ($oldWorkspaceContentStreamIdState === null) { + throw new \DomainException('Cannot publish nodes on a workspace with a stateless content stream', 1710410114); + } $baseWorkspace = $this->requireBaseWorkspace($workspace, $contentRepository); - // 1) separate commands in two halves - the ones MATCHING the nodes from the command, and the REST - $workspaceContentStreamName = ContentStreamEventStreamName::fromContentStreamId( - $workspace->currentContentStreamId + // 1) close old content stream + $contentRepository->handle( + CloseContentStream::create($oldWorkspaceContentStreamId) ); - $originalCommands = $this->extractCommandsFromContentStreamMetadata($workspaceContentStreamName); - /** @var RebasableToOtherContentStreamsInterface[] $matchingCommands */ + // 2) separate commands in two parts - the ones MATCHING the nodes from the command, and the REST + /** @var RebasableToOtherWorkspaceInterface[] $matchingCommands */ $matchingCommands = []; - /** @var RebasableToOtherContentStreamsInterface[] $remainingCommands */ $remainingCommands = []; + $this->separateMatchingAndRemainingCommands($command, $workspace, $matchingCommands, $remainingCommands); + /** @var array $matchingCommands */ + /** @var array $remainingCommands */ - foreach ($originalCommands as $originalCommand) { - if (!$originalCommand instanceof MatchableWithNodeIdToPublishOrDiscardInterface) { - throw new \Exception( - 'Command class ' . get_class($originalCommand) . ' does not implement ' - . MatchableWithNodeIdToPublishOrDiscardInterface::class, - 1645393655 - ); - } - if ($this->commandMatchesAtLeastOneNode($originalCommand, $command->nodesToPublish)) { - $matchingCommands[] = $originalCommand; - } else { - $remainingCommands[] = $originalCommand; - } - } - - // 2) fork a new contentStream, based on the base WS, and apply MATCHING - $matchingContentStream = $command->contentStreamIdForMatchingPart; + // 3) fork a new contentStream, based on the base WS, and apply MATCHING $contentRepository->handle( ForkContentStream::create( - $matchingContentStream, + $command->contentStreamIdForMatchingPart, $baseWorkspace->currentContentStreamId, ) )->block(); - foreach ($matchingCommands as $matchingCommand) { - if (!($matchingCommand instanceof RebasableToOtherContentStreamsInterface)) { - throw new \RuntimeException( - 'ERROR: The command ' . get_class($matchingCommand) - . ' does not implement RebasableToOtherContentStreamsInterface; but it should!' - ); - } + try { + // 4) using the new content stream, apply the matching commands + $this->withContentStreamIdToUse( + $command->contentStreamIdForMatchingPart, + function () use ($matchingCommands, $contentRepository, $baseWorkspace, $command): void { + foreach ($matchingCommands as $matchingCommand) { + if (!($matchingCommand instanceof RebasableToOtherWorkspaceInterface)) { + throw new \RuntimeException( + 'ERROR: The command ' . get_class($matchingCommand) + . ' does not implement RebasableToOtherContentStreamsInterface; but it should!' + ); + } + + $contentRepository->handle($matchingCommand->createCopyForWorkspace( + $baseWorkspace->workspaceName, + $command->contentStreamIdForMatchingPart + ))->block(); + } + } + ); - $contentRepository->handle($matchingCommand->createCopyForContentStream($matchingContentStream))->block(); - } + // 5) take EVENTS(MATCHING) and apply them to base WS. + $this->publishContentStream( + $command->contentStreamIdForMatchingPart, + $baseWorkspace->currentContentStreamId + )?->block(); + + // 6) fork a new content stream, based on the base WS, and apply REST + $contentRepository->handle( + ForkContentStream::create( + $command->contentStreamIdForRemainingPart, + $baseWorkspace->currentContentStreamId + ) + )->block(); + + // 7) apply REMAINING commands to the workspace's new content stream + $this->withContentStreamIdToUse( + $command->contentStreamIdForRemainingPart, + function () use ($contentRepository, $remainingCommands) { + foreach ($remainingCommands as $remainingCommand) { + $contentRepository->handle($remainingCommand)->block(); + } + } + ); + } catch (\Exception $exception) { + // 4.E) In case of an exception, reopen the old content stream and remove the newly created + $contentRepository->handle( + ReopenContentStream::create( + $oldWorkspaceContentStreamId, + $oldWorkspaceContentStreamIdState, + ) + )->block(); - // 3) fork a new contentStream, based on the matching content stream, and apply REST - $remainingContentStream = $command->contentStreamIdForRemainingPart; - $contentRepository->handle( - ForkContentStream::create( - $remainingContentStream, - $matchingContentStream, - ) - )->block(); + $contentRepository->handle(RemoveContentStream::create( + $command->contentStreamIdForMatchingPart + ))->block(); - foreach ($remainingCommands as $remainingCommand) { - if (!$remainingCommand instanceof RebasableToOtherContentStreamsInterface) { - throw new \Exception( - 'Command class ' . get_class($remainingCommand) . ' does not implement ' - . RebasableToOtherContentStreamsInterface::class, - 1645393626 - ); + try { + $contentRepository->handle(RemoveContentStream::create( + $command->contentStreamIdForRemainingPart + ))->block(); + } catch (ContentStreamDoesNotExistYet $contentStreamDoesNotExistYet) { + // in case the exception was thrown before 6), this does not exist } - $contentRepository->handle($remainingCommand->createCopyForContentStream($remainingContentStream)) - ->block(); - } - // 4) if that all worked out, take EVENTS(MATCHING) and apply them to base WS. - $this->publishContentStream( - $matchingContentStream, - $baseWorkspace->currentContentStreamId - )?->block(); - - // 5) TODO Re-target base workspace - - // 6) switch content stream to forked WS. - // if we got so far without an Exception, we can switch the Workspace's active Content stream. - $streamName = WorkspaceEventStreamName::fromWorkspaceName($command->workspaceName)->getEventStreamName(); - $events = Events::with( - new WorkspaceWasPartiallyPublished( - $command->workspaceName, - $baseWorkspace->workspaceName, - $remainingContentStream, - $workspace->currentContentStreamId, - $command->nodesToPublish, - ), - ); + throw $exception; + } - // to avoid dangling content streams, we need to remove our temporary content stream (whose events - // have already been published) + // 8) to avoid dangling content streams, we need to remove our temporary content stream (whose events + // have already been published) as well as the old one + $contentRepository->handle(RemoveContentStream::create( + $command->contentStreamIdForMatchingPart + )); $contentRepository->handle(RemoveContentStream::create( - $matchingContentStream + $oldWorkspaceContentStreamId )); - // It is safe to only return the last command result, - // as the commands which were rebased are already executed "synchronously" + $streamName = WorkspaceEventStreamName::fromWorkspaceName($command->workspaceName)->getEventStreamName(); + return new EventsToPublish( $streamName, - $events, + Events::fromArray([ + new WorkspaceWasPartiallyPublished( + $command->workspaceName, + $baseWorkspace->workspaceName, + $command->contentStreamIdForRemainingPart, + $oldWorkspaceContentStreamId, + $command->nodesToPublish + ) + ]), ExpectedVersion::ANY() ); } @@ -619,72 +638,127 @@ private function handleDiscardIndividualNodesFromWorkspace( ContentRepository $contentRepository, ): EventsToPublish { $workspace = $this->requireWorkspace($command->workspaceName, $contentRepository); + $oldWorkspaceContentStreamId = $workspace->currentContentStreamId; + $oldWorkspaceContentStreamIdState = $contentRepository->getContentStreamFinder()->findStateForContentStream($oldWorkspaceContentStreamId); + if ($oldWorkspaceContentStreamIdState === null) { + throw new \DomainException('Cannot discard nodes on a workspace with a stateless content stream', 1710408112); + } $baseWorkspace = $this->requireBaseWorkspace($workspace, $contentRepository); - // 1) filter commands, only keeping the ones NOT MATCHING the nodes from the command - // (i.e. the modifications we want to keep) - $workspaceContentStreamName = ContentStreamEventStreamName::fromContentStreamId( - $workspace->currentContentStreamId - ); + // 1) close old content stream + $contentRepository->handle( + CloseContentStream::create($oldWorkspaceContentStreamId) + )->block(); - $originalCommands = $this->extractCommandsFromContentStreamMetadata($workspaceContentStreamName); + // 2) filter commands, only keeping the ones NOT MATCHING the nodes from the command + // (i.e. the modifications we want to keep) + /** @var array $commandsToDiscard */ + $commandsToDiscard = []; + /** @var array $commandsToKeep */ $commandsToKeep = []; + $this->separateMatchingAndRemainingCommands($command, $workspace, $commandsToDiscard, $commandsToKeep); - foreach ($originalCommands as $originalCommand) { - if (!$originalCommand instanceof MatchableWithNodeIdToPublishOrDiscardInterface) { - throw new \Exception( - 'Command class ' . get_class($originalCommand) . ' does not implement ' - . MatchableWithNodeIdToPublishOrDiscardInterface::class, - 1645393476 - ); - } - if (!$this->commandMatchesAtLeastOneNode($originalCommand, $command->nodesToDiscard)) { - $commandsToKeep[] = $originalCommand; - } - } - - // 2) fork a new contentStream, based on the base WS, and apply the commands to keep - $newContentStream = $command->newContentStreamId; + // 3) fork a new contentStream, based on the base WS, and apply the commands to keep $contentRepository->handle( ForkContentStream::create( - $newContentStream, + $command->newContentStreamId, $baseWorkspace->currentContentStreamId, ) )->block(); - foreach ($commandsToKeep as $commandToKeep) { - if (!$commandToKeep instanceof RebasableToOtherContentStreamsInterface) { - throw new \Exception( - 'Command class ' . get_class($commandToKeep) . ' does not implement ' - . RebasableToOtherContentStreamsInterface::class, - 1645393476 - ); - } - $contentRepository->handle($commandToKeep->createCopyForContentStream($newContentStream)) - ->block(); + // 4) using the new content stream, apply the commands to keep + try { + $this->withContentStreamIdToUse( + $command->newContentStreamId, + function () use ($commandsToKeep, $contentRepository, $baseWorkspace, $command): void { + foreach ($commandsToKeep as $matchingCommand) { + if (!($matchingCommand instanceof RebasableToOtherWorkspaceInterface)) { + throw new \RuntimeException( + 'ERROR: The command ' . get_class($matchingCommand) + . ' does not implement RebasableToOtherContentStreamsInterface; but it should!' + ); + } + + $contentRepository->handle($matchingCommand->createCopyForWorkspace( + $baseWorkspace->workspaceName, + $command->newContentStreamId + ))->block(); + } + } + ); + } catch (\Exception $exception) { + // 4.E) In case of an exception, reopen the old content stream and remove the newly created + $contentRepository->handle( + ReopenContentStream::create( + $oldWorkspaceContentStreamId, + $oldWorkspaceContentStreamIdState, + ) + )->block(); + + $contentRepository->handle(RemoveContentStream::create( + $command->newContentStreamId + ))->block(); + + throw $exception; } - // 3) switch content stream to forked WS. - // if we got so far without an Exception, we can switch the Workspace's active Content stream. + // 5) If everything worked, to avoid dangling content streams, we need to remove the old content stream + $contentRepository->handle(RemoveContentStream::create( + $oldWorkspaceContentStreamId + ))->block(); + $streamName = WorkspaceEventStreamName::fromWorkspaceName($command->workspaceName)->getEventStreamName(); - $events = Events::with( - new WorkspaceWasPartiallyDiscarded( - $command->workspaceName, - $newContentStream, - $workspace->currentContentStreamId, - $command->nodesToDiscard, - ) - ); - // It is safe to only return the last command result, - // as the commands which were rebased are already executed "synchronously" return new EventsToPublish( $streamName, - $events, + Events::with( + new WorkspaceWasPartiallyDiscarded( + $command->workspaceName, + $command->newContentStreamId, + $workspace->currentContentStreamId, + $command->nodesToDiscard, + ) + ), ExpectedVersion::ANY() ); } + + /** + * @param array &$matchingCommands + * @param array &$remainingCommands + */ + private function separateMatchingAndRemainingCommands( + PublishIndividualNodesFromWorkspace|DiscardIndividualNodesFromWorkspace $command, + Workspace $workspace, + array &$matchingCommands, + array &$remainingCommands + ): void { + $workspaceContentStreamName = ContentStreamEventStreamName::fromContentStreamId( + $workspace->currentContentStreamId + ); + + $originalCommands = $this->extractCommandsFromContentStreamMetadata($workspaceContentStreamName); + + foreach ($originalCommands as $originalCommand) { + if (!$originalCommand instanceof MatchableWithNodeIdToPublishOrDiscardInterface) { + throw new \Exception( + 'Command class ' . get_class($originalCommand) . ' does not implement ' + . MatchableWithNodeIdToPublishOrDiscardInterface::class, + 1645393655 + ); + } + $nodeIds = $command instanceof PublishIndividualNodesFromWorkspace + ? $command->nodesToPublish + : $command->nodesToDiscard; + if ($this->commandMatchesAtLeastOneNode($originalCommand, $nodeIds)) { + $matchingCommands[] = $originalCommand; + } else { + $remainingCommands[] = $originalCommand; + } + } + } + private function commandMatchesAtLeastOneNode( MatchableWithNodeIdToPublishOrDiscardInterface $command, NodeIdsToPublishOrDiscard $nodeIds, @@ -916,4 +990,19 @@ private function hasEventsInContentStreamExceptForking( return false; } + + private function withContentStreamIdToUse(ContentStreamId $contentStreamIdToUse, callable $function): void + { + if (ContentStreamIdOverride::$contentStreamIdToUse !== null) { + throw new \Exception('Recursive content stream override is not supported'); + } + ContentStreamIdOverride::useContentStreamId($contentStreamIdToUse); + try { + $function(); + } catch (\Exception $exception) { + ContentStreamIdOverride::useContentStreamId(null); + throw $exception; + } + ContentStreamIdOverride::useContentStreamId(null); + } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCreation/Command/CreateRootWorkspace.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCreation/Command/CreateRootWorkspace.php index 82b6adaf2b9..748c7585684 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCreation/Command/CreateRootWorkspace.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCreation/Command/CreateRootWorkspace.php @@ -27,7 +27,7 @@ * * @api commands are the write-API of the ContentRepository */ -final class CreateRootWorkspace implements CommandInterface +final readonly class CreateRootWorkspace implements CommandInterface { /** * @param WorkspaceName $workspaceName Unique name of the workspace to create @@ -36,10 +36,10 @@ final class CreateRootWorkspace implements CommandInterface * @param ContentStreamId $newContentStreamId The id of the content stream the new workspace is assigned to initially */ private function __construct( - public readonly WorkspaceName $workspaceName, - public readonly WorkspaceTitle $workspaceTitle, - public readonly WorkspaceDescription $workspaceDescription, - public readonly ContentStreamId $newContentStreamId + public WorkspaceName $workspaceName, + public WorkspaceTitle $workspaceTitle, + public WorkspaceDescription $workspaceDescription, + public ContentStreamId $newContentStreamId ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCreation/Command/CreateWorkspace.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCreation/Command/CreateWorkspace.php index 9971f046acd..ac79a30cf0d 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCreation/Command/CreateWorkspace.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceCreation/Command/CreateWorkspace.php @@ -26,7 +26,7 @@ * * @api commands are the write-API of the ContentRepository */ -final class CreateWorkspace implements CommandInterface +final readonly class CreateWorkspace implements CommandInterface { /** * @param WorkspaceName $workspaceName Unique name of the workspace to create @@ -37,12 +37,12 @@ final class CreateWorkspace implements CommandInterface * @param UserId|null $workspaceOwner Owner of the new workspace (optional) */ private function __construct( - public readonly WorkspaceName $workspaceName, - public readonly WorkspaceName $baseWorkspaceName, - public readonly WorkspaceTitle $workspaceTitle, - public readonly WorkspaceDescription $workspaceDescription, - public readonly ContentStreamId $newContentStreamId, - public readonly ?UserId $workspaceOwner, + public WorkspaceName $workspaceName, + public WorkspaceName $baseWorkspaceName, + public WorkspaceTitle $workspaceTitle, + public WorkspaceDescription $workspaceDescription, + public ContentStreamId $newContentStreamId, + public ?UserId $workspaceOwner, ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/ChangeBaseWorkspace.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/ChangeBaseWorkspace.php index 16bf8773721..2b28a64d602 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/ChangeBaseWorkspace.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/ChangeBaseWorkspace.php @@ -13,7 +13,7 @@ * * @api commands are the write-API of the ContentRepository */ -final class ChangeBaseWorkspace implements CommandInterface +final readonly class ChangeBaseWorkspace implements CommandInterface { /** * @param WorkspaceName $workspaceName Name of the affected workspace @@ -21,9 +21,9 @@ final class ChangeBaseWorkspace implements CommandInterface * @param ContentStreamId $newContentStreamId The id of the new content stream id that will be assigned to the workspace */ private function __construct( - public readonly WorkspaceName $workspaceName, - public readonly WorkspaceName $baseWorkspaceName, - public readonly ContentStreamId $newContentStreamId, + public WorkspaceName $workspaceName, + public WorkspaceName $baseWorkspaceName, + public ContentStreamId $newContentStreamId, ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/ChangeWorkspaceOwner.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/ChangeWorkspaceOwner.php index 228321c4cfe..e5b36e4eae2 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/ChangeWorkspaceOwner.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/ChangeWorkspaceOwner.php @@ -13,15 +13,15 @@ * * @api commands are the write-API of the ContentRepository */ -final class ChangeWorkspaceOwner implements CommandInterface +final readonly class ChangeWorkspaceOwner implements CommandInterface { /** * @param WorkspaceName $workspaceName Name of the workspace to change the owner for * @param string|null $newWorkspaceOwner The id of the new workspace owner or NULL to remove the owner */ private function __construct( - public readonly WorkspaceName $workspaceName, - public readonly ?string $newWorkspaceOwner, + public WorkspaceName $workspaceName, + public ?string $newWorkspaceOwner, ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/DeleteWorkspace.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/DeleteWorkspace.php index f685b459506..ab182194ba0 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/DeleteWorkspace.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/DeleteWorkspace.php @@ -12,13 +12,13 @@ * * @api commands are the write-API of the ContentRepository */ -final class DeleteWorkspace implements CommandInterface +final readonly class DeleteWorkspace implements CommandInterface { /** * @param WorkspaceName $workspaceName Name of the workspace to delete */ private function __construct( - public readonly WorkspaceName $workspaceName, + public WorkspaceName $workspaceName, ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/RenameWorkspace.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/RenameWorkspace.php index 4f2fc517517..38c91a85f11 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/RenameWorkspace.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceModification/Command/RenameWorkspace.php @@ -14,7 +14,7 @@ * * @api commands are the write-API of the ContentRepository */ -final class RenameWorkspace implements CommandInterface +final readonly class RenameWorkspace implements CommandInterface { /** * @param WorkspaceName $workspaceName Name of the workspace to rename @@ -22,9 +22,9 @@ final class RenameWorkspace implements CommandInterface * @param WorkspaceDescription $workspaceDescription New description of the workspace */ private function __construct( - public readonly WorkspaceName $workspaceName, - public readonly WorkspaceTitle $workspaceTitle, - public readonly WorkspaceDescription $workspaceDescription, + public WorkspaceName $workspaceName, + public WorkspaceTitle $workspaceTitle, + public WorkspaceDescription $workspaceDescription, ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/DiscardIndividualNodesFromWorkspace.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/DiscardIndividualNodesFromWorkspace.php index 44b3e6d4b24..fec436be434 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/DiscardIndividualNodesFromWorkspace.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/DiscardIndividualNodesFromWorkspace.php @@ -24,7 +24,7 @@ * * @api commands are the write-API of the ContentRepository */ -final class DiscardIndividualNodesFromWorkspace implements CommandInterface +final readonly class DiscardIndividualNodesFromWorkspace implements CommandInterface { /** * @param WorkspaceName $workspaceName Name of the affected workspace @@ -32,9 +32,9 @@ final class DiscardIndividualNodesFromWorkspace implements CommandInterface * @param ContentStreamId $newContentStreamId The id of the new content stream, that will contain the remaining changes which were not discarded */ private function __construct( - public readonly WorkspaceName $workspaceName, - public readonly NodeIdsToPublishOrDiscard $nodesToDiscard, - public readonly ContentStreamId $newContentStreamId + public WorkspaceName $workspaceName, + public NodeIdsToPublishOrDiscard $nodesToDiscard, + public ContentStreamId $newContentStreamId ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/DiscardWorkspace.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/DiscardWorkspace.php index 3e05fe9086b..8771ec296d8 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/DiscardWorkspace.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/DiscardWorkspace.php @@ -23,15 +23,15 @@ * * @api commands are the write-API of the ContentRepository */ -final class DiscardWorkspace implements CommandInterface +final readonly class DiscardWorkspace implements CommandInterface { /** * @param WorkspaceName $workspaceName Name of the affected workspace * @param ContentStreamId $newContentStreamId The id of the newly created content stream that will contain the remaining changes that were not discarded */ private function __construct( - public readonly WorkspaceName $workspaceName, - public readonly ContentStreamId $newContentStreamId + public WorkspaceName $workspaceName, + public ContentStreamId $newContentStreamId ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php index 5f4100b6e2f..452eeeeec54 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishIndividualNodesFromWorkspace.php @@ -24,7 +24,7 @@ * * @api commands are the write-API of the ContentRepository */ -final class PublishIndividualNodesFromWorkspace implements CommandInterface +final readonly class PublishIndividualNodesFromWorkspace implements CommandInterface { /** * @param WorkspaceName $workspaceName Name of the affected workspace @@ -33,10 +33,10 @@ final class PublishIndividualNodesFromWorkspace implements CommandInterface * @param ContentStreamId $contentStreamIdForRemainingPart The id of the new content stream that will contain all remaining events {@see self::withContentStreamIdForRemainingPart()} */ private function __construct( - public readonly WorkspaceName $workspaceName, - public readonly NodeIdsToPublishOrDiscard $nodesToPublish, - public readonly ContentStreamId $contentStreamIdForMatchingPart, - public readonly ContentStreamId $contentStreamIdForRemainingPart + public WorkspaceName $workspaceName, + public NodeIdsToPublishOrDiscard $nodesToPublish, + public ContentStreamId $contentStreamIdForMatchingPart, + public ContentStreamId $contentStreamIdForRemainingPart ) { } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php index 8d905ea5747..5364d13054d 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Command/PublishWorkspace.php @@ -15,6 +15,7 @@ namespace Neos\ContentRepository\Core\Feature\WorkspacePublication\Command; use Neos\ContentRepository\Core\CommandHandler\CommandInterface; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** @@ -22,21 +23,33 @@ * * @api commands are the write-API of the ContentRepository */ -final class PublishWorkspace implements CommandInterface +final readonly class PublishWorkspace implements CommandInterface { /** * @param WorkspaceName $workspaceName Name of the workspace to publish */ private function __construct( - public readonly WorkspaceName $workspaceName, + public WorkspaceName $workspaceName, + public ContentStreamId $newContentStreamId, ) { } + /** + * During the publish process, we create a new content stream. + * + * This method adds its ID, so that the command + * can run fully deterministic - we need this for the test cases. + */ + public function withNewContentStreamId(ContentStreamId $newContentStreamId): self + { + return new self($this->workspaceName, $newContentStreamId); + } + /** * @param WorkspaceName $workspaceName Name of the workspace to publish */ public static function create(WorkspaceName $workspaceName): self { - return new self($workspaceName); + return new self($workspaceName, ContentStreamId::create()); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdToPublishOrDiscard.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdToPublishOrDiscard.php index fc82430f4cf..99c09bcf96f 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdToPublishOrDiscard.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspacePublication/Dto/NodeIdToPublishOrDiscard.php @@ -15,10 +15,8 @@ namespace Neos\ContentRepository\Core\Feature\WorkspacePublication\Dto; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; -use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\DiscardIndividualNodesFromWorkspace; -use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\PublishIndividualNodesFromWorkspace; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * A node id (Content Stream, NodeAggregateId, DimensionSpacePoint); used when @@ -29,12 +27,13 @@ * * @api used as part of commands */ -final class NodeIdToPublishOrDiscard implements \JsonSerializable +final readonly class NodeIdToPublishOrDiscard implements \JsonSerializable { public function __construct( - public readonly ContentStreamId $contentStreamId, - public readonly NodeAggregateId $nodeAggregateId, - public readonly DimensionSpacePoint $dimensionSpacePoint, + /** @todo do we really need this? should be unique per command, not per node in the command */ + public WorkspaceName $workspaceName, + public NodeAggregateId $nodeAggregateId, + public DimensionSpacePoint $dimensionSpacePoint, ) { } @@ -44,7 +43,7 @@ public function __construct( public static function fromArray(array $array): self { return new self( - ContentStreamId::fromString($array['contentStreamId']), + WorkspaceName::fromString($array['workspaceName']), NodeAggregateId::fromString($array['nodeAggregateId']), DimensionSpacePoint::fromArray($array['dimensionSpacePoint']), ); @@ -55,10 +54,6 @@ public static function fromArray(array $array): self */ public function jsonSerialize(): array { - return [ - 'contentStreamId' => $this->contentStreamId, - 'nodeAggregateId' => $this->nodeAggregateId, - 'dimensionSpacePoint' => $this->dimensionSpacePoint, - ]; + return get_object_vars($this); } } diff --git a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php index dc3a67382f4..867bf88806e 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php +++ b/Neos.ContentRepository.Core/Classes/Feature/WorkspaceRebase/Command/RebaseWorkspace.php @@ -23,15 +23,15 @@ * * @api commands are the write-API of the ContentRepository */ -final class RebaseWorkspace implements CommandInterface +final readonly class RebaseWorkspace implements CommandInterface { /** * @param WorkspaceName $workspaceName Name of the workspace that should be rebased * @param ContentStreamId $rebasedContentStreamId The id of the new content stream which is created during the rebase */ private function __construct( - public readonly WorkspaceName $workspaceName, - public readonly ContentStreamId $rebasedContentStreamId + public WorkspaceName $workspaceName, + public ContentStreamId $rebasedContentStreamId ) { } diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php index 97560f5668b..1ea87139400 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php @@ -1,7 +1,7 @@ removed from all other projections │◀─┘ - * └────────────────────────────────────────┘ Cleanup - * │ - * ▼ - * ┌────────────────────────────────────────┐ - * │ completely deleted from event stream │ - * └────────────────────────────────────────┘ + * @see ContentStreamState * * @internal */ -final class ContentStreamFinder implements ProjectionStateInterface +final readonly class ContentStreamFinder implements ProjectionStateInterface { - /** - * the content stream was created, but not yet assigned to a workspace. - * - * **temporary state** which should not appear if the system is idle (for content streams which are used with workspaces). - */ - public const STATE_CREATED = 'CREATED'; - - /** - * STATE_FORKED means the content stream was forked from an existing content stream, but not yet assigned - * to a workspace. - * - * **temporary state** which should not appear if the system is idle (for content streams which are used with workspaces). - */ - public const STATE_FORKED = 'FORKED'; - - /** - * the content stream is currently referenced as the "active" content stream by a workspace. - */ - public const STATE_IN_USE_BY_WORKSPACE = 'IN_USE_BY_WORKSPACE'; - - /** - * a workspace was tried to be rebased, and during the rebase an error occured. This is the content stream - * which contains the errored state - so that we can recover content from it (probably manually) - */ - public const STATE_REBASE_ERROR = 'REBASE_ERROR'; - - /** - * the content stream is not used anymore, and can be removed. - */ - public const STATE_NO_LONGER_IN_USE = 'NO_LONGER_IN_USE'; - public function __construct( - private readonly DbalClientInterface $client, - private readonly string $tableName, + private DbalClientInterface $client, + private string $tableName, ) { } @@ -128,13 +69,13 @@ public function findAllIds(): iterable public function findUnusedContentStreams(bool $findTemporaryContentStreams): iterable { $states = [ - self::STATE_NO_LONGER_IN_USE, - self::STATE_REBASE_ERROR, + ContentStreamState::STATE_NO_LONGER_IN_USE, + ContentStreamState::STATE_REBASE_ERROR, ]; if ($findTemporaryContentStreams === true) { - $states[] = self::STATE_CREATED; - $states[] = self::STATE_FORKED; + $states[] = ContentStreamState::STATE_CREATED; + $states[] = ContentStreamState::STATE_FORKED; } $connection = $this->client->getConnection(); @@ -142,23 +83,23 @@ public function findUnusedContentStreams(bool $findTemporaryContentStreams): ite ' SELECT contentstreamid FROM ' . $this->tableName . ' WHERE removed = FALSE - AND state IN (:state) + AND state IN (:states) ', [ - 'state' => $states + 'states' => array_map( + fn (ContentStreamState $contentStreamState): string => $contentStreamState->value, + $states + ) ], [ - 'state' => Connection::PARAM_STR_ARRAY + 'states' => Connection::PARAM_STR_ARRAY ] )->fetchFirstColumn(); + return array_map(ContentStreamId::fromString(...), $contentStreamIds); } - /** - * @param ContentStreamId $contentStreamId - * @return string one of the self::STATE_* constants - */ - public function findStateForContentStream(ContentStreamId $contentStreamId): ?string + public function findStateForContentStream(ContentStreamId $contentStreamId): ?ContentStreamState { $connection = $this->client->getConnection(); /* @var $state string|false */ @@ -173,11 +114,7 @@ public function findStateForContentStream(ContentStreamId $contentStreamId): ?st ] )->fetchOne(); - if ($state === false) { - return null; - } - - return $state; + return ContentStreamState::tryFrom($state ?: ''); } /** @@ -216,7 +153,7 @@ public function findUnusedAndRemovedContentStreams(): iterable ) ', [ - 'inUseState' => self::STATE_IN_USE_BY_WORKSPACE + 'inUseState' => ContentStreamState::STATE_IN_USE_BY_WORKSPACE->value ] )->fetchFirstColumn(); return array_map(ContentStreamId::fromString(...), $contentStreamIds); diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentStream/ContentStreamProjection.php b/Neos.ContentRepository.Core/Classes/Projection/ContentStream/ContentStreamProjection.php index d6310dff799..b9e658d2097 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentStream/ContentStreamProjection.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentStream/ContentStreamProjection.php @@ -22,10 +22,13 @@ use Doctrine\DBAL\Types\Types; use Neos\ContentRepository\Core\EventStore\EventInterface; use Neos\ContentRepository\Core\Feature\Common\EmbedsContentStreamAndNodeAggregateId; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Event\ContentStreamWasReopened; use Neos\ContentRepository\Core\Feature\ContentStreamCreation\Event\ContentStreamWasCreated; use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; +use Neos\ContentRepository\Core\Feature\ContentStreamClosing\Event\ContentStreamWasClosed; use Neos\ContentRepository\Core\Feature\ContentStreamForking\Event\ContentStreamWasForked; use Neos\ContentRepository\Core\Feature\ContentStreamRemoval\Event\ContentStreamWasRemoved; +use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Event\DimensionShineThroughWasAdded; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Event\RootWorkspaceWasCreated; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Event\WorkspaceWasCreated; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Event\WorkspaceWasDiscarded; @@ -44,6 +47,7 @@ use Neos\ContentRepository\Core\Projection\ProjectionStateInterface; use Neos\ContentRepository\Core\Projection\ProjectionStatus; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamState; use Neos\EventStore\Model\Event\SequenceNumber; use Neos\EventStore\Model\EventEnvelope; @@ -157,7 +161,10 @@ public function canHandle(EventInterface $event): bool WorkspaceWasPublished::class, WorkspaceWasRebased::class, WorkspaceRebaseFailed::class, + ContentStreamWasClosed::class, + ContentStreamWasReopened::class, ContentStreamWasRemoved::class, + DimensionShineThroughWasAdded::class, ]) || $event instanceof EmbedsContentStreamAndNodeAggregateId; } @@ -179,7 +186,10 @@ public function apply(EventInterface $event, EventEnvelope $eventEnvelope): void WorkspaceWasPublished::class => $this->whenWorkspaceWasPublished($event), WorkspaceWasRebased::class => $this->whenWorkspaceWasRebased($event), WorkspaceRebaseFailed::class => $this->whenWorkspaceRebaseFailed($event), + ContentStreamWasClosed::class => $this->whenContentStreamWasClosed($event, $eventEnvelope), + ContentStreamWasReopened::class => $this->whenContentStreamWasReopened($event, $eventEnvelope), ContentStreamWasRemoved::class => $this->whenContentStreamWasRemoved($event, $eventEnvelope), + DimensionShineThroughWasAdded::class => $this->whenDimensionShineThroughWasAdded($event, $eventEnvelope), default => throw new \InvalidArgumentException(sprintf('Unsupported event %s', get_debug_type($event))), }; } @@ -205,28 +215,26 @@ private function whenContentStreamWasCreated(ContentStreamWasCreated $event, Eve $this->getDatabaseConnection()->insert($this->tableName, [ 'contentStreamId' => $event->contentStreamId->value, 'version' => self::extractVersion($eventEnvelope), - 'state' => ContentStreamFinder::STATE_CREATED, + 'state' => ContentStreamState::STATE_CREATED->value, ]); } private function whenRootWorkspaceWasCreated(RootWorkspaceWasCreated $event): void { // the content stream is in use now - $this->getDatabaseConnection()->update($this->tableName, [ - 'state' => ContentStreamFinder::STATE_IN_USE_BY_WORKSPACE, - ], [ - 'contentStreamId' => $event->newContentStreamId->value - ]); + $this->updateStateForContentStream( + $event->newContentStreamId, + ContentStreamState::STATE_IN_USE_BY_WORKSPACE, + ); } private function whenWorkspaceWasCreated(WorkspaceWasCreated $event): void { // the content stream is in use now - $this->getDatabaseConnection()->update($this->tableName, [ - 'state' => ContentStreamFinder::STATE_IN_USE_BY_WORKSPACE, - ], [ - 'contentStreamId' => $event->newContentStreamId->value - ]); + $this->updateStateForContentStream( + $event->newContentStreamId, + ContentStreamState::STATE_IN_USE_BY_WORKSPACE, + ); } private function whenContentStreamWasForked(ContentStreamWasForked $event, EventEnvelope $eventEnvelope): void @@ -235,7 +243,7 @@ private function whenContentStreamWasForked(ContentStreamWasForked $event, Event 'contentStreamId' => $event->newContentStreamId->value, 'version' => self::extractVersion($eventEnvelope), 'sourceContentStreamId' => $event->sourceContentStreamId->value, - 'state' => ContentStreamFinder::STATE_FORKED, + 'state' => ContentStreamState::STATE_FORKED->value ]); } @@ -244,13 +252,13 @@ private function whenWorkspaceWasDiscarded(WorkspaceWasDiscarded $event): void // the new content stream is in use now $this->updateStateForContentStream( $event->newContentStreamId, - ContentStreamFinder::STATE_IN_USE_BY_WORKSPACE + ContentStreamState::STATE_IN_USE_BY_WORKSPACE ); // the previous content stream is no longer in use $this->updateStateForContentStream( $event->previousContentStreamId, - ContentStreamFinder::STATE_NO_LONGER_IN_USE + ContentStreamState::STATE_NO_LONGER_IN_USE ); } @@ -259,13 +267,13 @@ private function whenWorkspaceWasPartiallyDiscarded(WorkspaceWasPartiallyDiscard // the new content stream is in use now $this->updateStateForContentStream( $event->newContentStreamId, - ContentStreamFinder::STATE_IN_USE_BY_WORKSPACE + ContentStreamState::STATE_IN_USE_BY_WORKSPACE ); // the previous content stream is no longer in use $this->updateStateForContentStream( $event->previousContentStreamId, - ContentStreamFinder::STATE_NO_LONGER_IN_USE + ContentStreamState::STATE_NO_LONGER_IN_USE ); } @@ -274,13 +282,13 @@ private function whenWorkspaceWasPartiallyPublished(WorkspaceWasPartiallyPublish // the new content stream is in use now $this->updateStateForContentStream( $event->newSourceContentStreamId, - ContentStreamFinder::STATE_IN_USE_BY_WORKSPACE + ContentStreamState::STATE_IN_USE_BY_WORKSPACE ); // the previous content stream is no longer in use $this->updateStateForContentStream( $event->previousSourceContentStreamId, - ContentStreamFinder::STATE_NO_LONGER_IN_USE + ContentStreamState::STATE_NO_LONGER_IN_USE ); } @@ -289,13 +297,13 @@ private function whenWorkspaceWasPublished(WorkspaceWasPublished $event): void // the new content stream is in use now $this->updateStateForContentStream( $event->newSourceContentStreamId, - ContentStreamFinder::STATE_IN_USE_BY_WORKSPACE + ContentStreamState::STATE_IN_USE_BY_WORKSPACE ); // the previous content stream is no longer in use $this->updateStateForContentStream( $event->previousSourceContentStreamId, - ContentStreamFinder::STATE_NO_LONGER_IN_USE + ContentStreamState::STATE_NO_LONGER_IN_USE ); } @@ -304,13 +312,13 @@ private function whenWorkspaceWasRebased(WorkspaceWasRebased $event): void // the new content stream is in use now $this->updateStateForContentStream( $event->newContentStreamId, - ContentStreamFinder::STATE_IN_USE_BY_WORKSPACE + ContentStreamState::STATE_IN_USE_BY_WORKSPACE ); // the previous content stream is no longer in use $this->updateStateForContentStream( $event->previousContentStreamId, - ContentStreamFinder::STATE_NO_LONGER_IN_USE + ContentStreamState::STATE_NO_LONGER_IN_USE ); } @@ -318,8 +326,34 @@ private function whenWorkspaceRebaseFailed(WorkspaceRebaseFailed $event): void { $this->updateStateForContentStream( $event->candidateContentStreamId, - ContentStreamFinder::STATE_REBASE_ERROR + ContentStreamState::STATE_REBASE_ERROR + ); + } + + private function whenContentStreamWasClosed(ContentStreamWasClosed $event, EventEnvelope $eventEnvelope): void + { + $this->updateStateForContentStream( + $event->contentStreamId, + ContentStreamState::STATE_CLOSED, + ); + $this->getDatabaseConnection()->update($this->tableName, [ + 'version' => self::extractVersion($eventEnvelope), + ], [ + 'contentStreamId' => $event->contentStreamId->value + ]); + } + + private function whenContentStreamWasReopened(ContentStreamWasReopened $event, EventEnvelope $eventEnvelope): void + { + $this->updateStateForContentStream( + $event->contentStreamId, + $event->previousState, ); + $this->getDatabaseConnection()->update($this->tableName, [ + 'version' => self::extractVersion($eventEnvelope), + ], [ + 'contentStreamId' => $event->contentStreamId->value + ]); } private function whenContentStreamWasRemoved(ContentStreamWasRemoved $event, EventEnvelope $eventEnvelope): void @@ -332,10 +366,19 @@ private function whenContentStreamWasRemoved(ContentStreamWasRemoved $event, Eve ]); } - private function updateStateForContentStream(ContentStreamId $contentStreamId, string $state): void + private function whenDimensionShineThroughWasAdded(DimensionShineThroughWasAdded $event, EventEnvelope $eventEnvelope): void + { + $this->getDatabaseConnection()->update($this->tableName, [ + 'version' => self::extractVersion($eventEnvelope), + ], [ + 'contentStreamId' => $event->contentStreamId->value + ]); + } + + private function updateStateForContentStream(ContentStreamId $contentStreamId, ContentStreamState $state): void { $this->getDatabaseConnection()->update($this->tableName, [ - 'state' => $state, + 'state' => $state->value, ], [ 'contentStreamId' => $contentStreamId->value ]); diff --git a/Neos.ContentRepository.Core/Classes/Service/ContentRepositoryBootstrapper.php b/Neos.ContentRepository.Core/Classes/Service/ContentRepositoryBootstrapper.php index 578fe1c1eb3..70512980b83 100644 --- a/Neos.ContentRepository.Core/Classes/Service/ContentRepositoryBootstrapper.php +++ b/Neos.ContentRepository.Core/Classes/Service/ContentRepositoryBootstrapper.php @@ -10,7 +10,6 @@ use Neos\ContentRepository\Core\Projection\Workspace\Workspace; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\NodeType\NodeTypeName; -use Neos\ContentRepository\Core\SharedModel\User\UserId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceDescription; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; @@ -22,10 +21,10 @@ * * @api */ -final class ContentRepositoryBootstrapper +final readonly class ContentRepositoryBootstrapper { private function __construct( - private readonly ContentRepository $contentRepository, + private ContentRepository $contentRepository, ) { } @@ -38,22 +37,28 @@ public static function create(ContentRepository $contentRepository): self * Retrieve the Content Stream ID of the "live" workspace. * If the "live" workspace does not exist yet, it will be created */ - public function getOrCreateLiveContentStream(): ContentStreamId + public function getOrCreateLiveWorkspace(): Workspace { - $liveWorkspace = $this->contentRepository->getWorkspaceFinder()->findOneByName(WorkspaceName::forLive()); + $liveWorkspaceName = WorkspaceName::forLive(); + $liveWorkspace = $this->contentRepository->getWorkspaceFinder()->findOneByName($liveWorkspaceName); if ($liveWorkspace instanceof Workspace) { - return $liveWorkspace->currentContentStreamId; + return $liveWorkspace; } - $liveContentStreamId = ContentStreamId::create(); + $this->contentRepository->handle( CreateRootWorkspace::create( - WorkspaceName::forLive(), + $liveWorkspaceName, WorkspaceTitle::fromString('Live'), WorkspaceDescription::fromString('Public live workspace'), - $liveContentStreamId + ContentStreamId::create() ) )->block(); - return $liveContentStreamId; + $liveWorkspace = $this->contentRepository->getWorkspaceFinder()->findOneByName($liveWorkspaceName); + if (!$liveWorkspace) { + throw new \Exception('Live workspace creation failed', 1699002435); + } + + return $liveWorkspace; } /** @@ -61,10 +66,11 @@ public function getOrCreateLiveContentStream(): ContentStreamId * If no root node of the specified $rootNodeTypeName exist, it will be created */ public function getOrCreateRootNodeAggregate( - ContentStreamId $contentStreamId, + Workspace $workspace, NodeTypeName $rootNodeTypeName ): NodeAggregateId { try { + $contentStreamId = $workspace->currentContentStreamId; return $this->contentRepository->getContentGraph()->findRootNodeAggregateByType( $contentStreamId, $rootNodeTypeName @@ -74,7 +80,7 @@ public function getOrCreateRootNodeAggregate( } catch (\Exception $exception) { $rootNodeAggregateId = NodeAggregateId::create(); $this->contentRepository->handle(CreateRootNodeAggregateWithNode::create( - $contentStreamId, + $workspace->workspaceName, $rootNodeAggregateId, $rootNodeTypeName, ))->block(); diff --git a/Neos.ContentRepository.Core/Classes/SharedModel/Exception/ContentStreamIsClosed.php b/Neos.ContentRepository.Core/Classes/SharedModel/Exception/ContentStreamIsClosed.php new file mode 100644 index 00000000000..5c08d80f642 --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/SharedModel/Exception/ContentStreamIsClosed.php @@ -0,0 +1,24 @@ + removed from all other projections │◀─┘ + * └────────────────────────────────────────┘ Cleanup + * │ + * ▼ + * ┌────────────────────────────────────────┐ + * │ completely deleted from event stream │ + * └────────────────────────────────────────┘ + * + * @api + */ +enum ContentStreamState: string implements \JsonSerializable +{ + /** + * the content stream was created, but not yet assigned to a workspace. + * + * **temporary state** which should not appear if the system is idle (for content streams which are used with workspaces). + */ + case STATE_CREATED = 'CREATED'; + + /** + * STATE_FORKED means the content stream was forked from an existing content stream, but not yet assigned + * to a workspace. + * + * **temporary state** which should not appear if the system is idle (for content streams which are used with workspaces). + */ + case STATE_FORKED = 'FORKED'; + + /** + * the content stream is currently referenced as the "active" content stream by a workspace. + */ + case STATE_IN_USE_BY_WORKSPACE = 'IN_USE_BY_WORKSPACE'; + + /** + * a workspace was tried to be rebased, and during the rebase an error occured. This is the content stream + * which contains the errored state - so that we can recover content from it (probably manually) + */ + case STATE_REBASE_ERROR = 'REBASE_ERROR'; + + /** + * the content stream was closed and must no longer accept new events + */ + case STATE_CLOSED = 'CLOSED'; + + /** + * the content stream is not used anymore, and can be removed. + */ + case STATE_NO_LONGER_IN_USE = 'NO_LONGER_IN_USE'; + + public static function fromString(string $value): self + { + return self::from($value); + } + + public function jsonSerialize(): string + { + return $this->value; + } +} diff --git a/Neos.ContentRepository.Core/Tests/Unit/DimensionSpace/ContentSubgraphVariationWeightTest.php b/Neos.ContentRepository.Core/Tests/Unit/DimensionSpace/ContentSubgraphVariationWeightTest.php index 1165962827a..8ffb3d4679b 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/DimensionSpace/ContentSubgraphVariationWeightTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/DimensionSpace/ContentSubgraphVariationWeightTest.php @@ -125,7 +125,7 @@ public function testNormalizeCorrectlyCalculatesNormalizedWeight(int $weightNorm /** * @return array */ - public function normalizationProvider(): array + public static function normalizationProvider(): array { return [ [ diff --git a/Neos.ContentRepository.Core/Tests/Unit/Infrastructure/Property/PropertyTypeTest.php b/Neos.ContentRepository.Core/Tests/Unit/Infrastructure/Property/PropertyTypeTest.php index e89220a81c8..d0adea86b2a 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/Infrastructure/Property/PropertyTypeTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/Infrastructure/Property/PropertyTypeTest.php @@ -51,7 +51,7 @@ public function testIsMatchedBy(array $declarationsByType, array $validValues, a } } - public function declarationAndValueProvider(): array + public static function declarationAndValueProvider(): array { $bool = true; $int = 42; @@ -154,7 +154,7 @@ public function testGetSerializationType(array $declaredTypes, string $expectedS } } - public function declarationTypeProvider(): array + public static function declarationTypeProvider(): array { return [ [['bool', 'boolean'], 'boolean'], diff --git a/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/NodePropertyValue/PropertyValueCriteriaParserTest.php b/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/NodePropertyValue/PropertyValueCriteriaParserTest.php index 7f93a678291..fb0cdb00ef8 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/NodePropertyValue/PropertyValueCriteriaParserTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/NodePropertyValue/PropertyValueCriteriaParserTest.php @@ -21,7 +21,7 @@ class PropertyValueCriteriaParserTest extends TestCase { - public function validQueries(): \Generator + public static function validQueries(): \Generator { yield ['query' => 'prop1 = "foo"', 'expectedResult' => ['type' => 'PropertyValueEquals', 'propertyName' => 'prop1', 'value' => 'foo', 'caseSensitive' => true]]; yield ['query' => 'prop1= \'foo\'', 'expectedResult' => ['type' => 'PropertyValueEquals', 'propertyName' => 'prop1', 'value' => 'foo', 'caseSensitive' => true]]; @@ -57,7 +57,7 @@ public function parseValidQueriesTest(string $query, array $expectedResult): voi self::assertSame($expectedResult, self::propertyValueCriteriaToArray(PropertyValueCriteriaParser::parse($query))); } - public function invalidQueries(): \Generator + public static function invalidQueries(): \Generator { yield ['query' => '', 'expectedExceptionMessage' => "Query must not be empty"]; yield ['query' => ' ', 'expectedExceptionMessage' => "Query must not be empty"]; diff --git a/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/Ordering/OrderingTest.php b/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/Ordering/OrderingTest.php index d8a74e9fff7..e37cea590b4 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/Ordering/OrderingTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/Ordering/OrderingTest.php @@ -58,7 +58,7 @@ public function iterationTest(): void ->andByTimestampField(TimestampField::CREATED, OrderingDirection::ASCENDING) ->andByProperty(PropertyName::fromString('someOtherProperty'), OrderingDirection::DESCENDING) ->andByTimestampField(TimestampField::ORIGINAL_LAST_MODIFIED, OrderingDirection::DESCENDING); - self::assertCount(4, $ordering); + self::assertCount(4, iterator_to_array($ordering)); } /** @@ -77,7 +77,7 @@ public function fromArrayTest(): void self::assertOrderingEquals($array, $ordering); } - public function invalidOrderingArrays(): \Generator + public static function invalidOrderingArrays(): \Generator { yield ['empty array' => []]; yield ['empty nested array' => [[]]]; diff --git a/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/Pagination/PaginationTest.php b/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/Pagination/PaginationTest.php index fa1a35dddce..8d882ec9ea6 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/Pagination/PaginationTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/Projection/ContentGraph/Filter/Pagination/PaginationTest.php @@ -16,7 +16,7 @@ class PaginationTest extends TestCase { - public function invalidLimitAndOffsets(): \Generator + public static function invalidLimitAndOffsets(): \Generator { yield ['limit' => 0, 'offset' => 0]; yield ['limit' => 1, 'offset' => -1]; @@ -71,7 +71,7 @@ public function fromArrayCastsNumericStrings(): void self::assertSame(23, $pagination->offset); } - public function invalidLimitAndOffsetArrays(): \Generator + public static function invalidLimitAndOffsetArrays(): \Generator { yield ['no numeric limit' => ['limit' => 'not a number']]; yield ['no numeric offset' => ['offset' => 'not a number']]; diff --git a/Neos.ContentRepository.Core/Tests/Unit/SharedModel/Node/NodeNameTest.php b/Neos.ContentRepository.Core/Tests/Unit/SharedModel/Node/NodeNameTest.php index ddc1a227210..e32e6af31b1 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/SharedModel/Node/NodeNameTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/SharedModel/Node/NodeNameTest.php @@ -25,9 +25,9 @@ class NodeNameTest extends TestCase /** * A data provider returning titles and the expected valid node names based on those. * - * @return array + * @return array> */ - public function sourcesAndNodeNames() + public static function sourcesAndNodeNames(): array { return [ ['Überlandstraßen; adé', 'uberlandstrassen-ade'], diff --git a/Neos.ContentRepository.Export/Tests/Behavior/Features/Export/Export.feature b/Neos.ContentRepository.Export/Tests/Behavior/Features/Export/Export.feature index 92c6208fe87..34f3efa5f8e 100644 --- a/Neos.ContentRepository.Export/Tests/Behavior/Features/Export/Export.feature +++ b/Neos.ContentRepository.Export/Tests/Behavior/Features/Export/Export.feature @@ -17,9 +17,9 @@ Feature: As a user of the CR I want to export the event stream | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: @@ -39,7 +39,7 @@ Feature: As a user of the CR I want to export the event stream When the events are exported Then I expect the following jsonl: """ - {"identifier":"random-event-uuid","type":"RootNodeAggregateWithNodeWasCreated","payload":{"contentStreamId":"cs-identifier","nodeAggregateId":"lady-eleonode-rootford","nodeTypeName":"Neos.ContentRepository:Root","coveredDimensionSpacePoints":[{"language":"de"},{"language":"gsw"},{"language":"fr"}],"nodeAggregateClassification":"root"},"metadata":{"commandClass":"Neos\\ContentRepository\\Core\\Feature\\RootNodeCreation\\Command\\CreateRootNodeAggregateWithNode","commandPayload":{"contentStreamId":"cs-identifier","nodeAggregateId":"lady-eleonode-rootford","nodeTypeName":"Neos.ContentRepository:Root","tetheredDescendantNodeAggregateIds":[]},"initiatingUserId":"system","initiatingTimestamp":"random-time"}} + {"identifier":"random-event-uuid","type":"RootNodeAggregateWithNodeWasCreated","payload":{"contentStreamId":"cs-identifier","nodeAggregateId":"lady-eleonode-rootford","nodeTypeName":"Neos.ContentRepository:Root","coveredDimensionSpacePoints":[{"language":"de"},{"language":"gsw"},{"language":"fr"}],"nodeAggregateClassification":"root"},"metadata":{"commandClass":"Neos\\ContentRepository\\Core\\Feature\\RootNodeCreation\\Command\\CreateRootNodeAggregateWithNode","commandPayload":{"workspaceName":"live","nodeAggregateId":"lady-eleonode-rootford","nodeTypeName":"Neos.ContentRepository:Root","tetheredDescendantNodeAggregateIds":[]},"initiatingUserId":"system","initiatingTimestamp":"random-time"}} {"identifier":"random-event-uuid","type":"NodeAggregateWithNodeWasCreated","payload":{"contentStreamId":"cs-identifier","nodeAggregateId":"nody-mc-nodeface","nodeTypeName":"Neos.ContentRepository.Testing:Document","originDimensionSpacePoint":{"language":"de"},"coveredDimensionSpacePoints":[{"language":"de"},{"language":"gsw"},{"language":"fr"}],"parentNodeAggregateId":"lady-eleonode-rootford","nodeName":"child-document","initialPropertyValues":[],"nodeAggregateClassification":"regular","succeedingNodeAggregateId":null},"metadata":{"initiatingTimestamp":"random-time"}} """ diff --git a/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php b/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php index ccf503359f6..4cc4a5ec35f 100644 --- a/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php +++ b/Neos.ContentRepository.NodeMigration/src/NodeMigrationService.php @@ -7,6 +7,7 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; +use Neos\ContentRepository\Core\Projection\Workspace\Workspace; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\NodeMigration\Filter\InvalidMigrationFilterSpecified; use Neos\ContentRepository\NodeMigration\Command\ExecuteMigration; @@ -47,12 +48,12 @@ * you'll operate on the result state of all *previous* submigrations; * but you do not see the modified state of the current submigration while you are running it. */ -class NodeMigrationService implements ContentRepositoryServiceInterface +readonly class NodeMigrationService implements ContentRepositoryServiceInterface { public function __construct( - private readonly ContentRepository $contentRepository, - private readonly FiltersFactory $filterFactory, - private readonly TransformationsFactory $transformationFactory + private ContentRepository $contentRepository, + private FiltersFactory $filterFactory, + private TransformationsFactory $transformationFactory ) { } @@ -68,9 +69,10 @@ public function executeMigration(ExecuteMigration $command): void foreach ($command->getMigrationConfiguration()->getMigration() as $step => $migrationDescription) { $contentStreamForWriting = $command->getOrCreateContentStreamIdForWriting($step); + $workspaceNameForWriting = WorkspaceName::fromString($contentStreamForWriting->value); $this->contentRepository->handle( CreateWorkspace::create( - WorkspaceName::fromString($contentStreamForWriting->value), + $workspaceNameForWriting, $workspace->workspaceName, WorkspaceTitle::fromString($contentStreamForWriting->value), WorkspaceDescription::fromString(''), @@ -80,7 +82,8 @@ public function executeMigration(ExecuteMigration $command): void /** array $migrationDescription */ $this->executeSubMigrationAndBlock( $migrationDescription, - $workspace->currentContentStreamId, + $workspace, + $workspaceNameForWriting, $contentStreamForWriting ); } @@ -94,7 +97,8 @@ public function executeMigration(ExecuteMigration $command): void */ protected function executeSubMigrationAndBlock( array $migrationDescription, - ContentStreamId $contentStreamForReading, + Workspace $workspaceForReading, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): void { $filters = $this->filterFactory->buildFilterConjunction($migrationDescription['filters'] ?? []); @@ -124,17 +128,17 @@ protected function executeSubMigrationAndBlock( } if ($transformations->containsGlobal()) { - $transformations->executeGlobalAndBlock($contentStreamForReading, $contentStreamForWriting); + $transformations->executeGlobalAndBlock($workspaceForReading->workspaceName, $contentStreamForWriting); } elseif ($transformations->containsNodeAggregateBased()) { foreach ($this->contentRepository->getContentGraph()->findUsedNodeTypeNames() as $nodeTypeName) { foreach ( $this->contentRepository->getContentGraph()->findNodeAggregatesByType( - $contentStreamForReading, + $workspaceForReading->currentContentStreamId, $nodeTypeName ) as $nodeAggregate ) { if ($filters->matchesNodeAggregate($nodeAggregate)) { - $transformations->executeNodeAggregateBasedAndBlock($nodeAggregate, $contentStreamForWriting); + $transformations->executeNodeAggregateBasedAndBlock($nodeAggregate, $workspaceNameForWriting, $contentStreamForWriting); } } } @@ -142,7 +146,7 @@ protected function executeSubMigrationAndBlock( foreach ($this->contentRepository->getContentGraph()->findUsedNodeTypeNames() as $nodeTypeName) { foreach ( $this->contentRepository->getContentGraph()->findNodeAggregatesByType( - $contentStreamForReading, + $workspaceForReading->currentContentStreamId, $nodeTypeName ) as $nodeAggregate ) { @@ -163,6 +167,7 @@ protected function executeSubMigrationAndBlock( $transformations->executeNodeBasedAndBlock( $node, $coveredDimensionSpacePoints, + $workspaceNameForWriting, $contentStreamForWriting ); } diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/AddDimensionShineThroughTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/AddDimensionShineThroughTransformationFactory.php index c3d397da3ca..2d8e7a6764d 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/AddDimensionShineThroughTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/AddDimensionShineThroughTransformationFactory.php @@ -19,6 +19,7 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Command\AddDimensionShineThrough; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Add a Dimension Space Point Shine-Through; @@ -49,7 +50,7 @@ public function __construct( } public function execute( - ContentStreamId $contentStreamForReading, + WorkspaceName $workspaceNameForReading, ContentStreamId $contentStreamForWriting ): CommandResult { return $this->contentRepository->handle( diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php index 9f68ecac1fe..6f77895d3ef 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/AddNewPropertyTransformationFactory.php @@ -23,6 +23,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; class AddNewPropertyTransformationFactory implements TransformationFactoryInterface { @@ -56,6 +57,7 @@ public function __construct( public function execute( Node $node, DimensionSpacePointSet $coveredDimensionSpacePoints, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): ?CommandResult { if ($this->serializedValue === null) { @@ -66,7 +68,7 @@ public function execute( if (!$node->hasProperty($this->newPropertyName)) { return $this->contentRepository->handle( SetSerializedNodeProperties::create( - $contentStreamForWriting, + $workspaceNameForWriting, $node->nodeAggregateId, $node->originDimensionSpacePoint, SerializedPropertyValues::fromArray([ diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php index ca1b472827a..743993ed621 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangeNodeTypeTransformationFactory.php @@ -21,6 +21,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** @codingStandardsIgnoreStart */ /** @codingStandardsIgnoreEnd */ @@ -62,10 +63,11 @@ public function __construct( public function execute( NodeAggregate $nodeAggregate, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): CommandResult { return $this->contentRepository->handle(ChangeNodeAggregateType::create( - $contentStreamForWriting, + $workspaceNameForWriting, $nodeAggregate->nodeAggregateId, NodeTypeName::fromString($this->newType), $this->strategy, diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php index 6199ec4a071..4a3f1db1184 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/ChangePropertyValueTransformationFactory.php @@ -23,6 +23,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValue; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Change the value of a given property. @@ -103,6 +104,7 @@ public function __construct( public function execute( Node $node, DimensionSpacePointSet $coveredDimensionSpacePoints, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): ?CommandResult { $currentProperty = $node->properties->serialized()->getProperty($this->propertyName); @@ -128,7 +130,7 @@ public function execute( return $this->contentRepository->handle( SetSerializedNodeProperties::create( - $contentStreamForWriting, + $workspaceNameForWriting, $node->nodeAggregateId, $node->originDimensionSpacePoint, SerializedPropertyValues::fromArray([ diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/GlobalTransformationInterface.php b/Neos.ContentRepository.NodeMigration/src/Transformation/GlobalTransformationInterface.php index 7f5ec053a8e..55fd28f8b19 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/GlobalTransformationInterface.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/GlobalTransformationInterface.php @@ -15,7 +15,9 @@ namespace Neos\ContentRepository\NodeMigration\Transformation; use Neos\ContentRepository\Core\CommandHandler\CommandResult; +use Neos\ContentRepository\Core\Projection\Workspace\Workspace; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * A globally-done transformation, like changing dimension space points globally. @@ -25,7 +27,7 @@ interface GlobalTransformationInterface { public function execute( - ContentStreamId $contentStreamForReading, + WorkspaceName $workspaceNameForReading, ContentStreamId $contentStreamForWriting ): CommandResult; } diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/MoveDimensionSpacePointTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/MoveDimensionSpacePointTransformationFactory.php index 4ebbdd69f36..9bd9a544b99 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/MoveDimensionSpacePointTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/MoveDimensionSpacePointTransformationFactory.php @@ -19,6 +19,7 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Command\MoveDimensionSpacePoint; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * move a dimension space point globally @@ -47,7 +48,7 @@ public function __construct( } public function execute( - ContentStreamId $contentStreamForReading, + WorkspaceName $workspaceNameForReading, ContentStreamId $contentStreamForWriting ): CommandResult { return $this->contentRepository->handle( diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/NodeAggregateBasedTransformationInterface.php b/Neos.ContentRepository.NodeMigration/src/Transformation/NodeAggregateBasedTransformationInterface.php index 89a67fff0c9..e5421f8114a 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/NodeAggregateBasedTransformationInterface.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/NodeAggregateBasedTransformationInterface.php @@ -17,6 +17,7 @@ use Neos\ContentRepository\Core\CommandHandler\CommandResult; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * A node-aggregate-based transformation, like changing the node aggregate type @@ -27,6 +28,7 @@ interface NodeAggregateBasedTransformationInterface { public function execute( NodeAggregate $nodeAggregate, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): CommandResult; } diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/NodeBasedTransformationInterface.php b/Neos.ContentRepository.NodeMigration/src/Transformation/NodeBasedTransformationInterface.php index 87d59b3ce68..b4862d625b2 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/NodeBasedTransformationInterface.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/NodeBasedTransformationInterface.php @@ -18,6 +18,7 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * A node-specific transformation, like setting node properties. @@ -29,6 +30,7 @@ interface NodeBasedTransformationInterface public function execute( Node $node, DimensionSpacePointSet $coveredDimensionSpacePoints, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): ?CommandResult; } diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php index bd97abc0574..5a0107947ac 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/RemoveNodeTransformationFactory.php @@ -22,6 +22,7 @@ use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\Feature\NodeRemoval\Command\RemoveNodeAggregate; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Remove Node @@ -63,6 +64,7 @@ public function __construct( public function execute( Node $node, DimensionSpacePointSet $coveredDimensionSpacePoints, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): ?CommandResult { if ($this->strategy === null) { @@ -86,7 +88,7 @@ public function execute( } return $this->contentRepository->handle(RemoveNodeAggregate::create( - $contentStreamForWriting, + $workspaceNameForWriting, $node->nodeAggregateId, $coveredDimensionSpacePoint, $this->strategy, diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/RemovePropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/RemovePropertyTransformationFactory.php index d87558cb47a..f65460a007f 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/RemovePropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/RemovePropertyTransformationFactory.php @@ -23,6 +23,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; use Neos\ContentRepository\Core\SharedModel\User\UserId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Remove the property from nodes @@ -52,12 +53,13 @@ public function __construct( public function execute( Node $node, DimensionSpacePointSet $coveredDimensionSpacePoints, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): ?CommandResult { if ($node->hasProperty($this->propertyName)) { return $this->contentRepository->handle( SetSerializedNodeProperties::create( - $contentStreamForWriting, + $workspaceNameForWriting, $node->nodeAggregateId, $node->originDimensionSpacePoint, SerializedPropertyValues::createEmpty(), diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php index 783cfa7a5f6..207a34b3869 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/RenameNodeAggregateTransformationFactory.php @@ -20,6 +20,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; class RenameNodeAggregateTransformationFactory implements TransformationFactoryInterface { @@ -47,10 +48,11 @@ public function __construct( public function execute( NodeAggregate $nodeAggregate, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): CommandResult { return $this->contentRepository->handle(ChangeNodeAggregateName::create( - $contentStreamForWriting, + $workspaceNameForWriting, $nodeAggregate->nodeAggregateId, NodeName::fromString($this->newNodeName), )); diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php index 2161c2e26ec..f925a8dd910 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/RenamePropertyTransformationFactory.php @@ -22,6 +22,7 @@ use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Remove the property @@ -58,6 +59,7 @@ public function __construct( public function execute( Node $node, DimensionSpacePointSet $coveredDimensionSpacePoints, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): ?CommandResult { @@ -65,7 +67,7 @@ public function execute( if ($serializedPropertyValue !== null) { return $this->contentRepository->handle( SetSerializedNodeProperties::create( - $contentStreamForWriting, + $workspaceNameForWriting, $node->nodeAggregateId, $node->originDimensionSpacePoint, SerializedPropertyValues::fromArray([ diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php b/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php index cff73e27871..eec109682c0 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/StripTagsOnPropertyTransformationFactory.php @@ -23,6 +23,7 @@ use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; /** * Strip all tags on a given property @@ -52,6 +53,7 @@ public function __construct( public function execute( Node $node, DimensionSpacePointSet $coveredDimensionSpacePoints, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): ?CommandResult { $serializedPropertyValue = $node->properties->serialized()->getProperty($this->propertyName); @@ -66,7 +68,7 @@ public function execute( $newValue = strip_tags($propertyValue); return $this->contentRepository->handle( SetSerializedNodeProperties::create( - $contentStreamForWriting, + $workspaceNameForWriting, $node->nodeAggregateId, $node->originDimensionSpacePoint, SerializedPropertyValues::fromArray([ diff --git a/Neos.ContentRepository.NodeMigration/src/Transformation/Transformations.php b/Neos.ContentRepository.NodeMigration/src/Transformation/Transformations.php index 74dbcd58abb..11fa95db33c 100644 --- a/Neos.ContentRepository.NodeMigration/src/Transformation/Transformations.php +++ b/Neos.ContentRepository.NodeMigration/src/Transformation/Transformations.php @@ -7,7 +7,9 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; +use Neos\ContentRepository\Core\Projection\Workspace\Workspace; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; final class Transformations { @@ -90,30 +92,32 @@ public function containsMoreThanOneTransformationType(): bool } public function executeGlobalAndBlock( - ContentStreamId $contentStreamForReading, + WorkspaceName $workspaceNameForReading, ContentStreamId $contentStreamForWriting ): void { foreach ($this->globalTransformations as $globalTransformation) { - $globalTransformation->execute($contentStreamForReading, $contentStreamForWriting)->block(); + $globalTransformation->execute($workspaceNameForReading, $contentStreamForWriting)->block(); } } public function executeNodeAggregateBasedAndBlock( NodeAggregate $nodeAggregate, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): void { foreach ($this->nodeAggregateBasedTransformations as $nodeAggregateBasedTransformation) { - $nodeAggregateBasedTransformation->execute($nodeAggregate, $contentStreamForWriting)->block(); + $nodeAggregateBasedTransformation->execute($nodeAggregate, $workspaceNameForWriting, $contentStreamForWriting)->block(); } } public function executeNodeBasedAndBlock( Node $node, DimensionSpacePointSet $coveredDimensionSpacePoints, + WorkspaceName $workspaceNameForWriting, ContentStreamId $contentStreamForWriting ): void { foreach ($this->nodeBasedTransformations as $nodeBasedTransformation) { - $nodeBasedTransformation->execute($node, $coveredDimensionSpacePoints, $contentStreamForWriting)?->block(); + $nodeBasedTransformation->execute($node, $coveredDimensionSpacePoints, $workspaceNameForWriting, $contentStreamForWriting)?->block(); } } } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php index b4e6246665b..98eccc08308 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php @@ -40,6 +40,8 @@ trait CRTestSuiteRuntimeVariables protected ?ContentStreamId $currentContentStreamId = null; + protected ?WorkspaceName $currentWorkspaceName = null; + protected ?DimensionSpacePoint $currentDimensionSpacePoint = null; protected ?VisibilityConstraints $currentVisibilityConstraints = null; @@ -96,6 +98,14 @@ public function iAmInContentStream(string $contentStreamId): void $this->currentContentStreamId = ContentStreamId::fromString($contentStreamId); } + /** + * @Given /^I am in workspace "([^"]*)"$/ + */ + public function iAmInWorkspace(string $workspaceName): void + { + $this->currentWorkspaceName = WorkspaceName::fromString($workspaceName); + } + /** * @Given /^I am in the active content stream of workspace "([^"]*)"$/ * @throws \Exception @@ -106,6 +116,7 @@ public function iAmInTheActiveContentStreamOfWorkspace(string $workspaceName): v if ($workspace === null) { throw new \Exception(sprintf('Workspace "%s" does not exist, projection not yet up to date?', $workspaceName), 1548149355); } + $this->currentWorkspaceName = WorkspaceName::fromString($workspaceName); $this->currentContentStreamId = $workspace->currentContentStreamId; } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteTrait.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteTrait.php index b999777ad02..453805a1774 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteTrait.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteTrait.php @@ -31,7 +31,9 @@ use Neos\ContentRepository\Core\SharedModel\Exception\RootNodeAggregateDoesNotExist; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamState; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; +use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Features\ContentStreamClosing; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Features\ContentStreamForking; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Features\NodeCopying; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Features\NodeCreation; @@ -64,6 +66,7 @@ trait CRTestSuiteTrait use GenericCommandExecutionAndEventPublication; use ContentStreamForking; + use ContentStreamClosing; use NodeCreation; use NodeCopying; @@ -275,7 +278,7 @@ public function theContentStreamHasState(string $contentStreamId, string $expect $contentStreamFinder = $this->currentContentRepository->getContentStreamFinder(); $actual = $contentStreamFinder->findStateForContentStream($contentStreamId); - Assert::assertEquals($expectedState, $actual); + Assert::assertSame(ContentStreamState::tryFrom($expectedState), $actual); } /** diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/ContentStreamClosing.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/ContentStreamClosing.php new file mode 100644 index 00000000000..8e9589fc490 --- /dev/null +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/ContentStreamClosing.php @@ -0,0 +1,58 @@ +readPayloadTable($payloadTable); + $contentStreamId = isset($commandArguments['contentStreamId']) + ? ContentStreamId::fromString($commandArguments['contentStreamId']) + : $this->currentContentStreamId; + + $command = CloseContentStream::create($contentStreamId); + + $this->lastCommandOrEventResult = $this->currentContentRepository->handle($command); + } + + /** + * @Given /^the command CloseContentStream is executed with payload and exceptions are caught:$/ + */ + public function theCommandCloseContentStreamIsExecutedWithPayloadAndExceptionsAreCaught(TableNode $payloadTable): void + { + try { + $this->theCommandCloseContentStreamIsExecutedWithPayload($payloadTable); + } catch (\Exception $exception) { + $this->lastCommandException = $exception; + } + } +} diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/ContentStreamForking.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/ContentStreamForking.php index 750d5369b83..68b2b80f2aa 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/ContentStreamForking.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/ContentStreamForking.php @@ -47,4 +47,18 @@ public function theCommandForkContentStreamIsExecutedWithPayload(TableNode $payl $this->lastCommandOrEventResult = $this->currentContentRepository->handle($command); } + + /** + * @Given /^the command ForkContentStream is executed with payload and exceptions are caught:$/ + * @param TableNode $payloadTable + * @throws \Exception + */ + public function theCommandForkContentStreamIsExecutedWithPayloadAndExceptionsAreCaught(TableNode $payloadTable): void + { + try { + $this->theCommandForkContentStreamIsExecutedWithPayload($payloadTable); + } catch (\Exception $exception) { + $this->lastCommandException = $exception; + } + } } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCopying.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCopying.php index eb5cb0b226f..40e2953551c 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCopying.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCopying.php @@ -21,6 +21,7 @@ use Neos\ContentRepository\Core\Feature\NodeDuplication\Command\CopyNodesRecursively; use Neos\ContentRepository\Core\Feature\NodeDuplication\Dto\NodeAggregateIdMapping; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteRuntimeVariables; /** @@ -52,9 +53,13 @@ public function theCommandCopyNodesRecursivelyIsExecutedCopyingTheCurrentNodeAgg $targetNodeName = isset($commandArguments['targetNodeName']) ? NodeName::fromString($commandArguments['targetNodeName']) : null; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $command = CopyNodesRecursively::createFromSubgraphAndStartNode( $subgraph, + $workspaceName, $this->currentNode, $targetDimensionSpacePoint, NodeAggregateId::fromString($commandArguments['targetParentNodeAggregateId']), diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCreation.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCreation.php index 41f04d7afff..dda31a797dd 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCreation.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeCreation.php @@ -29,6 +29,7 @@ use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteRuntimeVariables; use Neos\EventStore\Model\Event\StreamName; @@ -54,13 +55,13 @@ abstract protected function publishEvent(string $eventType, StreamName $streamNa public function theCommandCreateRootNodeAggregateWithNodeIsExecutedWithPayload(TableNode $payloadTable) { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $nodeAggregateId = NodeAggregateId::fromString($commandArguments['nodeAggregateId']); $command = CreateRootNodeAggregateWithNode::create( - $contentStreamId, + $workspaceName, $nodeAggregateId, NodeTypeName::fromString($commandArguments['nodeTypeName']), ); @@ -113,13 +114,13 @@ public function theEventRootNodeAggregateWithNodeWasCreatedWasPublishedToStreamW public function theCommandUpdateRootNodeAggregateDimensionsIsExecutedWithPayload(TableNode $payloadTable) { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $nodeAggregateId = NodeAggregateId::fromString($commandArguments['nodeAggregateId']); $command = UpdateRootNodeAggregateDimensions::create( - $contentStreamId, + $workspaceName, $nodeAggregateId, ); @@ -134,15 +135,15 @@ public function theCommandUpdateRootNodeAggregateDimensionsIsExecutedWithPayload public function theCommandCreateNodeAggregateWithNodeIsExecutedWithPayload(TableNode $payloadTable) { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $originDimensionSpacePoint = isset($commandArguments['originDimensionSpacePoint']) ? OriginDimensionSpacePoint::fromArray($commandArguments['originDimensionSpacePoint']) : OriginDimensionSpacePoint::fromDimensionSpacePoint($this->currentDimensionSpacePoint); $command = CreateNodeAggregateWithNode::create( - $contentStreamId, + $workspaceName, NodeAggregateId::fromString($commandArguments['nodeAggregateId']), NodeTypeName::fromString($commandArguments['nodeTypeName']), $originDimensionSpacePoint, @@ -182,15 +183,15 @@ public function theCommandCreateNodeAggregateWithNodeIsExecutedWithPayloadAndExc public function theFollowingCreateNodeAggregateWithNodeCommandsAreExecuted(TableNode $table): void { foreach ($table->getHash() as $row) { - $contentStreamId = isset($row['contentStreamId']) - ? ContentStreamId::fromString($row['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($row['workspaceName']) + ? WorkspaceName::fromString($row['workspaceName']) + : $this->currentWorkspaceName; $originDimensionSpacePoint = isset($row['originDimensionSpacePoint']) ? OriginDimensionSpacePoint::fromJsonString($row['originDimensionSpacePoint']) : OriginDimensionSpacePoint::fromDimensionSpacePoint($this->currentDimensionSpacePoint); $rawParentNodeAggregateId = $row['parentNodeAggregateId']; $command = CreateNodeAggregateWithNode::create( - $contentStreamId, + $workspaceName, NodeAggregateId::fromString($row['nodeAggregateId']), NodeTypeName::fromString($row['nodeTypeName']), $originDimensionSpacePoint, @@ -230,15 +231,15 @@ private function parsePropertyValuesJsonString(string $jsonString): PropertyValu public function theCommandCreateNodeAggregateWithNodeAndSerializedPropertiesIsExecutedWithPayload(TableNode $payloadTable) { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $originDimensionSpacePoint = isset($commandArguments['originDimensionSpacePoint']) ? OriginDimensionSpacePoint::fromArray($commandArguments['originDimensionSpacePoint']) : OriginDimensionSpacePoint::fromDimensionSpacePoint($this->currentDimensionSpacePoint); $command = CreateNodeAggregateWithNodeAndSerializedProperties::create( - $contentStreamId, + $workspaceName, NodeAggregateId::fromString($commandArguments['nodeAggregateId']), NodeTypeName::fromString($commandArguments['nodeTypeName']), $originDimensionSpacePoint, diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeDisabling.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeDisabling.php index a794a506c34..144c8fc27bc 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeDisabling.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeDisabling.php @@ -22,6 +22,7 @@ use Neos\ContentRepository\Core\Feature\NodeDisabling\Command\DisableNodeAggregate; use Neos\ContentRepository\Core\Feature\NodeDisabling\Command\EnableNodeAggregate; use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteRuntimeVariables; use Neos\EventStore\Model\Event\StreamName; @@ -44,15 +45,15 @@ abstract protected function publishEvent(string $eventType, StreamName $streamNa public function theCommandDisableNodeAggregateIsExecutedWithPayload(TableNode $payloadTable): void { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $coveredDimensionSpacePoint = isset($commandArguments['coveredDimensionSpacePoint']) ? DimensionSpacePoint::fromArray($commandArguments['coveredDimensionSpacePoint']) : $this->currentDimensionSpacePoint; $command = DisableNodeAggregate::create( - $contentStreamId, + $workspaceName, NodeAggregateId::fromString($commandArguments['nodeAggregateId']), $coveredDimensionSpacePoint, NodeVariantSelectionStrategy::from($commandArguments['nodeVariantSelectionStrategy']), @@ -118,15 +119,15 @@ public function theEventNodeAggregateWasEnabledWasPublishedWithPayload(TableNode public function theCommandEnableNodeAggregateIsExecutedWithPayload(TableNode $payloadTable): void { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $coveredDimensionSpacePoint = isset($commandArguments['coveredDimensionSpacePoint']) ? DimensionSpacePoint::fromArray($commandArguments['coveredDimensionSpacePoint']) : $this->currentDimensionSpacePoint; $command = EnableNodeAggregate::create( - $contentStreamId, + $workspaceName, NodeAggregateId::fromString($commandArguments['nodeAggregateId']), $coveredDimensionSpacePoint, NodeVariantSelectionStrategy::from($commandArguments['nodeVariantSelectionStrategy']), diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeModification.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeModification.php index 9e4ea82ca59..77b23f64b50 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeModification.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeModification.php @@ -21,6 +21,7 @@ use Neos\ContentRepository\Core\Feature\NodeModification\Command\SetNodeProperties; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteRuntimeVariables; use Neos\EventStore\Model\Event\StreamName; use PHPUnit\Framework\Assert; @@ -43,8 +44,8 @@ abstract protected function publishEvent(string $eventType, StreamName $streamNa public function theCommandSetPropertiesIsExecutedWithPayload(TableNode $payloadTable) { $commandArguments = $this->readPayloadTable($payloadTable); - if (!isset($commandArguments['contentStreamId'])) { - $commandArguments['contentStreamId'] = $this->currentContentStreamId->value; + if (!isset($commandArguments['workspaceName'])) { + $commandArguments['workspaceName'] = $this->currentWorkspaceName->value; } if (!isset($commandArguments['originDimensionSpacePoint'])) { $commandArguments['originDimensionSpacePoint'] = $this->currentDimensionSpacePoint->jsonSerialize(); @@ -52,7 +53,7 @@ public function theCommandSetPropertiesIsExecutedWithPayload(TableNode $payloadT $rawNodeAggregateId = $commandArguments['nodeAggregateId']; $command = SetNodeProperties::create( - ContentStreamId::fromString($commandArguments['contentStreamId']), + WorkspaceName::fromString($commandArguments['workspaceName']), \str_starts_with($rawNodeAggregateId, '$') ? $this->rememberedNodeAggregateIds[\mb_substr($rawNodeAggregateId, 1)] : NodeAggregateId::fromString($rawNodeAggregateId), diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeMove.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeMove.php index e785fd6d011..4da91ddd975 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeMove.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeMove.php @@ -21,6 +21,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; use Neos\ContentRepository\Core\Feature\NodeMove\Dto\RelationDistributionStrategy; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteRuntimeVariables; use Neos\EventStore\Model\Event\StreamName; @@ -43,9 +44,9 @@ abstract protected function publishEvent(string $eventType, StreamName $streamNa public function theCommandMoveNodeIsExecutedWithPayload(TableNode $payloadTable): void { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $dimensionSpacePoint = isset($commandArguments['dimensionSpacePoint']) ? DimensionSpacePoint::fromArray($commandArguments['dimensionSpacePoint']) : $this->currentDimensionSpacePoint; @@ -63,7 +64,7 @@ public function theCommandMoveNodeIsExecutedWithPayload(TableNode $payloadTable) ); $command = MoveNodeAggregate::create( - $contentStreamId, + $workspaceName, $dimensionSpacePoint, NodeAggregateId::fromString($commandArguments['nodeAggregateId']), $relationDistributionStrategy, diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeReferencing.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeReferencing.php index d43d4b26628..0dbb988e9c1 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeReferencing.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeReferencing.php @@ -24,6 +24,7 @@ use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; use Neos\ContentRepository\Core\Feature\NodeReferencing\Command\SetNodeReferences; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteRuntimeVariables; use Neos\EventStore\Model\Event\StreamName; @@ -48,9 +49,9 @@ abstract protected function publishEvent(string $eventType, StreamName $streamNa public function theCommandSetNodeReferencesIsExecutedWithPayload(TableNode $payloadTable) { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $sourceOriginDimensionSpacePoint = isset($commandArguments['sourceOriginDimensionSpacePoint']) ? OriginDimensionSpacePoint::fromArray($commandArguments['sourceOriginDimensionSpacePoint']) : OriginDimensionSpacePoint::fromDimensionSpacePoint($this->currentDimensionSpacePoint); @@ -67,7 +68,7 @@ public function theCommandSetNodeReferencesIsExecutedWithPayload(TableNode $payl ); $command = SetNodeReferences::create( - $contentStreamId, + $workspaceName, NodeAggregateId::fromString($commandArguments['sourceNodeAggregateId']), $sourceOriginDimensionSpacePoint, ReferenceName::fromString($commandArguments['referenceName']), diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeRemoval.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeRemoval.php index be95f8c1a0c..2459afff269 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeRemoval.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeRemoval.php @@ -21,6 +21,7 @@ use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; use Neos\ContentRepository\Core\Feature\NodeRemoval\Command\RemoveNodeAggregate; use Neos\ContentRepository\Core\SharedModel\Node\NodeVariantSelectionStrategy; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteRuntimeVariables; use Neos\EventStore\Model\Event\StreamName; @@ -43,15 +44,15 @@ abstract protected function publishEvent(string $eventType, StreamName $streamNa public function theCommandRemoveNodeAggregateIsExecutedWithPayload(TableNode $payloadTable) { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $coveredDimensionSpacePoint = isset($commandArguments['coveredDimensionSpacePoint']) ? DimensionSpacePoint::fromArray($commandArguments['coveredDimensionSpacePoint']) : $this->currentDimensionSpacePoint; $command = RemoveNodeAggregate::create( - $contentStreamId, + $workspaceName, NodeAggregateId::fromString($commandArguments['nodeAggregateId']), $coveredDimensionSpacePoint, NodeVariantSelectionStrategy::from($commandArguments['nodeVariantSelectionStrategy']), diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeRenaming.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeRenaming.php index bae8d6d1163..1a4d2a85baa 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeRenaming.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeRenaming.php @@ -19,6 +19,7 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteRuntimeVariables; use PHPUnit\Framework\Assert; @@ -37,12 +38,12 @@ trait NodeRenaming public function theCommandChangeNodeAggregateNameIsExecutedWithPayload(TableNode $payloadTable) { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $command = ChangeNodeAggregateName::create( - $contentStreamId, + $workspaceName, NodeAggregateId::fromString($commandArguments['nodeAggregateId']), NodeName::fromString($commandArguments['newNodeName']), ); diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeTypeChange.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeTypeChange.php index b8599625fd5..98c49c5bb64 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeTypeChange.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeTypeChange.php @@ -21,6 +21,7 @@ use Neos\ContentRepository\Core\Feature\NodeTypeChange\Command\ChangeNodeAggregateType; use Neos\ContentRepository\Core\Feature\NodeCreation\Dto\NodeAggregateIdsByNodePaths; use Neos\ContentRepository\Core\Feature\NodeTypeChange\Dto\NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteRuntimeVariables; /** @@ -40,11 +41,11 @@ abstract protected function readPayloadTable(TableNode $payloadTable): array; public function theCommandChangeNodeAggregateTypeIsExecutedWithPayload(TableNode $payloadTable) { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $command = ChangeNodeAggregateType::create( - $contentStreamId, + $workspaceName, NodeAggregateId::fromString($commandArguments['nodeAggregateId']), NodeTypeName::fromString($commandArguments['newNodeTypeName']), NodeAggregateTypeChangeChildConstraintConflictResolutionStrategy::from($commandArguments['strategy']), diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeVariation.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeVariation.php index bc453cf6054..3f539ce3bc9 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeVariation.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/NodeVariation.php @@ -20,6 +20,7 @@ use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; use Neos\ContentRepository\Core\Feature\NodeVariation\Command\CreateNodeVariant; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteRuntimeVariables; use Neos\EventStore\Model\Event\StreamName; @@ -42,12 +43,12 @@ abstract protected function publishEvent(string $eventType, StreamName $streamNa public function theCommandCreateNodeVariantIsExecutedWithPayload(TableNode $payloadTable) { $commandArguments = $this->readPayloadTable($payloadTable); - $contentStreamId = isset($commandArguments['contentStreamId']) - ? ContentStreamId::fromString($commandArguments['contentStreamId']) - : $this->currentContentStreamId; + $workspaceName = isset($commandArguments['workspaceName']) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName; $command = CreateNodeVariant::create( - $contentStreamId, + $workspaceName, NodeAggregateId::fromString($commandArguments['nodeAggregateId']), OriginDimensionSpacePoint::fromArray($commandArguments['sourceOrigin']), OriginDimensionSpacePoint::fromArray($commandArguments['targetOrigin']), diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/WorkspaceDiscarding.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/WorkspaceDiscarding.php index 16334fe990b..91793091233 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/WorkspaceDiscarding.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/WorkspaceDiscarding.php @@ -69,4 +69,17 @@ public function theCommandDiscardIndividualNodesFromWorkspaceIsExecuted(TableNod $this->lastCommandOrEventResult = $this->currentContentRepository->handle($command); } + + + /** + * @Given /^the command DiscardIndividualNodesFromWorkspace is executed with payload and exceptions are caught:$/ + */ + public function theCommandDiscardIndividualNodesFromWorkspaceIsExecutedAndExceptionsAreCaught(TableNode $payloadTable): void + { + try { + $this->theCommandDiscardIndividualNodesFromWorkspaceIsExecuted($payloadTable); + } catch (\Exception $exception) { + $this->lastCommandException = $exception; + } + } } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/WorkspacePublishing.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/WorkspacePublishing.php index 4d23e13bbcd..f4e2479da90 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/WorkspacePublishing.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Features/WorkspacePublishing.php @@ -33,7 +33,6 @@ abstract protected function readPayloadTable(TableNode $payloadTable): array; /** * @Given /^the command PublishIndividualNodesFromWorkspace is executed with payload:$/ - * @param TableNode $payloadTable * @throws \Exception */ public function theCommandPublishIndividualNodesFromWorkspaceIsExecuted(TableNode $payloadTable): void @@ -42,7 +41,9 @@ public function theCommandPublishIndividualNodesFromWorkspaceIsExecuted(TableNod $nodesToPublish = NodeIdsToPublishOrDiscard::fromArray($commandArguments['nodesToPublish']); $command = PublishIndividualNodesFromWorkspace::create( - WorkspaceName::fromString($commandArguments['workspaceName']), + array_key_exists('workspaceName', $commandArguments) + ? WorkspaceName::fromString($commandArguments['workspaceName']) + : $this->currentWorkspaceName, $nodesToPublish, ); if (isset($commandArguments['contentStreamIdForMatchingPart'])) { @@ -55,9 +56,20 @@ public function theCommandPublishIndividualNodesFromWorkspaceIsExecuted(TableNod $this->lastCommandOrEventResult = $this->currentContentRepository->handle($command); } + /** + * @Given /^the command PublishIndividualNodesFromWorkspace is executed with payload and exceptions are caught:$/ + */ + public function theCommandPublishIndividualNodesFromWorkspaceIsExecutedAndExceptionsAreCaught(TableNode $payloadTable): void + { + try { + $this->theCommandPublishIndividualNodesFromWorkspaceIsExecuted($payloadTable); + } catch (\Exception $exception) { + $this->lastCommandException = $exception; + } + } + /** * @Given /^the command PublishWorkspace is executed with payload:$/ - * @param TableNode $payloadTable * @throws \Exception */ public function theCommandPublishWorkspaceIsExecuted(TableNode $payloadTable): void @@ -67,14 +79,17 @@ public function theCommandPublishWorkspaceIsExecuted(TableNode $payloadTable): v $command = PublishWorkspace::create( WorkspaceName::fromString($commandArguments['workspaceName']), ); + if (array_key_exists('newContentStreamId', $commandArguments)) { + $command = $command->withNewContentStreamId( + ContentStreamId::fromString($commandArguments['newContentStreamId']) + ); + } $this->lastCommandOrEventResult = $this->currentContentRepository->handle($command); } /** * @Given /^the command PublishWorkspace is executed with payload and exceptions are caught:$/ - * @param TableNode $payloadTable - * @throws \Exception */ public function theCommandPublishWorkspaceIsExecutedAndExceptionsAreCaught(TableNode $payloadTable): void { diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/MigrationsTrait.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/MigrationsTrait.php index 154a8337ea7..84268243da3 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/MigrationsTrait.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/MigrationsTrait.php @@ -40,7 +40,11 @@ public function iRunTheFollowingNodeMigration(string $workspaceName, string $con fn (string $cs) => ContentStreamId::fromString($cs), explode(',', $contentStreams) ); - $command = new ExecuteMigration($migrationConfiguration, WorkspaceName::fromString($workspaceName), $contentStreamIds); + $command = new ExecuteMigration( + $migrationConfiguration, + WorkspaceName::fromString($workspaceName), + $contentStreamIds + ); /** @var NodeMigrationService $nodeMigrationService */ $nodeMigrationService = $this->getContentRepositoryService(new NodeMigrationServiceFactory()); diff --git a/Neos.ContentRepository.TestSuite/composer.json b/Neos.ContentRepository.TestSuite/composer.json index e47e4b4d011..b37a5d03a3e 100644 --- a/Neos.ContentRepository.TestSuite/composer.json +++ b/Neos.ContentRepository.TestSuite/composer.json @@ -16,7 +16,8 @@ "neos/contentrepository-structureadjustment": "self.version", "neos/contentrepository-nodemigration": "self.version", "behat/behat": "^3.5", - "phpunit/phpunit": "^9.0" + "phpunit/phpunit": "^9.6", + "brianium/paratest": "^6.11" }, "autoload": { "psr-4": { diff --git a/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php b/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php index af6c9e041d2..d04b8b8db8a 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php +++ b/Neos.ContentRepositoryRegistry/Classes/Command/ContentCommandController.php @@ -73,7 +73,7 @@ public function refreshRootNodeDimensionsCommand(string $contentRepository = 'de ]); $contentRepositoryInstance->handle( UpdateRootNodeAggregateDimensions::create( - $workspaceInstance->currentContentStreamId, + $workspaceInstance->workspaceName, $rootNodeAggregate->nodeAggregateId ) )->block(); @@ -171,7 +171,7 @@ public function createVariantsRecursivelyCommand(string $source, string $target, $rootNodeAggregate->nodeAggregateId, $sourceSubgraph, $targetSpacePoint, - $workspaceInstance->currentContentStreamId, + $workspaceInstance->workspaceName, $contentRepositoryInstance, ) ); @@ -180,7 +180,7 @@ public function createVariantsRecursivelyCommand(string $source, string $target, $this->outputLine('Done!'); } - private function createVariantRecursivelyInternal(int $level, NodeAggregateId $parentNodeAggregateId, ContentSubgraphInterface $sourceSubgraph, OriginDimensionSpacePoint $target, ContentStreamId $contentStreamId, ContentRepository $contentRepository): void + private function createVariantRecursivelyInternal(int $level, NodeAggregateId $parentNodeAggregateId, ContentSubgraphInterface $sourceSubgraph, OriginDimensionSpacePoint $target, WorkspaceName $workspaceName, ContentRepository $contentRepository): void { $childNodes = $sourceSubgraph->findChildNodes( $parentNodeAggregateId, @@ -199,7 +199,7 @@ private function createVariantRecursivelyInternal(int $level, NodeAggregateId $p try { // Tethered nodes' variants are automatically created when the parent is translated. $contentRepository->handle(CreateNodeVariant::create( - $contentStreamId, + $workspaceName, $childNode->nodeAggregateId, $childNode->originDimensionSpacePoint, $target @@ -218,7 +218,7 @@ private function createVariantRecursivelyInternal(int $level, NodeAggregateId $p $childNode->nodeAggregateId, $sourceSubgraph, $target, - $contentStreamId, + $workspaceName, $contentRepository ); } diff --git a/Neos.Neos/Classes/Controller/Backend/ModuleController.php b/Neos.Neos/Classes/Controller/Backend/ModuleController.php index 99e464b8fcc..8ff53ddeb7f 100644 --- a/Neos.Neos/Classes/Controller/Backend/ModuleController.php +++ b/Neos.Neos/Classes/Controller/Backend/ModuleController.php @@ -18,6 +18,7 @@ use Neos\Flow\Mvc\ActionResponse; use Neos\Flow\Mvc\Controller\ActionController; use Neos\Flow\Mvc\Dispatcher; +use Neos\Flow\Security\Account; use Neos\Flow\Security\Context; use Neos\Utility\Arrays; use Neos\Utility\MediaTypes; @@ -114,6 +115,7 @@ public function indexAction(array $module) } return $moduleResponse->getContent(); } else { + /** @var ?Account $authenticatedAccount */ $authenticatedAccount = $this->securityContext->getAccount(); $user = $authenticatedAccount === null ? null : $this->partyService->getAssignedPartyOfAccount($authenticatedAccount); diff --git a/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php b/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php index 8ef9b1becfe..21908b1313b 100755 --- a/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php +++ b/Neos.Neos/Classes/Controller/Module/Administration/SitesController.php @@ -216,7 +216,7 @@ public function updateSiteAction(Site $site, $newSiteNodeName) foreach ($siteNodeAggregates as $siteNodeAggregate) { $contentRepository->handle(ChangeNodeAggregateName::create( - $workspace->currentContentStreamId, + $workspace->workspaceName, $siteNodeAggregate->nodeAggregateId, NodeName::fromString($newSiteNodeName), )); diff --git a/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php b/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php index e22e9b41fed..ba5c61d7da3 100644 --- a/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php +++ b/Neos.Neos/Classes/Controller/Module/Management/WorkspacesController.php @@ -26,6 +26,7 @@ use Neos\Flow\I18n\Exception\IndexOutOfBoundsException; use Neos\Flow\I18n\Exception\InvalidFormatPlaceholderException; use Neos\Flow\Mvc\Exception\StopActionException; +use Neos\Flow\Security\Account; use Neos\Neos\Domain\Model\SiteNodeName; use Neos\Neos\Domain\Service\NodeTypeNameFactory; use Neos\Neos\PendingChangesProjection\ChangeFinder; @@ -106,6 +107,7 @@ public function indexAction() ->contentRepositoryId; $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); + /** @var ?Account $currentAccount */ $currentAccount = $this->securityContext->getAccount(); if ($currentAccount === null) { throw new \RuntimeException('No account is authenticated', 1710068839); @@ -446,6 +448,7 @@ public function rebaseAndRedirectAction(Node $targetNode, Workspace $targetWorks ->contentRepositoryId; $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); + /** @var ?Account $currentAccount */ $currentAccount = $this->securityContext->getAccount(); if ($currentAccount === null) { throw new \RuntimeException('No account is authenticated', 1710068880); @@ -519,7 +522,7 @@ public function publishNodeAction(string $nodeAddress, WorkspaceName $selectedWo $selectedWorkspace, NodeIdsToPublishOrDiscard::create( new NodeIdToPublishOrDiscard( - $nodeAddress->contentStreamId, + $selectedWorkspace, $nodeAddress->nodeAggregateId, $nodeAddress->dimensionSpacePoint ) @@ -557,7 +560,7 @@ public function discardNodeAction(string $nodeAddress, WorkspaceName $selectedWo $selectedWorkspace, NodeIdsToPublishOrDiscard::create( new NodeIdToPublishOrDiscard( - $nodeAddress->contentStreamId, + $selectedWorkspace, $nodeAddress->nodeAggregateId, $nodeAddress->dimensionSpacePoint ) @@ -585,7 +588,7 @@ public function discardNodeAction(string $nodeAddress, WorkspaceName $selectedWo */ public function publishOrDiscardNodesAction(array $nodes, string $action, string $selectedWorkspace): void { - $selectedWorkspace = WorkspaceName::fromString($selectedWorkspace); + $selectedWorkspaceName = WorkspaceName::fromString($selectedWorkspace); $contentRepositoryId = SiteDetectionResult::fromRequest($this->request->getHttpRequest()) ->contentRepositoryId; $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); @@ -595,7 +598,7 @@ public function publishOrDiscardNodesAction(array $nodes, string $action, string foreach ($nodes as $node) { $nodeAddress = $nodeAddressFactory->createFromUriString($node); $nodesToPublishOrDiscard[] = new NodeIdToPublishOrDiscard( - $nodeAddress->contentStreamId, + $selectedWorkspaceName, $nodeAddress->nodeAggregateId, $nodeAddress->dimensionSpacePoint ); @@ -604,7 +607,7 @@ public function publishOrDiscardNodesAction(array $nodes, string $action, string switch ($action) { case 'publish': $command = PublishIndividualNodesFromWorkspace::create( - $selectedWorkspace, + $selectedWorkspaceName, NodeIdsToPublishOrDiscard::create(...$nodesToPublishOrDiscard), ); $contentRepository->handle($command) @@ -620,7 +623,7 @@ public function publishOrDiscardNodesAction(array $nodes, string $action, string break; case 'discard': $command = DiscardIndividualNodesFromWorkspace::create( - $selectedWorkspace, + $selectedWorkspaceName, NodeIdsToPublishOrDiscard::create(...$nodesToPublishOrDiscard), ); $contentRepository->handle($command) @@ -638,7 +641,7 @@ public function publishOrDiscardNodesAction(array $nodes, string $action, string throw new \RuntimeException('Invalid action "' . htmlspecialchars($action) . '" given.', 1346167441); } - $this->redirect('show', null, null, ['workspace' => $selectedWorkspace->value]); + $this->redirect('show', null, null, ['workspace' => $selectedWorkspaceName->value]); } /** diff --git a/Neos.Neos/Classes/Controller/Service/NodesController.php b/Neos.Neos/Classes/Controller/Service/NodesController.php index 8e88aa12c55..a6bc59895c4 100644 --- a/Neos.Neos/Classes/Controller/Service/NodesController.php +++ b/Neos.Neos/Classes/Controller/Service/NodesController.php @@ -297,7 +297,7 @@ public function createAction( if ($mode === 'adoptFromAnotherDimension' || $mode === 'adoptFromAnotherDimensionAndCopyContent') { CatchUpTriggerWithSynchronousOption::synchronously(fn() => $this->adoptNodeAndParents( - $workspace->currentContentStreamId, + $workspace->workspaceName, $nodeAggregateId, $sourceSubgraph, $targetSubgraph, @@ -381,22 +381,18 @@ private static function firstNodeAggregate(iterable $nodeAggregates): ?NodeAggre /** * Adopt (translate) the given node and parents that are not yet visible to the given context * - * @param NodeAggregateId $nodeAggregateId - * @param ContentSubgraphInterface $sourceSubgraph - * @param ContentSubgraphInterface $targetSubgraph - * @param ContentRepository $contentRepository * @param boolean $copyContent true if the content from the nodes that are translated should be copied * @return void */ protected function adoptNodeAndParents( - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, ContentSubgraphInterface $sourceSubgraph, ContentSubgraphInterface $targetSubgraph, DimensionSpacePoint $targetDimensionSpacePoint, ContentRepository $contentRepository, bool $copyContent - ) { + ): void { $identifiersFromRootlineToTranslate = []; while ( $nodeAggregateId @@ -422,7 +418,7 @@ protected function adoptNodeAndParents( } $contentRepository->handle( CreateNodeVariant::create( - $contentStreamId, + $workspaceName, $identifier, $sourceNode->originDimensionSpacePoint, OriginDimensionSpacePoint::fromDimensionSpacePoint($targetDimensionSpacePoint), @@ -432,7 +428,7 @@ protected function adoptNodeAndParents( if ($copyContent === true) { $contentNodeConstraint = NodeTypeCriteria::fromFilterString('!' . NodeTypeNameFactory::NAME_DOCUMENT); $this->createNodeVariantsForChildNodes( - $contentStreamId, + $workspaceName, $identifier, $contentNodeConstraint, $sourceSubgraph, @@ -445,7 +441,7 @@ protected function adoptNodeAndParents( } private function createNodeVariantsForChildNodes( - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeAggregateId $parentNodeId, NodeTypeCriteria $constraints, ContentSubgraphInterface $sourceSubgraph, @@ -464,7 +460,7 @@ private function createNodeVariantsForChildNodes( // TODO: DOES THIS MAKE SENSE? $contentRepository->handle( CreateNodeVariant::create( - $contentStreamId, + $workspaceName, $childNode->nodeAggregateId, $childNode->originDimensionSpacePoint, OriginDimensionSpacePoint::fromDimensionSpacePoint($targetDimensionSpacePoint), @@ -473,7 +469,7 @@ private function createNodeVariantsForChildNodes( } $this->createNodeVariantsForChildNodes( - $contentStreamId, + $workspaceName, $childNode->nodeAggregateId, $constraints, $sourceSubgraph, diff --git a/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php b/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php index 77c66be3809..f8804deab40 100644 --- a/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php +++ b/Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php @@ -34,12 +34,12 @@ use Neos\Neos\Domain\Model\Site; use Neos\Neos\Domain\Model\SiteNodeName; -class SiteServiceInternals implements ContentRepositoryServiceInterface +readonly class SiteServiceInternals implements ContentRepositoryServiceInterface { public function __construct( - private readonly ContentRepository $contentRepository, - private readonly InterDimensionalVariationGraph $interDimensionalVariationGraph, - private readonly NodeTypeManager $nodeTypeManager + private ContentRepository $contentRepository, + private InterDimensionalVariationGraph $interDimensionalVariationGraph, + private NodeTypeManager $nodeTypeManager ) { } @@ -56,13 +56,13 @@ public function removeSiteNode(SiteNodeName $siteNodeName): void } $contentGraph = $this->contentRepository->getContentGraph(); - foreach ($this->contentRepository->getContentStreamFinder()->findAllIds() as $contentStreamId) { + foreach ($this->contentRepository->getWorkspaceFinder()->findAll() as $workspace) { $sitesNodeAggregate = $contentGraph->findRootNodeAggregateByType( - $contentStreamId, + $workspace->currentContentStreamId, NodeTypeNameFactory::forSites() ); $siteNodeAggregates = $contentGraph->findChildNodeAggregatesByName( - $contentStreamId, + $workspace->currentContentStreamId, $sitesNodeAggregate->nodeAggregateId, $siteNodeName->toNodeName() ); @@ -70,7 +70,7 @@ public function removeSiteNode(SiteNodeName $siteNodeName): void foreach ($siteNodeAggregates as $siteNodeAggregate) { assert($siteNodeAggregate instanceof NodeAggregate); $this->contentRepository->handle(RemoveNodeAggregate::create( - $contentStreamId, + $workspace->workspaceName, $siteNodeAggregate->nodeAggregateId, $arbitraryDimensionSpacePoint, NodeVariantSelectionStrategy::STRATEGY_ALL_VARIANTS, @@ -82,9 +82,9 @@ public function removeSiteNode(SiteNodeName $siteNodeName): void public function createSiteNodeIfNotExists(Site $site, string $nodeTypeName): void { $bootstrapper = ContentRepositoryBootstrapper::create($this->contentRepository); - $liveContentStreamId = $bootstrapper->getOrCreateLiveContentStream(); + $liveWorkspace = $bootstrapper->getOrCreateLiveWorkspace(); $sitesNodeIdentifier = $bootstrapper->getOrCreateRootNodeAggregate( - $liveContentStreamId, + $liveWorkspace, NodeTypeNameFactory::forSites() ); try { @@ -102,7 +102,7 @@ public function createSiteNodeIfNotExists(Site $site, string $nodeTypeName): voi } $siteNodeAggregate = $this->contentRepository->getContentGraph()->findChildNodeAggregatesByName( - $liveContentStreamId, + $liveWorkspace->currentContentStreamId, $sitesNodeIdentifier, $site->getNodeName()->toNodeName(), ); @@ -122,7 +122,7 @@ public function createSiteNodeIfNotExists(Site $site, string $nodeTypeName): voi $siteNodeAggregateId = NodeAggregateId::create(); $this->contentRepository->handle(CreateNodeAggregateWithNode::create( - $liveContentStreamId, + $liveWorkspace->workspaceName, $siteNodeAggregateId, NodeTypeName::fromString($nodeTypeName), OriginDimensionSpacePoint::fromDimensionSpacePoint($arbitraryRootDimensionSpacePoint), @@ -137,7 +137,7 @@ public function createSiteNodeIfNotExists(Site $site, string $nodeTypeName): voi // Handle remaining root dimension space points by creating peer variants foreach ($rootDimensionSpacePoints as $rootDimensionSpacePoint) { $this->contentRepository->handle(CreateNodeVariant::create( - $liveContentStreamId, + $liveWorkspace->workspaceName, $siteNodeAggregateId, OriginDimensionSpacePoint::fromDimensionSpacePoint($arbitraryRootDimensionSpacePoint), OriginDimensionSpacePoint::fromDimensionSpacePoint($rootDimensionSpacePoint), diff --git a/Neos.Neos/Classes/Service/ImpersonateService.php b/Neos.Neos/Classes/Service/ImpersonateService.php index 8704568637c..052d52d0ab1 100644 --- a/Neos.Neos/Classes/Service/ImpersonateService.php +++ b/Neos.Neos/Classes/Service/ImpersonateService.php @@ -60,6 +60,7 @@ class ImpersonateService public function impersonate(Account $account): void { $currentAccount = $this->securityContext->getAccount(); + /** @var ?Account $currentAccount */ if ($currentAccount === null) { throw new \RuntimeException('No account is authenticated', 1710068887); } diff --git a/Neos.Neos/Classes/Service/UserService.php b/Neos.Neos/Classes/Service/UserService.php index b66afaf4e98..3e893dbcd88 100644 --- a/Neos.Neos/Classes/Service/UserService.php +++ b/Neos.Neos/Classes/Service/UserService.php @@ -15,6 +15,7 @@ namespace Neos\Neos\Service; use Neos\Flow\Annotations as Flow; +use Neos\Flow\Security\Account; use Neos\Neos\Domain\Model\User; use Neos\Neos\Utility\User as UserUtility; @@ -74,6 +75,7 @@ public function getPersonalWorkspaceName(): ?string if (!$currentUser instanceof User) { return null; } + /** @var ?Account $currentAccount */ $currentAccount = $this->securityContext->getAccount(); if ($currentAccount === null) { return null; diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Basic.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Basic.feature index da5635f69db..42fdfa0c5d4 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Basic.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Basic.feature @@ -31,9 +31,9 @@ Feature: Basic routing functionality (match & resolve document nodes in one dime | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date @@ -90,7 +90,6 @@ Feature: Basic routing functionality (match & resolve document nodes in one dime Scenario: Change uri path segment When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | originDimensionSpacePoint | {} | | propertyValues | {"uriPathSegment": "david-nodenborough-updated"} | @@ -102,14 +101,12 @@ Feature: Basic routing functionality (match & resolve document nodes in one dime Scenario: Change uri path segment works multiple times (bug #4253) When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | originDimensionSpacePoint | {} | | propertyValues | {"uriPathSegment": "david-nodenborough-updated-a"} | And The documenturipath projection is up to date When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | originDimensionSpacePoint | {} | | propertyValues | {"uriPathSegment": "david-nodenborough-updated-b"} | @@ -129,7 +126,6 @@ Feature: Basic routing functionality (match & resolve document nodes in one dime Scenario: Move node upwards in the tree When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "earl-o-documentbourgh" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "shernode-homes" | @@ -142,7 +138,6 @@ Feature: Basic routing functionality (match & resolve document nodes in one dime Scenario: Move node downwards in the tree When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "earl-o-documentbourgh" | diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Dimensions.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Dimensions.feature index c6a9da1b7bf..4e4fcc69784 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Dimensions.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Dimensions.feature @@ -43,13 +43,12 @@ Feature: Routing functionality with multiple content dimensions | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {"market":"DE", "language":"en"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {"market":"DE", "language":"en"} And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | nodeName | | sir-david-nodenborough | lady-eleonode-rootford | Neos.Neos:Test.Routing.Page | {"uriPathSegment": "ignore-me"} | node1 | @@ -57,14 +56,12 @@ Feature: Routing functionality with multiple content dimensions | carl-destinode | nody-mc-nodeface | Neos.Neos:Test.Routing.Page | {"uriPathSegment": "carl"} | node3 | And the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "carl-destinode" | | sourceOrigin | {"market":"DE", "language":"en"} | | targetOrigin | {"market":"DE", "language":"de"} | And the graph projection is fully up to date And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "carl-destinode" | | originDimensionSpacePoint | {"market":"DE", "language":"de"} | | propertyValues | {"uriPathSegment": "karl-de"} | @@ -335,14 +332,12 @@ Feature: Routing functionality with multiple content dimensions # create variant for fr and sites node When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | sourceOrigin | {"market":"DE", "language":"en"} | | targetOrigin | {"market":"DE", "language":"fr"} | And the graph projection is fully up to date When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | sourceOrigin | {"market":"DE", "language":"en"} | | targetOrigin | {"market":"DE", "language":"fr"} | @@ -350,7 +345,6 @@ Feature: Routing functionality with multiple content dimensions And the graph projection is fully up to date And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | originDimensionSpacePoint | {"market":"DE", "language":"fr"} | | propertyValues | {"uriPathSegment": "nody-fr"} | @@ -399,14 +393,12 @@ Feature: Routing functionality with multiple content dimensions # create variant for fr and sites node When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | sourceOrigin | {"market":"DE", "language":"en"} | | targetOrigin | {"market":"DE", "language":"fr"} | And the graph projection is fully up to date When the command CreateNodeVariant is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | sourceOrigin | {"market":"DE", "language":"en"} | | targetOrigin | {"market":"DE", "language":"fr"} | @@ -415,16 +407,13 @@ Feature: Routing functionality with multiple content dimensions And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | originDimensionSpacePoint | {"market":"DE", "language":"fr"} | | propertyValues | {"uriPathSegment": "nody-fr"} | And the graph projection is fully up to date - When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {"market":"DE", "language":"fr"} | | newParentNodeAggregateId | "lady-eleonode-rootford" | diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/DisableNodes.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/DisableNodes.feature index 8912929e8f3..7713ae5b2fe 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/DisableNodes.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/DisableNodes.feature @@ -30,9 +30,9 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date @@ -45,7 +45,6 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes # leaf-mc-node # nody-mc-nodeface # - And I am in content stream "cs-identifier" and dimension space point {} And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | nodeName | | shernode-homes | lady-eleonode-rootford | Neos.Neos:Test.Routing.Page | {"uriPathSegment": "ignore-me"} | node1 | @@ -70,9 +69,8 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And The documenturipath projection is up to date Scenario: Disable leaf node - When the command "DisableNodeAggregate" is executed with payload: + When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "leaf-mc-node" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -81,9 +79,8 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And The node "leaf-mc-node" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough/earl-document/leaf" Scenario: Disable node with child nodes - When the command "DisableNodeAggregate" is executed with payload: + When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -94,15 +91,13 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And The node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough/earl-document" Scenario: Disable two nodes, re-enable the higher one - When the command "DisableNodeAggregate" is executed with payload: + When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | - And the command "DisableNodeAggregate" is executed with payload: + And the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "earl-o-documentbourgh" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -112,9 +107,8 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And No node should match URL "/david-nodenborough/earl-document" And The node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough" And The node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough/earl-document" - When the command "EnableNodeAggregate" is executed with payload: + When the command EnableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -127,15 +121,13 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And The node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough/earl-document" Scenario: Disable two nodes, re-enable the lower one - When the command "DisableNodeAggregate" is executed with payload: + When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | - And the command "DisableNodeAggregate" is executed with payload: + And the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "earl-o-documentbourgh" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -145,9 +137,8 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And No node should match URL "/david-nodenborough/earl-document" And The node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough" And The node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough/earl-document" - When the command "EnableNodeAggregate" is executed with payload: + When the command EnableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "earl-o-documentbourgh" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -159,15 +150,14 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And The node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough/earl-document" Scenario: Disable the same node twice - When the command "DisableNodeAggregate" is executed with payload: + When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | And the event NodeAggregateWasDisabled was published with payload: | Key | Value | - | contentStreamId | "cs-identifier" | + | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | affectedDimensionSpacePoints | [{}] | And the graph projection is fully up to date @@ -176,9 +166,8 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And No node should match URL "/david-nodenborough/earl-document" And The node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough" And The node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough/earl-document" - When the command "EnableNodeAggregate" is executed with payload: + When the command EnableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -190,9 +179,8 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And The node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough/earl-document" Scenario: Re-enable the same node twice - When the command "DisableNodeAggregate" is executed with payload: + When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -207,9 +195,8 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And No node should match URL "/david-nodenborough/earl-document" And The node "sir-david-nodenborough" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough" And The node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough/earl-document" - When the command "EnableNodeAggregate" is executed with payload: + When the command EnableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -226,16 +213,14 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And The node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/david-nodenborough/earl-document" Scenario: Move implicit disabled node - When the command "DisableNodeAggregate" is executed with payload: + When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "earl-o-documentbourgh" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "nody-mc-nodeface" | @@ -245,16 +230,14 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes Then the matched node should be "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" Scenario: Move explicit disabled node - When the command "DisableNodeAggregate" is executed with payload: + When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "earl-o-documentbourgh" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "earl-o-documentbourgh" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "nody-mc-nodeface" | @@ -264,9 +247,8 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes And The node "leaf-mc-node" in content stream "cs-identifier" and dimension "{}" should resolve to URL "/nody/earl-document/leaf" Scenario: Add child node underneath disabled node and re-enable parent (see https://github.com/neos/neos-development-collection/issues/4639) - When the command "DisableNodeAggregate" is executed with payload: + When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -275,9 +257,8 @@ Feature: Routing behavior of removed, disabled and re-enabled nodes | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | nody-mc-nodeface-child | nody-mc-nodeface | Neos.Neos:Test.Routing.Page | {"uriPathSegment": "nody-child"} | And The documenturipath projection is up to date - When the command "EnableNodeAggregate" is executed with payload: + When the command EnableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Lowlevel_ProjectionTests.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Lowlevel_ProjectionTests.feature index 2cdc69e6bcb..2ca042c1632 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Lowlevel_ProjectionTests.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Lowlevel_ProjectionTests.feature @@ -39,14 +39,13 @@ Feature: Low level tests covering the inner behavior of the routing projection | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | nodeName | | shernode-homes | lady-eleonode-rootford | Neos.Neos:Test.Routing.Page | {"uriPathSegment": "ignore-me"} | site | @@ -68,7 +67,6 @@ Feature: Low level tests covering the inner behavior of the routing projection Scenario: abc => acb (moving b) When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "b" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -85,7 +83,6 @@ Feature: Low level tests covering the inner behavior of the routing projection Scenario: abc => acb (moving c) When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "c" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -102,7 +99,6 @@ Feature: Low level tests covering the inner behavior of the routing projection Scenario: abc => bac (moving b) When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "b" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -119,7 +115,6 @@ Feature: Low level tests covering the inner behavior of the routing projection Scenario: abc => bac (moving a) When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "a" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -136,7 +131,6 @@ Feature: Low level tests covering the inner behavior of the routing projection Scenario: abc => bca (moving a) When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "a" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -153,7 +147,6 @@ Feature: Low level tests covering the inner behavior of the routing projection Scenario: abc => bca (moving b and c) When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "b" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -161,7 +154,6 @@ Feature: Low level tests covering the inner behavior of the routing projection And the graph projection is fully up to date And the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "c" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -178,7 +170,6 @@ Feature: Low level tests covering the inner behavior of the routing projection Scenario: abc => a(> b)c (moving b below a) When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "b" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "a" | @@ -195,7 +186,6 @@ Feature: Low level tests covering the inner behavior of the routing projection Scenario: ab(> b1)c => a(> b > b1)c (moving b & b1 below a) When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "b1" | | nodeTypeName | "Neos.Neos:Test.Routing.Page" | | originDimensionSpacePoint | {} | @@ -205,7 +195,6 @@ Feature: Low level tests covering the inner behavior of the routing projection And the graph projection is fully up to date And the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "b" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "a" | @@ -223,7 +212,6 @@ Feature: Low level tests covering the inner behavior of the routing projection Scenario: ab(> b1)c => a(> b1)bc (moving b1 below a) When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "b1" | | nodeTypeName | "Neos.Neos:Test.Routing.Page" | | originDimensionSpacePoint | {} | @@ -233,7 +221,6 @@ Feature: Low level tests covering the inner behavior of the routing projection And the graph projection is fully up to date And the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "b1" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "a" | @@ -257,7 +244,6 @@ Feature: Low level tests covering the inner behavior of the routing projection | b2a | b2 | Neos.Neos:Test.Routing.Page | {"uriPathSegment": "b2a"} | b2a | When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "b2" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "a" | @@ -283,7 +269,6 @@ Feature: Low level tests covering the inner behavior of the routing projection | b2a | b2 | Neos.Neos:Test.Routing.Page | {"uriPathSegment": "b2a"} | b2a | When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "a" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "b" | @@ -303,7 +288,6 @@ Feature: Low level tests covering the inner behavior of the routing projection Scenario: Changing the NodeTypeName of a NodeAggregate When the command ChangeNodeAggregateType was published with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "c" | | newNodeTypeName | "Neos.Neos:Test.Routing.SomeOtherPage" | | strategy | "happypath" | diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/MultiSiteLinking.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/MultiSiteLinking.feature index 33b0b36b404..b054eb1f25d 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/MultiSiteLinking.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/MultiSiteLinking.feature @@ -39,9 +39,9 @@ Feature: Linking between multiple websites | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date @@ -52,7 +52,6 @@ Feature: Linking between multiple websites # duke-of-contentshire (content node) # earl-o-documentbourgh # - And I am in content stream "cs-identifier" and dimension space point {} And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | nodeName | | homepage1 | lady-eleonode-rootford | Neos.Neos:Test.Routing.Page | {"uriPathSegment": "ignore-me"} | site-1 | diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/RouteCache.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/RouteCache.feature index 4a5df7fc03d..046c965289e 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/RouteCache.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/RouteCache.feature @@ -30,9 +30,9 @@ Feature: Route cache invalidation | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date @@ -72,7 +72,6 @@ Feature: Route cache invalidation And The URL "/david-nodenborough/earl-document" should match the node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" And the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | originDimensionSpacePoint | {} | | propertyValues | {"uriPathSegment": "david-nodenborough-updated"} | @@ -87,14 +86,12 @@ Feature: Route cache invalidation And The URL "/david-nodenborough/earl-document" should match the node "earl-o-documentbourgh" in content stream "cs-identifier" and dimension "{}" When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | originDimensionSpacePoint | {} | | propertyValues | {"uriPathSegment": "david-nodenborough-updated-a"} | And The documenturipath projection is up to date When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | originDimensionSpacePoint | {} | | propertyValues | {"uriPathSegment": "david-nodenborough-updated-b"} | @@ -113,7 +110,6 @@ Feature: Route cache invalidation When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "earl-o-documentbourgh" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "shernode-homes" | @@ -128,7 +124,6 @@ Feature: Route cache invalidation When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-nodeface" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "earl-o-documentbourgh" | @@ -144,7 +139,6 @@ Feature: Route cache invalidation When the command DisableNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | @@ -161,7 +155,6 @@ Feature: Route cache invalidation When the command RemoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough" | | coveredDimensionSpacePoint | {} | | nodeVariantSelectionStrategy | "allVariants" | diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Shortcuts.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Shortcuts.feature index 3bba3d61557..8b315048502 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Shortcuts.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/Shortcuts.feature @@ -47,9 +47,9 @@ Feature: Routing behavior of shortcut nodes | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date @@ -67,7 +67,6 @@ Feature: Routing behavior of shortcut nodes # sir-david-nodenborough-ii # sir-nodeward-nodington-iii # - And I am in content stream "cs-identifier" and dimension space point {} And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | nodeName | | shernode-homes | lady-eleonode-rootford | Neos.Neos:Test.Routing.Page | {"uriPathSegment": "ignore-me"} | node1 | @@ -116,7 +115,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut selected target relative URL When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "shortcut-external-url" | | originDimensionSpacePoint | {} | | propertyValues | {"target": "/some/relative/url"} | @@ -127,7 +125,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut selected target URL keeps schema, port, query and fragment of absolute target URLs When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "shortcut-external-url" | | originDimensionSpacePoint | {} | | propertyValues | {"target": "https://www.some-domain.tld:1234/some/url/path?some=query#some-fragment"} | @@ -142,7 +139,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut first child node is updated when a new first child node aggregate is created When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-newface" | | nodeTypeName | "Neos.Neos:Test.Routing.Page" | | originDimensionSpacePoint | {} | @@ -156,7 +152,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut first child node is updated when a node aggregate gets moved to be the new first child node When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-nodeward-nodington-iii" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "shortcut-first-child-node" | @@ -168,7 +163,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut first child node is updated when a node aggregate gets moved to be the new first child node on the same leve When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "second-child-node" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -180,7 +174,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut first child node is not updated when a node aggregate gets moved behind an existing first child node When the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-nodeward-nodington-iii" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | "shortcut-first-child-node" | @@ -192,7 +185,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut first child node is not updated when a node aggregate gets moved behind an existing first child node on the same leve When the command CreateNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-newface" | | nodeTypeName | "Neos.Neos:Test.Routing.Page" | | originDimensionSpacePoint | {} | @@ -202,7 +194,6 @@ Feature: Routing behavior of shortcut nodes And the graph projection is fully up to date And the command MoveNodeAggregate is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "nody-mc-newface" | | dimensionSpacePoint | {} | | newParentNodeAggregateId | null | @@ -214,7 +205,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Regular document node gets turned into a shortcut node When the command ChangeNodeAggregateType was published with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "sir-david-nodenborough-ii" | | newNodeTypeName | "Neos.Neos:Shortcut" | | strategy | "happypath" | @@ -225,7 +215,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut node gets turned into a regular document node When the command ChangeNodeAggregateType was published with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "shortcut-first-child-node" | | newNodeTypeName | "Neos.Neos:Test.Routing.Page" | | strategy | "happypath" | @@ -236,7 +225,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Change shortcut targetMode from "firstChildNode" to "parentNode" When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "shortcut-first-child-node" | | originDimensionSpacePoint | {} | | propertyValues | {"targetMode": "parentNode"} | @@ -247,7 +235,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Change shortcut targetMode from "firstChildNode" to "selectedTarget" (URL) When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "shortcut-first-child-node" | | originDimensionSpacePoint | {} | | propertyValues | {"targetMode": "selectedTarget", "target": "http://www.neos.io"} | @@ -262,7 +249,6 @@ Feature: Routing behavior of shortcut nodes | new-child-node | shortcut-parent-node | Neos.Neos:Test.Routing.Page | {"uriPathSegment": "new-child"} | new | When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "shortcut-parent-node" | | originDimensionSpacePoint | {} | | propertyValues | {"targetMode": "firstChildNode"} | @@ -273,7 +259,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Change shortcut targetMode from "parentNode" to "selectedTarget" (URL) When the command SetNodeProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "shortcut-parent-node" | | originDimensionSpacePoint | {} | | propertyValues | {"targetMode": "selectedTarget", "target": "https://neos.io/"} | @@ -284,7 +269,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut node with an invalid targetMode Given the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "invalid-target-mode" | | nodeTypeName | "Neos.Neos:Shortcut" | | originDimensionSpacePoint | {} | @@ -298,7 +282,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut node with targetMode "selectedTarget" but without target Given the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "invalid-missing-target" | | nodeTypeName | "Neos.Neos:Shortcut" | | originDimensionSpacePoint | {} | @@ -312,7 +295,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut node without child nodes and targetMode "firstChildNode" Given the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "invalid-shortcut-first-child-node" | | nodeTypeName | "Neos.Neos:Shortcut" | | originDimensionSpacePoint | {} | @@ -326,7 +308,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut node with targetMode "selectedTarget" and a non-existing target node Given the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "invalid-shortcut-selected-node" | | nodeTypeName | "Neos.Neos:Shortcut" | | originDimensionSpacePoint | {} | @@ -340,7 +321,6 @@ Feature: Routing behavior of shortcut nodes Scenario: Shortcut node with targetMode "selectedTarget" and a empty target node Given the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "invalid-shortcut-selected-node" | | nodeTypeName | "Neos.Neos:Shortcut" | | originDimensionSpacePoint | {} | diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/TetheredSiteChildDocuments.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/TetheredSiteChildDocuments.feature index 5b644025b96..df5b10e9ccc 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/TetheredSiteChildDocuments.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/TetheredSiteChildDocuments.feature @@ -30,13 +30,12 @@ Feature: Tests for site node child documents. These are special in that they hav | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} # We explicitly create a site node with a tethered child document without uriPathSegment, so its uriPath is empty, exactly as the site node's And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | nodeName | diff --git a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/UnknownNodeTypes.feature b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/UnknownNodeTypes.feature index bc02ed1efab..7923dac5f9e 100644 --- a/Neos.Neos/Tests/Behavior/Features/FrontendRouting/UnknownNodeTypes.feature +++ b/Neos.Neos/Tests/Behavior/Features/FrontendRouting/UnknownNodeTypes.feature @@ -24,9 +24,9 @@ Feature: Basic routing functionality (match & resolve nodes with unknown types) | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date diff --git a/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCase.feature b/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCase.feature index 3c18ebada65..d73a80cf0cf 100644 --- a/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCase.feature +++ b/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCase.feature @@ -33,13 +33,12 @@ Feature: Tests for the "Neos.Neos:ContentCase" Fusion prototype | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "root" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | | a | root | Neos.Neos:Site | diff --git a/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature b/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature index c834e9cb06e..f68a96cf08b 100644 --- a/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature +++ b/Neos.Neos/Tests/Behavior/Features/Fusion/ContentCollection.feature @@ -41,13 +41,12 @@ Feature: Tests for the "Neos.Neos:ContentCollection" Fusion prototype | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "root" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | | a | root | Neos.Neos:Site | @@ -112,7 +111,6 @@ Feature: Tests for the "Neos.Neos:ContentCollection" Fusion prototype Scenario: When the command CreateNodeAggregateWithNodeAndSerializedProperties is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "a1" | | nodeTypeName | "Neos.Neos:Test.DocumentType" | | parentNodeAggregateId | "a" | diff --git a/Neos.Neos/Tests/Behavior/Features/Fusion/ConvertUris.feature b/Neos.Neos/Tests/Behavior/Features/Fusion/ConvertUris.feature index 8ed0e7184ca..fccf8d719b6 100644 --- a/Neos.Neos/Tests/Behavior/Features/Fusion/ConvertUris.feature +++ b/Neos.Neos/Tests/Behavior/Features/Fusion/ConvertUris.feature @@ -30,9 +30,9 @@ Feature: Tests for the "Neos.Neos:ConvertUris" Fusion prototype | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "root" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date diff --git a/Neos.Neos/Tests/Behavior/Features/Fusion/FlowQuery.feature b/Neos.Neos/Tests/Behavior/Features/Fusion/FlowQuery.feature index 07835b41d8a..b7073940274 100644 --- a/Neos.Neos/Tests/Behavior/Features/Fusion/FlowQuery.feature +++ b/Neos.Neos/Tests/Behavior/Features/Fusion/FlowQuery.feature @@ -46,9 +46,9 @@ Feature: Tests for the "Neos.ContentRepository" Flow Query methods. | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "root" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date diff --git a/Neos.Neos/Tests/Behavior/Features/Fusion/Menu.feature b/Neos.Neos/Tests/Behavior/Features/Fusion/Menu.feature index 9d94f027ac5..d137b1b77ec 100644 --- a/Neos.Neos/Tests/Behavior/Features/Fusion/Menu.feature +++ b/Neos.Neos/Tests/Behavior/Features/Fusion/Menu.feature @@ -46,13 +46,12 @@ Feature: Tests for the "Neos.Neos:Menu" and related Fusion prototypes | Key | Value | | workspaceName | "live" | | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "root" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date - And I am in content stream "cs-identifier" and dimension space point {} And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | nodeName | | a | root | Neos.Neos:Site | {"title": "Node a"} | a | diff --git a/Neos.TimeableNodeVisibility/Classes/Service/TimeableNodeVisibilityService.php b/Neos.TimeableNodeVisibility/Classes/Service/TimeableNodeVisibilityService.php index 1e761c51f14..ea41073c453 100644 --- a/Neos.TimeableNodeVisibility/Classes/Service/TimeableNodeVisibilityService.php +++ b/Neos.TimeableNodeVisibility/Classes/Service/TimeableNodeVisibilityService.php @@ -54,11 +54,12 @@ public function handleExceededNodeDates(ContentRepositoryId $contentRepositoryId $results = []; foreach ($nodes as $node) { + /** @var Node $node */ $nodeIsHidden = $this->isHidden($node, $nodeHiddenStateFinder); if ($this->needsEnabling($node, $now) && $nodeIsHidden) { $contentRepository->handle( EnableNodeAggregate::create( - $node->subgraphIdentity->contentStreamId, + $liveWorkspace->workspaceName, $node->nodeAggregateId, $node->subgraphIdentity->dimensionSpacePoint, NodeVariantSelectionStrategy::STRATEGY_ALL_SPECIALIZATIONS @@ -72,7 +73,7 @@ public function handleExceededNodeDates(ContentRepositoryId $contentRepositoryId if ($this->needsDisabling($node, $now) && !$nodeIsHidden) { $contentRepository->handle( DisableNodeAggregate::create( - $node->subgraphIdentity->contentStreamId, + $liveWorkspace->workspaceName, $node->nodeAggregateId, $node->subgraphIdentity->dimensionSpacePoint, NodeVariantSelectionStrategy::STRATEGY_ALL_SPECIALIZATIONS diff --git a/Neos.TimeableNodeVisibility/Tests/Behavior/Features/HandleExceeded.feature b/Neos.TimeableNodeVisibility/Tests/Behavior/Features/HandleExceeded.feature index 54419c8d110..845bb8fc66c 100644 --- a/Neos.TimeableNodeVisibility/Tests/Behavior/Features/HandleExceeded.feature +++ b/Neos.TimeableNodeVisibility/Tests/Behavior/Features/HandleExceeded.feature @@ -32,9 +32,10 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat | workspaceName | "live" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date + And I am in workspace "live" + And I am in the active content stream of workspace "live" and dimension space point {} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | - | contentStreamId | "cs-identifier" | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.Neos:Sites" | And the graph projection is fully up to date @@ -43,8 +44,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # -----|Enable|++++++++++++++|+++|+++++++++++++|Disable|----- Scenario: A enabled node with enableAfter in past and disableAfter in future must stay enabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}, "disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+10 days"}} | @@ -58,8 +58,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # -----|Enable|++++++++++++++|---|+++++++++++++|Disable|----- Scenario: A disabled node with enableAfter in past and disableAfter in future must be enabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}, "disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+10 days"}} | @@ -78,8 +77,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # +++++|Disable|-------------|+++|--------------|Enable|+++++ Scenario: A enabled node with enableAfter in future and disableAfter past in must be disabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+10 days"},"disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}} | @@ -93,8 +91,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # +++++|Disable|-------------|---|--------------|Enable|+++++ Scenario: A disabled node with enableAfter in future and disableAfter past in must stay disabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+10 days"},"disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}} | @@ -113,8 +110,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # ---|Enable|+++|Disable|----|+++|--------------------------- Scenario: A enabled node with enableAfter and disableAfter in past, but enableAfter before disableAfter must be disabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}, "disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-9 days"}} | @@ -128,8 +124,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # ---|Enable|+++|Disable|----|---|--------------------------- Scenario: A disabled node with enableAfter and disableAfter in past, but enableAfter before disableAfter must stay disabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}, "disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-9 days"}} | @@ -148,8 +143,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # +++|Disable|---|Enable|++++|+++|+++++++++++++++++++++++++++ Scenario: A enabled node with enableAfter and disableAfter in past, but disableAfter before enableAfter must stay enabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-9 days"}, "disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}} | @@ -163,8 +157,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # +++|Disable|---|Enable|++++|---|+++++++++++++++++++++++++++ Scenario: A disabled node with enableAfter and disableAfter in past, but disableAfter before enableAfter must be enabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-9 days"}, "disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}} | @@ -183,10 +176,9 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # +++++|Disable|-------------|+++|--------------------------- Scenario: A enabled node with disableAfter past in must be disabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: - | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | - | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | + When the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | + | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}} | Then I expect node aggregate identifier "duke-of-contentshire" to lead to node cs-identifier;duke-of-contentshire;{} And I expect exactly 4 events to be published on stream "ContentStream:cs-identifier" @@ -198,10 +190,9 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # +++++|Disable|-------------|---|--------------------------- Scenario: A enabled node with disableAfter past in must stay disabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: - | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | - | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | + When the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | + | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}} | Then I expect node aggregate identifier "duke-of-contentshire" to lead to node cs-identifier;duke-of-contentshire;{} And the command DisableNodeAggregate is executed with payload: @@ -218,10 +209,9 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # -----|Enable|++++++++++++++|+++|+++++++++++++++++++++++++++ Scenario: A enabled node with enableAfter past in must stay enabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: - | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | - | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | + When the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | + | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}} | Then I expect node aggregate identifier "duke-of-contentshire" to lead to node cs-identifier;duke-of-contentshire;{} And I expect exactly 4 events to be published on stream "ContentStream:cs-identifier" @@ -233,10 +223,9 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # -----|Enable|++++++++++++++|---|+++++++++++++++++++++++++++ Scenario: A disabled node with enableAfter past in must be enabled - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: - | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | - | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | + When the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | + | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "-10 days"}} | Then I expect node aggregate identifier "duke-of-contentshire" to lead to node cs-identifier;duke-of-contentshire;{} And the command DisableNodeAggregate is executed with payload: @@ -253,8 +242,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # ---------------------------|---|---|Enable|+++++|Disable|-- Scenario: A disabled node with enableAfter and disableAfter in future must not be changed - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+9 days"}, "disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+10 days"}} | @@ -273,8 +261,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # ---------------------------|+++|---|Enable|+++++|Disable|-- Scenario: A enabled node with enableAfter and disableAfter in future must not be changed - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+9 days"}, "disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+10 days"}} | @@ -289,8 +276,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # +++++++++++++++++++++++++++|---|+++|Disable|-----|Enable|++ Scenario: A disabled node with disableAfter and enableAfter in future must not be changed - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+9 days"}, "disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+10 days"}} | @@ -308,8 +294,7 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # +++++++++++++++++++++++++++|+++|+++|Disable|-----|Enable|++ Scenario: A enabled node with disableAfter and enableAfter in future must not be changed - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: + When the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+9 days"}, "disableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+10 days"}} | @@ -324,10 +309,9 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # ---------------------------|---|---|Enable|+++++++++++++++ Scenario: A disabled node with enableAfter in future must not be changed - When I am in content stream "cs-identifier" and dimension space point {} - And the following CreateNodeAggregateWithNode commands are executed: - | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | - | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | + When the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | + | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | | duke-of-contentshire | shernode-homes | Some.Package:Content | {"enableAfterDateTime": {"__type": "DateTimeImmutable", "value": "+9 days"}} | Then I expect node aggregate identifier "duke-of-contentshire" to lead to node cs-identifier;duke-of-contentshire;{} And the command DisableNodeAggregate is executed with payload: @@ -344,7 +328,6 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # ---------------------------|+++|---|Enable|+++++++++++++++ Scenario: A enabled node with enableAfter in future must not be changed - When I am in content stream "cs-identifier" and dimension space point {} And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | @@ -360,7 +343,6 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # +++++++++++++++++++++++++++|---|+++|Disable|--------------- Scenario: A disabled node with disableAfter in future must not be changed - When I am in content stream "cs-identifier" and dimension space point {} And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | @@ -379,7 +361,6 @@ Feature: Simple handling of nodes with exceeded enableAfter and disableAfter dat # <===========================|now|===========================> # +++++++++++++++++++++++++++|+++|+++|Disable|--------------- Scenario: A enabled node with disableAfter and enableAfter in future must not be changed - When I am in content stream "cs-identifier" and dimension space point {} And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | parentNodeAggregateId | nodeTypeName | initialPropertyValues | | shernode-homes | lady-eleonode-rootford | Some.Package:Homepage | {} | diff --git a/composer.json b/composer.json index ef5a937ac53..b1dc6ed5afa 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "webmozart/assert": "^1.11", "neos/flow": "*", "behat/behat": "^3.5", - "phpunit/phpunit": "^9.0", + "phpunit/phpunit": "^9.6", + "brianium/paratest": "^6.11", "neos/behat": "^9.0", "neos/contentrepositoryregistry-storageclient": "self.version", "symfony/property-access": "^5.4|^6.0", @@ -114,7 +115,7 @@ "../../bin/phpunit --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/UnitTests.xml Neos.ContentRepositoryRegistry/Tests/Unit" ], "test:functional": [ - "../../bin/phpunit --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.Core/Tests/Functional" + "FLOW_CONTEXT=Testing ../../bin/phpunit --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.Core/Tests/Functional" ], "test:behat-cli": "../../bin/behat -f progress --strict --no-interaction", "test:behavioral": [ @@ -135,10 +136,16 @@ "../../flow doctrine:migrate --quiet; ../../flow cr:setup", "@test:behat-cli -vvv --stop-on-failure -c Neos.Neos/Tests/Behavior/behat.yml" ], + "test:parallel": [ + "FLOW_CONTEXT=Testing/Behat ../../bin/paratest --debug -v --functional --group parallel --processes 2 --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php", + "FLOW_CONTEXT=Testing/Behat ../../bin/paratest --debug -v --functional --group parallel --processes 2 --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php", + "FLOW_CONTEXT=Testing/Behat ../../bin/paratest --debug -v --functional --group parallel --processes 2 --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.BehavioralTests/Tests/Functional/Feature/WorkspacePublication/WorkspaceWritingDuringPublication.php" + ], "test": [ "@test:unit", "@test:functional", - "@test:behavioral" + "@test:behavioral", + "@test:parallel" ] }, "autoload": { @@ -297,8 +304,9 @@ "roave/security-advisories": "dev-latest", "phpstan/phpstan": "^1.8", "squizlabs/php_codesniffer": "^3.6", - "phpunit/phpunit": "^9.0", + "phpunit/phpunit": "^9.6", "neos/behat": "*", + "brianium/paratest": "^6.11", "league/flysystem-memory": "^3" } } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ac7130ac599..158d86aa599 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -165,11 +165,6 @@ parameters: count: 1 path: Neos.Neos/Classes/Controller/Module/User/UserSettingsController.php - - - message: "#^The internal method \"Neos\\\\ContentRepository\\\\Core\\\\Projection\\\\ContentStream\\\\ContentStreamFinder\\:\\:findAllIds\" is called\\.$#" - count: 1 - path: Neos.Neos/Classes/Domain/Service/SiteServiceInternals.php - - message: "#^The internal method \"Neos\\\\ContentRepository\\\\Core\\\\DimensionSpace\\\\WeightedDimensionSpacePoint\\:\\:getIdentityHash\" is called\\.$#" count: 3