[TASK] Respect editlock of pages in inline editing 34/41734/13
authorAndreas Fernandez <a.fernandez@scripting-base.de>
Mon, 20 Jul 2015 12:30:03 +0000 (14:30 +0200)
committerBenni Mack <benni@typo3.org>
Thu, 20 Aug 2015 07:34:22 +0000 (09:34 +0200)
Disable drag and drop of content elements in Page module
and inline page title editing if page's editlock is set.

Resolves: #68388
Related: #68279
Releases: master
Change-Id: Ibcb285babb84f0777eb621f244f2a9e40498596b
Reviewed-on: http://review.typo3.org/41734
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
Reviewed-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Tested-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Reviewed-by: Daniel Goerz <ervaude@gmail.com>
Tested-by: Daniel Goerz <ervaude@gmail.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
typo3/sysext/backend/Classes/Controller/PageLayoutController.php
typo3/sysext/backend/Classes/Tree/Pagetree/DataProvider.php
typo3/sysext/backend/Classes/Tree/Pagetree/PagetreeNode.php
typo3/sysext/backend/Classes/View/PageLayoutView.php
typo3/sysext/recordlist/Classes/RecordList.php
typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php

index 74f4423..b2f41ef 100755 (executable)
@@ -1408,7 +1408,7 @@ class PageLayoutController {
         * @return bool
         */
        public function pageIsNotLockedForEditors() {
-               return !($this->pageinfo['editlock'] && ($this->CALC_PERMS & Permission::PAGE_EDIT));
+               return $this->getBackendUser()->isAdmin() || !($this->CALC_PERMS & Permission::PAGE_EDIT && $this->pageinfo['editlock']);
        }
 
        /**
index f4f1908..6f2b0d4 100644 (file)
@@ -161,6 +161,9 @@ class DataProvider extends \TYPO3\CMS\Backend\Tree\AbstractTreeDataProvider {
                                } else {
                                        $subNode->setLeaf(!$this->hasNodeSubPages($subNode->getId()));
                                }
+                               if (!$GLOBALS['BE_USER']->isAdmin() && (int)$subpage['editlock'] === 1) {
+                                       $subNode->setLabelIsEditable(FALSE);
+                               }
                                $nodeCollection->append($subNode);
                        }
                }
index 63a6061..bdd9861 100644 (file)
@@ -177,7 +177,12 @@ class PagetreeNode extends \TYPO3\CMS\Backend\Tree\ExtDirectNode {
         */
        protected function canEdit() {
                if (!isset($this->cachedAccessRights['edit'])) {
-                       $this->cachedAccessRights['edit'] = $GLOBALS['BE_USER']->doesUserHaveAccess($this->record, 2);
+                       $this->cachedAccessRights['edit'] =
+                               $GLOBALS['BE_USER']->isAdmin()
+                               || (
+                                       (int)$this->record['editlock'] === 0
+                                       && $GLOBALS['BE_USER']->doesUserHaveAccess($this->record, 2)
+                               );
                }
                return $this->cachedAccessRights['edit'];
        }
@@ -189,7 +194,12 @@ class PagetreeNode extends \TYPO3\CMS\Backend\Tree\ExtDirectNode {
         */
        protected function canRemove() {
                if (!isset($this->cachedAccessRights['remove'])) {
-                       $this->cachedAccessRights['remove'] = $GLOBALS['BE_USER']->doesUserHaveAccess($this->record, 4);
+                       $this->cachedAccessRights['remove'] =
+                               $GLOBALS['BE_USER']->isAdmin()
+                               || (
+                                       (int)$this->record['editlock'] === 0
+                                       && $GLOBALS['BE_USER']->doesUserHaveAccess($this->record, 4)
+                               );
                        if (!$this->isLeafNode() && !$GLOBALS['BE_USER']->uc['recursiveDelete']) {
                                $this->cachedAccessRights['remove'] = FALSE;
                        }
index 2c09bce..9c1a688 100644 (file)
@@ -173,6 +173,13 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
        public $ext_CALC_PERMS;
 
        /**
+        * Current ids page record
+        *
+        * @var array
+        */
+       protected $pageinfo;
+
+       /**
         * @var IconFactory
         */
        protected $iconFactory;
@@ -385,6 +392,8 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
         * @return string HTML for the listing
         */
        public function getTable_tt_content($id) {
+               $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->ext_CALC_PERMS);
+               $backendUser = $this->getBackendUser();
                $this->initializeLanguages();
                $this->initializeClipboard();
                $pageTitleParamForAltDoc = '&recTitle=' . rawurlencode(BackendUtility::getRecordTitle('pages', BackendUtility::getRecordWSOL('pages', $id), TRUE));
@@ -392,7 +401,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
                $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/DragDrop');
                $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal');
-               $userCanEditPage = $this->ext_CALC_PERMS & Permission::PAGE_EDIT && !empty($this->id);
+               $userCanEditPage = $this->ext_CALC_PERMS & Permission::PAGE_EDIT && !empty($this->id) && ($backendUser->isAdmin() || (int)$this->pageinfo['editlock'] === 0);
                if ($this->tt_contentConfig['languageColsPointer'] > 0) {
                        $userCanEditPage = $this->getBackendUser()->check('tables_modify', 'pages_language_overlay');
                }
@@ -1107,7 +1116,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                        }
                        if ($pasteParams) {
                                $elFromTable = $this->clipboard->elFromTable('tt_content');
-                               if (!empty($elFromTable)) {
+                               if (!empty($elFromTable) && $this->getPageLayoutController()->pageIsNotLockedForEditors()) {
                                        $iconsArr['paste'] = '<a href="'
                                                . htmlspecialchars($this->clipboard->pasteUrl('tt_content', $this->id, TRUE, $pasteParams))
                                                . '" onclick="' . htmlspecialchars(('return '
@@ -1287,7 +1296,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                }
                // Wrap the whole header
                // NOTE: end-tag for <div class="t3-page-ce-body"> is in getTable_tt_content()
-               return '<div class="t3-page-ce-header ' . ($this->getBackendUser()->user['admin'] || (int)$row['editlock'] === 0 ? 't3-page-ce-header-draggable t3js-page-ce-draghandle' : '') . '">
+               return '<div class="t3-page-ce-header ' . ($this->getBackendUser()->user['admin'] || ((int)$row['editlock'] === 0 && (int)$this->pageinfo['editlock'] === 0)  ? 't3-page-ce-header-draggable t3js-page-ce-draghandle' : '') . '">
                                        <div class="t3-page-ce-header-icons-left">' . implode('', $additionalIcons) . '</div>
                                        <div class="t3-page-ce-header-icons-right">' . ($out ? '<div class="btn-toolbar">' .$out . '</div>' : '') . '</div>
                                </div>
index a5e31b5..029ab34 100644 (file)
@@ -274,9 +274,10 @@ class RecordList {
                $this->doc->setModuleTemplate('EXT:recordlist/Resources/Private/Templates/db_list.html');
                $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/AjaxDataHandler');
                $calcPerms = $backendUser->calcPerms($this->pageinfo);
+               $userCanEditPage = $calcPerms & Permission::PAGE_EDIT && !empty($this->id) && ($backendUser->isAdmin() || (int)$this->pageinfo['editlock'] === 0);
                $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/PageActions', 'function(PageActions) {
                        PageActions.setPageId(' . (int)$this->id . ');
-                       PageActions.setCanEditPage(' . ($calcPerms & Permission::PAGE_EDIT && !empty($this->id) ? 'true' : 'false') . ');
+                       PageActions.setCanEditPage(' . ($userCanEditPage ? 'true' : 'false') . ');
                        PageActions.initializePageTitleRenaming();
                }');
                $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Recordlist/Tooltip');
index 85f9d99..16d943b 100644 (file)
@@ -27,7 +27,6 @@ use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
-use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Frontend\Page\PageRepository;
 
 /**
@@ -202,6 +201,7 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
         * Constructor
         */
        public function __construct() {
+               parent::__construct();
                $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
        }
 
@@ -259,8 +259,8 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
                                        . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">'
                                        . $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL) . '</a>';
                        }
-                       // New record
-                       if (!$module->modTSconfig['properties']['noCreateRecordsLink']) {
+                       // New record on pages that are not locked by editlock
+                       if (!$module->modTSconfig['properties']['noCreateRecordsLink'] && $this->editLockPermissions()) {
                                $onClick = htmlspecialchars('return jumpExt(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('db_new', ['id' => $this->id])) . ');');
                                $buttons['new_record'] = '<a href="#" onclick="' . $onClick . '" title="'
                                        . $lang->getLL('newRecordGeneral', TRUE) . '">'
@@ -268,7 +268,7 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
                        }
                        // If edit permissions are set, see
                        // \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
-                       if ($localCalcPerms & Permission::PAGE_EDIT && !empty($this->id)) {
+                       if ($localCalcPerms & Permission::PAGE_EDIT && !empty($this->id) && $this->editLockPermissions()) {
                                // Edit
                                $params = '&edit[pages][' . $this->pageRow['uid'] . ']=edit';
                                $onClick = htmlspecialchars(BackendUtility::editOnClick($params, '', -1));
@@ -277,7 +277,7 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
                                        . IconUtility::getSpriteIcon('actions-page-open') . '</a>';
                        }
                        // Paste
-                       if ($localCalcPerms & Permission::PAGE_NEW || $localCalcPerms & Permission::CONTENT_EDIT) {
+                       if (($localCalcPerms & Permission::PAGE_NEW || $localCalcPerms & Permission::CONTENT_EDIT) && $this->editLockPermissions()) {
                                $elFromTable = $this->clipObj->elFromTable('');
                                if (!empty($elFromTable)) {
                                        $onClick = htmlspecialchars(('return ' . $this->clipObj->confirmMsg('pages', $this->pageRow, 'into', $elFromTable)));
@@ -884,7 +884,7 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
                // Traverse the fields:
                foreach ($this->fieldArray as $fCol) {
                        // Calculate users permissions to edit records in the table:
-                       $permsEdit = $this->calcPerms & ($table == 'pages' ? 2 : 16);
+                       $permsEdit = $this->calcPerms & ($table == 'pages' ? 2 : 16) && $this->overlayEditLockPermissions($table);
                        switch ((string)$fCol) {
                                case '_PATH_':
                                        // Path
@@ -908,10 +908,10 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
                                        }
                                        // Clipboard:
                                        $cells = array();
-                                       // If there are elements on the clipboard for this table, then display the
-                                       // "paste into" icon:
+                                       // If there are elements on the clipboard for this table, and the parent page is not locked by editlock
+                                       // then display the "paste into" icon:
                                        $elFromTable = $this->clipObj->elFromTable($table);
-                                       if (!empty($elFromTable)) {
+                                       if (!empty($elFromTable) && $this->overlayEditLockPermissions($table)) {
                                                $href = htmlspecialchars($this->clipObj->pasteUrl($table, $this->id));
                                                $onClick = htmlspecialchars('return ' . $this->clipObj->confirmMsg('pages', $this->pageRow, 'into', $elFromTable));
                                                $cells['pasteAfter'] = '<a class="btn btn-default" href="' . $href . '" onclick="' . $onClick
@@ -1274,10 +1274,6 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
                                $vers = BackendUtility::selectVersionsOfRecord($table, $row['uid'], 'uid', $this->getBackendUserAuthentication()->workspace, FALSE, $row);
                                // If table can be versionized.
                                if (is_array($vers)) {
-                                       $versionIcon = 'no-version';
-                                       if (count($vers) > 1) {
-                                               $versionIcon = count($vers) - 1;
-                                       }
                                        $href = BackendUtility::getModuleUrl('web_txversionM1', array(
                                                'table' => $table, 'uid' => $row['uid']
                                        ));
@@ -1297,7 +1293,7 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
                        }
                        // "New record after" link (ONLY if the records in the table are sorted by a "sortby"-row
                        // or if default values can depend on previous record):
-                       if ($GLOBALS['TCA'][$table]['ctrl']['sortby'] || $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']) {
+                       if (($GLOBALS['TCA'][$table]['ctrl']['sortby'] || $GLOBALS['TCA'][$table]['ctrl']['useColumnsForDefaultValues']) && $permsEdit) {
                                if ($table !== 'pages' && $this->calcPerms & Permission::CONTENT_EDIT || $table === 'pages' && $this->calcPerms & Permission::PAGE_NEW) {
                                        if ($this->showNewRecLink($table)) {
                                                $params = '&edit[' . $table . '][' . -($row['_MOVE_PLH'] ? $row['_MOVE_PLH_uid'] : $row['uid']) . ']=new';
@@ -1563,8 +1559,8 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
                // Now, looking for selected elements from the current table:
                $elFromTable = $this->clipObj->elFromTable($table);
                if (!empty($elFromTable) && $GLOBALS['TCA'][$table]['ctrl']['sortby']) {
-                       // IF elements are found and they can be individually ordered, then add a "paste after" icon:
-                       $cells['pasteAfter'] = $isL10nOverlay
+                       // IF elements are found, they can be individually ordered and are not locked by editlock, then add a "paste after" icon:
+                       $cells['pasteAfter'] = $isL10nOverlay || !$this->overlayEditLockPermissions($table, $row)
                                ? $this->spaceIcon
                                : '<a class="btn btn-default" href="' . htmlspecialchars($this->clipObj->pasteUrl($table, -$row['uid'])) . '" onclick="'
                                        . htmlspecialchars(('return ' . $this->clipObj->confirmMsg($table, $row, 'after', $elFromTable)))
@@ -1986,8 +1982,12 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
         * @param bool $editPermission
         * @return bool
         */
-       protected function overlayEditLockPermissions($table, $row, $editPermission = TRUE) {
+       protected function overlayEditLockPermissions($table, $row = array(), $editPermission = TRUE) {
                if ($editPermission && !$this->getBackendUserAuthentication()->isAdmin()) {
+                       // If no $row is submitted we only check for general edit lock of current page (except for table "pages")
+                       if (empty($row)) {
+                               return $table === 'pages' ? TRUE : !$this->pageRow['editlock'];
+                       }
                        if (($table === 'pages' && $row['editlock']) || ($table !== 'pages' && $this->pageRow['editlock'])) {
                                $editPermission = FALSE;
                        } elseif (isset($GLOBALS['TCA'][$table]['ctrl']['editlock']) && $row[$GLOBALS['TCA'][$table]['ctrl']['editlock']]) {
@@ -1998,6 +1998,16 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
        }
 
        /**
+        * Check whether or not the current backend user is an admin or the current page is
+        * locked by editlock.
+        *
+        * @return bool
+        */
+       protected function editLockPermissions() {
+               return $this->getBackendUserAuthentication()->isAdmin() || !$this->pageRow['editlock'];
+       }
+
+       /**
         * @return DatabaseConnection
         */
        protected function getDatabaseConnection() {