3fc18c222a93c2e8122c6274d8362cca421a343d
[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\Session\Backend\SessionBackendInterface;
19 use TYPO3\CMS\Core\Session\SessionManager;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
22 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
23 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
24
25 /**
26 * Backend module user administration controller
27 * @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API.
28 */
29 class BackendUserController extends ActionController
30 {
31 /**
32 * @var int
33 */
34 const RECENT_USERS_LIMIT = 3;
35
36 /**
37 * @var \TYPO3\CMS\Beuser\Domain\Model\ModuleData
38 */
39 protected $moduleData;
40
41 /**
42 * @var \TYPO3\CMS\Beuser\Service\ModuleDataStorageService
43 */
44 protected $moduleDataStorageService;
45
46 /**
47 * @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository
48 */
49 protected $backendUserRepository;
50
51 /**
52 * @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository
53 */
54 protected $backendUserGroupRepository;
55
56 /**
57 * @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository
58 */
59 protected $backendUserSessionRepository;
60
61 /**
62 * @param \TYPO3\CMS\Beuser\Service\ModuleDataStorageService $moduleDataStorageService
63 */
64 public function injectModuleDataStorageService(\TYPO3\CMS\Beuser\Service\ModuleDataStorageService $moduleDataStorageService)
65 {
66 $this->moduleDataStorageService = $moduleDataStorageService;
67 }
68
69 /**
70 * @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository $backendUserRepository
71 */
72 public function injectBackendUserRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository $backendUserRepository)
73 {
74 $this->backendUserRepository = $backendUserRepository;
75 }
76
77 /**
78 * @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository $backendUserGroupRepository
79 */
80 public function injectBackendUserGroupRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository $backendUserGroupRepository)
81 {
82 $this->backendUserGroupRepository = $backendUserGroupRepository;
83 }
84
85 /**
86 * @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository $backendUserSessionRepository
87 */
88 public function injectBackendUserSessionRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository $backendUserSessionRepository)
89 {
90 $this->backendUserSessionRepository = $backendUserSessionRepository;
91 }
92
93 /**
94 * Load and persist module data
95 *
96 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request
97 * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response
98 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
99 */
100 public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response)
101 {
102 $this->moduleData = $this->moduleDataStorageService->loadModuleData();
103 // We "finally" persist the module data.
104 try {
105 parent::processRequest($request, $response);
106 $this->moduleDataStorageService->persistModuleData($this->moduleData);
107 } catch (\TYPO3\CMS\Extbase\Mvc\Exception\StopActionException $e) {
108 $this->moduleDataStorageService->persistModuleData($this->moduleData);
109 throw $e;
110 }
111 }
112
113 /**
114 * Assign default variables to view
115 * @param ViewInterface $view
116 */
117 protected function initializeView(ViewInterface $view)
118 {
119 $view->assignMultiple([
120 'shortcutLabel' => 'backendUsers',
121 'dateFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'],
122 'timeFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'],
123 ]);
124 }
125
126 /**
127 * Displays all BackendUsers
128 * - Switch session to different user
129 *
130 * @param \TYPO3\CMS\Beuser\Domain\Model\Demand $demand
131 */
132 public function indexAction(\TYPO3\CMS\Beuser\Domain\Model\Demand $demand = null)
133 {
134 if ($demand === null) {
135 $demand = $this->moduleData->getDemand();
136 } else {
137 $this->moduleData->setDemand($demand);
138 }
139 // Switch user until logout
140 $switchUser = (int)GeneralUtility::_GP('SwitchUser');
141 if ($switchUser > 0) {
142 $this->switchUser($switchUser);
143 }
144 $compareUserList = $this->moduleData->getCompareUserList();
145
146 // Create online user list for easy parsing
147 $onlineUsers = $this->backendUserSessionRepository->findAllActive();
148 $onlineBackendUsers = [];
149 if (is_array($onlineUsers)) {
150 foreach ($onlineUsers as $onlineUser) {
151 $onlineBackendUsers[$onlineUser['ses_userid']] = true;
152 }
153 }
154
155 $this->view->assignMultiple([
156 'onlineBackendUsers' => $onlineBackendUsers,
157 'demand' => $demand,
158 'backendUsers' => $this->backendUserRepository->findDemanded($demand),
159 'backendUserGroups' => array_merge([''], $this->backendUserGroupRepository->findAll()->toArray()),
160 'compareUserUidList' => array_combine(array_keys($compareUserList), array_fill(0, count($compareUserList), true)),
161 'currentUserUid' => $this->getBackendUserAuthentication()->user['uid'],
162 'compareUserList' => !empty($compareUserList) ? $this->backendUserRepository->findByUidList($compareUserList) : '',
163 ]);
164 }
165
166 /**
167 * Views all currently logged in BackendUsers and their sessions
168 */
169 public function onlineAction()
170 {
171 $onlineUsersAndSessions = [];
172 $onlineUsers = $this->backendUserRepository->findOnline();
173 foreach ($onlineUsers as $onlineUser) {
174 $onlineUsersAndSessions[] = [
175 'backendUser' => $onlineUser,
176 'sessions' => $this->backendUserSessionRepository->findByBackendUser($onlineUser)
177 ];
178 }
179
180 $this->view->assignMultiple([
181 'shortcutLabel' => 'onlineUsers',
182 'onlineUsersAndSessions' => $onlineUsersAndSessions,
183 'currentSessionId' => $this->getBackendUserAuthentication()->user['ses_id'],
184 ]);
185 }
186
187 /**
188 * Compare backend users from demand
189 */
190 public function compareAction()
191 {
192 $compareUserList = $this->moduleData->getCompareUserList();
193 if (empty($compareUserList)) {
194 $this->redirect('index');
195 }
196
197 $this->view->assignMultiple([
198 'shortcutLabel' => 'compareUsers',
199 'compareUserList' => $this->backendUserRepository->findByUidList($compareUserList),
200 ]);
201 }
202
203 /**
204 * Attaches one backend user to the compare list
205 *
206 * @param int $uid
207 */
208 public function addToCompareListAction($uid)
209 {
210 $this->moduleData->attachUidCompareUser($uid);
211 $this->moduleDataStorageService->persistModuleData($this->moduleData);
212 $this->forward('index');
213 }
214
215 /**
216 * Removes given backend user to the compare list
217 *
218 * @param int $uid
219 */
220 public function removeFromCompareListAction($uid)
221 {
222 $this->moduleData->detachUidCompareUser($uid);
223 $this->moduleDataStorageService->persistModuleData($this->moduleData);
224 $this->forward('index');
225 }
226
227 /**
228 * Terminate BackendUser session and logout corresponding client
229 * Redirects to onlineAction with message
230 *
231 * @param \TYPO3\CMS\Beuser\Domain\Model\BackendUser $backendUser
232 * @param string $sessionId
233 */
234 protected function terminateBackendUserSessionAction(\TYPO3\CMS\Beuser\Domain\Model\BackendUser $backendUser, $sessionId)
235 {
236 $sessionBackend = $this->getSessionBackend();
237 $success = $sessionBackend->remove($sessionId);
238
239 if ($success) {
240 $this->addFlashMessage(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:terminateSessionSuccess', 'beuser'));
241 }
242 $this->forward('online');
243 }
244
245 /**
246 * Switches to a given user (SU-mode) and then redirects to the start page of the backend to refresh the navigation etc.
247 *
248 * @param string $switchUser BE-user record that will be switched to
249 */
250 protected function switchUser($switchUser)
251 {
252 $targetUser = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('be_users', $switchUser);
253 if (is_array($targetUser) && $this->getBackendUserAuthentication()->isAdmin()) {
254 // Set backend user listing module as starting module for switchback
255 $this->getBackendUserAuthentication()->uc['startModuleOnFirstLogin'] = 'system_BeuserTxBeuser';
256 $this->getBackendUserAuthentication()->uc['recentSwitchedToUsers'] = $this->generateListOfMostRecentSwitchedUsers($targetUser['uid']);
257 $this->getBackendUserAuthentication()->writeUC();
258
259 $sessionBackend = $this->getSessionBackend();
260 $sessionBackend->update(
261 $this->getBackendUserAuthentication()->getSessionId(),
262 [
263 'ses_userid' => (int)$targetUser['uid'],
264 'ses_backuserid' => (int)$this->getBackendUserAuthentication()->user['uid']
265 ]
266 );
267
268 $this->emitSwitchUserSignal($targetUser);
269
270 $redirectUrl = 'index.php' . ($GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces'] ? '' : '?commandLI=1');
271 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($redirectUrl);
272 }
273 }
274
275 /**
276 * Generates a list of users to whom where switched in the past. This is limited by RECENT_USERS_LIMIT.
277 *
278 * @param int $targetUserUid
279 * @return int[]
280 */
281 protected function generateListOfMostRecentSwitchedUsers(int $targetUserUid): array
282 {
283 $latestUserUids = [];
284 $backendUser = $this->getBackendUserAuthentication();
285
286 if (isset($backendUser->uc['recentSwitchedToUsers']) && is_array($backendUser->uc['recentSwitchedToUsers'])) {
287 $latestUserUids = $backendUser->uc['recentSwitchedToUsers'];
288 }
289
290 // Remove potentially existing user in that list
291 $index = array_search($targetUserUid, $latestUserUids, true);
292 if ($index !== false) {
293 unset($latestUserUids[$index]);
294 }
295
296 array_unshift($latestUserUids, $targetUserUid);
297 $latestUserUids = array_slice($latestUserUids, 0, static::RECENT_USERS_LIMIT);
298
299 return $latestUserUids;
300 }
301
302 /**
303 * Emit a signal when using the "switch to user" functionality
304 *
305 * @param array $targetUser
306 */
307 protected function emitSwitchUserSignal(array $targetUser)
308 {
309 $this->signalSlotDispatcher->dispatch(__CLASS__, 'switchUser', [$targetUser]);
310 }
311
312 /**
313 * @return BackendUserAuthentication
314 */
315 protected function getBackendUserAuthentication(): BackendUserAuthentication
316 {
317 return $GLOBALS['BE_USER'];
318 }
319
320 /**
321 * @return SessionBackendInterface
322 */
323 protected function getSessionBackend()
324 {
325 $loginType = $this->getBackendUserAuthentication()->getLoginType();
326 return GeneralUtility::makeInstance(SessionManager::class)->getSessionBackend($loginType);
327 }
328 }