first commit

This commit is contained in:
salam committed 2026-10-19 08:18:39 +02:00
commit 1218dd1517
12716 files changed
+989233

No files matched your search

@@ -0,0 +1,344 @@
<?php
namespace TYPO3\CMS\Beuser\Controller;
/*
* 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!
*/
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait;
use TYPO3\CMS\Core\Session\Backend\HashableSessionBackendInterface;
use TYPO3\CMS\Core\Session\Backend\SessionBackendInterface;
use TYPO3\CMS\Core\Session\SessionManager;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* Backend module user 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 PublicMethodDeprecationTrait;
/**
* @var array
*/
private $deprecatedPublicMethods = [
'initializeView' => 'Using BackendUserController::initializeView() is deprecated and will not be possible anymore in TYPO3 v10.0.',
];
/**
* @var int
*/
const RECENT_USERS_LIMIT = 3;
/**
* @var \TYPO3\CMS\Beuser\Domain\Model\ModuleData
*/
protected $moduleData;
/**
* @var \TYPO3\CMS\Beuser\Service\ModuleDataStorageService
*/
protected $moduleDataStorageService;
/**
* @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository
*/
protected $backendUserRepository;
/**
* @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository
*/
protected $backendUserGroupRepository;
/**
* @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository
*/
protected $backendUserSessionRepository;
/**
* @param \TYPO3\CMS\Beuser\Service\ModuleDataStorageService $moduleDataStorageService
*/
public function injectModuleDataStorageService(\TYPO3\CMS\Beuser\Service\ModuleDataStorageService $moduleDataStorageService)
{
$this->moduleDataStorageService = $moduleDataStorageService;
}
/**
* @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository $backendUserRepository
*/
public function injectBackendUserRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository $backendUserRepository)
{
$this->backendUserRepository = $backendUserRepository;
}
/**
* @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository $backendUserGroupRepository
*/
public function injectBackendUserGroupRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository $backendUserGroupRepository)
{
$this->backendUserGroupRepository = $backendUserGroupRepository;
}
/**
* @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository $backendUserSessionRepository
*/
public function injectBackendUserSessionRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository $backendUserSessionRepository)
{
$this->backendUserSessionRepository = $backendUserSessionRepository;
}
/**
* Load and persist module data
*
* @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request
* @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
*/
public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response)
{
$this->moduleData = $this->moduleDataStorageService->loadModuleData();
// We "finally" persist the module data.
try {
parent::processRequest($request, $response);
$this->moduleDataStorageService->persistModuleData($this->moduleData);
} catch (\TYPO3\CMS\Extbase\Mvc\Exception\StopActionException $e) {
$this->moduleDataStorageService->persistModuleData($this->moduleData);
throw $e;
}
}
/**
* Assign default variables to view
* @param ViewInterface $view
*/
protected function initializeView(ViewInterface $view)
{
$view->assignMultiple([
'shortcutLabel' => 'backendUsers',
'dateFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'],
'timeFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'],
]);
}
/**
* Displays all BackendUsers
* - Switch session to different user
*
* @param \TYPO3\CMS\Beuser\Domain\Model\Demand $demand
*/
public function indexAction(\TYPO3\CMS\Beuser\Domain\Model\Demand $demand = null)
{
if ($demand === null) {
$demand = $this->moduleData->getDemand();
} else {
$this->moduleData->setDemand($demand);
}
// Switch user until logout
$switchUser = (int)GeneralUtility::_GP('SwitchUser');
if ($switchUser > 0) {
$this->switchUser($switchUser);
}
$compareUserList = $this->moduleData->getCompareUserList();
// Create online user list for easy parsing
$onlineUsers = $this->backendUserSessionRepository->findAllActive();
$onlineBackendUsers = [];
if (is_array($onlineUsers)) {
foreach ($onlineUsers as $onlineUser) {
$onlineBackendUsers[$onlineUser['ses_userid']] = true;
}
}
$this->view->assignMultiple([
'onlineBackendUsers' => $onlineBackendUsers,
'demand' => $demand,
'backendUsers' => $this->backendUserRepository->findDemanded($demand),
'backendUserGroups' => array_merge([''], $this->backendUserGroupRepository->findAll()->toArray()),
'compareUserUidList' => array_combine($compareUserList, $compareUserList),
'currentUserUid' => $this->getBackendUserAuthentication()->user['uid'],
'compareUserList' => !empty($compareUserList) ? $this->backendUserRepository->findByUidList($compareUserList) : '',
]);
}
/**
* Views all currently logged in BackendUsers and their sessions
*/
public function onlineAction()
{
$onlineUsersAndSessions = [];
$onlineUsers = $this->backendUserRepository->findOnline();
foreach ($onlineUsers as $onlineUser) {
$onlineUsersAndSessions[] = [
'backendUser' => $onlineUser,
'sessions' => $this->backendUserSessionRepository->findByBackendUser($onlineUser)
];
}
$currentSessionId = $this->getBackendUserAuthentication()->getSessionId();
$sessionBackend = $this->getSessionBackend();
if ($sessionBackend instanceof HashableSessionBackendInterface) {
$currentSessionId = $sessionBackend->hash($currentSessionId);
}
$this->view->assignMultiple([
'shortcutLabel' => 'onlineUsers',
'onlineUsersAndSessions' => $onlineUsersAndSessions,
'currentSessionId' => $currentSessionId,
]);
}
/**
* Compare backend users from demand
*/
public function compareAction()
{
$compareUserList = $this->moduleData->getCompareUserList();
if (empty($compareUserList)) {
$this->redirect('index');
}
$this->view->assignMultiple([
'shortcutLabel' => 'compareUsers',
'compareUserList' => $this->backendUserRepository->findByUidList($compareUserList),
]);
}
/**
* Attaches one backend user to the compare list
*
* @param int $uid
*/
public function addToCompareListAction($uid)
{
$this->moduleData->attachUidCompareUser($uid);
$this->moduleDataStorageService->persistModuleData($this->moduleData);
$this->forward('index');
}
/**
* Removes given backend user to the compare list
*
* @param int $uid
*/
public function removeFromCompareListAction($uid)
{
$this->moduleData->detachUidCompareUser($uid);
$this->moduleDataStorageService->persistModuleData($this->moduleData);
$this->forward('index');
}
/**
* Terminate BackendUser session and logout corresponding client
* Redirects to onlineAction with message
*
* @param \TYPO3\CMS\Beuser\Domain\Model\BackendUser $backendUser
* @param string $sessionId
*/
protected function terminateBackendUserSessionAction(\TYPO3\CMS\Beuser\Domain\Model\BackendUser $backendUser, $sessionId)
{
// terminating value of persisted session ID (probably hashed value)
$sessionBackend = $this->getSessionBackend();
$success = $sessionBackend->remove($sessionId);
if ($success) {
$this->addFlashMessage(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:terminateSessionSuccess', 'beuser'));
}
$this->forward('online');
}
/**
* Switches to a given user (SU-mode) and then redirects to the start page of the backend to refresh the navigation etc.
*
* @param string $switchUser BE-user record that will be switched to
*/
protected function switchUser($switchUser)
{
$targetUser = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('be_users', $switchUser);
if (is_array($targetUser) && $this->getBackendUserAuthentication()->isAdmin()) {
// Set backend user listing module as starting module for switchback
$this->getBackendUserAuthentication()->uc['startModuleOnFirstLogin'] = 'system_BeuserTxBeuser';
$this->getBackendUserAuthentication()->uc['recentSwitchedToUsers'] = $this->generateListOfMostRecentSwitchedUsers($targetUser['uid']);
$this->getBackendUserAuthentication()->writeUC();
$this->getSessionBackend()->update(
$this->getBackendUserAuthentication()->getSessionId(),
[
'ses_userid' => (int)$targetUser['uid'],
'ses_backuserid' => (int)$this->getBackendUserAuthentication()->user['uid']
]
);
$this->emitSwitchUserSignal($targetUser);
$redirectUrl = 'index.php' . ($GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces'] ? '' : '?commandLI=1');
\TYPO3\CMS\Core\Utility\HttpUtility::redirect($redirectUrl);
}
}
/**
* Generates a list of users to whom where switched in the past. This is limited by RECENT_USERS_LIMIT.
*
* @param int $targetUserUid
* @return int[]
*/
protected function generateListOfMostRecentSwitchedUsers(int $targetUserUid): array
{
$latestUserUids = [];
$backendUser = $this->getBackendUserAuthentication();
if (isset($backendUser->uc['recentSwitchedToUsers']) && is_array($backendUser->uc['recentSwitchedToUsers'])) {
$latestUserUids = $backendUser->uc['recentSwitchedToUsers'];
}
// Remove potentially existing user in that list
$index = array_search($targetUserUid, $latestUserUids, true);
if ($index !== false) {
unset($latestUserUids[$index]);
}
array_unshift($latestUserUids, $targetUserUid);
$latestUserUids = array_slice($latestUserUids, 0, static::RECENT_USERS_LIMIT);
return $latestUserUids;
}
/**
* Emit a signal when using the "switch to user" functionality
*
* @param array $targetUser
*/
protected function emitSwitchUserSignal(array $targetUser)
{
$this->signalSlotDispatcher->dispatch(__CLASS__, 'switchUser', [$targetUser]);
}
/**
* @return BackendUserAuthentication
*/
protected function getBackendUserAuthentication(): BackendUserAuthentication
{
return $GLOBALS['BE_USER'];
}
/**
* @return SessionBackendInterface
*/
protected function getSessionBackend()
{
$loginType = $this->getBackendUserAuthentication()->getLoginType();
return GeneralUtility::makeInstance(SessionManager::class)->getSessionBackend($loginType);
}
}
@@ -0,0 +1,50 @@
<?php
namespace TYPO3\CMS\Beuser\Controller;
/*
* 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!
*/
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
/**
* Backend module user group administration controller
* @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API.
*/
class BackendUserGroupController extends ActionController
{
/**
* @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository
*/
protected $backendUserGroupRepository;
/**
* @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository $backendUserGroupRepository
*/
public function injectBackendUserGroupRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository $backendUserGroupRepository)
{
$this->backendUserGroupRepository = $backendUserGroupRepository;
}
/**
* Displays all BackendUserGroups
*/
public function indexAction()
{
$this->view->assignMultiple(
[
'shortcutLabel' => 'backendUserGroupsMenu',
'backendUserGroups' => $this->backendUserGroupRepository->findAll(),
]
);
}
}
@@ -0,0 +1,316 @@
<?php
namespace TYPO3\CMS\Beuser\Controller;
/*
* 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!
*/
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Http\HtmlResponse;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;
/**
* This class extends the permissions module in the TYPO3 Backend to provide
* convenient methods of editing of page permissions (including page ownership
* (user and group)) via new AjaxRequestHandler facility
* @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API.
*/
class PermissionAjaxController
{
/**
* The local configuration array
*
* @var array
*/
protected $conf;
/**
* @var IconFactory
*/
protected $iconFactory;
/**
* The constructor of this class
*/
public function __construct()
{
$this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
$this->getLanguageService()->includeLLFile('EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf');
}
/**
* The main dispatcher function. Collect data and prepare HTML output.
*
* @param ServerRequestInterface $request
* @return ResponseInterface
*/
public function dispatch(ServerRequestInterface $request): ResponseInterface
{
$parsedBody = $request->getParsedBody();
$this->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),
];
$extPath = ExtensionManagementUtility::extPath('beuser');
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setPartialRootPaths(['default' => ExtensionManagementUtility::extPath('beuser') . 'Resources/Private/Partials']);
$view->assign('pageId', $this->conf['page']);
$response = new HtmlResponse('');
// Basic test for required value
if ($this->conf['page'] <= 0) {
$response->getBody()->write('This script cannot be called directly');
return $response->withStatus(500);
}
$content = '';
// Init TCE for execution of update
$tce = GeneralUtility::makeInstance(DataHandler::class);
// Determine the scripts to execute
switch ($this->conf['action']) {
case 'show_change_owner_selector':
$content = $this->renderUserSelector($this->conf['page'], $this->conf['ownerUid'], $this->conf['username']);
break;
case 'change_owner':
$userId = $this->conf['new_owner_uid'];
if (is_int($userId)) {
// Prepare data to change
$data = [];
$data['pages'][$this->conf['page']]['perms_userid'] = $userId;
// Execute TCE Update
$tce->start($data, []);
$tce->process_datamap();
$view->setTemplatePathAndFilename($extPath . 'Resources/Private/Templates/PermissionAjax/ChangeOwner.html');
$view->assign('userId', $userId);
$usernameArray = BackendUtility::getUserNames('username', ' AND uid = ' . $userId);
$view->assign('username', $usernameArray[$userId]['username']);
$content = $view->render();
} else {
$response->getBody()->write('An error occurred: No page owner uid specified');
$response = $response->withStatus(500);
}
break;
case 'show_change_group_selector':
$content = $this->renderGroupSelector($this->conf['page'], $this->conf['groupUid'], $this->conf['groupname']);
break;
case 'change_group':
$groupId = $this->conf['new_group_uid'];
if (is_int($groupId)) {
// Prepare data to change
$data = [];
$data['pages'][$this->conf['page']]['perms_groupid'] = $groupId;
// Execute TCE Update
$tce->start($data, []);
$tce->process_datamap();
$view->setTemplatePathAndFilename($extPath . 'Resources/Private/Templates/PermissionAjax/ChangeGroup.html');
$view->assign('groupId', $groupId);
$groupnameArray = BackendUtility::getGroupNames('title', ' AND uid = ' . $groupId);
$view->assign('groupname', $groupnameArray[$groupId]['title']);
$content = $view->render();
} else {
$response->getBody()->write('An error occurred: No page group uid specified');
$response = $response->withStatus(500);
}
break;
case 'toggle_edit_lock':
// Prepare data to change
$data = [];
$data['pages'][$this->conf['page']]['editlock'] = $this->conf['editLockState'] === 1 ? 0 : 1;
// Execute TCE Update
$tce->start($data, []);
$tce->process_datamap();
$content = $this->renderToggleEditLock($this->conf['page'], $data['pages'][$this->conf['page']]['editlock']);
break;
default:
if ($this->conf['mode'] === 'delete') {
$this->conf['permissions'] = (int)($this->conf['permissions'] - $this->conf['bits']);
} else {
$this->conf['permissions'] = (int)($this->conf['permissions'] + $this->conf['bits']);
}
// Prepare data to change
$data = [];
$data['pages'][$this->conf['page']]['perms_' . $this->conf['who']] = $this->conf['permissions'];
// Execute TCE Update
$tce->start($data, []);
$tce->process_datamap();
$view->setTemplatePathAndFilename($extPath . 'Resources/Private/Templates/PermissionAjax/ChangePermission.html');
$view->assign('permission', $this->conf['permissions']);
$view->assign('scope', $this->conf['who']);
$content = $view->render();
}
$response->getBody()->write($content);
return $response;
}
/**
* Generate the user selector element
*
* @param int $page The page id to change the user for
* @param int $ownerUid The page owner uid
* @param string $username The username to display
* @return string The html select element
*/
protected function renderUserSelector($page, $ownerUid, $username = '')
{
$page = (int)$page;
$ownerUid = (int)$ownerUid;
// Get usernames
$beUsers = BackendUtility::getUserNames();
// Owner selector:
$options = '';
// Loop through the users
foreach ($beUsers as $uid => $row) {
$uid = (int)$uid;
$selected = $uid === $ownerUid ? ' selected="selected"' : '';
$options .= '<option value="' . $uid . '"' . $selected . '>' . htmlspecialchars($row['username']) . '</option>';
}
$elementId = 'o_' . $page;
$options = '<option value="0"></option>' . $options;
$selector = '<select name="new_page_owner" id="new_page_owner">' . $options . '</select>';
$saveButton = '<a class="saveowner btn btn-default" data-page="' . $page . '" data-owner="' . $ownerUid
. '" data-element-id="' . $elementId . '" title="Change owner">'
. $this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL)->render()
. '</a>';
$cancelButton = '<a class="restoreowner btn btn-default" data-page="' . $page . '" data-owner="' . $ownerUid
. '" data-element-id="' . $elementId . '"'
. (!empty($username) ? ' data-username="' . htmlspecialchars($username) . '"' : '')
. ' title="Cancel">'
. $this->iconFactory->getIcon('actions-close', Icon::SIZE_SMALL)->render()
. '</a>';
return '<span id="' . $elementId . '">'
. $selector
. '<span class="btn-group">'
. $saveButton
. $cancelButton
. '</span>'
. '</span>';
}
/**
* Generate the group selector element
*
* @param int $page The page id to change the user for
* @param int $groupUid The page group uid
* @param string $groupname The groupname to display
* @return string The html select element
*/
protected function renderGroupSelector($page, $groupUid, $groupname = '')
{
$page = (int)$page;
$groupUid = (int)$groupUid;
// Get group names
$beGroupsO = $beGroups = BackendUtility::getGroupNames();
// Group selector:
$options = '';
// flag: is set if the page-groupid equals one from the group-list
$userset = 0;
// Loop through the groups
foreach ($beGroups as $uid => $row) {
$uid = (int)$uid;
if ($uid === $groupUid) {
$userset = 1;
$selected = ' selected="selected"';
} else {
$selected = '';
}
$options .= '<option value="' . $uid . '"' . $selected . '>' . htmlspecialchars($row['title']) . '</option>';
}
// If the group was not set AND there is a group for the page
if (!$userset && $groupUid) {
$options = '<option value="' . $groupUid . '" selected="selected">' .
htmlspecialchars($beGroupsO[$groupUid]['title']) . '</option>' . $options;
}
$elementId = 'g_' . $page;
$options = '<option value="0"></option>' . $options;
$selector = '<select name="new_page_group" id="new_page_group">' . $options . '</select>';
$saveButton = '<a class="savegroup btn btn-default" data-page="' . $page . '" data-group-id="' . $groupUid
. '" data-element-id="' . $elementId . '" title="Change group">'
. $this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL)->render()
. '</a>';
$cancelButton = '<a class="restoregroup btn btn-default" data-page="' . $page . '" data-group-id="' . $groupUid
. '" data-element-id="' . $elementId . '"'
. (!empty($groupname) ? ' data-groupname="' . htmlspecialchars($groupname) . '"' : '')
. ' title="Cancel">'
. $this->iconFactory->getIcon('actions-close', Icon::SIZE_SMALL)->render()
. '</a>';
return '<span id="' . $elementId . '">'
. $selector
. '<span class="btn-group">'
. $saveButton
. $cancelButton
. '</span>'
. '</span>';
}
/**
* Print the string with the new edit lock state of a page record
*
* @param int $page The TYPO3 page id
* @param string $editLockState The state of the TYPO3 page (locked, unlocked)
* @return string The new edit lock string wrapped in HTML
*/
protected function renderToggleEditLock($page, $editLockState)
{
$page = (int)$page;
if ($editLockState === 1) {
$ret = '<span id="el_' . $page . '"><a class="editlock btn btn-default" data-page="' . $page
. '" data-lockstate="1" title="The page and all content is locked for editing by all non-Admin users.">'
. $this->iconFactory->getIcon('actions-lock', Icon::SIZE_SMALL)->render() . '</a></span>';
} else {
$ret = '<span id="el_' . $page . '"><a class="editlock btn btn-default" data-page="' . $page .
'" data-lockstate="0" title="Enable the &raquo;Admin-only&laquo; edit lock for this page">'
. $this->iconFactory->getIcon('actions-unlock', Icon::SIZE_SMALL)->render() . '</a></span>';
}
return $ret;
}
/**
* @return \TYPO3\CMS\Core\Localization\LanguageService
*/
protected function getLanguageService()
{
return $GLOBALS['LANG'];
}
/**
* @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
*/
protected function getBackendUser()
{
return $GLOBALS['BE_USER'];
}
}
@@ -0,0 +1,417 @@
<?php
namespace TYPO3\CMS\Beuser\Controller;
/*
* 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!
*/
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
use TYPO3\CMS\Backend\Tree\View\PageTreeView;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\View\BackendTemplateView;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* Backend module page permissions
* @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API.
*/
class PermissionController extends ActionController
{
/**
* @var string prefix for session
*/
const SESSION_PREFIX = 'tx_Beuser_';
/**
* @var int the current page id
*/
protected $id;
/**
* @var string
*/
protected $returnUrl = '';
/**
* @var int
*/
protected $depth;
/**
* Number of levels to enable recursive settings for
*
* @var int
*/
protected $getLevels = 10;
/**
* @var array
*/
protected $pageInfo = [];
/**
* Backend Template Container
*
* @var string
*/
protected $defaultViewObjectName = BackendTemplateView::class;
/**
* BackendTemplateContainer
*
* @var BackendTemplateView
*/
protected $view;
/**
* Initialize action
*/
protected function initializeAction()
{
// determine depth parameter
$this->depth = (int)GeneralUtility::_GP('depth') > 0
? (int)GeneralUtility::_GP('depth')
: (int)$this->getBackendUser()->getSessionData(self::SESSION_PREFIX . 'depth');
if ($this->request->hasArgument('depth')) {
$this->depth = (int)$this->request->getArgument('depth');
}
$this->getBackendUser()->setAndSaveSessionData(self::SESSION_PREFIX . 'depth', $this->depth);
// determine id parameter
$this->id = (int)GeneralUtility::_GP('id');
if ($this->request->hasArgument('id')) {
$this->id = (int)$this->request->getArgument('id');
}
if (!BackendUtility::getRecord('pages', $this->id)) {
$this->id = 0;
}
$this->returnUrl = GeneralUtility::_GP('returnUrl');
if ($this->request->hasArgument('returnUrl')) {
$this->returnUrl = $this->request->getArgument('returnUrl');
}
$this->setPageInfo();
}
/**
* Initializes view
*
* @param ViewInterface $view The view to be initialized
*/
protected function initializeView(ViewInterface $view)
{
parent::initializeView($view);
$this->setPageInfo();
$view->assign(
'previewUrl',
BackendUtility::viewOnClick(
(int)$this->pageInfo['uid'],
'',
BackendUtility::BEgetRootLine((int)$this->pageInfo['uid'])
)
);
// the view of the update action has a different view class
if ($view instanceof BackendTemplateView) {
$view->getModuleTemplate()->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Beuser/Permissions');
$view->getModuleTemplate()->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Tooltip');
$this->registerDocHeaderButtons();
$this->view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($this->pageInfo);
$this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
}
}
/**
* Registers the Icons into the docheader
*
* @throws \InvalidArgumentException
*/
protected function registerDocHeaderButtons()
{
/** @var ButtonBar $buttonBar */
$buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
$currentRequest = $this->request;
$moduleName = $currentRequest->getPluginName();
$getVars = $this->request->getArguments();
$lang = $this->getLanguageService();
$extensionName = $currentRequest->getControllerExtensionName();
if (empty($getVars)) {
$modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName);
$getVars = ['id', 'route', $modulePrefix];
}
if ($currentRequest->getControllerActionName() === 'edit') {
// CLOSE button:
if (!empty($this->returnUrl)) {
$closeButton = $buttonBar->makeLinkButton()
->setHref($this->returnUrl)
->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.closeDoc'))
->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon(
'actions-close',
Icon::SIZE_SMALL
));
$buttonBar->addButton($closeButton);
}
// SAVE button:
$saveButton = $buttonBar->makeInputButton()
->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.saveCloseDoc'))
->setName('tx_beuser_system_beusertxpermission[submit]')
->setValue('Save')
->setForm('PermissionControllerEdit')
->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon(
'actions-document-save',
Icon::SIZE_SMALL
))
->setShowLabelText(true);
$buttonBar->addButton($saveButton);
}
// SHORTCUT botton:
$shortcutButton = $buttonBar->makeShortcutButton()
->setModuleName($moduleName)
->setGetVariables($getVars);
$buttonBar->addButton($shortcutButton);
}
/**
* Index action
*/
public function indexAction()
{
if (!$this->id) {
$this->pageInfo = ['title' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'], 'uid' => 0, 'pid' => 0];
}
if ($this->getBackendUser()->workspace != 0) {
// Adding section with the permission setting matrix:
$this->addFlashMessage(
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:WorkspaceWarningText', 'beuser'),
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:WorkspaceWarning', 'beuser'),
FlashMessage::WARNING
);
}
// depth options
$depthOptions = [];
$url = $this->uriBuilder->reset()->setArguments([
'action' => 'index',
'depth' => '__DEPTH__',
'id' => $this->id
])->buildBackendUri();
foreach ([1, 2, 3, 4, 10] as $depthLevel) {
$levelLabel = $depthLevel === 1 ? 'level' : 'levels';
$depthOptions[$depthLevel] = $depthLevel . ' ' . LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:' . $levelLabel, 'beuser');
}
$this->view->assign('currentId', $this->id);
$this->view->assign('depthBaseUrl', $url);
$this->view->assign('depth', $this->depth);
$this->view->assign('depthOptions', $depthOptions);
$beUserArray = BackendUtility::getUserNames();
$this->view->assign('beUsers', $beUserArray);
$beGroupArray = BackendUtility::getGroupNames();
$this->view->assign('beGroups', $beGroupArray);
/** @var PageTreeView $tree */
$tree = GeneralUtility::makeInstance(PageTreeView::class);
$tree->init();
$tree->addField('perms_user', true);
$tree->addField('perms_group', true);
$tree->addField('perms_everybody', true);
$tree->addField('perms_userid', true);
$tree->addField('perms_groupid', true);
$tree->addField('hidden');
$tree->addField('fe_group');
$tree->addField('starttime');
$tree->addField('endtime');
$tree->addField('editlock');
// Create the tree from $this->id
if ($this->id) {
$tree->tree[] = ['row' => $this->pageInfo, 'HTML' => $tree->getIcon($this->id)];
} else {
$tree->tree[] = ['row' => $this->pageInfo, 'HTML' => $tree->getRootIcon($this->pageInfo)];
}
$tree->getTree($this->id, $this->depth);
$this->view->assign('viewTree', $tree->tree);
// CSH for permissions setting
$this->view->assign('cshItem', BackendUtility::cshItem('xMOD_csh_corebe', 'perm_module', null, '<span class="btn btn-default btn-sm">|</span>'));
}
/**
* Edit action
*/
public function editAction()
{
$this->view->assign('id', $this->id);
$this->view->assign('depth', $this->depth);
if (!$this->id) {
$this->pageInfo = ['title' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'], 'uid' => 0, 'pid' => 0];
}
if ($this->getBackendUser()->workspace != 0) {
// Adding FlashMessage with the permission setting matrix:
$this->addFlashMessage(
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:WorkspaceWarningText', 'beuser'),
LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:WorkspaceWarning', 'beuser'),
FlashMessage::WARNING
);
}
// Get user names and group names
$beGroupArray = BackendUtility::getGroupNames();
$beUserArray = BackendUtility::getUserNames();
// Owner selector
$beUserDataArray = [0 => LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:selectNone', 'beuser')];
foreach ($beUserArray as $uid => &$row) {
$beUserDataArray[$uid] = $row['username'];
}
$beUserDataArray[-1] = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:selectUnchanged', 'beuser');
$this->view->assign('currentBeUser', $this->pageInfo['perms_userid']);
$this->view->assign('beUserData', $beUserDataArray);
// Group selector
$beGroupDataArray = [0 => LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:selectNone', 'beuser')];
foreach ($beGroupArray as $uid => $row) {
$beGroupDataArray[$uid] = $row['title'];
}
$beGroupDataArray[-1] = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:selectUnchanged', 'beuser');
$this->view->assign('currentBeGroup', $this->pageInfo['perms_groupid']);
$this->view->assign('beGroupData', $beGroupDataArray);
$this->view->assign('pageInfo', $this->pageInfo);
$this->view->assign('returnUrl', $this->returnUrl);
$this->view->assign('recursiveSelectOptions', $this->getRecursiveSelectOptions());
}
/**
* Update action
*
* @param array $data
* @param array $mirror
*/
protected function updateAction(array $data, array $mirror)
{
$dataHandlerInput = [];
// Prepare the input data for data handler
if (!empty($data['pages'])) {
foreach ($data['pages'] as $pageUid => $properties) {
// if the owner and group field shouldn't be touched, unset the option
if ((int)$properties['perms_userid'] === -1) {
unset($properties['perms_userid']);
}
if ((int)$properties['perms_groupid'] === -1) {
unset($properties['perms_groupid']);
}
$dataHandlerInput[$pageUid] = $properties;
if (!empty($mirror['pages'][$pageUid])) {
$mirrorPages = GeneralUtility::intExplode(',', $mirror['pages'][$pageUid]);
foreach ($mirrorPages as $mirrorPageUid) {
$dataHandlerInput[$mirrorPageUid] = $properties;
}
}
}
}
$dataHandler = GeneralUtility::makeInstance(DataHandler::class);
$dataHandler->start(
[
'pages' => $dataHandlerInput
],
[]
);
$dataHandler->process_datamap();
$this->redirectToUri($this->returnUrl);
}
/**
* @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
*/
protected function getBackendUser()
{
return $GLOBALS['BE_USER'];
}
/**
* Finding tree and offer setting of values recursively.
*
* @return array
*/
protected function getRecursiveSelectOptions()
{
// Initialize tree object:
$tree = GeneralUtility::makeInstance(PageTreeView::class);
$tree->init();
$tree->addField('perms_userid', true);
$tree->makeHTML = 0;
$tree->setRecs = 1;
// Make tree:
$tree->getTree($this->id, $this->getLevels, '');
$options = [];
$options[''] = '';
// If there are a hierarchy of page ids, then...
if ($this->getBackendUser()->user['uid'] && !empty($tree->orig_ids_hierarchy)) {
// Init:
$labelRecursive = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:recursive', 'beuser');
$labelLevel = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:level', 'beuser');
$labelLevels = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:levels', 'beuser');
$labelPageAffected = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:page_affected', 'beuser');
$labelPagesAffected = LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod_permission.xlf:pages_affected', 'beuser');
$theIdListArr = [];
// Traverse the number of levels we want to allow recursive
// setting of permissions for:
for ($a = $this->getLevels; $a > 0; $a--) {
if (is_array($tree->orig_ids_hierarchy[$a])) {
foreach ($tree->orig_ids_hierarchy[$a] as $theId) {
$theIdListArr[] = $theId;
}
$lKey = $this->getLevels - $a + 1;
$pagesCount = count($theIdListArr);
$options[implode(',', $theIdListArr)] = $labelRecursive . ' ' . $lKey . ' ' . ($lKey === 1 ? $labelLevel : $labelLevels) .
' (' . $pagesCount . ' ' . ($pagesCount === 1 ? $labelPageAffected : $labelPagesAffected) . ')';
}
}
}
return $options;
}
/**
* Check if page record exists and set pageInfo
*/
protected function setPageInfo(): void
{
$this->pageInfo = BackendUtility::readPageAccess(BackendUtility::getRecord('pages', $this->id) ? $this->id : 0, ' 1=1');
}
/**
* Returns LanguageService
*
* @return \TYPO3\CMS\Core\Localization\LanguageService
*/
protected function getLanguageService()
{
return $GLOBALS['LANG'];
}
}