From 4ef998794dc3ae0ffec1aa7b696f2eed018e45a4 Mon Sep 17 00:00:00 2001 From: Denny Lubitz Date: Thu, 15 Aug 2024 12:29:19 +0200 Subject: [PATCH 1/5] TASK: Ensure migration works case sensitive and will end in a workspaceName with a leading letter. Also applying to baseWorkspaceName. --- .../Classes/Service/EventMigrationService.php | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php b/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php index d51eabd5ef2..50eb79b7315 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php +++ b/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php @@ -385,24 +385,35 @@ public function migratePayloadToValidWorkspaceNames(\Closure $outputFn): void $eventTableName = DoctrineEventStoreFactory::databaseTableName($this->contentRepositoryId); $this->connection->beginTransaction(); - $statement = <<connection->executeStatement($statement); + $affectedRowsWorkspaceName = $this->connection->executeStatement($statementWorkspaceName); + + $statementBaseWorkspaceName = <<connection->executeStatement($statementBaseWorkspaceName); $this->connection->commit(); - if ($affectedRows === 0) { + if ($affectedRowsWorkspaceName + $affectedRowsBaseWorkspaceName === 0) { $outputFn('Migration was not necessary.'); return; } $outputFn(); - $outputFn(sprintf('Migration applied to %s events.', $affectedRows)); + $outputFn(sprintf('Migration applied to %s events and changed the workspaceName.', $affectedRowsWorkspaceName)); + $outputFn(sprintf('Migration applied to %s events and changed the baseWorkspaceName.', $affectedRowsBaseWorkspaceName)); } /** ------------------------ */ From 6acb21f8f291714acb1c6ad496c36468cd71d015 Mon Sep 17 00:00:00 2001 From: Denny Lubitz Date: Thu, 15 Aug 2024 14:26:21 +0200 Subject: [PATCH 2/5] TASK: Ensure migration works case sensitive and will end in a workspaceName with a leading letter. Also applying to baseWorkspaceName. --- .../Classes/Service/EventMigrationService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php b/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php index 50eb79b7315..011e7b589ee 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php +++ b/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php @@ -406,7 +406,7 @@ public function migratePayloadToValidWorkspaceNames(\Closure $outputFn): void $affectedRowsBaseWorkspaceName = $this->connection->executeStatement($statementBaseWorkspaceName); $this->connection->commit(); - if ($affectedRowsWorkspaceName + $affectedRowsBaseWorkspaceName === 0) { + if ($affectedRowsWorkspaceName === 0 && $affectedRowsBaseWorkspaceName === 0) { $outputFn('Migration was not necessary.'); return; } From c4f6c912217439251fb129433e4c07a92ee814ef Mon Sep 17 00:00:00 2001 From: Denny Lubitz Date: Fri, 16 Aug 2024 15:13:11 +0200 Subject: [PATCH 3/5] TASK: Lower constraints on workspaceName and adapted migration --- .../SharedModel/Workspace/WorkspaceName.php | 7 +++--- .../Workspace/WorkspaceNameTest.php | 7 +++--- .../Classes/Service/EventMigrationService.php | 22 +++++++++++++++---- .../Domain/Service/WorkspaceNameBuilder.php | 2 +- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/WorkspaceName.php b/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/WorkspaceName.php index 512c52aa368..e6d9e4a87e2 100644 --- a/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/WorkspaceName.php +++ b/Neos.ContentRepository.Core/Classes/SharedModel/Workspace/WorkspaceName.php @@ -23,9 +23,9 @@ */ final class WorkspaceName implements \JsonSerializable { - public const MAX_LENGTH = 30; + public const MAX_LENGTH = 36; - private const PATTERN = '/^[a-z][a-z0-9\-]{0,' . (self::MAX_LENGTH - 1) . '}$/'; + private const PATTERN = '/^[a-z0-9][a-z0-9\-]{0,' . (self::MAX_LENGTH - 1) . '}$/'; public const WORKSPACE_NAME_LIVE = 'live'; @@ -89,8 +89,7 @@ public static function transliterateFromString(string $name): self // If the name is still invalid at this point, we fall back to md5 if (!self::hasValidFormat($name)) { - $prefix = 'workspace-'; - $name = $prefix . substr(md5($originalName), 0, self::MAX_LENGTH - strlen($prefix)); + $name = substr(md5($originalName), 0, self::MAX_LENGTH); } return self::fromString($name); diff --git a/Neos.ContentRepository.Core/Tests/Unit/SharedModel/Workspace/WorkspaceNameTest.php b/Neos.ContentRepository.Core/Tests/Unit/SharedModel/Workspace/WorkspaceNameTest.php index 6d01e897715..d31cd4e7cad 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/SharedModel/Workspace/WorkspaceNameTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/SharedModel/Workspace/WorkspaceNameTest.php @@ -58,11 +58,10 @@ public function tryFromStringReturnsInstanceForValidValues(string $value): void private static function invalidWorkspaceNames(): iterable { yield 'empty string' => ['']; - yield 'only digits' => ['123']; yield 'leading dash' => ['-invalid']; yield 'upper case characters' => ['thisIsNotAllowed']; yield 'whitespace' => ['this neither']; - yield 'exceeding max length' => ['this-is-just-a-little-too-long-']; + yield 'exceeding max length' => ['this-is-just-a-little-little-bit-too-long-']; } /** @@ -99,8 +98,8 @@ private static function transliterateFromStringDataProvider(): iterable yield 'chinese characters' => ['value' => '北京', 'expectedResult' => 'bei-jing']; yield 'german umlauts' => ['value' => 'ümläute', 'expectedResult' => 'umlaute']; yield 'white space' => ['value' => ' Contains spaces ', 'expectedResult' => 'contains-spaces']; - yield 'exceeding max length' => ['value' => 'This name is just a little too long', 'expectedResult' => 'this-name-is-just-a-little-too']; - yield 'only special characters' => ['value' => '-', 'expectedResult' => 'workspace-336d5ebc5436534e61d1']; + yield 'exceeding max length' => ['value' => 'This name is just a little little bit too long', 'expectedResult' => 'this-name-is-just-a-little-little-bi']; + yield 'only special characters' => ['value' => '-', 'expectedResult' => '336d5ebc5436534e61d16e63ddfca327']; } /** diff --git a/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php b/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php index 011e7b589ee..ba739111f89 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php +++ b/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php @@ -388,20 +388,34 @@ public function migratePayloadToValidWorkspaceNames(\Closure $outputFn): void $statementWorkspaceName = <<connection->executeStatement($statementWorkspaceName); $statementBaseWorkspaceName = <<connection->executeStatement($statementBaseWorkspaceName); $this->connection->commit(); diff --git a/Neos.Neos/Classes/Domain/Service/WorkspaceNameBuilder.php b/Neos.Neos/Classes/Domain/Service/WorkspaceNameBuilder.php index 44d75e72086..fc08f99cb26 100644 --- a/Neos.Neos/Classes/Domain/Service/WorkspaceNameBuilder.php +++ b/Neos.Neos/Classes/Domain/Service/WorkspaceNameBuilder.php @@ -30,6 +30,6 @@ public static function fromAccountIdentifier(string $accountIdentifier): Workspa 1645656253 ); } - return WorkspaceName::fromString($name); + return WorkspaceName::transliterateFromString($name); } } From 30096c7af941d5840ab1fa998ad39a1bf979bb00 Mon Sep 17 00:00:00 2001 From: Denny Lubitz Date: Fri, 16 Aug 2024 15:19:45 +0200 Subject: [PATCH 4/5] TASK: Add info for migration --- .../Classes/Service/EventMigrationService.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php b/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php index ba739111f89..c2b7b5b6ebd 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php +++ b/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php @@ -428,6 +428,7 @@ public function migratePayloadToValidWorkspaceNames(\Closure $outputFn): void $outputFn(); $outputFn(sprintf('Migration applied to %s events and changed the workspaceName.', $affectedRowsWorkspaceName)); $outputFn(sprintf('Migration applied to %s events and changed the baseWorkspaceName.', $affectedRowsBaseWorkspaceName)); + $outputFn(sprintf('You need to replay your projection for workspaces. Please run: ./flow cr:projectionreplay --projection=workspace')); } /** ------------------------ */ From 09faadc0288f61343518f4718ded57ddcdefcb6d Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Sat, 17 Aug 2024 01:37:57 +0200 Subject: [PATCH 5/5] 5201 - Add missing workspace property name handling --- .../Classes/Service/EventMigrationService.php | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php b/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php index c2b7b5b6ebd..c917634e799 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php +++ b/Neos.ContentRepositoryRegistry/Classes/Service/EventMigrationService.php @@ -389,7 +389,7 @@ public function migratePayloadToValidWorkspaceNames(\Closure $outputFn): void UPDATE {$eventTableName} SET payload = JSON_SET( - payload, + payload, '$.workspaceName', IF(JSON_UNQUOTE(JSON_EXTRACT(payload, '$.workspaceName')) REGEXP '^[a-z0-9][a-z0-9\-]{0,35}$', LOWER(JSON_UNQUOTE(JSON_EXTRACT(payload, '$.workspaceName'))), @@ -406,7 +406,7 @@ public function migratePayloadToValidWorkspaceNames(\Closure $outputFn): void UPDATE {$eventTableName} SET payload = JSON_SET( - payload, + payload, '$.baseWorkspaceName', IF(JSON_UNQUOTE(JSON_EXTRACT(payload, '$.baseWorkspaceName')) REGEXP '^[a-z0-9][a-z0-9\-]{0,35}$', LOWER(JSON_UNQUOTE(JSON_EXTRACT(payload, '$.baseWorkspaceName'))), @@ -418,9 +418,43 @@ public function migratePayloadToValidWorkspaceNames(\Closure $outputFn): void AND BINARY JSON_UNQUOTE(JSON_EXTRACT(payload, '$.baseWorkspaceName')) NOT REGEXP '^[a-z0-9][a-z0-9\-]{0,35}$' SQL; $affectedRowsBaseWorkspaceName = $this->connection->executeStatement($statementBaseWorkspaceName); + + $sourceWorkspaceNameStatement = <<connection->executeStatement($sourceWorkspaceNameStatement); + + $targetWorkspaceNameStatement = <<connection->executeStatement($targetWorkspaceNameStatement); $this->connection->commit(); - if ($affectedRowsWorkspaceName === 0 && $affectedRowsBaseWorkspaceName === 0) { + if ($affectedRowsWorkspaceName === 0 && $affectedRowsBaseWorkspaceName === 0 && $sourceWorkspaceAffectedRows === 0 && $targetWorkspaceAffectedRows === 0) { $outputFn('Migration was not necessary.'); return; } @@ -428,6 +462,8 @@ public function migratePayloadToValidWorkspaceNames(\Closure $outputFn): void $outputFn(); $outputFn(sprintf('Migration applied to %s events and changed the workspaceName.', $affectedRowsWorkspaceName)); $outputFn(sprintf('Migration applied to %s events and changed the baseWorkspaceName.', $affectedRowsBaseWorkspaceName)); + $outputFn(sprintf('Migration applied to %s events and changed the sourceWorkspaceName.', $sourceWorkspaceAffectedRows)); + $outputFn(sprintf('Migration applied to %s events and changed the targetWorkspaceName.', $targetWorkspaceAffectedRows)); $outputFn(sprintf('You need to replay your projection for workspaces. Please run: ./flow cr:projectionreplay --projection=workspace')); }