BackendUserController.php 25.3 KB
Newer Older
1
<?php
2

3
4
declare(strict_types=1);

5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
9
10
 * 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.
11
 *
12
13
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
16
 * The TYPO3 project - inspiring people to share!
 */
17

18
19
namespace TYPO3\CMS\Beuser\Controller;

20
use Psr\Http\Message\ResponseInterface;
21
use TYPO3\CMS\Backend\Authentication\PasswordReset;
22
use TYPO3\CMS\Backend\Module\ModuleData;
23
24
25
26
use TYPO3\CMS\Backend\Routing\UriBuilder as BackendUriBuilder;
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
use TYPO3\CMS\Backend\Template\ModuleTemplate;
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
27
use TYPO3\CMS\Beuser\Domain\Model\BackendUser;
28
use TYPO3\CMS\Beuser\Domain\Model\Demand;
29
30
31
32
use TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository;
use TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository;
use TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository;
use TYPO3\CMS\Beuser\Service\UserInformationService;
33
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
34
use TYPO3\CMS\Core\Context\Context;
35
36
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
37
use TYPO3\CMS\Core\Messaging\FlashMessage;
38
use TYPO3\CMS\Core\Page\PageRenderer;
39
use TYPO3\CMS\Core\Pagination\SimplePagination;
40
use TYPO3\CMS\Core\Utility\GeneralUtility;
41
use TYPO3\CMS\Extbase\Http\ForwardResponse;
42
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
43
44
use TYPO3\CMS\Extbase\Mvc\Request;
use TYPO3\CMS\Extbase\Mvc\RequestInterface;
45
use TYPO3\CMS\Extbase\Pagination\QueryResultPaginator;
46
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
47
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
48

49
/**
50
51
 * Backend module user and user group administration controller.
 *
52
 * @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API.
53
 */
54
class BackendUserController extends ActionController
55
{
56
    protected ?ModuleData $moduleData = null;
57
    protected ModuleTemplate $moduleTemplate;
58

59
    public function __construct(
60
61
62
63
64
65
66
67
        protected readonly BackendUserRepository $backendUserRepository,
        protected readonly BackendUserGroupRepository $backendUserGroupRepository,
        protected readonly BackendUserSessionRepository $backendUserSessionRepository,
        protected readonly UserInformationService $userInformationService,
        protected readonly ModuleTemplateFactory $moduleTemplateFactory,
        protected readonly BackendUriBuilder $backendUriBuilder,
        protected readonly IconFactory $iconFactory,
        protected readonly PageRenderer $pageRenderer
68
    ) {
69
70
71
72
73
74
75
    }

    /**
     * Override the default action if found in user uc
     */
    public function processRequest(RequestInterface $request): ResponseInterface
    {
76
        /** @var Request $request */
77
        $arguments = $request->getArguments();
78
79
80
81
82
        $moduleData = $request->getAttribute('moduleData');
        if (
            isset($arguments['action'])
            && in_array((string)$arguments['action'], ['index', 'groups', 'online'])
            && (string)$moduleData->get('defaultAction') !== (string)$arguments['action']
83
        ) {
84
85
86
87
88
89
            $moduleData->set('defaultAction', (string)$arguments['action']);
            $this->getBackendUser()->pushModuleData($moduleData->getModuleIdentifier(), $moduleData->toArray());
        } elseif (
            !isset($arguments['action'])
            && $moduleData->has('defaultAction')
            && in_array((string)$moduleData->get('defaultAction'), ['index', 'groups', 'online'])
90
        ) {
91
            $request->setControllerActionName((string)$moduleData->get('defaultAction'));
92
93
        }
        return parent::processRequest($request);
94
    }
95

96
    /**
97
98
99
100
     * Init module state.
     * This isn't done within __construct() since the controller
     * object is only created once in extbase when multiple actions are called in
     * one call. When those change module state, the second action would see old state.
101
     */
102
    public function initializeAction(): void
103
    {
104
        $this->moduleData = $this->request->getAttribute('moduleData');
105
        $this->moduleTemplate = $this->moduleTemplateFactory->create($this->request);
106
        $this->moduleTemplate->setTitle(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang_mod.xlf:mlang_tabs_tab'));
107
        $this->moduleTemplate->setFlashMessageQueue($this->getFlashMessageQueue());
108
    }
109

110
    /**
111
     * Assign default variables to ModuleTemplate view
112
     */
113
    protected function initializeView(): void
114
    {
115
        $this->moduleTemplate->assignMultiple([
116
117
118
            'dateFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'],
            'timeFormat' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'],
        ]);
119
        // Load requireJS modules
120
121
122
        $this->pageRenderer->loadJavaScriptModule('@typo3/backend/context-menu.js');
        $this->pageRenderer->loadJavaScriptModule('@typo3/backend/modal.js');
        $this->pageRenderer->loadJavaScriptModule('@typo3/beuser/backend-user-listing.js');
123
    }
124

125
126
127
    /**
     * Displays all BackendUsers
     *
128
     * @param Demand|null $demand
129
     * @param int $currentPage
130
     * @param string $operation
131
     * @return ResponseInterface
132
     */
133
    public function indexAction(Demand $demand = null, int $currentPage = 1, string $operation = ''): ResponseInterface
134
    {
135
136
        $backendUser = $this->getBackendUser();

137
138
        if ($operation === 'reset-filters') {
            // Reset the module data demand object
139
            $this->moduleData->set('demand', []);
140
141
            $demand = null;
        }
142
        if ($demand === null) {
143
            $demand = Demand::fromUc((array)$this->moduleData->get('demand', []));
144
        } else {
145
            $this->moduleData->set('demand', $demand->forUc());
146
        }
147
148
149
        $backendUser->pushModuleData($this->moduleData->getModuleIdentifier(), $this->moduleData->toArray());

        $compareUserList = array_keys((array)$this->moduleData->get('compareUserList', []));
150

151
152
153
154
        $backendUsers = $this->backendUserRepository->findDemanded($demand);
        $paginator = new QueryResultPaginator($backendUsers, $currentPage, 50);
        $pagination = new SimplePagination($paginator);

155
        $this->moduleTemplate->assignMultiple([
156
            'onlineBackendUsers' => $this->getOnlineBackendUsers(),
157
            'demand' => $demand,
158
159
160
            'paginator' => $paginator,
            'pagination' => $pagination,
            'totalAmountOfBackendUsers' => $backendUsers->count(),
161
            'backendUserGroups' => array_merge([''], $this->backendUserGroupRepository->findAll()->toArray()),
162
            'compareUserUidList' => array_combine($compareUserList, $compareUserList),
163
            'currentUserUid' => $backendUser->user['uid'],
164
165
            'compareUserList' => !empty($compareUserList) ? $this->backendUserRepository->findByUidList($compareUserList) : '',
        ]);
166

167
168
169
170
171
        $this->addMainMenu('index');
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
        $addUserButton = $buttonBar->makeLinkButton()
            ->setIcon($this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL))
            ->setTitle(LocalizationUtility::translate('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newRecordGeneral'))
172
            ->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
173
                'edit' => ['be_users' => [0 => 'new']],
174
                'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
175
176
177
178
            ]));
        $buttonBar->addButton($addUserButton);
        $shortcutButton = $buttonBar->makeShortcutButton()
            ->setRouteIdentifier('system_BeuserTxBeuser')
179
            ->setArguments(['action' => 'index'])
180
181
182
            ->setDisplayName(LocalizationUtility::translate('backendUsers', 'beuser'));
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);

183
        $this->pageRenderer->loadJavaScriptModule('@typo3/backend/switch-user.js');
184

185
        return $this->moduleTemplate->renderResponse('BackendUser/Index');
186
    }
187

188
189
190
    /**
     * Views all currently logged in BackendUsers and their sessions
     */
191
    public function onlineAction(): ResponseInterface
192
    {
193
        $onlineUsersAndSessions = [];
194
195
        $onlineUsers = $this->backendUserRepository->findOnline();
        foreach ($onlineUsers as $onlineUser) {
196
            $onlineUsersAndSessions[] = [
197
                'backendUser' => $onlineUser,
198
                'sessions' => $this->backendUserSessionRepository->findByBackendUser($onlineUser),
199
            ];
200
        }
201

202
        $currentSessionId = $this->backendUserSessionRepository->getPersistedSessionIdentifier($this->getBackendUser());
203

204
        $this->moduleTemplate->assignMultiple([
205
            'onlineUsersAndSessions' => $onlineUsersAndSessions,
206
            'currentSessionId' => $currentSessionId,
207
        ]);
208

209
210
211
212
        $this->addMainMenu('online');
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
        $shortcutButton = $buttonBar->makeShortcutButton()
            ->setRouteIdentifier('system_BeuserTxBeuser')
213
            ->setArguments(['action' => 'online'])
214
215
216
            ->setDisplayName(LocalizationUtility::translate('onlineUsers', 'beuser'));
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);

217
        return $this->moduleTemplate->renderResponse('BackendUser/Online');
218
    }
219

220
    public function showAction(int $uid = 0): ResponseInterface
221
    {
222
        $data = $this->userInformationService->getUserInformation($uid);
223
        $this->moduleTemplate->assign('data', $data);
224
225
226
227
228
229

        $this->addMainMenu('show');
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
        $backButton = $buttonBar->makeLinkButton()
            ->setIcon($this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL))
            ->setTitle(LocalizationUtility::translate('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
230
            ->setHref((string)$this->backendUriBuilder->buildUriFromRoute('system_BeuserTxBeuser'));
231
232
233
234
        $buttonBar->addButton($backButton);
        $editButton = $buttonBar->makeLinkButton()
            ->setIcon($this->iconFactory->getIcon('actions-open', Icon::SIZE_SMALL))
            ->setTitle(LocalizationUtility::translate('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
235
            ->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
236
                'edit' => ['be_users' => [$uid => 'edit']],
237
                'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
238
239
240
241
242
            ]));
        $buttonBar->addButton($editButton);
        $addUserButton = $buttonBar->makeLinkButton()
            ->setIcon($this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL))
            ->setTitle(LocalizationUtility::translate('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newRecordGeneral'))
243
            ->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
244
                'edit' => ['be_users' => [0 => 'new']],
245
                'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
246
247
248
249
            ]));
        $buttonBar->addButton($addUserButton);
        $shortcutButton = $buttonBar->makeShortcutButton()
            ->setRouteIdentifier('system_BeuserTxBeuser')
250
            ->setArguments(['action' => 'show', 'uid' => $uid])
251
252
253
            ->setDisplayName(LocalizationUtility::translate('backendUser', 'beuser') . ': ' . (string)$data['user']['username']);
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);

254
        return $this->moduleTemplate->renderResponse('BackendUser/Show');
255
256
    }

257
258
259
    /**
     * Compare backend users from demand
     */
260
    public function compareAction(): ResponseInterface
261
    {
262
        $compareUserList = array_keys((array)$this->moduleData->get('compareUserList', []));
263
        if (empty($compareUserList)) {
264
            return $this->redirect('index');
265
266
        }

267
268
        $compareData = [];
        foreach ($compareUserList as $uid) {
269
270
271
            if ($compareInformation = $this->userInformationService->getUserInformation($uid)) {
                $compareData[] = $compareInformation;
            }
272
273
        }

274
        $this->moduleTemplate->assignMultiple([
275
            'compareUserList' => $compareData,
276
            'onlineBackendUsers' => $this->getOnlineBackendUsers(),
277
        ]);
278

279
280
281
282
283
        $this->addMainMenu('compare');
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
        $backButton = $buttonBar->makeLinkButton()
            ->setIcon($this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL))
            ->setTitle(LocalizationUtility::translate('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
284
            ->setHref((string)$this->backendUriBuilder->buildUriFromRoute('system_BeuserTxBeuser'));
285
286
287
        $buttonBar->addButton($backButton);
        $shortcutButton = $buttonBar->makeShortcutButton()
            ->setRouteIdentifier('system_BeuserTxBeuser')
288
            ->setArguments(['action' => 'compare'])
289
290
291
            ->setDisplayName(LocalizationUtility::translate('compareUsers', 'beuser'));
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);

292
        return $this->moduleTemplate->renderResponse('BackendUser/Compare');
293
    }
294

295
296
297
298
299
    /**
     * Starts the password reset process for a selected user.
     *
     * @param int $user
     */
300
    public function initiatePasswordResetAction(int $user): ResponseInterface
301
302
303
304
305
306
307
    {
        $context = GeneralUtility::makeInstance(Context::class);
        /** @var BackendUser $user */
        $user = $this->backendUserRepository->findByUid($user);
        if (!$user || !$user->isPasswordResetEnabled() || !$context->getAspect('backend.user')->isAdmin()) {
            // Add an error message
            $this->addFlashMessage(
308
309
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.error.text', 'beuser') ?? '',
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.error.title', 'beuser') ?? '',
310
311
312
313
                FlashMessage::ERROR
            );
        } else {
            GeneralUtility::makeInstance(PasswordReset::class)->initiateReset(
314
                $this->request,
315
316
317
318
                $context,
                $user->getEmail()
            );
            $this->addFlashMessage(
319
320
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.success.text', 'beuser', [$user->getEmail()]) ?? '',
                LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:flashMessage.resetPassword.success.title', 'beuser') ?? '',
321
322
323
                FlashMessage::OK
            );
        }
324
        return new ForwardResponse('index');
325
326
    }

327
328
329
    /**
     * Attaches one backend user to the compare list
     */
330
    public function addToCompareListAction(int $uid): ResponseInterface
331
    {
332
        $this->addToCompareList('compareUserList', $uid);
333
        return new ForwardResponse('index');
334
    }
335

336
337
338
    /**
     * Removes given backend user to the compare list
     */
339
    public function removeFromCompareListAction(int $uid, int $redirectToCompare = 0): ResponseInterface
340
    {
341
        $this->removeFromCompareList('compareUserList', $uid);
342
        if ($redirectToCompare) {
343
            return $this->redirect('compare');
344
        }
345
        return $this->redirect('index');
346
347
348
349
350
    }

    /**
     * Removes all backend users from the compare list
     */
351
    public function removeAllFromCompareListAction(): ResponseInterface
352
    {
353
        $this->cleanCompareList('compareUserList');
354
        return $this->redirect('index');
355
    }
356

357
358
359
360
361
362
    /**
     * Terminate BackendUser session and logout corresponding client
     * Redirects to onlineAction with message
     *
     * @param string $sessionId
     */
363
    protected function terminateBackendUserSessionAction($sessionId): ResponseInterface
364
    {
365
        // terminating value of persisted session ID
366
        $success = $this->backendUserSessionRepository->terminateSessionByIdentifier($sessionId);
367
        if ($success) {
368
            $this->addFlashMessage(LocalizationUtility::translate('LLL:EXT:beuser/Resources/Private/Language/locallang.xlf:terminateSessionSuccess', 'beuser') ?? '');
369
        }
370
        return new ForwardResponse('online');
371
    }
372

373
374
375
376
377
378
379
380
381
382
383
384
    /**
     * Displays all BackendUserGroups
     *
     * @param int $currentPage
     * @return ResponseInterface
     */
    public function groupsAction(int $currentPage = 1): ResponseInterface
    {
        /** @var QueryResultInterface $backendUsers */
        $backendUsers = $this->backendUserGroupRepository->findAll();
        $paginator = new QueryResultPaginator($backendUsers, $currentPage, 50);
        $pagination = new SimplePagination($paginator);
385
        $compareGroupUidList = array_keys((array)$this->moduleData->get('compareGroupUidList', []));
386
        $this->moduleTemplate->assignMultiple(
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
            [
                'paginator' => $paginator,
                'pagination' => $pagination,
                'totalAmountOfBackendUserGroups' => $backendUsers->count(),
                'compareGroupUidList' => array_map(static function ($value) { // uid as key and force value to 1
                    return 1;
                }, array_flip($compareGroupUidList)),
                'compareGroupList' => !empty($compareGroupUidList) ? $this->backendUserGroupRepository->findByUidList($compareGroupUidList) : [],
            ]
        );

        $this->addMainMenu('groups');
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
        $addGroupButton = $buttonBar->makeLinkButton()
            ->setIcon($this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL))
            ->setTitle(LocalizationUtility::translate('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newRecordGeneral'))
403
            ->setHref((string)$this->backendUriBuilder->buildUriFromRoute('record_edit', [
404
                'edit' => ['be_groups' => [0 => 'new']],
405
                'returnUrl' => $this->request->getAttribute('normalizedParams')->getRequestUri(),
406
407
408
409
            ]));
        $buttonBar->addButton($addGroupButton);
        $shortcutButton = $buttonBar->makeShortcutButton()
            ->setRouteIdentifier('system_BeuserTxBeuser')
410
            ->setArguments(['action' => 'groups'])
411
412
413
            ->setDisplayName(LocalizationUtility::translate('backendUserGroupsMenu', 'beuser'));
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);

414
        return $this->moduleTemplate->renderResponse('BackendUser/Groups');
415
416
417
418
    }

    public function compareGroupsAction(): ResponseInterface
    {
419
        $compareGroupUidList = array_keys((array)$this->moduleData->get('compareGroupUidList', []));
420
421
422
423
424
425
426
427

        $compareData = [];
        foreach ($compareGroupUidList as $uid) {
            if ($compareInformation = $this->userInformationService->getGroupInformation($uid)) {
                $compareData[] = $compareInformation;
            }
        }
        if (empty($compareData)) {
428
            return $this->redirect('groups');
429
430
        }

431
        $this->moduleTemplate->assign('compareGroupList', $compareData);
432
433
434
435
436
437
438
439
440
441

        $this->addMainMenu('compareGroups');
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
        $backButton = $buttonBar->makeLinkButton()
            ->setIcon($this->iconFactory->getIcon('actions-view-go-back', Icon::SIZE_SMALL))
            ->setTitle(LocalizationUtility::translate('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
            ->setHref($this->uriBuilder->uriFor('groups'));
        $buttonBar->addButton($backButton);
        $shortcutButton = $buttonBar->makeShortcutButton()
            ->setRouteIdentifier('system_BeuserTxBeuser')
442
            ->setArguments(['action' => 'compareGroups'])
443
444
445
            ->setDisplayName(LocalizationUtility::translate('compareBackendUsersGroups', 'beuser'));
        $buttonBar->addButton($shortcutButton, ButtonBar::BUTTON_POSITION_RIGHT);

446
        return $this->moduleTemplate->renderResponse('BackendUser/CompareGroups');
447
448
449
450
451
    }

    /**
     * Attaches one backend user group to the compare list
     */
452
    public function addGroupToCompareListAction(int $uid): ResponseInterface
453
    {
454
        $this->addToCompareList('compareGroupUidList', $uid);
455
        return $this->redirect('groups');
456
457
458
459
460
    }

    /**
     * Removes given backend user group to the compare list
     */
461
    public function removeGroupFromCompareListAction(int $uid, int $redirectToCompare = 0): ResponseInterface
462
    {
463
        $this->removeFromCompareList('compareGroupUidList', $uid);
464
        if ($redirectToCompare) {
465
            return $this->redirect('compareGroups');
466
        }
467
        return $this->redirect('groups');
468
469
470
471
472
    }

    /**
     * Removes all backend user groups from the compare list
     */
473
    public function removeAllGroupsFromCompareListAction(): ResponseInterface
474
    {
475
        $this->cleanCompareList('compareGroupUidList');
476
        return $this->redirect('groups');
477
478
    }

479
480
481
482
483
484
485
486
487
488
489
490
    /**
     * Create an array with the uids of online users as the keys
     * [
     *   1 => true,
     *   5 => true
     * ]
     * @return array
     */
    protected function getOnlineBackendUsers(): array
    {
        $onlineUsers = $this->backendUserSessionRepository->findAllActive();
        $onlineBackendUsers = [];
491
492
        foreach ($onlineUsers as $onlineUser) {
            $onlineBackendUsers[$onlineUser['ses_userid']] = true;
493
494
495
        }
        return $onlineBackendUsers;
    }
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551

    /**
     * Doc header main drop down
     *
     * @param string $currentAction
     */
    protected function addMainMenu(string $currentAction): void
    {
        $this->uriBuilder->setRequest($this->request);
        $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
        $menu->setIdentifier('BackendUserModuleMenu');
        $menu->addMenuItem(
            $menu->makeMenuItem()
            ->setTitle(LocalizationUtility::translate('backendUsers', 'beuser'))
            ->setHref($this->uriBuilder->uriFor('index'))
            ->setActive($currentAction === 'index')
        );
        if ($currentAction === 'show') {
            $menu->addMenuItem(
                $menu->makeMenuItem()
                ->setTitle(LocalizationUtility::translate('backendUserDetails', 'beuser'))
                ->setHref($this->uriBuilder->uriFor('show'))
                ->setActive(true)
            );
        }
        if ($currentAction === 'compare') {
            $menu->addMenuItem(
                $menu->makeMenuItem()
                ->setTitle(LocalizationUtility::translate('compareBackendUsers', 'beuser'))
                ->setHref($this->uriBuilder->uriFor('index'))
                ->setActive(true)
            );
        }
        $menu->addMenuItem(
            $menu->makeMenuItem()
            ->setTitle(LocalizationUtility::translate('backendUserGroupsMenu', 'beuser'))
            ->setHref($this->uriBuilder->uriFor('groups'))
            ->setActive($currentAction === 'groups')
        );
        if ($currentAction === 'compareGroups') {
            $menu->addMenuItem(
                $menu->makeMenuItem()
                ->setTitle(LocalizationUtility::translate('compareBackendUsersGroups', 'beuser'))
                ->setHref($this->uriBuilder->uriFor('compareGroups'))
                ->setActive(true)
            );
        }
        $menu->addMenuItem(
            $menu->makeMenuItem()
            ->setTitle(LocalizationUtility::translate('onlineUsers', 'beuser'))
            ->setHref($this->uriBuilder->uriFor('online'))
            ->setActive($currentAction === 'online')
        );
        $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
    }

552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
    /**
     * Attaches the given uid to the requested compare list
     */
    protected function addToCompareList(string $listIdentifier, int $uid): void
    {
        $compareList = (array)$this->moduleData->get($listIdentifier, []);
        $compareList[$uid] = true;
        $this->moduleData->set($listIdentifier, $compareList);
        $this->getBackendUser()->pushModuleData($this->moduleData->getModuleIdentifier(), $this->moduleData->toArray());
    }

    /**
     * Removes the given uid from the requested compare list
     */
    protected function removeFromCompareList(string $listIdentifier, int $uid): void
    {
        $compareList = (array)$this->moduleData->get($listIdentifier, []);
        unset($compareList[$uid]);
        $this->moduleData->set($listIdentifier, $compareList);
        $this->getBackendUser()->pushModuleData($this->moduleData->getModuleIdentifier(), $this->moduleData->toArray());
    }

    /**
     * Removes all items from the requested compare list
     */
    protected function cleanCompareList(string $listIdentifier): void
    {
        $this->moduleData->set($listIdentifier, []);
        $this->getBackendUser()->pushModuleData($this->moduleData->getModuleIdentifier(), $this->moduleData->toArray());
    }

583
584
585
586
    protected function getBackendUser(): BackendUserAuthentication
    {
        return $GLOBALS['BE_USER'];
    }
587
}