TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:03 +02:00
commit 61d66df078
65 changed files with 8311 additions and 0 deletions
@@ -0,0 +1,771 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Beuser\Controller;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Backend\Authentication\PasswordReset;
use TYPO3\CMS\Backend\Module\ModuleData;
use TYPO3\CMS\Backend\Routing\UriBuilder as BackendUriBuilder;
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
use TYPO3\CMS\Backend\Template\Components\ComponentFactory;
use TYPO3\CMS\Backend\Template\Enum\ModuleLayout;
use TYPO3\CMS\Backend\Template\ModuleTemplate;
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
use TYPO3\CMS\Beuser\Domain\Dto\BackendUserGroup;
use TYPO3\CMS\Beuser\Domain\Model\BackendUser;
use TYPO3\CMS\Beuser\Domain\Model\Demand;
use TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository;
use TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository;
use TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository;
use TYPO3\CMS\Beuser\Domain\Repository\FileMountRepository;
use TYPO3\CMS\Beuser\Event\AfterBackendGroupFilterListIsAssembledEvent;
use TYPO3\CMS\Beuser\Event\AfterFilemountsListIsAssembledEvent;
use TYPO3\CMS\Beuser\Service\UserInformationService;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Http\AllowedMethodsTrait;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Imaging\IconSize;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Pagination\ArrayPaginator;
use TYPO3\CMS\Core\Pagination\SimplePagination;
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Http\ForwardResponse;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\Request;
use TYPO3\CMS\Extbase\Mvc\RequestInterface;
use TYPO3\CMS\Extbase\Pagination\QueryResultPaginator;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* Backend module user and user group administration controller.
*
* @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API.
*/
class BackendUserController extends ActionController
{
use AllowedMethodsTrait;
protected ?ModuleData $moduleData = null;
protected ModuleTemplate $moduleTemplate;
public function __construct(
protected readonly ComponentFactory $componentFactory,
protected readonly BackendUserRepository $backendUserRepository,
protected readonly BackendUserGroupRepository $backendUserGroupRepository,
protected readonly BackendUserSessionRepository $backendUserSessionRepository,
protected readonly UserInformationService $userInformationService,
protected readonly ModuleTemplateFactory $moduleTemplateFactory,
protected readonly BackendUriBuilder $backendUriBuilder,
protected readonly IconFactory $iconFactory,
protected readonly PageRenderer $pageRenderer,
protected readonly FileMountRepository $fileMountRepository
) {}
/**
* Store a valid selected action as defaultAction
*/
public function processRequest(RequestInterface $request): ResponseInterface
{
/** @var Request $request */
$arguments = $request->getArguments();
$moduleData = $request->getAttribute('moduleData');
if (in_array((string)($arguments['action'] ?? ''), ['list', 'groups', 'online', 'filemounts'], true)
&& (string)$moduleData->get('defaultAction') !== (string)$arguments['action']
) {
$moduleData->set('defaultAction', (string)$arguments['action']);
$this->getBackendUser()->pushModuleData($moduleData->getModuleIdentifier(), $moduleData->toArray());
}
return parent::processRequest($request);
}
/**
* Init module state.
* This isn't done within __construct() since the controller
* object is only created once in extbase when multiple actions are called in
* one call. When those change module state, the second action would see old state.
*/
public function initializeAction(): void
{
$this->moduleData = $this->request->getAttribute('moduleData');
$this->moduleTemplate = $this->moduleTemplateFactory->create($this->request);
$this->moduleTemplate->setTitle(LocalizationUtility::translate('beuser.modules.user_management:title'));
$this->moduleTemplate->setLayout(ModuleLayout::NORMAL);
$this->moduleTemplate->setFlashMessageQueue($this->getFlashMessageQueue());
}
/**
* Assign default variables to ModuleTemplate view
*/
protected function initializeView(): void
{
$this->moduleTemplate->assignMultiple([
'dateFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'],
'timeFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'],
]);
// Load JavaScript modules
$this->pageRenderer->loadJavaScriptModule('@typo3/backend/context-menu.js');
$this->pageRenderer->loadJavaScriptModule('@typo3/backend/modal.js');
$this->pageRenderer->loadJavaScriptModule('@typo3/backend/element/status-indicator-element.js');
$this->pageRenderer->loadJavaScriptModule('@typo3/beuser/backend-user-listing.js');
}
/**
* Default action, forwarding the request to either a defined default action or the default entry point "list"
*/
public function indexAction(): ResponseInterface
{
$moduleData = $this->request->getAttribute('moduleData');
if ($moduleData->has('defaultAction')
&& in_array((string)$moduleData->get('defaultAction'), ['list', 'groups', 'online', 'filemounts'], true)
) {
return new ForwardResponse((string)$moduleData->get('defaultAction'));
}
return new ForwardResponse('list');
}
/**
* Displays all BackendUsers
*/
public function listAction(?Demand $demand = null, int $currentPage = 1, string $operation = ''): ResponseInterface
{
$backendUser = $this->getBackendUser();
if ($operation === 'reset-filters') {
// Reset the module data demand object
$this->moduleData->set('demand', []);
$demand = null;
}
if ($demand === null) {
$demand = Demand::fromUc((array)$this->moduleData->get('demand', []));
} else {
$this->moduleData->set('demand', $demand->forUc());
}
$backendUser->pushModuleData($this->moduleData->getModuleIdentifier(), $this->moduleData->toArray());
$compareUserList = array_keys((array)$this->moduleData->get('compareUserList', []));
$backendUsers = $this->backendUserRepository->findDemanded($demand);
$paginator = new QueryResultPaginator($backendUsers, $currentPage, 50);
$pagination = new SimplePagination($paginator);
$backendUserGroups = $this->eventDispatcher->dispatch(
new AfterBackendGroupFilterListIsAssembledEvent(
$this->request,
array_merge([''], $this->backendUserGroupRepository->findAll()->toArray())
)
)->backendGroups;
$this->moduleTemplate->assignMultiple([
'onlineBackendUsers' => $this->getOnlineBackendUsers(),
'demand' => $demand,
'paginator' => $paginator,
'pagination' => $pagination,
'totalAmountOfBackendUsers' => $backendUsers->count(),
'backendUserGroups' => $backendUserGroups,
'compareUserUidList' => array_combine($compareUserList, $compareUserList),
'currentUserUid' => $backendUser->user['uid'] ?? null,
'compareUserList' => !empty($compareUserList) ? $this->backendUserRepository->findByUidList($compareUserList) : '',
]);
$this->addMainMenu('list');
$createEditorButton = $this->componentFactory->createLinkButton()
->setIcon($this->iconFactory->getIcon('actions-plus', IconSize::SMALL))
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:btn.editor.create', 'beuser'))
->setShowLabelText(true)
->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
'edit' => ['be_users' => [0 => 'new']],
'module' => 'backend_user_management',
'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
]));
$this->moduleTemplate->addButtonToButtonBar($createEditorButton);
$createAdminButton = $this->componentFactory->createLinkButton()
->setIcon($this->iconFactory->getIcon('actions-plus', IconSize::SMALL))
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:btn.admin.create', 'beuser'))
->setShowLabelText(true)
->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
'edit' => ['be_users' => [0 => 'new']],
'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
'defVals' => ['be_users' => ['admin' => 1]],
]));
$this->moduleTemplate->addButtonToButtonBar($createAdminButton, ButtonBar::BUTTON_POSITION_LEFT, 2);
$this->moduleTemplate->getDocHeaderComponent()->setShortcutContext(
'backend_user_management',
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:backendUsers', 'beuser'),
['action' => 'list']
);
$this->pageRenderer->loadJavaScriptModule('@typo3/backend/switch-user.js');
return $this->moduleTemplate->renderResponse('BackendUser/List');
}
/**
* Views all currently logged in BackendUsers and their sessions
*/
public function onlineAction(): ResponseInterface
{
$onlineUsersAndSessions = [];
$onlineUsers = $this->backendUserRepository->findOnline();
foreach ($onlineUsers as $onlineUser) {
$onlineUsersAndSessions[] = [
'backendUser' => $onlineUser,
'sessions' => $this->backendUserSessionRepository->findByBackendUser($onlineUser),
];
}
$currentSessionId = $this->backendUserSessionRepository->getPersistedSessionIdentifier($this->getBackendUser());
$this->moduleTemplate->assignMultiple([
'onlineUsersAndSessions' => $onlineUsersAndSessions,
'currentSessionId' => $currentSessionId,
]);
$this->addMainMenu('online');
$this->moduleTemplate->getDocHeaderComponent()->setShortcutContext(
'backend_user_management',
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:onlineUsers', 'beuser'),
['action' => 'online']
);
return $this->moduleTemplate->renderResponse('BackendUser/Online');
}
public function showAction(int $uid = 0): ResponseInterface
{
$data = $this->userInformationService->getUserInformation($uid);
$this->moduleTemplate->assignMultiple([
'data' => $data,
'showUid' => $this->getBackendUser()->shallDisplayDebugInformation(),
]);
$this->addMainMenu('show');
$this->moduleTemplate->addButtonToButtonBar($this->componentFactory->createBackButton((string)$this->backendUriBuilder->buildUriFromRoute('backend_user_management')));
$editButton = $this->componentFactory->createLinkButton()
->setIcon($this->iconFactory->getIcon('actions-open', IconSize::SMALL))
->setTitle(LocalizationUtility::translate('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.edit'))
->setShowLabelText(true)
->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
'edit' => ['be_users' => [$uid => 'edit']],
'module' => 'backend_user_management',
'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
]));
$this->moduleTemplate->addButtonToButtonBar($editButton, ButtonBar::BUTTON_POSITION_LEFT, 2);
$addUserButton = $this->componentFactory->createLinkButton()
->setIcon($this->iconFactory->getIcon('actions-plus', IconSize::SMALL))
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:btn.backendUser.create', 'beuser'))
->setShowLabelText(true)
->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
'edit' => ['be_users' => [0 => 'new']],
'module' => 'backend_user_management',
'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
]));
$this->moduleTemplate->addButtonToButtonBar($addUserButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
$username = empty($data['user']['username']) ? '' : ': ' . $data['user']['username'];
$this->moduleTemplate->getDocHeaderComponent()->setShortcutContext(
'backend_user_management',
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:backendUser', 'beuser') . $username,
['action' => 'show', 'uid' => $uid]
);
return $this->moduleTemplate->renderResponse('BackendUser/Show');
}
/**
* Compare backend users from demand
*/
public function compareAction(): ResponseInterface
{
$compareUserList = array_keys((array)$this->moduleData->get('compareUserList', []));
if (empty($compareUserList)) {
return $this->redirect('list');
}
$compareData = [];
foreach ($compareUserList as $uid) {
if ($compareInformation = $this->userInformationService->getUserInformation($uid)) {
$compareData[] = $compareInformation;
}
}
$this->moduleTemplate->assignMultiple([
'compareUserList' => $compareData,
'onlineBackendUsers' => $this->getOnlineBackendUsers(),
'showUid' => $this->getBackendUser()->shallDisplayDebugInformation(),
]);
$this->addMainMenu('compare');
$this->moduleTemplate->addButtonToButtonBar($this->componentFactory->createBackButton((string)$this->backendUriBuilder->buildUriFromRoute('backend_user_management')));
$this->moduleTemplate->getDocHeaderComponent()->setShortcutContext(
'backend_user_management',
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:compareBackendUsers', 'beuser'),
['action' => 'compare']
);
return $this->moduleTemplate->renderResponse('BackendUser/Compare');
}
protected function initializeInitiatePasswordResetAction(): void
{
$this->assertAllowedHttpMethod($this->request, 'POST');
}
/**
* Starts the password reset process for a selected user.
*/
public function initiatePasswordResetAction(int $user): ResponseInterface
{
$context = GeneralUtility::makeInstance(Context::class);
/** @var BackendUser|null $userObject */
$userObject = $this->backendUserRepository->findByUid($user);
if (!$userObject || !$userObject->isPasswordResetEnabled() || !$context->getAspect('backend.user')->isAdmin()) {
// Add an error message
$this->addFlashMessage(
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.error.text', 'beuser') ?? '',
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.error.title', 'beuser') ?? '',
ContextualFeedbackSeverity::ERROR
);
} else {
GeneralUtility::makeInstance(PasswordReset::class)->initiateReset(
$this->request,
$context,
$userObject->getEmail()
);
$this->addFlashMessage(
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.success.text', 'beuser', [$userObject->getEmail()]) ?? '',
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.success.title', 'beuser') ?? ''
);
}
return $this->redirect('list');
}
protected function initializeAddToCompareListAction(): void
{
$this->assertAllowedHttpMethod($this->request, 'POST');
}
/**
* Attaches one backend user to the compare list
*/
public function addToCompareListAction(int $uid): ResponseInterface
{
$this->addToCompareList('compareUserList', $uid);
return $this->redirect('list');
}
protected function initializeRemoveFromCompareListAction(): void
{
$this->assertAllowedHttpMethod($this->request, 'POST');
}
/**
* Removes given backend user to the compare list
*/
public function removeFromCompareListAction(int $uid, int $redirectToCompare = 0): ResponseInterface
{
$this->removeFromCompareList('compareUserList', $uid);
if ($redirectToCompare) {
return $this->redirect('compare');
}
return $this->redirect('list');
}
protected function initializeRemoveAllFromCompareListAction(): void
{
$this->assertAllowedHttpMethod($this->request, 'POST');
}
/**
* Removes all backend users from the compare list
*/
public function removeAllFromCompareListAction(): ResponseInterface
{
$this->cleanCompareList('compareUserList');
return $this->redirect('list');
}
protected function initializeTerminateBackendUserSessionAction(): void
{
$this->assertAllowedHttpMethod($this->request, 'POST');
}
/**
* Terminate BackendUser session and logout corresponding client
* Redirects to onlineAction with message
*/
protected function terminateBackendUserSessionAction(string $sessionId): ResponseInterface
{
// terminating value of persisted session ID
$success = $this->backendUserSessionRepository->terminateSessionByIdentifier($sessionId);
if ($success) {
$this->addFlashMessage(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:backendUser.online.flashMessage.terminateSessionSuccess', 'beuser') ?? '');
}
return $this->redirect('online');
}
/**
* Displays all BackendUserGroups
*/
public function groupsAction(?BackendUserGroup $userGroupDto = null, int $currentPage = 1, string $operation = ''): ResponseInterface
{
$backendUser = $this->getBackendUser();
if ($operation === 'reset-filters') {
$this->moduleData->set('userGroupDto', []);
$userGroupDto = null;
}
if ($userGroupDto === null) {
$userGroupDto = BackendUserGroup::fromUc((array)$this->moduleData->get('userGroupDto', []));
} else {
$this->moduleData->set('userGroupDto', $userGroupDto->forUc());
}
$backendUser->pushModuleData($this->moduleData->getModuleIdentifier(), $this->moduleData->toArray());
$backendUserGroups = $this->backendUserGroupRepository->findByFilter($userGroupDto);
$paginator = new QueryResultPaginator($backendUserGroups, $currentPage, 50);
$pagination = new SimplePagination($paginator);
$compareGroupUidList = array_keys((array)$this->moduleData->get('compareGroupUidList', []));
$this->moduleTemplate->assignMultiple(
[
'paginator' => $paginator,
'pagination' => $pagination,
'totalAmountOfBackendUserGroups' => $backendUserGroups->count(),
'compareGroupUidList' => array_map(static function (int $value): int { // uid as key and force value to 1
return 1;
}, array_flip($compareGroupUidList)),
'compareGroupList' => !empty($compareGroupUidList) ? $this->backendUserGroupRepository->findByUidList($compareGroupUidList) : [],
'userGroupDto' => $userGroupDto,
]
);
$this->addMainMenu('groups');
$addGroupButton = $this->componentFactory->createLinkButton()
->setIcon($this->iconFactory->getIcon('actions-plus', IconSize::SMALL))
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:btn.backendUserGroup.create', 'beuser'))
->setShowLabelText(true)
->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
'edit' => ['be_groups' => [0 => 'new']],
'module' => 'backend_user_management',
'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
]));
$this->moduleTemplate->addButtonToButtonBar($addGroupButton);
$this->moduleTemplate->getDocHeaderComponent()->setShortcutContext(
'backend_user_management',
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:backendUserGroupsMenu', 'beuser'),
['action' => 'groups']
);
return $this->moduleTemplate->renderResponse('BackendUserGroup/List');
}
/**
* Show a single backend user group.
*/
public function showGroupAction(int $uid = 0): ResponseInterface
{
$data = $this->userInformationService->getGroupInformation($uid);
$this->moduleTemplate->assignMultiple([
'data' => $data,
'showUid' => $this->getBackendUser()->shallDisplayDebugInformation(),
]);
$this->addMainMenu('showGroup');
$this->moduleTemplate->addButtonToButtonBar($this->componentFactory->createBackButton((string)$this->backendUriBuilder->buildUriFromRoute('backend_user_management', ['action' => 'groups'])));
$editButton = $this->componentFactory->createLinkButton()
->setIcon($this->iconFactory->getIcon('actions-open', IconSize::SMALL))
->setTitle(
LocalizationUtility::translate(
'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.edit'
)
)
->setShowLabelText(true)
->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
'edit' => ['be_groups' => [$uid => 'edit']],
'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
]));
$this->moduleTemplate->addButtonToButtonBar($editButton, ButtonBar::BUTTON_POSITION_LEFT, 2);
$addUserButton = $this->componentFactory->createLinkButton()
->setIcon($this->iconFactory->getIcon('actions-plus', IconSize::SMALL))
->setTitle(
LocalizationUtility::translate(
'LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:btn.backendUserGroup.create',
'beuser'
)
)
->setShowLabelText(true)
->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
'edit' => ['be_groups' => [0 => 'new']],
'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
]));
$this->moduleTemplate->addButtonToButtonBar($addUserButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
$backendGroupTitle = empty($data['group']['title']) ? '' : ': ' . $data['group']['title'];
$this->moduleTemplate->getDocHeaderComponent()->setShortcutContext(
'backend_user_management',
LocalizationUtility::translate(
'LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:backendUserGroup',
'beuser'
) . $backendGroupTitle,
['action' => 'showGroup', 'uid' => $uid]
);
return $this->moduleTemplate->renderResponse('BackendUserGroup/Show');
}
public function compareGroupsAction(): ResponseInterface
{
$compareGroupUidList = array_keys((array)$this->moduleData->get('compareGroupUidList', []));
$compareData = [];
foreach ($compareGroupUidList as $uid) {
if ($compareInformation = $this->userInformationService->getGroupInformation($uid)) {
$compareData[] = $compareInformation;
}
}
if (empty($compareData)) {
return $this->redirect('groups');
}
$this->moduleTemplate->assignMultiple([
'compareGroupList' => $compareData,
'showUid' => $this->getBackendUser()->shallDisplayDebugInformation(),
]);
$this->addMainMenu('compareGroups');
$this->moduleTemplate->addButtonToButtonBar($this->componentFactory->createBackButton($this->uriBuilder->uriFor('groups')));
$this->moduleTemplate->getDocHeaderComponent()->setShortcutContext(
'backend_user_management',
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:compareBackendUsersGroups', 'beuser'),
['action' => 'compareGroups']
);
return $this->moduleTemplate->renderResponse('BackendUserGroup/Compare');
}
protected function initializeAddGroupToCompareListAction(): void
{
$this->assertAllowedHttpMethod($this->request, 'POST');
}
/**
* Attaches one backend user group to the compare list
*/
public function addGroupToCompareListAction(int $uid): ResponseInterface
{
$this->addToCompareList('compareGroupUidList', $uid);
return $this->redirect('groups');
}
protected function initializeRemoveGroupFromCompareListAction(): void
{
$this->assertAllowedHttpMethod($this->request, 'POST');
}
/**
* Removes given backend user group to the compare list
*/
public function removeGroupFromCompareListAction(int $uid, int $redirectToCompare = 0): ResponseInterface
{
$this->removeFromCompareList('compareGroupUidList', $uid);
if ($redirectToCompare) {
return $this->redirect('compareGroups');
}
return $this->redirect('groups');
}
protected function initializeRemoveAllGroupsFromCompareListAction(): void
{
$this->assertAllowedHttpMethod($this->request, 'POST');
}
/**
* Removes all backend user groups from the compare list
*/
public function removeAllGroupsFromCompareListAction(): ResponseInterface
{
$this->cleanCompareList('compareGroupUidList');
return $this->redirect('groups');
}
protected function filemountsAction(int $currentPage = 1): ResponseInterface
{
$filemounts = $this->eventDispatcher->dispatch(
new AfterFilemountsListIsAssembledEvent(
$this->request,
$this->fileMountRepository->findAll()->toArray()
)
)->filemounts;
$this->addMainMenu('filemounts');
$paginator = new ArrayPaginator($filemounts, $currentPage, 50);
$pagination = new SimplePagination($paginator);
$this->moduleTemplate->assignMultiple(
[
'paginator' => $paginator,
'pagination' => $pagination,
'totalAmountOfFilemounts' => count($filemounts),
]
);
$addFilemountButton = $this->componentFactory->createLinkButton()
->setIcon($this->iconFactory->getIcon('actions-plus', IconSize::SMALL))
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:filemount.create', 'beuser'))
->setShowLabelText(true)
->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
'edit' => ['sys_filemounts' => [0 => 'new']],
'module' => 'backend_user_management',
'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
]));
$this->moduleTemplate->addButtonToButtonBar($addFilemountButton);
return $this->moduleTemplate->renderResponse('Filemount/List');
}
/**
* Create an array with the uids of online users as the keys
* [
* 1 => true,
* 5 => true
* ]
*/
protected function getOnlineBackendUsers(): array
{
$onlineUsers = $this->backendUserSessionRepository->findAllActive();
$onlineBackendUsers = [];
foreach ($onlineUsers as $onlineUser) {
$onlineBackendUsers[$onlineUser['ses_userid']] = true;
}
return $onlineBackendUsers;
}
/**
* Doc header main drop down
*/
protected function addMainMenu(string $currentAction): void
{
$this->uriBuilder->setRequest($this->request);
$menu = $this->componentFactory->createMenu();
$menu->setIdentifier('BackendUserModuleMenu');
$menu->setLabel(
LocalizationUtility::translate(
'LLL:EXT:backend/Resources/Private/Language/locallang.xlf:modulemenu.label',
'backend',
)
);
$menu->addMenuItem(
$this->componentFactory->createMenuItem()
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:backendUsers', 'beuser'))
->setHref($this->uriBuilder->uriFor('list'))
->setActive($currentAction === 'list')
);
if ($currentAction === 'show') {
$menu->addMenuItem(
$this->componentFactory->createMenuItem()
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:backendUserDetails', 'beuser'))
->setHref($this->uriBuilder->uriFor('show'))
->setActive(true)
);
}
if ($currentAction === 'compare') {
$menu->addMenuItem(
$this->componentFactory->createMenuItem()
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:compareBackendUsers', 'beuser'))
->setHref($this->uriBuilder->uriFor('list'))
->setActive(true)
);
}
$menu->addMenuItem(
$this->componentFactory->createMenuItem()
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:backendUserGroupsMenu', 'beuser'))
->setHref($this->uriBuilder->uriFor('groups'))
->setActive($currentAction === 'groups')
);
if ($currentAction === 'showGroup') {
$menu->addMenuItem(
$this->componentFactory->createMenuItem()
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:backendUserGroupDetails', 'beuser'))
->setHref($this->uriBuilder->uriFor('showGroup'))
->setActive(true)
);
}
if ($currentAction === 'compareGroups') {
$menu->addMenuItem(
$this->componentFactory->createMenuItem()
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:compareBackendUsersGroups', 'beuser'))
->setHref($this->uriBuilder->uriFor('compareGroups'))
->setActive(true)
);
}
$menu->addMenuItem(
$this->componentFactory->createMenuItem()
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:onlineUsers', 'beuser'))
->setHref($this->uriBuilder->uriFor('online'))
->setActive($currentAction === 'online')
);
$menu->addMenuItem(
$this->componentFactory->createMenuItem()
->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:filemounts', 'beuser'))
->setHref($this->uriBuilder->uriFor('filemounts'))
->setActive($currentAction === 'filemounts')
);
$this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
}
/**
* Attaches the given uid to the requested compare list
*/
protected function addToCompareList(string $listIdentifier, int $uid): void
{
$compareList = (array)$this->moduleData->get($listIdentifier, []);
$compareList[$uid] = true;
$this->moduleData->set($listIdentifier, $compareList);
$this->getBackendUser()->pushModuleData($this->moduleData->getModuleIdentifier(), $this->moduleData->toArray());
}
/**
* Removes the given uid from the requested compare list
*/
protected function removeFromCompareList(string $listIdentifier, int $uid): void
{
$compareList = (array)$this->moduleData->get($listIdentifier, []);
unset($compareList[$uid]);
$this->moduleData->set($listIdentifier, $compareList);
$this->getBackendUser()->pushModuleData($this->moduleData->getModuleIdentifier(), $this->moduleData->toArray());
}
/**
* Removes all items from the requested compare list
*/
protected function cleanCompareList(string $listIdentifier): void
{
$this->moduleData->set($listIdentifier, []);
$this->getBackendUser()->pushModuleData($this->moduleData->getModuleIdentifier(), $this->moduleData->toArray());
}
protected function getBackendUser(): BackendUserAuthentication
{
return $GLOBALS['BE_USER'];
}
}
+548
View File
@@ -0,0 +1,548 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Beuser\Controller;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Backend\Attribute\AsController;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
use TYPO3\CMS\Backend\Template\Components\ComponentFactory;
use TYPO3\CMS\Backend\Template\ModuleTemplate;
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
use TYPO3\CMS\Backend\Tree\View\PageTreeView;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\View\BackendViewFactory;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Imaging\IconSize;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Messaging\FlashMessageService;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Backend module page permissions. This is the "Access" module in main module.
* Also includes the ajax endpoint for convenient methods for editing
* of page permissions (including page ownership (user and group)).
*
* @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API.
*/
#[AsController]
class PermissionController
{
private const string SESSION_PREFIX = 'tx_Beuser_';
private const array DEPTH_LEVELS = [1, 2, 3, 4, 10];
private const int RECURSIVE_LEVELS = 10;
protected int $id = 0;
protected string $returnUrl = '';
protected int $depth;
protected array $pageInfo = [];
public function __construct(
protected readonly ComponentFactory $componentFactory,
protected readonly ModuleTemplateFactory $moduleTemplateFactory,
protected readonly PageRenderer $pageRenderer,
protected readonly IconFactory $iconFactory,
protected readonly UriBuilder $uriBuilder,
protected readonly ResponseFactoryInterface $responseFactory,
protected readonly BackendViewFactory $backendViewFactory,
protected readonly FlashMessageService $flashMessageService,
) {}
public function handleRequest(ServerRequestInterface $request): ResponseInterface
{
$parsedBody = $request->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 = '<span title="' . BackendUtility::getRecordIconAltText($this->pageInfo, 'pages') . '">' . $icon->render() . '</span>';
$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'];
}
}