Passed
Push — master ( 6c08ab...5a4560 )
by
unknown
34:08 queued 20:19
created

BackendUserController::getOnlineBackendUsers()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Beuser\Controller;
17
18
use Psr\Http\Message\ResponseInterface;
19
use Psr\Http\Message\ServerRequestInterface;
20
use TYPO3\CMS\Backend\Authentication\Event\SwitchUserEvent;
21
use TYPO3\CMS\Backend\Authentication\PasswordReset;
22
use TYPO3\CMS\Backend\Routing\UriBuilder as BackendUriBuilder;
23
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
24
use TYPO3\CMS\Backend\Template\ModuleTemplate;
25
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
26
use TYPO3\CMS\Backend\Utility\BackendUtility;
27
use TYPO3\CMS\Beuser\Domain\Model\BackendUser;
28
use TYPO3\CMS\Beuser\Domain\Model\Demand;
29
use TYPO3\CMS\Beuser\Domain\Model\ModuleData;
30
use TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository;
31
use TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository;
32
use TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository;
33
use TYPO3\CMS\Beuser\Service\UserInformationService;
34
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
35
use TYPO3\CMS\Core\Context\Context;
36
use TYPO3\CMS\Core\Http\PropagateResponseException;
37
use TYPO3\CMS\Core\Http\RedirectResponse;
38
use TYPO3\CMS\Core\Imaging\Icon;
39
use TYPO3\CMS\Core\Imaging\IconFactory;
40
use TYPO3\CMS\Core\Messaging\FlashMessage;
41
use TYPO3\CMS\Core\Page\PageRenderer;
42
use TYPO3\CMS\Core\Pagination\SimplePagination;
43
use TYPO3\CMS\Core\Utility\GeneralUtility;
44
use TYPO3\CMS\Extbase\Http\ForwardResponse;
45
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
46
use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
47
use TYPO3\CMS\Extbase\Mvc\Request;
48
use TYPO3\CMS\Extbase\Mvc\RequestInterface;
49
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
50
use TYPO3\CMS\Extbase\Pagination\QueryResultPaginator;
51
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
52
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
53
54
/**
55
 * Backend module user and user group administration controller
56
 * @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API.
57
 */
58
class BackendUserController extends ActionController
59
{
60
    /**
61
     * @var int
62
     */
63
    const RECENT_USERS_LIMIT = 3;
64
65
    protected ?ModuleData $moduleData = null;
66
    protected ?ModuleTemplate $moduleTemplate = null;
67
    protected BackendUserRepository $backendUserRepository;
68
    protected BackendUserGroupRepository $backendUserGroupRepository;
69
    protected BackendUserSessionRepository $backendUserSessionRepository;
70
    protected UserInformationService $userInformationService;
71
    protected ModuleTemplateFactory $moduleTemplateFactory;
72
    protected BackendUriBuilder $backendUriBuilder;
73
    protected IconFactory $iconFactory;
74
    protected PageRenderer $pageRenderer;
75
76
    public function __construct(
77
        BackendUserRepository $backendUserRepository,
78
        BackendUserGroupRepository $backendUserGroupRepository,
79
        BackendUserSessionRepository $backendUserSessionRepository,
80
        UserInformationService $userInformationService,
81
        ModuleTemplateFactory $moduleTemplateFactory,
82
        BackendUriBuilder $backendUriBuilder,
83
        IconFactory $iconFactory,
84
        PageRenderer $pageRenderer
85
    ) {
86
        $this->backendUserRepository = $backendUserRepository;
87
        $this->backendUserGroupRepository = $backendUserGroupRepository;
88
        $this->backendUserSessionRepository = $backendUserSessionRepository;
89
        $this->userInformationService = $userInformationService;
90
        $this->moduleTemplateFactory = $moduleTemplateFactory;
91
        $this->backendUriBuilder = $backendUriBuilder;
92
        $this->iconFactory = $iconFactory;
93
        $this->pageRenderer = $pageRenderer;
94
    }
95
96
    /**
97
     * Override the default action if found in user uc
98
     *
99
     * @param RequestInterface $request
100
     * @return ResponseInterface
101
     */
102
    public function processRequest(RequestInterface $request): ResponseInterface
103
    {
104
        $arguments = $request->getArguments();
105
        $backendUser = $this->getBackendUser();
106
        if (is_array($arguments) && isset($arguments['action']) && in_array((string)$arguments['action'], ['index', 'groups', 'online'])
107
            && (string)($backendUser->uc['beuser']['defaultAction'] ?? '') !== (string)$arguments['action']
108
        ) {
109
            $backendUser->uc['beuser']['defaultAction'] = (string)$arguments['action'];
110
            $backendUser->writeUC();
111
        } elseif (!isset($arguments['action']) && isset($backendUser->uc['beuser']['defaultAction'])
112
            && in_array((string)$backendUser->uc['beuser']['defaultAction'], ['index', 'groups', 'online'])
113
        ) {
114
            if ($request instanceof Request) {
115
                $request->setControllerActionName((string)$backendUser->uc['beuser']['defaultAction']);
116
            }
117
        }
118
        return parent::processRequest($request);
119
    }
120
121
    /**
122
     * Init module state.
123
     * This isn't done within __construct() since the controller
124
     * object is only created once in extbase when multiple actions are called in
125
     * one call. When those change module state, the second action would see old state.
126
     */
127
    public function initializeAction(): void
128
    {
129
        $this->moduleData = ModuleData::fromUc((array)($this->getBackendUser()->getModuleData('tx_beuser')));
130
        $this->moduleTemplate = $this->moduleTemplateFactory->create($this->getRequest());
131
        $this->moduleTemplate->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod.xlf:mlang_tabs_tab'));
132
    }
133
134
    /**
135
     * Assign default variables to view
136
     * @param ViewInterface $view
137
     */
138
    protected function initializeView(ViewInterface $view): void
139
    {
140
        $view->assignMultiple([
141
            'dateFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'],
142
            'timeFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'],
143
        ]);
144
145
        // Load requireJS modules
146
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
147
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal');
148
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Beuser/BackendUserListing');
149
    }
150
151
    /**
152
     * Displays all BackendUsers
153
     * - Switch session to different user
154
     *
155
     * @param Demand|null $demand
156
     * @param int $currentPage
157
     * @param string $operation
158
     * @return ResponseInterface
159
     */
160
    public function indexAction(Demand $demand = null, int $currentPage = 1, string $operation = ''): ResponseInterface
161
    {
162
        $backendUser = $this->getBackendUser();
163
164
        if ($operation === 'reset-filters') {
165
            // Reset the module data demand object
166
            $this->moduleData->setDemand(new Demand());
0 ignored issues
show
Bug introduced by
The method setDemand() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

166
            $this->moduleData->/** @scrutinizer ignore-call */ 
167
                               setDemand(new Demand());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
167
            $demand = null;
168
        }
169
        if ($demand === null) {
170
            $demand = $this->moduleData->getDemand();
171
        } else {
172
            $this->moduleData->setDemand($demand);
173
        }
174
        $backendUser->pushModuleData('tx_beuser', $this->moduleData->forUc());
175
176
        // Switch user until logout
177
        $switchUser = (int)GeneralUtility::_GP('SwitchUser');
178
        if ($switchUser > 0) {
179
            $this->switchUser($switchUser);
180
        }
181
        $compareUserList = $this->moduleData->getCompareUserList();
182
183
        $backendUsers = $this->backendUserRepository->findDemanded($demand);
184
        $paginator = new QueryResultPaginator($backendUsers, $currentPage, 50);
185
        $pagination = new SimplePagination($paginator);
186
187
        $this->view->assignMultiple([
188
            'onlineBackendUsers' => $this->getOnlineBackendUsers(),
189
            'demand' => $demand,
190
            'paginator' => $paginator,
191
            'pagination' => $pagination,
192
            'totalAmountOfBackendUsers' => $backendUsers->count(),
193
            'backendUserGroups' => array_merge([''], $this->backendUserGroupRepository->findAll()->toArray()),
194
            'compareUserUidList' => array_combine($compareUserList, $compareUserList),
195
            'currentUserUid' => $backendUser->user['uid'],
196
            'compareUserList' => !empty($compareUserList) ? $this->backendUserRepository->findByUidList($compareUserList) : '',
197
        ]);
198
199
        $this->addMainMenu('index');
200
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
0 ignored issues
show
Bug introduced by
The method getDocHeaderComponent() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

200
        $buttonBar = $this->moduleTemplate->/** @scrutinizer ignore-call */ getDocHeaderComponent()->getButtonBar();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
201
        $addUserButton = $buttonBar->makeLinkButton()
202
            ->setIcon($this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL))
203
            ->setTitle(LocalizationUtility::translate('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newRecordGeneral'))
204
            ->setHref($this->backendUriBuilder->buildUriFromRoute('record_edit', [
205
                'edit' => ['be_users' => [0 => 'new']],
206
                'returnUrl' => $this->getRequest()->getAttribute('normalizedParams')->getRequestUri()
207
            ]));
208
        $buttonBar->addButton($addUserButton);
209
        $shortcutButton = $buttonBar->makeShortcutButton()
210
            ->setRouteIdentifier('system_BeuserTxBeuser')
211
            ->setArguments(['tx_beuser_system_beusertxbeuser' => ['action' => 'index']])
212
            ->setDisplayName(LocalizationUtility::translate('backendUsers', 'beuser'));
213
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);
214
215
        $this->moduleTemplate->setContent($this->view->render());
216
        return $this->htmlResponse($this->moduleTemplate->renderContent());
217
    }
218
219
    /**
220
     * Views all currently logged in BackendUsers and their sessions
221
     */
222
    public function onlineAction(): ResponseInterface
223
    {
224
        $onlineUsersAndSessions = [];
225
        $onlineUsers = $this->backendUserRepository->findOnline();
226
        foreach ($onlineUsers as $onlineUser) {
227
            $onlineUsersAndSessions[] = [
228
                'backendUser' => $onlineUser,
229
                'sessions' => $this->backendUserSessionRepository->findByBackendUser($onlineUser)
230
            ];
231
        }
232
233
        $currentSessionId = $this->backendUserSessionRepository->getPersistedSessionIdentifier($this->getBackendUser());
234
235
        $this->view->assignMultiple([
236
            'onlineUsersAndSessions' => $onlineUsersAndSessions,
237
            'currentSessionId' => $currentSessionId,
238
        ]);
239
240
        $this->addMainMenu('online');
241
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
242
        $shortcutButton = $buttonBar->makeShortcutButton()
243
            ->setRouteIdentifier('system_BeuserTxBeuser')
244
            ->setArguments(['tx_beuser_system_beusertxbeuser' => ['action' => 'online']])
245
            ->setDisplayName(LocalizationUtility::translate('onlineUsers', 'beuser'));
246
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);
247
248
        $this->moduleTemplate->setContent($this->view->render());
249
        return $this->htmlResponse($this->moduleTemplate->renderContent());
250
    }
251
252
    public function showAction(int $uid = 0): ResponseInterface
253
    {
254
        $data = $this->userInformationService->getUserInformation($uid);
255
        $this->view->assign('data', $data);
256
257
        $this->addMainMenu('show');
258
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
259
        $backButton = $buttonBar->makeLinkButton()
260
            ->setIcon($this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL))
261
            ->setTitle(LocalizationUtility::translate('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
262
            ->setHref($this->backendUriBuilder->buildUriFromRoute('system_BeuserTxBeuser'));
263
        $buttonBar->addButton($backButton);
264
        $editButton = $buttonBar->makeLinkButton()
265
            ->setIcon($this->iconFactory->getIcon('actions-open', Icon::SIZE_SMALL))
266
            ->setTitle(LocalizationUtility::translate('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
267
            ->setHref($this->backendUriBuilder->buildUriFromRoute('record_edit', [
268
                'edit' => ['be_users' => [$uid => 'edit']],
269
                'returnUrl' => $this->getRequest()->getAttribute('normalizedParams')->getRequestUri()
270
            ]));
271
        $buttonBar->addButton($editButton);
272
        $addUserButton = $buttonBar->makeLinkButton()
273
            ->setIcon($this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL))
274
            ->setTitle(LocalizationUtility::translate('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newRecordGeneral'))
275
            ->setHref($this->backendUriBuilder->buildUriFromRoute('record_edit', [
276
                'edit' => ['be_users' => [0 => 'new']],
277
                'returnUrl' => $this->getRequest()->getAttribute('normalizedParams')->getRequestUri()
278
            ]));
279
        $buttonBar->addButton($addUserButton);
280
        $shortcutButton = $buttonBar->makeShortcutButton()
281
            ->setRouteIdentifier('system_BeuserTxBeuser')
282
            ->setArguments(['tx_beuser_system_beusertxbeuser' => ['action' => 'show', 'uid' => $uid]])
283
            ->setDisplayName(LocalizationUtility::translate('backendUser', 'beuser') . ': ' . (string)$data['user']['username']);
284
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);
285
286
        $this->moduleTemplate->setContent($this->view->render());
287
        return $this->htmlResponse($this->moduleTemplate->renderContent());
288
    }
289
290
    /**
291
     * Compare backend users from demand
292
     */
293
    public function compareAction(): ResponseInterface
294
    {
295
        $compareUserList = $this->moduleData->getCompareUserList();
296
        if (empty($compareUserList)) {
297
            $this->redirect('index');
298
        }
299
300
        $compareData = [];
301
        foreach ($compareUserList as $uid) {
302
            if ($compareInformation = $this->userInformationService->getUserInformation($uid)) {
303
                $compareData[] = $compareInformation;
304
            }
305
        }
306
307
        $this->view->assignMultiple([
308
            'compareUserList' => $compareData,
309
            'onlineBackendUsers' => $this->getOnlineBackendUsers()
310
        ]);
311
312
        $this->addMainMenu('compare');
313
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
314
        $backButton = $buttonBar->makeLinkButton()
315
            ->setIcon($this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL))
316
            ->setTitle(LocalizationUtility::translate('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
317
            ->setHref($this->backendUriBuilder->buildUriFromRoute('system_BeuserTxBeuser'));
318
        $buttonBar->addButton($backButton);
319
        $shortcutButton = $buttonBar->makeShortcutButton()
320
            ->setRouteIdentifier('system_BeuserTxBeuser')
321
            ->setArguments(['tx_beuser_system_beusertxbeuser' => ['action' => 'compare']])
322
            ->setDisplayName(LocalizationUtility::translate('compareUsers', 'beuser'));
323
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);
324
325
        $this->moduleTemplate->setContent($this->view->render());
326
        return $this->htmlResponse($this->moduleTemplate->renderContent());
327
    }
328
329
    /**
330
     * Starts the password reset process for a selected user.
331
     *
332
     * @param int $user
333
     */
334
    public function initiatePasswordResetAction(int $user): ResponseInterface
335
    {
336
        $context = GeneralUtility::makeInstance(Context::class);
337
        /** @var BackendUser $user */
338
        $user = $this->backendUserRepository->findByUid($user);
0 ignored issues
show
Bug introduced by
$user of type TYPO3\CMS\Beuser\Domain\Model\BackendUser is incompatible with the type integer expected by parameter $uid of TYPO3\CMS\Extbase\Persis...Repository::findByUid(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

338
        $user = $this->backendUserRepository->findByUid(/** @scrutinizer ignore-type */ $user);
Loading history...
339
        if (!$user || !$user->isPasswordResetEnabled() || !$context->getAspect('backend.user')->isAdmin()) {
0 ignored issues
show
introduced by
$user is of type TYPO3\CMS\Beuser\Domain\Model\BackendUser, thus it always evaluated to true.
Loading history...
340
            // Add an error message
341
            $this->addFlashMessage(
342
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.error.text', 'beuser') ?? '',
343
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.error.title', 'beuser') ?? '',
344
                FlashMessage::ERROR
345
            );
346
        } else {
347
            GeneralUtility::makeInstance(PasswordReset::class)->initiateReset(
348
                $this->getRequest(),
349
                $context,
350
                $user->getEmail()
351
            );
352
            $this->addFlashMessage(
353
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.success.text', 'beuser', [$user->getEmail()]) ?? '',
354
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.success.title', 'beuser') ?? '',
355
                FlashMessage::OK
356
            );
357
        }
358
        return new ForwardResponse('index');
359
    }
360
361
    /**
362
     * Attaches one backend user to the compare list
363
     *
364
     * @param int $uid
365
     */
366
    public function addToCompareListAction($uid): ResponseInterface
367
    {
368
        $this->moduleData->attachUidCompareUser($uid);
369
        $this->getBackendUser()->pushModuleData('tx_beuser', $this->moduleData->forUc());
370
        return new ForwardResponse('index');
371
    }
372
373
    /**
374
     * Removes given backend user to the compare list
375
     *
376
     * @param int $uid
377
     * @param int $redirectToCompare
378
     */
379
    public function removeFromCompareListAction($uid, int $redirectToCompare = 0): void
380
    {
381
        $this->moduleData->detachUidCompareUser($uid);
382
        $this->getBackendUser()->pushModuleData('tx_beuser', $this->moduleData->forUc());
383
        if ($redirectToCompare) {
384
            $this->redirect('compare');
385
        } else {
386
            $this->redirect('index');
387
        }
388
    }
389
390
    /**
391
     * Removes all backend users from the compare list
392
     * @throws StopActionException
393
     */
394
    public function removeAllFromCompareListAction(): void
395
    {
396
        $this->moduleData->resetCompareUserList();
397
        $this->getBackendUser()->pushModuleData('tx_beuser', $this->moduleData->forUc());
398
        $this->redirect('index');
399
    }
400
401
    /**
402
     * Terminate BackendUser session and logout corresponding client
403
     * Redirects to onlineAction with message
404
     *
405
     * @param string $sessionId
406
     */
407
    protected function terminateBackendUserSessionAction($sessionId): ResponseInterface
408
    {
409
        // terminating value of persisted session ID
410
        $success = $this->backendUserSessionRepository->terminateSessionByIdentifier($sessionId);
411
        if ($success) {
412
            $this->addFlashMessage(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:terminateSessionSuccess', 'beuser') ?? '');
413
        }
414
        return new ForwardResponse('online');
415
    }
416
417
    /**
418
     * Displays all BackendUserGroups
419
     *
420
     * @param int $currentPage
421
     * @return ResponseInterface
422
     */
423
    public function groupsAction(int $currentPage = 1): ResponseInterface
424
    {
425
        /** @var QueryResultInterface $backendUsers */
426
        $backendUsers = $this->backendUserGroupRepository->findAll();
427
        $paginator = new QueryResultPaginator($backendUsers, $currentPage, 50);
428
        $pagination = new SimplePagination($paginator);
429
        $compareGroupUidList = array_keys($this->getBackendUser()->uc['beuser']['compareGroupUidList'] ?? []);
430
        $this->view->assignMultiple(
431
            [
432
                'paginator' => $paginator,
433
                'pagination' => $pagination,
434
                'totalAmountOfBackendUserGroups' => $backendUsers->count(),
435
                'compareGroupUidList' => array_map(static function ($value) { // uid as key and force value to 1
436
                    return 1;
437
                }, array_flip($compareGroupUidList)),
438
                'compareGroupList' => !empty($compareGroupUidList) ? $this->backendUserGroupRepository->findByUidList($compareGroupUidList) : [],
439
            ]
440
        );
441
442
        $this->addMainMenu('groups');
443
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
444
        $addGroupButton = $buttonBar->makeLinkButton()
445
            ->setIcon($this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL))
446
            ->setTitle(LocalizationUtility::translate('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newRecordGeneral'))
447
            ->setHref($this->backendUriBuilder->buildUriFromRoute('record_edit', [
448
                'edit' => ['be_groups' => [0 => 'new']],
449
                'returnUrl' => $this->getRequest()->getAttribute('normalizedParams')->getRequestUri()
450
            ]));
451
        $buttonBar->addButton($addGroupButton);
452
        $shortcutButton = $buttonBar->makeShortcutButton()
453
            ->setRouteIdentifier('system_BeuserTxBeuser')
454
            ->setArguments(['tx_beuser_system_beusertxbeuser' => ['action' => 'groups']])
455
            ->setDisplayName(LocalizationUtility::translate('backendUserGroupsMenu', 'beuser'));
456
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);
457
458
        $this->moduleTemplate->setContent($this->view->render());
459
        return $this->htmlResponse($this->moduleTemplate->renderContent());
460
    }
461
462
    public function compareGroupsAction(): ResponseInterface
463
    {
464
        $compareGroupUidList = array_keys($this->getBackendUser()->uc['beuser']['compareGroupUidList'] ?? []);
465
466
        $compareData = [];
467
        foreach ($compareGroupUidList as $uid) {
468
            if ($compareInformation = $this->userInformationService->getGroupInformation($uid)) {
469
                $compareData[] = $compareInformation;
470
            }
471
        }
472
        if (empty($compareData)) {
473
            $this->redirect('groups');
474
        }
475
476
        $this->view->assign('compareGroupList', $compareData);
477
478
        $this->addMainMenu('compareGroups');
479
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
480
        $backButton = $buttonBar->makeLinkButton()
481
            ->setIcon($this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL))
482
            ->setTitle(LocalizationUtility::translate('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
483
            ->setHref($this->uriBuilder->uriFor('groups'));
484
        $buttonBar->addButton($backButton);
485
        $shortcutButton = $buttonBar->makeShortcutButton()
486
            ->setRouteIdentifier('system_BeuserTxBeuser')
487
            ->setArguments(['tx_beuser_system_beusertxbeuser' => ['action' => 'compareGroups']])
488
            ->setDisplayName(LocalizationUtility::translate('compareBackendUsersGroups', 'beuser'));
489
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);
490
491
        $this->moduleTemplate->setContent($this->view->render());
492
        return $this->htmlResponse($this->moduleTemplate->renderContent());
493
    }
494
495
    /**
496
     * Attaches one backend user group to the compare list
497
     *
498
     * @param int $uid
499
     */
500
    public function addGroupToCompareListAction(int $uid): void
501
    {
502
        $backendUser = $this->getBackendUser();
503
        $list = $backendUser->uc['beuser']['compareGroupUidList'] ?? [];
504
        $list[$uid] = true;
505
        $backendUser->uc['beuser']['compareGroupUidList'] = $list;
506
        $backendUser->writeUC();
507
        $this->redirect('groups');
508
    }
509
510
    /**
511
     * Removes given backend user group to the compare list
512
     *
513
     * @param int $uid
514
     * @param int $redirectToCompare
515
     */
516
    public function removeGroupFromCompareListAction(int $uid, int $redirectToCompare = 0): void
517
    {
518
        $backendUser = $this->getBackendUser();
519
        $list = $backendUser->uc['beuser']['compareGroupUidList'] ?? [];
520
        unset($list[$uid]);
521
        $backendUser->uc['beuser']['compareGroupUidList'] = $list;
522
        $backendUser->writeUC();
523
524
        if ($redirectToCompare) {
525
            $this->redirect('compareGroups');
526
        } else {
527
            $this->redirect('groups');
528
        }
529
    }
530
531
    /**
532
     * Removes all backend user groups from the compare list
533
     */
534
    public function removeAllGroupsFromCompareListAction(): void
535
    {
536
        $backendUser = $this->getBackendUser();
537
        $backendUser->uc['beuser']['compareGroupUidList'] = [];
538
        $backendUser->writeUC();
539
        $this->redirect('groups');
540
    }
541
542
    /**
543
     * Switches to a given user (SU-mode) and then redirects to the start page of the backend to refresh the navigation etc.
544
     *
545
     * @param int $switchUser BE-user record that will be switched to
546
     */
547
    protected function switchUser($switchUser)
548
    {
549
        $backendUser = $this->getBackendUser();
550
        $targetUser = BackendUtility::getRecord('be_users', $switchUser);
551
        if (is_array($targetUser) && $backendUser->isAdmin()) {
552
            // Set backend user listing module as starting module for switchback
553
            $backendUser->uc['startModuleOnFirstLogin'] = 'system_BeuserTxBeuser';
554
            $backendUser->uc['recentSwitchedToUsers'] = $this->generateListOfMostRecentSwitchedUsers($targetUser['uid']);
555
            $backendUser->writeUC();
556
557
            // User switch   written to log
558
            $backendUser->writelog(
559
                255,
560
                2,
561
                0,
562
                1,
563
                'User %s switched to user %s (be_users:%s)',
564
                [
565
                    $backendUser->user['username'],
566
                    $targetUser['username'],
567
                    $targetUser['uid'],
568
                ]
569
            );
570
571
            $this->backendUserSessionRepository->switchToUser($backendUser, (int)$targetUser['uid']);
572
573
            $event = new SwitchUserEvent(
574
                $backendUser->getSession()->getIdentifier(),
575
                $targetUser,
576
                (array)$backendUser->user
577
            );
578
            $this->eventDispatcher->dispatch($event);
579
580
            $redirectUri = $this->backendUriBuilder->buildUriFromRoute(
581
                'main',
582
                $GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces'] ? [] : ['commandLI' => '1']
583
            );
584
            throw new PropagateResponseException(new RedirectResponse($redirectUri, 303), 1607271592);
585
        }
586
    }
587
588
    /**
589
     * Generates a list of users to whom where switched in the past. This is limited by RECENT_USERS_LIMIT.
590
     *
591
     * @param int $targetUserUid
592
     * @return int[]
593
     */
594
    protected function generateListOfMostRecentSwitchedUsers(int $targetUserUid): array
595
    {
596
        $latestUserUids = [];
597
        $backendUser = $this->getBackendUser();
598
599
        if (isset($backendUser->uc['recentSwitchedToUsers']) && is_array($backendUser->uc['recentSwitchedToUsers'])) {
600
            $latestUserUids = $backendUser->uc['recentSwitchedToUsers'];
601
        }
602
603
        // Remove potentially existing user in that list
604
        $index = array_search($targetUserUid, $latestUserUids, true);
605
        if ($index !== false) {
606
            unset($latestUserUids[$index]);
607
        }
608
609
        array_unshift($latestUserUids, $targetUserUid);
610
        $latestUserUids = array_slice($latestUserUids, 0, static::RECENT_USERS_LIMIT);
611
612
        return $latestUserUids;
613
    }
614
615
    /**
616
     * Create an array with the uids of online users as the keys
617
     * [
618
     *   1 => true,
619
     *   5 => true
620
     * ]
621
     * @return array
622
     */
623
    protected function getOnlineBackendUsers(): array
624
    {
625
        $onlineUsers = $this->backendUserSessionRepository->findAllActive();
626
        $onlineBackendUsers = [];
627
        foreach ($onlineUsers as $onlineUser) {
628
            $onlineBackendUsers[$onlineUser['ses_userid']] = true;
629
        }
630
        return $onlineBackendUsers;
631
    }
632
633
    /**
634
     * Doc header main drop down
635
     *
636
     * @param string $currentAction
637
     */
638
    protected function addMainMenu(string $currentAction): void
639
    {
640
        $this->uriBuilder->setRequest($this->request);
641
        $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
642
        $menu->setIdentifier('BackendUserModuleMenu');
643
        $menu->addMenuItem(
644
            $menu->makeMenuItem()
645
            ->setTitle(LocalizationUtility::translate('backendUsers', 'beuser'))
646
            ->setHref($this->uriBuilder->uriFor('index'))
647
            ->setActive($currentAction === 'index')
648
        );
649
        if ($currentAction === 'show') {
650
            $menu->addMenuItem(
651
                $menu->makeMenuItem()
652
                ->setTitle(LocalizationUtility::translate('backendUserDetails', 'beuser'))
653
                ->setHref($this->uriBuilder->uriFor('show'))
654
                ->setActive(true)
655
            );
656
        }
657
        if ($currentAction === 'compare') {
658
            $menu->addMenuItem(
659
                $menu->makeMenuItem()
660
                ->setTitle(LocalizationUtility::translate('compareBackendUsers', 'beuser'))
661
                ->setHref($this->uriBuilder->uriFor('index'))
662
                ->setActive(true)
663
            );
664
        }
665
        $menu->addMenuItem(
666
            $menu->makeMenuItem()
667
            ->setTitle(LocalizationUtility::translate('backendUserGroupsMenu', 'beuser'))
668
            ->setHref($this->uriBuilder->uriFor('groups'))
669
            ->setActive($currentAction === 'groups')
670
        );
671
        if ($currentAction === 'compareGroups') {
672
            $menu->addMenuItem(
673
                $menu->makeMenuItem()
674
                ->setTitle(LocalizationUtility::translate('compareBackendUsersGroups', 'beuser'))
675
                ->setHref($this->uriBuilder->uriFor('compareGroups'))
676
                ->setActive(true)
677
            );
678
        }
679
        $menu->addMenuItem(
680
            $menu->makeMenuItem()
681
            ->setTitle(LocalizationUtility::translate('onlineUsers', 'beuser'))
682
            ->setHref($this->uriBuilder->uriFor('online'))
683
            ->setActive($currentAction === 'online')
684
        );
685
        $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
686
    }
687
688
    /**
689
     * @return BackendUserAuthentication
690
     */
691
    protected function getBackendUser(): BackendUserAuthentication
692
    {
693
        return $GLOBALS['BE_USER'];
694
    }
695
696
    /**
697
     * This is a temporary hack to receive the PSR-7 request until extbase
698
     * provides a PSR-7 compatible request in actions.
699
     *
700
     * @return ServerRequestInterface
701
     */
702
    protected function getRequest(): ServerRequestInterface
703
    {
704
        return $GLOBALS['TYPO3_REQUEST'];
705
    }
706
}
707