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