[FEATURE] Backend ViewHelpers for edit creation and editing
[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', (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('currentUserUid', $this->getBackendUserAuthentication()->user['uid']);
170 $this->view->assign('compareUserList', !empty($compareUserList) ? $this->backendUserRepository->findByUidList($compareUserList) : '');
171 }
172
173 /**
174 * Views all currently logged in BackendUsers and their sessions
175 */
176 public function onlineAction()
177 {
178 $onlineUsersAndSessions = [];
179 $onlineUsers = $this->backendUserRepository->findOnline();
180 foreach ($onlineUsers as $onlineUser) {
181 $onlineUsersAndSessions[] = [
182 'backendUser' => $onlineUser,
183 'sessions' => $this->backendUserSessionRepository->findByBackendUser($onlineUser)
184 ];
185 }
186 $this->view->assign('dateFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']);
187 $this->view->assign('timeFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm']);
188 $this->view->assign('onlineUsersAndSessions', $onlineUsersAndSessions);
189 $this->view->assign('currentSessionId', $this->getBackendUserAuthentication()->user['ses_id']);
190 }
191
192 /**
193 * Compare backend users from demand
194 */
195 public function compareAction()
196 {
197 $compareUserList = $this->moduleData->getCompareUserList();
198 $this->view->assign('dateFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']);
199 $this->view->assign('timeFormat', $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm']);
200 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
201 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
202 $returnUrl = (string)$uriBuilder->buildUriFromRoute(
203 'system_BeuserTxBeuser',
204 [
205 'tx_beuser_system_beusertxbeuser[action]' => 'compare',
206 'tx_beuser_system_beusertxbeuser[controller]' => 'BackendUser'
207 ]
208 );
209 $this->view->assign('returnUrl', $returnUrl);
210 $this->view->assign('compareUserList', !empty($compareUserList) ? $this->backendUserRepository->findByUidList($compareUserList) : '');
211 }
212
213 /**
214 * Attaches one backend user to the compare list
215 *
216 * @param int $uid
217 */
218 public function addToCompareListAction($uid)
219 {
220 $this->moduleData->attachUidCompareUser($uid);
221 $this->moduleDataStorageService->persistModuleData($this->moduleData);
222 $this->forward('index');
223 }
224
225 /**
226 * Removes given backend user to the compare list
227 *
228 * @param int $uid
229 */
230 public function removeFromCompareListAction($uid)
231 {
232 $this->moduleData->detachUidCompareUser($uid);
233 $this->moduleDataStorageService->persistModuleData($this->moduleData);
234 $this->forward('index');
235 }
236
237 /**
238 * Terminate BackendUser session and logout corresponding client
239 * Redirects to onlineAction with message
240 *
241 * @param \TYPO3\CMS\Beuser\Domain\Model\BackendUser $backendUser
242 * @param string $sessionId
243 */
244 protected function terminateBackendUserSessionAction(\TYPO3\CMS\Beuser\Domain\Model\BackendUser $backendUser, $sessionId)
245 {
246 $sessionBackend = $this->getSessionBackend();
247 $success = $sessionBackend->remove($sessionId);
248
249 if ($success) {
250 $this->addFlashMessage(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:terminateSessionSuccess', 'beuser'));
251 }
252 $this->forward('online');
253 }
254
255 /**
256 * Switches to a given user (SU-mode) and then redirects to the start page of the backend to refresh the navigation etc.
257 *
258 * @param string $switchUser BE-user record that will be switched to
259 */
260 protected function switchUser($switchUser)
261 {
262 $targetUser = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('be_users', $switchUser);
263 if (is_array($targetUser) && $this->getBackendUserAuthentication()->isAdmin()) {
264 // Set backend user listing module as starting module for switchback
265 $this->getBackendUserAuthentication()->uc['startModuleOnFirstLogin'] = 'system_BeuserTxBeuser';
266 $this->getBackendUserAuthentication()->uc['recentSwitchedToUsers'] = $this->generateListOfMostRecentSwitchedUsers($targetUser['uid']);
267 $this->getBackendUserAuthentication()->writeUC();
268
269 $sessionBackend = $this->getSessionBackend();
270 $sessionBackend->update(
271 $this->getBackendUserAuthentication()->getSessionId(),
272 [
273 'ses_userid' => (int)$targetUser['uid'],
274 'ses_backuserid' => (int)$this->getBackendUserAuthentication()->user['uid']
275 ]
276 );
277
278 $this->emitSwitchUserSignal($targetUser);
279
280 $redirectUrl = 'index.php' . ($GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces'] ? '' : '?commandLI=1');
281 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($redirectUrl);
282 }
283 }
284
285 /**
286 * Generates a list of users to whom where switched in the past. This is limited by RECENT_USERS_LIMIT.
287 *
288 * @param int $targetUserUid
289 * @return int[]
290 */
291 protected function generateListOfMostRecentSwitchedUsers(int $targetUserUid): array
292 {
293 $latestUserUids = [];
294 $backendUser = $this->getBackendUserAuthentication();
295
296 if (isset($backendUser->uc['recentSwitchedToUsers']) && is_array($backendUser->uc['recentSwitchedToUsers'])) {
297 $latestUserUids = $backendUser->uc['recentSwitchedToUsers'];
298 }
299
300 // Remove potentially existing user in that list
301 $index = array_search($targetUserUid, $latestUserUids, true);
302 if ($index !== false) {
303 unset($latestUserUids[$index]);
304 }
305
306 array_unshift($latestUserUids, $targetUserUid);
307 $latestUserUids = array_slice($latestUserUids, 0, static::RECENT_USERS_LIMIT);
308
309 return $latestUserUids;
310 }
311
312 /**
313 * Emit a signal when using the "switch to user" functionality
314 *
315 * @param array $targetUser
316 */
317 protected function emitSwitchUserSignal(array $targetUser)
318 {
319 $this->signalSlotDispatcher->dispatch(__CLASS__, 'switchUser', [$targetUser]);
320 }
321
322 /**
323 * @return BackendUserAuthentication
324 */
325 protected function getBackendUserAuthentication()
326 {
327 return $GLOBALS['BE_USER'];
328 }
329
330 /**
331 * @return LanguageService
332 */
333 protected function getLanguageService()
334 {
335 return $GLOBALS['LANG'];
336 }
337
338 /**
339 * @return SessionBackendInterface
340 */
341 protected function getSessionBackend()
342 {
343 $loginType = $this->getBackendUserAuthentication()->getLoginType();
344 return GeneralUtility::makeInstance(SessionManager::class)->getSessionBackend($loginType);
345 }
346 }