getParsedBody(); $queryParams = $request->getQueryParams(); $backendUser = $this->getBackendUser(); $lang = $this->getLanguageService(); // determine depth parameter $this->depth = (int)($parsedBody['depth'] ?? $queryParams['depth'] ?? 0); if (!$this->depth) { $this->depth = (int)$backendUser->getSessionData(self::SESSION_PREFIX . 'depth'); } else { $backendUser->setAndSaveSessionData(self::SESSION_PREFIX . 'depth', $this->depth); } // determine id parameter $this->id = (int)($parsedBody['id'] ?? $queryParams['id'] ?? 0); $pageRecord = BackendUtility::getRecord('pages', $this->id); // Check if a page with the given id exists, otherwise fall back if ($pageRecord === null) { $this->id = 0; } $this->returnUrl = GeneralUtility::sanitizeLocalUrl((string)($parsedBody['returnUrl'] ?? $queryParams['returnUrl'] ?? ''), $request); $this->pageInfo = BackendUtility::readPageAccess($this->id, ' 1=1') ?: [ 'title' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'], 'uid' => 0, 'pid' => 0, ]; $action = (string)($parsedBody['action'] ?? $queryParams['action'] ?? 'index'); if ($action === 'update') { // Update returns a redirect. No further fiddling with view here, return directly. return $this->updateAction($request); } $view = $this->moduleTemplateFactory->create($request); if ($backendUser->workspace !== 0) { $this->addFlashMessage( $lang->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:WorkspaceWarningText'), $lang->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:WorkspaceWarning'), ContextualFeedbackSeverity::WARNING ); } $this->registerDocHeaderButtons($view, $action); $view->setTitle( $this->getLanguageService()->translate('title', 'beuser.modules.permissions'), $this->id !== 0 && !empty($this->pageInfo['title']) ? $this->pageInfo['title'] : '' ); $view->getDocHeaderComponent()->setPageBreadcrumb($this->pageInfo); if ($action === 'edit') { return $this->editAction($view); } return $this->indexAction($view, $request); } public function handleAjaxRequest(ServerRequestInterface $request): ResponseInterface { $parsedBody = $request->getParsedBody(); $conf = [ 'page' => $parsedBody['page'] ?? null, 'who' => $parsedBody['who'] ?? null, 'mode' => $parsedBody['mode'] ?? null, 'bits' => (int)($parsedBody['bits'] ?? 0), 'permissions' => (int)($parsedBody['permissions'] ?? 0), 'action' => $parsedBody['action'] ?? null, 'ownerUid' => (int)($parsedBody['ownerUid'] ?? 0), 'username' => $parsedBody['username'] ?? null, 'groupUid' => (int)($parsedBody['groupUid'] ?? 0), 'groupname' => $parsedBody['groupname'] ?? '', 'editLockState' => (int)($parsedBody['editLockState'] ?? 0), 'new_owner_uid' => (int)($parsedBody['newOwnerUid'] ?? 0), 'new_group_uid' => (int)($parsedBody['newGroupUid'] ?? 0), ]; // Basic test for required value if ($conf['page'] <= 0) { return $this->htmlResponse('This script cannot be called directly', 500); } // Initialize view and always assign current page id $view = $this->backendViewFactory->create($request); $view->assign('pageId', $conf['page']); // Initialize TCE for execution of updates $tce = GeneralUtility::makeInstance(DataHandler::class); // Determine the action to execute switch ($conf['action'] ?? '') { case 'show_change_owner_selector': $template = 'Permission/ChangeOwnerSelector'; $users = BackendUtility::getUserNames(); $view->assignMultiple([ 'elementId' => 'o_' . $conf['page'], 'ownerUid' => $conf['ownerUid'], 'username' => $conf['username'], 'users' => $users, 'addCurrentUser' => !isset($users[$conf['ownerUid']]), ]); break; case 'show_change_group_selector': $template = 'Permission/ChangeGroupSelector'; $groups = BackendUtility::getGroupNames(); $view->assignMultiple([ 'elementId' => 'g_' . $conf['page'], 'groupUid' => $conf['groupUid'], 'groupname' => $conf['groupname'], 'groups' => $groups, 'addCurrentGroup' => !isset($groups[$conf['groupUid']]), ]); break; case 'toggle_edit_lock': // Initialize requested lock state $editLockState = $conf['editLockState'] ? 0 : 1; // Execute TCE Update $tce->start([ 'pages' => [ $conf['page'] => [ 'editlock' => $editLockState, ], ], ], []); $tce->process_datamap(); // Setup view $template = 'Permission/ToggleEditLock'; $view->assignMultiple([ 'elementId' => 'el_' . $conf['page'], 'editLockState' => $editLockState, ]); break; case 'change_owner': // Check if new owner uid is given (also accept 0 => [not set]) if ($conf['new_owner_uid'] < 0) { return $this->htmlResponse('An error occurred: No page owner uid specified', 500); } // Execute TCE Update $tce->start([ 'pages' => [ $conf['page'] => [ 'perms_userid' => $conf['new_owner_uid'], ], ], ], []); $tce->process_datamap(); // Setup and render view $template = 'Permission/ChangeOwner'; $view->assignMultiple([ 'userId' => $conf['new_owner_uid'], 'username' => BackendUtility::getUserNames( 'username', ' AND uid = ' . $conf['new_owner_uid'] )[$conf['new_owner_uid']]['username'] ?? '', ]); break; case 'change_group': // Check if new group uid is given (also accept 0 => [not set]) if ($conf['new_group_uid'] < 0) { return $this->htmlResponse('An error occurred: No page group uid specified', 500); } // Execute TCE Update $tce->start([ 'pages' => [ $conf['page'] => [ 'perms_groupid' => $conf['new_group_uid'], ], ], ], []); $tce->process_datamap(); // Setup and render view $template = 'Permission/ChangeGroup'; $view->assignMultiple([ 'groupId' => $conf['new_group_uid'], 'groupname' => BackendUtility::getGroupNames( 'title', ' AND uid = ' . $conf['new_group_uid'] )[$conf['new_group_uid']]['title'] ?? '', ]); break; default: // Initialize permissions state if ($conf['mode'] === 'delete') { $conf['permissions'] -= $conf['bits']; } else { $conf['permissions'] += $conf['bits']; } // Execute TCE Update $tce->start([ 'pages' => [ $conf['page'] => [ 'perms_' . $conf['who'] => $conf['permissions'], ], ], ], []); $tce->process_datamap(); // Setup and render view $template = 'Permission/ChangePermission'; $view->assignMultiple([ 'permission' => $conf['permissions'], 'scope' => $conf['who'], ]); } return $this->htmlResponse($view->render($template)); } public function indexAction(ModuleTemplate $view, ServerRequestInterface $request): ResponseInterface { $view->assignMultiple([ 'currentId' => $this->id, 'viewTree' => $this->getTree(), 'beUsers' => BackendUtility::getUserNames(), 'beGroups' => BackendUtility::getGroupNames(), 'depth' => $this->depth, 'depthBaseUrl' => $this->uriBuilder->buildUriFromRoute('permissions_pages', [ 'id' => $this->id, 'depth' => '${value}', 'action' => 'index', ]), 'returnUrl' => (string)$this->uriBuilder->buildUriFromRoute('permissions_pages', [ 'id' => $this->id, 'depth' => $this->depth, 'action' => 'index', ]), ]); return $view->renderResponse('Permission/Index'); } public function editAction(ModuleTemplate $view): ResponseInterface { $lang = $this->getLanguageService(); $selectNone = $lang->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:selectNone'); $selectUnchanged = $lang->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:selectUnchanged'); // Owner selector $beUserDataArray = [0 => $selectNone]; foreach (BackendUtility::getUserNames() as $uid => $row) { $beUserDataArray[$uid] = $row['username'] ?? ''; } $beUserDataArray[-1] = $selectUnchanged; // Group selector $beGroupDataArray = [0 => $selectNone]; foreach (BackendUtility::getGroupNames() as $uid => $row) { $beGroupDataArray[$uid] = $row['title'] ?? ''; } $beGroupDataArray[-1] = $selectUnchanged; $view->assignMultiple([ 'id' => $this->id, 'depth' => $this->depth, 'currentBeUser' => $this->pageInfo['perms_userid'] ?? 0, 'beUserData' => $beUserDataArray, 'currentBeGroup' => $this->pageInfo['perms_groupid'] ?? 0, 'beGroupData' => $beGroupDataArray, 'pageInfo' => $this->pageInfo, 'returnUrl' => $this->returnUrl, 'recursiveSelectOptions' => $this->getRecursiveSelectOptions(), 'formAction' => (string)$this->uriBuilder->buildUriFromRoute('permissions_pages', [ 'action' => 'update', 'id' => $this->id, 'depth' => $this->depth, 'returnUrl' => $this->returnUrl, ]), ]); return $view->renderResponse('Permission/Edit'); } protected function updateAction(ServerRequestInterface $request): ResponseInterface { $data = (array)($request->getParsedBody()['data'] ?? []); $mirror = (array)($request->getParsedBody()['mirror'] ?? []); $dataHandlerInput = []; // Prepare the input data for data handler $dataPages = $data['pages'] ?? null; if (is_array($dataPages) && $dataPages !== []) { foreach ($dataPages as $pageUid => $properties) { // if the owner and group field shouldn't be touched, unset the option if ((int)($properties['perms_userid'] ?? 0) === -1) { unset($properties['perms_userid']); } if ((int)($properties['perms_groupid'] ?? 0) === -1) { unset($properties['perms_groupid']); } $dataHandlerInput[$pageUid] = $properties; if (!empty($mirror['pages'][$pageUid])) { $mirrorPages = GeneralUtility::intExplode(',', (string)$mirror['pages'][$pageUid]); foreach ($mirrorPages as $mirrorPageUid) { $dataHandlerInput[$mirrorPageUid] = $properties; } } } } $dataHandler = GeneralUtility::makeInstance(DataHandler::class); $dataHandler->start( [ 'pages' => $dataHandlerInput, ], [] ); $dataHandler->process_datamap(); return $this->responseFactory->createResponse(303) ->withHeader('location', $this->returnUrl); } protected function registerDocHeaderButtons(ModuleTemplate $view, string $action): void { $lang = $this->getLanguageService(); if ($action === 'edit') { // CLOSE button: if ($this->returnUrl !== '') { $view->addButtonToButtonBar($this->componentFactory->createCloseButton($this->returnUrl)); } // SAVE button: $saveButton = $this->componentFactory ->createSaveButton('PermissionControllerEdit') ->setName('_save') ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.saveCloseDoc')); $view->addButtonToButtonBar($saveButton, ButtonBar::BUTTON_POSITION_LEFT, 2); } if ($action === 'index' && count($this->getDepthOptions()) > 0) { $viewModeItems = []; $viewModeItems[] = $this->componentFactory->createDropDownHeader() ->setLabel($lang->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:Depth')); foreach ($this->getDepthOptions() as $value => $label) { $viewModeItems[] = $this->componentFactory->createDropDownRadio() ->setActive($this->depth === $value) ->setLabel($label) ->setHref((string)$this->uriBuilder->buildUriFromRoute('permissions_pages', [ 'id' => $this->id, 'depth' => $value, ])); } $viewModeButton = $this->componentFactory->createDropDownButton() ->setLabel($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.view')) ->setIcon($this->iconFactory->getIcon('actions-cog')) ->setShowLabelText(true); foreach ($viewModeItems as $viewModeItem) { $viewModeButton->addItem($viewModeItem); } $view->addButtonToButtonBar($viewModeButton, ButtonBar::BUTTON_POSITION_RIGHT, 2); } $view->getDocHeaderComponent()->setShortcutContext( 'permissions_pages', $this->getShortcutTitle(), ['id' => $this->id, 'action' => $action] ); } protected function getTree(): array { $tree = GeneralUtility::makeInstance(PageTreeView::class); $tree->init(); // Create the tree from $this->id if ($this->id) { $icon = $this->iconFactory->getIconForRecord('pages', $this->pageInfo, IconSize::SMALL); } else { $icon = $this->iconFactory->getIcon('apps-pagetree-root', IconSize::SMALL); } $iconMarkup = '' . $icon->render() . ''; $tree->tree[] = ['row' => $this->pageInfo, 'HTML' => '', 'icon' => $iconMarkup]; $tree->getTree($this->id, $this->depth); return $tree->tree; } protected function getDepthOptions(): array { $depthOptions = []; foreach (self::DEPTH_LEVELS as $depthLevel) { $levelLabel = $depthLevel === 1 ? 'level' : 'levels'; $depthOptions[$depthLevel] = $depthLevel . ' ' . $this->getLanguageService()->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:' . $levelLabel); } return $depthOptions; } /** * Finding tree and offer setting of values recursively. */ protected function getRecursiveSelectOptions(): array { $lang = $this->getLanguageService(); // Initialize tree object: $tree = GeneralUtility::makeInstance(PageTreeView::class); $tree->init(); $tree->makeHTML = false; // Make tree: $tree->getTree($this->id, self::RECURSIVE_LEVELS); $options = [ '' => $lang->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:selectNone'), ]; // If there are a hierarchy of page ids, then... if (!empty($tree->orig_ids_hierarchy) && ($this->getBackendUser()->user['uid'] ?? false)) { // Init: $labelRecursive = $lang->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:recursive'); $labelLevel = $lang->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:level'); $labelLevels = $lang->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:levels'); $labelPageAffected = $lang->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:page_affected'); $labelPagesAffected = $lang->sL('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:pages_affected'); $theIdListArr = []; // Traverse the number of levels we want to allow recursive // setting of permissions for: for ($a = self::RECURSIVE_LEVELS; $a > 0; $a--) { if (is_array($tree->orig_ids_hierarchy[$a] ?? false)) { foreach ($tree->orig_ids_hierarchy[$a] as $theId) { $theIdListArr[] = $theId; } $lKey = self::RECURSIVE_LEVELS - $a + 1; $pagesCount = count($theIdListArr); $options[implode(',', $theIdListArr)] = $labelRecursive . ' ' . $lKey . ' ' . ($lKey === 1 ? $labelLevel : $labelLevels) . ' (' . $pagesCount . ' ' . ($pagesCount === 1 ? $labelPageAffected : $labelPagesAffected) . ')'; } } } return $options; } /** * Adds a flash message to the default flash message queue */ protected function addFlashMessage(string $message, string $title = '', ContextualFeedbackSeverity $severity = ContextualFeedbackSeverity::INFO): void { $flashMessage = new FlashMessage($message, $title, $severity, true); $defaultFlashMessageQueue = $this->flashMessageService->getMessageQueueByIdentifier(); $defaultFlashMessageQueue->enqueue($flashMessage); } /** * Returns the shortcut title for the current page */ protected function getShortcutTitle(): string { return sprintf( '%s: %s [%d]', $this->getLanguageService()->translate('title', 'beuser.modules.permissions'), BackendUtility::getRecordTitle('pages', $this->pageInfo), $this->id ); } protected function htmlResponse(string $html, int $code = 200): ResponseInterface { $response = $this->responseFactory->createResponse($code) ->withHeader('Content-Type', 'text/html; charset=utf-8'); $response->getBody()->write($html); return $response; } protected function getBackendUser(): BackendUserAuthentication { return $GLOBALS['BE_USER']; } protected function getLanguageService(): LanguageService { return $GLOBALS['LANG']; } }