[TASK] Use BE Routing / PSR-7 instead of BackendUtility::getModuleUrl
[Packages/TYPO3.CMS.git] / typo3 / sysext / beuser / Classes / Controller / BackendUserController.php
1 <?php
2 namespace TYPO3\CMS\Beuser\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
18 use TYPO3\CMS\Core\Localization\LanguageService;
19 use TYPO3\CMS\Core\Session\Backend\SessionBackendInterface;
20 use TYPO3\CMS\Core\Session\SessionManager;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
23
24 /**
25 * Backend module user administration controller
26 */
27 class BackendUserController extends BackendUserActionController
28 {
29 /**
30 * @var int
31 */
32 const RECENT_USERS_LIMIT = 3;
33
34 /**
35 * @var \TYPO3\CMS\Beuser\Domain\Model\ModuleData
36 */
37 protected $moduleData;
38
39 /**
40 * @var \TYPO3\CMS\Beuser\Service\ModuleDataStorageService
41 */
42 protected $moduleDataStorageService;
43
44 /**
45 * @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository
46 */
47 protected $backendUserRepository;
48
49 /**
50 * @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository
51 */
52 protected $backendUserGroupRepository;
53
54 /**
55 * @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository
56 */
57 protected $backendUserSessionRepository;
58
59 /**
60 * @param \TYPO3\CMS\Beuser\Service\ModuleDataStorageService $moduleDataStorageService
61 */
62 public function injectModuleDataStorageService(\TYPO3\CMS\Beuser\Service\ModuleDataStorageService $moduleDataStorageService)
63 {
64 $this->moduleDataStorageService = $moduleDataStorageService;
65 }
66
67 /**
68 * @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository $backendUserRepository
69 */
70 public function injectBackendUserRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository $backendUserRepository)
71 {
72 $this->backendUserRepository = $backendUserRepository;
73 }
74
75 /**
76 * @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository $backendUserGroupRepository
77 */
78 public function injectBackendUserGroupRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository $backendUserGroupRepository)
79 {
80 $this->backendUserGroupRepository = $backendUserGroupRepository;
81 }
82
83 /**
84 * @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository $backendUserSessionRepository
85 */
86 public function injectBackendUserSessionRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository $backendUserSessionRepository)
87 {
88 $this->backendUserSessionRepository = $backendUserSessionRepository;
89 }
90
91 /**
92 * Load and persist module data
93 *
94 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request
95 * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response
96 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
97 */
98 public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response)
99 {
100 $this->moduleData = $this->moduleDataStorageService->loadModuleData();
101 // We "finally" persist the module data.
102 try {
103 parent::processRequest($request, $response);
104 $this->moduleDataStorageService->persistModuleData($this->moduleData);
105 } catch (\TYPO3\CMS\Extbase\Mvc\Exception\StopActionException $e) {
106 $this->moduleDataStorageService->persistModuleData($this->moduleData);
107 throw $e;
108 }
109 }
110
111 /**
112 * Initialize actions
113 *
114 * @throws \RuntimeException
115 */
116 public function initializeAction()
117 {
118 // @TODO: Extbase backend modules relies on frontend TypoScript for view, persistence
119 // and settings. Thus, we need a TypoScript root template, that then loads the
120 // ext_typoscript_setup.txt file of this module. This is nasty, but can not be
121 // circumvented until there is a better solution in extbase.
122 // For now we throw an exception if no settings are detected.
123 if (empty($this->settings)) {
124 throw new \RuntimeException('No settings detected. This module can not work then. This usually happens if there is no frontend TypoScript template with root flag set. ' . 'Please create a frontend page with a TypoScript root template.', 1344375003);
125 }
126 }
127
128 /**
129 * Displays all BackendUsers
130 * - Switch session to different user
131 *
132 * @param \TYPO3\CMS\Beuser\Domain\Model\Demand $demand
133 */
134 public function indexAction(\TYPO3\CMS\Beuser\Domain\Model\Demand $demand = null)
135 {
136 if ($demand === null) {
137 $demand = $this->moduleData->getDemand();
138 } else {
139 $this->moduleData->setDemand($demand);
140 }
141 // Switch user until logout
142 $switchUser = (int)GeneralUtility::_GP('SwitchUser');
143 if ($switchUser > 0) {
144 $this->switchUser($switchUser);
145 }
146 $compareUserList = $this->moduleData->getCompareUserList();
147
148 // Create online user list for easy parsing
149 $onlineUsers = $this->backendUserSessionRepository->findAllActive();
150 $onlineBackendUsers = [];
151 if (is_array($onlineUsers)) {
152 foreach ($onlineUsers as $onlineUser) {
153 $onlineBackendUsers[$onlineUser['ses_userid']] = true;
154 }
155 }
156 $this->view->assign('onlineBackendUsers', $onlineBackendUsers);
157
158 $this->view->assign('demand', $demand);
159 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
160 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
161 $this->view->assign('returnUrl', rawurlencode((string)$uriBuilder->buildUriFromRoute('system_BeuserTxBeuser')));
162 $this->view->assign('dateFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']);
163 $this->view->assign('timeFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm']);
164 $this->view->assign('backendUsers', $this->backendUserRepository->findDemanded($demand));
165 $this->view->assign('backendUserGroups', array_merge([''], $this->backendUserGroupRepository->findAll()->toArray()));
166 $this->view->assign('compareUserUidList', array_map(function ($item) {
167 return true;
168 }, array_flip((array)$compareUserList)));
169 $this->view->assign('compareUserList', !empty($compareUserList) ? $this->backendUserRepository->findByUidList($compareUserList) : '');
170 }
171
172 /**
173 * Views all currently logged in BackendUsers and their sessions
174 */
175 public function onlineAction()
176 {
177 $onlineUsersAndSessions = [];
178 $onlineUsers = $this->backendUserRepository->findOnline();
179 foreach ($onlineUsers as $onlineUser) {
180 $onlineUsersAndSessions[] = [
181 'backendUser' => $onlineUser,
182 'sessions' => $this->backendUserSessionRepository->findByBackendUser($onlineUser)
183 ];
184 }
185 $this->view->assign('dateFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']);
186 $this->view->assign('timeFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm']);
187 $this->view->assign('onlineUsersAndSessions', $onlineUsersAndSessions);
188 $this->view->assign('currentSessionId', $this->getBackendUserAuthentication()->user['ses_id']);
189 }
190
191 /**
192 * Compare backend users from demand
193 */
194 public function compareAction()
195 {
196 $compareUserList = $this->moduleData->getCompareUserList();
197 $this->view->assign('dateFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']);
198 $this->view->assign('timeFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm']);
199 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
200 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
201 $returnUrl = (string)$uriBuilder->buildUriFromRoute(
202 'system_BeuserTxBeuser',
203 [
204 'tx_beuser_system_beusertxbeuser[action]' => 'compare',
205 'tx_beuser_system_beusertxbeuser[controller]' => 'BackendUser'
206 ]
207 );
208 $this->view->assign('returnUrl', rawurlencode($returnUrl));
209 $this->view->assign('compareUserList', !empty($compareUserList) ? $this->backendUserRepository->findByUidList($compareUserList) : '');
210 }
211
212 /**
213 * Attaches one backend user to the compare list
214 *
215 * @param int $uid
216 */
217 public function addToCompareListAction($uid)
218 {
219 $this->moduleData->attachUidCompareUser($uid);
220 $this->moduleDataStorageService->persistModuleData($this->moduleData);
221 $this->forward('index');
222 }
223
224 /**
225 * Removes given backend user to the compare list
226 *
227 * @param int $uid
228 */
229 public function removeFromCompareListAction($uid)
230 {
231 $this->moduleData->detachUidCompareUser($uid);
232 $this->moduleDataStorageService->persistModuleData($this->moduleData);
233 $this->forward('index');
234 }
235
236 /**
237 * Terminate BackendUser session and logout corresponding client
238 * Redirects to onlineAction with message
239 *
240 * @param \TYPO3\CMS\Beuser\Domain\Model\BackendUser $backendUser
241 * @param string $sessionId
242 */
243 protected function terminateBackendUserSessionAction(\TYPO3\CMS\Beuser\Domain\Model\BackendUser $backendUser, $sessionId)
244 {
245 $sessionBackend = $this->getSessionBackend();
246 $success = $sessionBackend->remove($sessionId);
247
248 if ($success) {
249 $this->addFlashMessage(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:terminateSessionSuccess', 'beuser'));
250 }
251 $this->forward('online');
252 }
253
254 /**
255 * Switches to a given user (SU-mode) and then redirects to the start page of the backend to refresh the navigation etc.
256 *
257 * @param string $switchUser BE-user record that will be switched to
258 */
259 protected function switchUser($switchUser)
260 {
261 $targetUser = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('be_users', $switchUser);
262 if (is_array($targetUser) && $this->getBackendUserAuthentication()->isAdmin()) {
263 // Set backend user listing module as starting module for switchback
264 $this->getBackendUserAuthentication()->uc['startModuleOnFirstLogin'] = 'system_BeuserTxBeuser';
265 $this->getBackendUserAuthentication()->uc['recentSwitchedToUsers'] = $this->generateListOfMostRecentSwitchedUsers($targetUser['uid']);
266 $this->getBackendUserAuthentication()->writeUC();
267
268 $sessionBackend = $this->getSessionBackend();
269 $sessionBackend->update(
270 $this->getBackendUserAuthentication()->getSessionId(),
271 [
272 'ses_userid' => (int)$targetUser['uid'],
273 'ses_backuserid' => (int)$this->getBackendUserAuthentication()->user['uid']
274 ]
275 );
276
277 $redirectUrl = 'index.php' . ($GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces'] ? '' : '?commandLI=1');
278 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($redirectUrl);
279 }
280 }
281
282 /**
283 * Generates a list of users to whom where switched in the past. This is limited by RECENT_USERS_LIMIT.
284 *
285 * @param int $targetUserUid
286 * @return int[]
287 */
288 protected function generateListOfMostRecentSwitchedUsers(int $targetUserUid): array
289 {
290 $latestUserUids = [];
291 $backendUser = $this->getBackendUserAuthentication();
292
293 if (isset($backendUser->uc['recentSwitchedToUsers']) && is_array($backendUser->uc['recentSwitchedToUsers'])) {
294 $latestUserUids = $backendUser->uc['recentSwitchedToUsers'];
295 }
296
297 // Remove potentially existing user in that list
298 $index = array_search($targetUserUid, $latestUserUids, true);
299 if ($index !== false) {
300 unset($latestUserUids[$index]);
301 }
302
303 array_unshift($latestUserUids, $targetUserUid);
304 $latestUserUids = array_slice($latestUserUids, 0, static::RECENT_USERS_LIMIT);
305
306 return $latestUserUids;
307 }
308
309 /**
310 * @return BackendUserAuthentication
311 */
312 protected function getBackendUserAuthentication()
313 {
314 return $GLOBALS['BE_USER'];
315 }
316
317 /**
318 * @return LanguageService
319 */
320 protected function getLanguageService()
321 {
322 return $GLOBALS['LANG'];
323 }
324
325 /**
326 * @return SessionBackendInterface
327 */
328 protected function getSessionBackend()
329 {
330 $loginType = $this->getBackendUserAuthentication()->getLoginType();
331 return GeneralUtility::makeInstance(SessionManager::class)->getSessionBackend($loginType);
332 }
333 }