From e98b794e814e2b59bff8c151a242be8b79dc899e Mon Sep 17 00:00:00 2001
From: Rudy Gnodde <rudy@famouswolf.com>
Date: Thu, 19 Dec 2019 13:48:41 +0100
Subject: [PATCH] [FEATURE] Option to copy page access settings from parent
 page

Add option to copy page access settings from the parent page.
Set by setting Page TSconfig TCEMAIN.permissions.* to "copyFromParent".
Can be set for groupid, userid, user, group and everybody.
For example: TCEMAIN.permissions.groupid = copyFromParent

Resolves: #89917
Releases: master
Change-Id: I4dd11177f533fd752f3b75287db2d8cb60c67005
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/62750
Tested-by: core-ci <typo3@b13.com>
Tested-by: Jochen <rothjochen@gmail.com>
Tested-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Jochen <rothjochen@gmail.com>
Reviewed-by: Oliver Bartsch <bo@cedev.de>
---
 .../DataHandling/PagePermissionAssembler.php  | 39 +++++++++++-----
 .../12.0/Feature-89917-InheritPageAccess.rst  | 28 ++++++++++++
 .../Regular/PagePermissionTest.php            | 44 +++++++++++++++++--
 3 files changed, 97 insertions(+), 14 deletions(-)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/12.0/Feature-89917-InheritPageAccess.rst

diff --git a/typo3/sysext/core/Classes/DataHandling/PagePermissionAssembler.php b/typo3/sysext/core/Classes/DataHandling/PagePermissionAssembler.php
index 24f0c7738d25..75a3c4af4aed 100644
--- a/typo3/sysext/core/Classes/DataHandling/PagePermissionAssembler.php
+++ b/typo3/sysext/core/Classes/DataHandling/PagePermissionAssembler.php
@@ -91,20 +91,39 @@ class PagePermissionAssembler
      */
     protected function setTSconfigPermissions(array $fieldArray, array $tsconfig): array
     {
-        if ((string)($tsconfig['userid'] ?? '') !== '') {
-            $fieldArray['perms_userid'] = (int)$tsconfig['userid'];
+        $parentPermissions = [];
+        if (in_array('copyFromParent', $tsconfig, true)) {
+            $parentPermissions = BackendUtility::getRecordWSOL('pages', $fieldArray['pid'], 'uid,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody') ?? [];
         }
-        if ((string)($tsconfig['groupid'] ?? '') !== '') {
-            $fieldArray['perms_groupid'] = (int)$tsconfig['groupid'];
+        if (
+            (string)($tsconfig['userid'] ?? '') !== ''
+            && ($tsconfig['userid'] !== 'copyFromParent' || isset($parentPermissions['perms_userid']))
+        ) {
+            $fieldArray['perms_userid'] = $tsconfig['userid'] === 'copyFromParent' ? (int)$parentPermissions['perms_userid'] : (int)$tsconfig['userid'];
         }
-        if ((string)($tsconfig['user'] ?? '') !== '') {
-            $fieldArray['perms_user'] = $this->assemblePermissions($tsconfig['user']);
+        if (
+            (string)($tsconfig['groupid'] ?? '') !== ''
+            && ($tsconfig['groupid'] !== 'copyFromParent' || isset($parentPermissions['perms_groupid']))
+        ) {
+            $fieldArray['perms_groupid'] = $tsconfig['groupid'] === 'copyFromParent' ? (int)$parentPermissions['perms_groupid'] : (int)$tsconfig['groupid'];
         }
-        if ((string)($tsconfig['group'] ?? '') !== '') {
-            $fieldArray['perms_group'] = $this->assemblePermissions($tsconfig['group']);
+        if (
+            (string)($tsconfig['user'] ?? '') !== ''
+            && ($tsconfig['user'] !== 'copyFromParent' || isset($parentPermissions['perms_user']))
+        ) {
+            $fieldArray['perms_user'] = $tsconfig['user'] === 'copyFromParent' ? (int)$parentPermissions['perms_user'] : $this->assemblePermissions($tsconfig['user']);
         }
-        if ((string)($tsconfig['everybody'] ?? '') !== '') {
-            $fieldArray['perms_everybody'] = $this->assemblePermissions($tsconfig['everybody']);
+        if (
+            (string)($tsconfig['group'] ?? '') !== ''
+            && ($tsconfig['group'] !== 'copyFromParent' || isset($parentPermissions['perms_group']))
+        ) {
+            $fieldArray['perms_group'] = $tsconfig['group'] === 'copyFromParent' ? (int)$parentPermissions['perms_group'] : $this->assemblePermissions($tsconfig['group']);
+        }
+        if (
+            (string)($tsconfig['everybody'] ?? '') !== ''
+            && ($tsconfig['everybody'] !== 'copyFromParent' || isset($parentPermissions['perms_everybody']))
+        ) {
+            $fieldArray['perms_everybody'] = $tsconfig['everybody'] === 'copyFromParent' ? (int)$parentPermissions['perms_everybody'] : $this->assemblePermissions($tsconfig['everybody']);
         }
         return $fieldArray;
     }
diff --git a/typo3/sysext/core/Documentation/Changelog/12.0/Feature-89917-InheritPageAccess.rst b/typo3/sysext/core/Documentation/Changelog/12.0/Feature-89917-InheritPageAccess.rst
new file mode 100644
index 000000000000..1c2730310897
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/12.0/Feature-89917-InheritPageAccess.rst
@@ -0,0 +1,28 @@
+.. include:: ../../Includes.txt
+
+=======================================================
+Feature: #89738 - Copy page access settings from parent
+=======================================================
+
+See :issue:`89738`
+
+Description
+===========
+
+It is now possible to copy page access permissions from the parent page,
+while creating new pages. This is possible, using :typoscript:`copyFromParent`
+as value for one of the page TSconfig :typoscript:`TCEMAIN.permissions.*`
+subkeys.
+
+Example
+=======
+
+.. code-block:: typoscript
+
+   TCEMAIN.permissions.userid = copyFromParent
+   TCEMAIN.permissions.groupid = copyFromParent
+   TCEMAIN.permissions.user = copyFromParent
+   TCEMAIN.permissions.group = copyFromParent
+   TCEMAIN.permissions.everybody = copyFromParent
+
+.. index:: Backend, ext:core
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/PagePermissionTest.php b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/PagePermissionTest.php
index 81e0bc62b48c..9fa1783d4985 100644
--- a/typo3/sysext/core/Tests/Functional/DataHandling/Regular/PagePermissionTest.php
+++ b/typo3/sysext/core/Tests/Functional/DataHandling/Regular/PagePermissionTest.php
@@ -89,14 +89,50 @@ TCEMAIN.permissions.everybody = show,delete
     }
 
     /**
-     * @return array
+     * @test
      */
-    protected function insertPage(): array
+    public function newPageReceivesOverriddenPageTsPermissionSetFromParent()
     {
-        // pid 88 comes from ImportDefault
-        $result = $this->actionService->createNewRecord('pages', 88, [
+        $this->backendUser->user['uid'] = 13;
+        $this->backendUser->firstMainGroup = 14;
+        $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPermissions'] = [
+            'user' => 'show,editcontent,edit,delete',
+            'group' => 'show,editcontent,new',
+            'everybody' => 'show',
+        ];
+        $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPageTSconfig'] = '
+TCEMAIN.permissions.userid = 12
+TCEMAIN.permissions.groupid = 42
+TCEMAIN.permissions.user = show,edit
+TCEMAIN.permissions.group = show,delete
+TCEMAIN.permissions.everybody = show,delete
+';
+        $parent = $this->insertPage(88, [
             'title' => 'Test page',
+            'TSconfig' => '
+TCEMAIN.permissions.userid = copyFromParent
+TCEMAIN.permissions.groupid = copyFromParent
+TCEMAIN.permissions.user = copyFromParent
+TCEMAIN.permissions.group = copyFromParent
+TCEMAIN.permissions.everybody = copyFromParent
+            ',
         ]);
+
+        $record = $this->insertPage((int)$parent['uid']);
+        self::assertEquals(12, $record['perms_userid']);
+        self::assertEquals(42, $record['perms_groupid']);
+        self::assertEquals(Permission::PAGE_SHOW + Permission::PAGE_EDIT, $record['perms_user']);
+        self::assertEquals(Permission::PAGE_SHOW + Permission::PAGE_DELETE, $record['perms_group']);
+        self::assertEquals(Permission::PAGE_SHOW + Permission::PAGE_DELETE, $record['perms_everybody']);
+    }
+
+    /**
+     * @return array
+     */
+    protected function insertPage(int $pageId = 88, array $fields = ['title' => 'Test page'])
+    {
+        // pid 88 comes from ImportDefault
+        $result = $this->actionService->createNewRecord('pages', $pageId, $fields);
         $recordUid = $result['pages'][0];
         return BackendUtility::getRecord('pages', $recordUid);
     }
-- 
GitLab