From 36b5fd558910c260e1daf08375ff4581b46402e8 Mon Sep 17 00:00:00 2001 From: Ted Bowman <ted+git@tedbow.com> Date: Fri, 18 Apr 2025 15:18:32 -0400 Subject: [PATCH 1/8] do not convert entity_form_fields if not auto-saving --- src/Controller/ApiLayoutController.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Controller/ApiLayoutController.php b/src/Controller/ApiLayoutController.php index 8f4a22f0a8..f9d0b194b5 100644 --- a/src/Controller/ApiLayoutController.php +++ b/src/Controller/ApiLayoutController.php @@ -380,7 +380,10 @@ final class ApiLayoutController { // correctly json encoded. But we need to convert it to an array before // we can extract it. 'model' => (array) $model, - 'entity_form_fields' => $body['entity_form_fields'], + // If we are not auto-saving there is not reason to convert the + // 'entity_form_fields'. This can cause access issue for just viewing the + // preview. + 'entity_form_fields' => $updateAutoSave ? $body['entity_form_fields'] : [], ], $entity, validate: FALSE); // Store the auto-save entry. if ($updateAutoSave) { -- GitLab From c62a9341cb7f21ee430b8add70c31aa6112707b3 Mon Sep 17 00:00:00 2001 From: Ted Bowman <ted+git@tedbow.com> Date: Fri, 18 Apr 2025 15:47:44 -0400 Subject: [PATCH 2/8] update comment --- src/Controller/ApiLayoutController.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Controller/ApiLayoutController.php b/src/Controller/ApiLayoutController.php index f9d0b194b5..3c1977c230 100644 --- a/src/Controller/ApiLayoutController.php +++ b/src/Controller/ApiLayoutController.php @@ -380,9 +380,11 @@ final class ApiLayoutController { // correctly json encoded. But we need to convert it to an array before // we can extract it. 'model' => (array) $model, - // If we are not auto-saving there is not reason to convert the + // If we are not auto-saving there is no reason to convert the // 'entity_form_fields'. This can cause access issue for just viewing the - // preview. + // preview. This runs the conversion as if the user had no access to edit + // the entity fields which is all the that is necessary when not + // auto-saving. 'entity_form_fields' => $updateAutoSave ? $body['entity_form_fields'] : [], ], $entity, validate: FALSE); // Store the auto-save entry. -- GitLab From 10303e79713a3168ed8b9e2d1f3aa4178d2bec96 Mon Sep 17 00:00:00 2001 From: Ted Bowman <ted+git@tedbow.com> Date: Tue, 22 Apr 2025 09:17:31 -0400 Subject: [PATCH 3/8] add test coverage --- .../src/Kernel/ApiLayoutControllerGetTest.php | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/src/Kernel/ApiLayoutControllerGetTest.php b/tests/src/Kernel/ApiLayoutControllerGetTest.php index 3d85ae20df..0f6c1b9d8d 100644 --- a/tests/src/Kernel/ApiLayoutControllerGetTest.php +++ b/tests/src/Kernel/ApiLayoutControllerGetTest.php @@ -16,6 +16,7 @@ use Drupal\node\NodeInterface; use Drupal\Tests\experience_builder\Kernel\Traits\RequestTrait; use Drupal\Tests\experience_builder\TestSite\XBTestSetup; use Drupal\Tests\user\Traits\UserCreationTrait; +use Drupal\user\Entity\User; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -376,6 +377,68 @@ class ApiLayoutControllerGetTest extends ApiLayoutControllerTestBase { self::assertSame($isPublished, $json['isPublished']); } + /** + * Tests that auto_save entries with inaccessible fields do not cause errors. + * + * @covers \Drupal\experience_builder\Controller\ApiLayoutController::buildPreviewRenderable + */ + public function testInaccessibleFieldsInAutoSave(): void { + // Create a node to work with. + $node = Node::create([ + 'type' => 'article', + 'title' => 'Test Node', + ]); + $node->save(); + + // Set up the current user without access to path field. + $authenticated_role = $this->createRole(['access administration pages']); + $limited_user = $this->createUser([], NULL, FALSE, ['roles' => [$authenticated_role]]); + assert($limited_user instanceof User); + $this->setCurrentUser($limited_user); + + // Create an auto-save entry with a value for a field that the user doesn't have access to. + $autoSave = $this->container->get(AutoSaveManager::class); + assert($autoSave instanceof AutoSaveManager); + + // Create test data with a field the user doesn't have access to (path field). + $data = [ + 'layout' => [ + [ + 'nodeType' => 'region', + 'id' => 'content', + 'name' => 'Content', + 'components' => [], + ], + ], + 'model' => [], + 'entity_form_fields' => [ + 'title[0][value]' => 'Test Node', + // Path field that user doesn't have access to + 'path[0][alias]' => '/test-path', + ], + ]; + + $autoSave->save($node, $data); + + $url = Url::fromRoute('experience_builder.api.layout.get', [ + 'entity' => $node->id(), + 'entity_type' => 'node', + ]); + + // This should not throw an exception even though the auto_save data + // contains a value for path field that the user doesn't have access to. + $response = $this->request(Request::create($url->toString())); + + // Verify that the response is successful. + self::assertEquals(Response::HTTP_OK, $response->getStatusCode()); + + // Check that the response contains the correct title. + self::assertInstanceOf(JsonResponse::class, $response); + $json = json_decode($response->getContent() ?: '', TRUE); + self::assertArrayHasKey('entity_form_fields', $json); + self::assertEquals('Test Node', $json['entity_form_fields']['title[0][value]']); + } + public function testFieldException(): void { $page_type = NodeType::create([ 'type' => 'page', -- GitLab From d7494b4a60959aad7162b09cd463e15bb71e0ffc Mon Sep 17 00:00:00 2001 From: Ted Bowman <ted+git@tedbow.com> Date: Tue, 22 Apr 2025 09:17:50 -0400 Subject: [PATCH 4/8] do not call setEntityFields if none provided --- src/ClientDataToEntityConverter.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ClientDataToEntityConverter.php b/src/ClientDataToEntityConverter.php index 18e16bb107..8eb14b9fd9 100644 --- a/src/ClientDataToEntityConverter.php +++ b/src/ClientDataToEntityConverter.php @@ -60,7 +60,11 @@ class ClientDataToEntityConverter { throw new ConstraintViolationException(new EntityConstraintViolationList($entity, iterator_to_array($e->getConstraintViolationList()))); } - $updated_entity_form_fields = $this->setEntityFields($entity, $entity_form_fields); + // The current user may not have access any other fields on the entity or + // this function maybe have been called to only update the layout. + if (!empty($entity_form_fields)) { + $updated_entity_form_fields = $this->setEntityFields($entity, $entity_form_fields); + } $original_entity_violations = $entity->validate(); // Validation happens using the server-side representation, but the // error message should use the client-side representation received in -- GitLab From faa80faa7b48709b01ceab41f088ae40b225e3cc Mon Sep 17 00:00:00 2001 From: Ted Bowman <ted+git@tedbow.com> Date: Tue, 22 Apr 2025 09:20:12 -0400 Subject: [PATCH 5/8] nit --- src/ClientDataToEntityConverter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ClientDataToEntityConverter.php b/src/ClientDataToEntityConverter.php index 8eb14b9fd9..cc794e3510 100644 --- a/src/ClientDataToEntityConverter.php +++ b/src/ClientDataToEntityConverter.php @@ -61,7 +61,7 @@ class ClientDataToEntityConverter { } // The current user may not have access any other fields on the entity or - // this function maybe have been called to only update the layout. + // this function may have been called to only update the layout. if (!empty($entity_form_fields)) { $updated_entity_form_fields = $this->setEntityFields($entity, $entity_form_fields); } -- GitLab From 1e692c76cc86fb796a610f95aa31c2d4c627c063 Mon Sep 17 00:00:00 2001 From: Ted Bowman <ted+git@tedbow.com> Date: Tue, 22 Apr 2025 11:19:38 -0400 Subject: [PATCH 6/8] ensure updated_entity_form_fields is set --- src/ClientDataToEntityConverter.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ClientDataToEntityConverter.php b/src/ClientDataToEntityConverter.php index cc794e3510..dabb317795 100644 --- a/src/ClientDataToEntityConverter.php +++ b/src/ClientDataToEntityConverter.php @@ -62,9 +62,9 @@ class ClientDataToEntityConverter { // The current user may not have access any other fields on the entity or // this function may have been called to only update the layout. - if (!empty($entity_form_fields)) { - $updated_entity_form_fields = $this->setEntityFields($entity, $entity_form_fields); - } + $updated_entity_form_fields = !empty($entity_form_fields) ? + $this->setEntityFields($entity, $entity_form_fields) : + []; $original_entity_violations = $entity->validate(); // Validation happens using the server-side representation, but the // error message should use the client-side representation received in -- GitLab From 55c9ce46d1eec2be0fb1e2019c43cb8304fbe141 Mon Sep 17 00:00:00 2001 From: Ted Bowman <ted+git@tedbow.com> Date: Tue, 29 Apr 2025 12:52:27 -0400 Subject: [PATCH 7/8] @larowlan fixes --- src/ClientDataToEntityConverter.php | 2 +- src/Controller/ApiLayoutController.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ClientDataToEntityConverter.php b/src/ClientDataToEntityConverter.php index dabb317795..b722f6530a 100644 --- a/src/ClientDataToEntityConverter.php +++ b/src/ClientDataToEntityConverter.php @@ -62,7 +62,7 @@ class ClientDataToEntityConverter { // The current user may not have access any other fields on the entity or // this function may have been called to only update the layout. - $updated_entity_form_fields = !empty($entity_form_fields) ? + $updated_entity_form_fields = \count($entity_form_fields) !== 0 ? $this->setEntityFields($entity, $entity_form_fields) : []; $original_entity_violations = $entity->validate(); diff --git a/src/Controller/ApiLayoutController.php b/src/Controller/ApiLayoutController.php index 3c1977c230..7aaa2328ad 100644 --- a/src/Controller/ApiLayoutController.php +++ b/src/Controller/ApiLayoutController.php @@ -37,7 +37,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; */ final class ApiLayoutController { - use ClientServerConversionTrait; use EntityFormTrait; const ENTITY_DUPLICATE_SUFFIX = ' (Copy)'; -- GitLab From 65334671343e07dd9c969964a2ead20149f037df Mon Sep 17 00:00:00 2001 From: Wim Leers <44946-wimleers@users.noreply.drupalcode.org> Date: Wed, 30 Apr 2025 07:18:41 +0000 Subject: [PATCH 8/8] Nits: indentation + s/auto_save/auto-save/ --- tests/src/Kernel/ApiLayoutControllerGetTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/src/Kernel/ApiLayoutControllerGetTest.php b/tests/src/Kernel/ApiLayoutControllerGetTest.php index 0f6c1b9d8d..2c9a2201ab 100644 --- a/tests/src/Kernel/ApiLayoutControllerGetTest.php +++ b/tests/src/Kernel/ApiLayoutControllerGetTest.php @@ -378,7 +378,7 @@ class ApiLayoutControllerGetTest extends ApiLayoutControllerTestBase { } /** - * Tests that auto_save entries with inaccessible fields do not cause errors. + * Tests that auto-save entries with inaccessible fields do not cause errors. * * @covers \Drupal\experience_builder\Controller\ApiLayoutController::buildPreviewRenderable */ @@ -413,7 +413,7 @@ class ApiLayoutControllerGetTest extends ApiLayoutControllerTestBase { 'model' => [], 'entity_form_fields' => [ 'title[0][value]' => 'Test Node', - // Path field that user doesn't have access to + // Path field that user doesn't have access to 'path[0][alias]' => '/test-path', ], ]; @@ -425,7 +425,7 @@ class ApiLayoutControllerGetTest extends ApiLayoutControllerTestBase { 'entity_type' => 'node', ]); - // This should not throw an exception even though the auto_save data + // This should not throw an exception even though the auto-save data // contains a value for path field that the user doesn't have access to. $response = $this->request(Request::create($url->toString())); -- GitLab