From e7887367db2769efca326f61937711ba88d3343e Mon Sep 17 00:00:00 2001
From: Georg Ringer <georg.ringer@gmail.com>
Date: Sun, 2 Feb 2020 19:39:19 +0100
Subject: [PATCH] [FEATURE] Improve user info in beuser module

Show all collected information of a user in the beuser module instead
of just the information directly added to the user record.

The UI will be improved with later patches

This patch also switched to constructor injection in
BackendUserController.

Resolves: #90298
Releases: master
Change-Id: I8cc19a475ae43404e29402b99852286bf6991b70
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/63149
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Daniel Goerz <daniel.goerz@posteo.de>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Daniel Goerz <daniel.goerz@posteo.de>
---
 .../Controller/BackendUserController.php      |  68 ++++---
 .../Service/UserInformationService.php        | 145 +++++++++++++++
 .../ViewHelpers/Display/PagesViewHelper.php   |  88 ---------
 .../Display/SysFileMountsViewHelper.php       |  88 ---------
 .../Display/SysLanguageViewHelper.php         |  88 ---------
 .../Display/TableAccessViewHelper.php         |  35 ++++
 .../Resources/Private/Language/locallang.xlf  |  45 +++++
 .../Partials/BackendUser/IndexListRow.html    |   3 +
 .../Partials/BackendUser/Information.html     | 126 +++++++++++++
 .../Templates/BackendUser/Compare.html        | 137 +++++++-------
 .../Private/Templates/BackendUser/Show.html   | 169 ++++++++++++++++++
 typo3/sysext/beuser/ext_tables.php            |   2 +-
 ...re-90298-ImproveUserInfoInBeuserModule.rst |  27 +++
 13 files changed, 650 insertions(+), 371 deletions(-)
 create mode 100644 typo3/sysext/beuser/Classes/Service/UserInformationService.php
 delete mode 100644 typo3/sysext/beuser/Classes/ViewHelpers/Display/PagesViewHelper.php
 delete mode 100644 typo3/sysext/beuser/Classes/ViewHelpers/Display/SysFileMountsViewHelper.php
 delete mode 100644 typo3/sysext/beuser/Classes/ViewHelpers/Display/SysLanguageViewHelper.php
 create mode 100644 typo3/sysext/beuser/Classes/ViewHelpers/Display/TableAccessViewHelper.php
 create mode 100644 typo3/sysext/beuser/Resources/Private/Partials/BackendUser/Information.html
 create mode 100644 typo3/sysext/beuser/Resources/Private/Templates/BackendUser/Show.html
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-90298-ImproveUserInfoInBeuserModule.rst

diff --git a/typo3/sysext/beuser/Classes/Controller/BackendUserController.php b/typo3/sysext/beuser/Classes/Controller/BackendUserController.php
index faeb8a03af51..2d8c1e87e674 100644
--- a/typo3/sysext/beuser/Classes/Controller/BackendUserController.php
+++ b/typo3/sysext/beuser/Classes/Controller/BackendUserController.php
@@ -1,4 +1,5 @@
 <?php
+
 namespace TYPO3\CMS\Beuser\Controller;
 
 /*
@@ -15,6 +16,11 @@ namespace TYPO3\CMS\Beuser\Controller;
  */
 
 use TYPO3\CMS\Backend\Authentication\Event\SwitchUserEvent;
+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\ModuleDataStorageService;
+use TYPO3\CMS\Beuser\Service\UserInformationService;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Session\Backend\SessionBackendInterface;
 use TYPO3\CMS\Core\Session\SessionManager;
@@ -41,55 +47,42 @@ class BackendUserController extends ActionController
     protected $moduleData;
 
     /**
-     * @var \TYPO3\CMS\Beuser\Service\ModuleDataStorageService
+     * @var ModuleDataStorageService
      */
     protected $moduleDataStorageService;
 
     /**
-     * @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository
+     * @var BackendUserRepository
      */
     protected $backendUserRepository;
 
     /**
-     * @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository
+     * @var BackendUserGroupRepository
      */
     protected $backendUserGroupRepository;
 
     /**
-     * @var \TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository
+     * @var BackendUserSessionRepository
      */
     protected $backendUserSessionRepository;
 
     /**
-     * @param \TYPO3\CMS\Beuser\Service\ModuleDataStorageService $moduleDataStorageService
+     * @var UserInformationService
      */
-    public function injectModuleDataStorageService(\TYPO3\CMS\Beuser\Service\ModuleDataStorageService $moduleDataStorageService)
-    {
+    protected $userInformationService;
+
+    public function __construct(
+        ModuleDataStorageService $moduleDataStorageService,
+        BackendUserRepository $backendUserRepository,
+        BackendUserGroupRepository $backendUserGroupRepository,
+        BackendUserSessionRepository $backendUserSessionRepository,
+        UserInformationService $userInformationService
+    ) {
         $this->moduleDataStorageService = $moduleDataStorageService;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository $backendUserRepository
-     */
-    public function injectBackendUserRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserRepository $backendUserRepository)
-    {
         $this->backendUserRepository = $backendUserRepository;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository $backendUserGroupRepository
-     */
-    public function injectBackendUserGroupRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserGroupRepository $backendUserGroupRepository)
-    {
         $this->backendUserGroupRepository = $backendUserGroupRepository;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository $backendUserSessionRepository
-     */
-    public function injectBackendUserSessionRepository(\TYPO3\CMS\Beuser\Domain\Repository\BackendUserSessionRepository $backendUserSessionRepository)
-    {
         $this->backendUserSessionRepository = $backendUserSessionRepository;
+        $this->userInformationService = $userInformationService;
     }
 
     /**
@@ -186,6 +179,18 @@ class BackendUserController extends ActionController
         ]);
     }
 
+    /**
+     * @param int $uid
+     */
+    public function showAction(int $uid = 0): void
+    {
+        $data = $this->userInformationService->get($uid);
+        $this->view->assignMultiple([
+            'shortcutLabel' => 'showUser',
+            'data' => $data
+        ]);
+    }
+
     /**
      * Compare backend users from demand
      */
@@ -196,9 +201,14 @@ class BackendUserController extends ActionController
             $this->redirect('index');
         }
 
+        $compareData = [];
+        foreach ($compareUserList as $uid) {
+            $compareData[] =  $this->userInformationService->get($uid);
+        }
+
         $this->view->assignMultiple([
             'shortcutLabel' => 'compareUsers',
-            'compareUserList' => $this->backendUserRepository->findByUidList($compareUserList),
+            'compareUserList' => $compareData
         ]);
     }
 
diff --git a/typo3/sysext/beuser/Classes/Service/UserInformationService.php b/typo3/sysext/beuser/Classes/Service/UserInformationService.php
new file mode 100644
index 000000000000..ea2e1f976e30
--- /dev/null
+++ b/typo3/sysext/beuser/Classes/Service/UserInformationService.php
@@ -0,0 +1,145 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Beuser\Service;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * 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.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Imaging\IconFactory;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Transform information of user and groups into better format
+ * @internal
+ */
+class UserInformationService
+{
+
+    /**
+     * @var IconFactory
+     */
+    protected $iconFactory;
+
+    public function __construct()
+    {
+        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
+    }
+
+    /**
+     * Get all relevant information of the user
+     *
+     * @param int $userId
+     * @return array
+     */
+    public function get(int $userId): array
+    {
+        $user = GeneralUtility::makeInstance(BackendUserAuthentication::class);
+        $user->enablecolumns = [];
+        $user->setBeUserByUid($userId);
+        $user->fetchGroupData();
+
+        // usergroups
+        $data = [
+            'user' => $user->user ?? [],
+            'groups' => [
+                'inherit' => GeneralUtility::trimExplode(',', $user->groupList, true),
+                'direct' => GeneralUtility::trimExplode(',', $user->user['usergroup'], true),
+            ],
+        ];
+        $data['groups']['diff'] = array_diff($data['groups']['inherit'], $data['groups']['direct']);
+        foreach ($data['groups'] as $type => $groups) {
+            foreach ($groups as $key => $id) {
+                $data['groups'][$type][$key] = BackendUtility::getRecord('be_groups', $id);
+            }
+        }
+
+        // languages
+        $languages = GeneralUtility::trimExplode(',', $user->dataLists['allowed_languages'], true);
+        asort($languages);
+        foreach ($languages as $language) {
+            $data['languages'][$language] = BackendUtility::getRecord('sys_language', $language);
+        }
+
+        // table permissions
+        foreach (['tables_select', 'tables_modify'] as $tableField) {
+            $temp = GeneralUtility::trimExplode(',', $user->dataLists[$tableField], true);
+            foreach ($temp as $tableName) {
+                $data['tables'][$tableField][$tableName] = $GLOBALS['TCA'][$tableName]['ctrl']['title'];
+            }
+        }
+        $data['tables']['all'] = array_replace($data['tables']['tables_select'] ?? [], $data['tables']['tables_modify'] ?? []);
+
+        // DB mounts
+        $dbMounts = GeneralUtility::trimExplode(',', $user->dataLists['webmount_list'], true);
+        asort($dbMounts);
+        foreach ($dbMounts as $mount) {
+            $record = BackendUtility::getRecord('pages', $mount, '*');
+            if ($record) {
+                $data['dbMounts'][] = $record;
+            }
+        }
+
+        // File mounts
+        $fileMounts = GeneralUtility::trimExplode(',', $user->dataLists['filemount_list'], true);
+        asort($fileMounts);
+        foreach ($fileMounts as $mount) {
+            $data['fileMounts'][] = BackendUtility::getRecord('sys_filemounts', $mount, '*');
+        }
+
+        // Modules
+        $modules = GeneralUtility::trimExplode(',', $user->dataLists['modList'], true);
+        foreach ($modules as $module) {
+            $data['modules'][$module] = $GLOBALS['TBE_MODULES']['_configuration'][$module];
+        }
+
+        // Categories
+        $categories = GeneralUtility::trimExplode(',', $user->user['category_perms'], true);
+        foreach ($categories as $category) {
+            $data['categories'][$category] = BackendUtility::getRecord('sys_category', $category);
+        }
+
+        // workspaces
+        if (ExtensionManagementUtility::isLoaded('workspaces')) {
+            $data['workspaces'] = [
+              'loaded' => true,
+              'record' => $user->workspaceRec
+            ];
+        }
+
+        // non_exclude_fields
+        $fieldListTmp = GeneralUtility::trimExplode(',', $user->dataLists['non_exclude_fields'], true);
+        $fieldList = [];
+        foreach ($fieldListTmp as $item) {
+            $split = explode(':', $item);
+            $fieldList[$split[0]]['label'] = $GLOBALS['TCA'][$split[0]]['ctrl']['title'];
+            $fieldList[$split[0]]['fields'][$split[1]] = $GLOBALS['TCA'][$split[0]]['columns'][$split[1]]['label'] ?? $split[1];
+        }
+        $data['non_exclude_fields'] = $fieldList;
+
+        $specialItems = $GLOBALS['TCA']['pages']['columns']['doktype']['config']['items'];
+        foreach ($specialItems as $specialItem) {
+            $value = $specialItem[1];
+            if (!GeneralUtility::inList($user->dataLists['pagetypes_select'], $value)) {
+                continue;
+            }
+            $label = $specialItem[0];
+            $icon = $this->iconFactory->mapRecordTypeToIconIdentifier('pages', ['doktype' => $specialItem[1]]);
+            $data['pageTypes'][] = ['label' => $label, 'value' => $value, 'icon' => $icon];
+        }
+
+        return $data;
+    }
+}
diff --git a/typo3/sysext/beuser/Classes/ViewHelpers/Display/PagesViewHelper.php b/typo3/sysext/beuser/Classes/ViewHelpers/Display/PagesViewHelper.php
deleted file mode 100644
index 56138b6b231e..000000000000
--- a/typo3/sysext/beuser/Classes/ViewHelpers/Display/PagesViewHelper.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-namespace TYPO3\CMS\Beuser\ViewHelpers\Display;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Database\Connection;
-use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
-use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
-
-/**
- * Converts comma separated list of pages uids to html unordered list (<ul>) with speaking titles
- * @internal
- */
-class PagesViewHelper extends AbstractViewHelper
-{
-    use CompileWithRenderStatic;
-
-    /**
-     * As this ViewHelper renders HTML, the output must not be escaped.
-     *
-     * @var bool
-     */
-    protected $escapeOutput = false;
-
-    /**
-     * Initializes the arguments
-     */
-    public function initializeArguments()
-    {
-        $this->registerArgument('uids', 'string', '', false, '');
-    }
-
-    /**
-     * Render unordered list for pages
-     *
-     * @param array $arguments
-     * @param \Closure $renderChildrenClosure
-     * @param RenderingContextInterface $renderingContext
-     *
-     * @return string
-     */
-    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
-    {
-        $uids = $arguments['uids'];
-        if (!$uids) {
-            return '';
-        }
-
-        $content = '';
-
-        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
-        $queryBuilder->getRestrictions()->removeAll();
-
-        $res = $queryBuilder
-            ->select('uid', 'title')
-            ->from('pages')
-            ->where(
-                $queryBuilder->expr()->in(
-                    'uid',
-                    $queryBuilder->createNamedParameter(
-                        GeneralUtility::intExplode(',', $uids),
-                        Connection::PARAM_INT_ARRAY
-                    )
-                )
-            )
-            ->orderBy('uid', 'ASC')
-            ->execute();
-
-        while ($row = $res->fetch()) {
-            $content .= '<li>' . htmlspecialchars($row['title']) . ' [' . htmlspecialchars($row['uid']) . ']</li>';
-        }
-        return '<ul>' . $content . '</ul>';
-    }
-}
diff --git a/typo3/sysext/beuser/Classes/ViewHelpers/Display/SysFileMountsViewHelper.php b/typo3/sysext/beuser/Classes/ViewHelpers/Display/SysFileMountsViewHelper.php
deleted file mode 100644
index 2faea9711066..000000000000
--- a/typo3/sysext/beuser/Classes/ViewHelpers/Display/SysFileMountsViewHelper.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-namespace TYPO3\CMS\Beuser\ViewHelpers\Display;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Database\Connection;
-use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
-use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
-
-/**
- * Converts comma separated list of sys_filemounts uids to html unordered list (<ul>) with speaking titles
- * @internal
- */
-class SysFileMountsViewHelper extends AbstractViewHelper
-{
-    use CompileWithRenderStatic;
-
-    /**
-     * As this ViewHelper renders HTML, the output must not be escaped.
-     *
-     * @var bool
-     */
-    protected $escapeOutput = false;
-
-    /**
-     * Initializes the arguments
-     */
-    public function initializeArguments()
-    {
-        $this->registerArgument('uids', 'string', '', false, '');
-    }
-
-    /**
-     * Render unordered list for sys_filemounts
-     *
-     * @param array $arguments
-     * @param \Closure $renderChildrenClosure
-     * @param RenderingContextInterface $renderingContext
-     *
-     * @return string
-     */
-    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
-    {
-        $uids = $arguments['uids'];
-        if (!$uids) {
-            return '';
-        }
-
-        $content = '';
-
-        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_filemounts');
-        $queryBuilder->getRestrictions()->removeAll();
-
-        $res = $queryBuilder
-            ->select('uid', 'title')
-            ->from('sys_filemounts')
-            ->where(
-                $queryBuilder->expr()->in(
-                    'uid',
-                    $queryBuilder->createNamedParameter(
-                        GeneralUtility::intExplode(',', $uids),
-                        Connection::PARAM_INT_ARRAY
-                    )
-                )
-            )
-            ->orderBy('title', 'ASC')
-            ->execute();
-
-        while ($row = $res->fetch()) {
-            $content .= '<li>' . htmlspecialchars($row['title']) . ' [' . htmlspecialchars($row['uid']) . ']</li>';
-        }
-        return '<ul>' . $content . '</ul>';
-    }
-}
diff --git a/typo3/sysext/beuser/Classes/ViewHelpers/Display/SysLanguageViewHelper.php b/typo3/sysext/beuser/Classes/ViewHelpers/Display/SysLanguageViewHelper.php
deleted file mode 100644
index 2cad5b3e9ffb..000000000000
--- a/typo3/sysext/beuser/Classes/ViewHelpers/Display/SysLanguageViewHelper.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-namespace TYPO3\CMS\Beuser\ViewHelpers\Display;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * 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.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Database\Connection;
-use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
-use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
-use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
-
-/**
- * Converts comma separated list of sys_language uids to html unordered list (<ul>) with speaking titles
- * @internal
- */
-class SysLanguageViewHelper extends AbstractViewHelper
-{
-    use CompileWithRenderStatic;
-
-    /**
-     * As this ViewHelper renders HTML, the output must not be escaped.
-     *
-     * @var bool
-     */
-    protected $escapeOutput = false;
-
-    /**
-     * Initializes the arguments
-     */
-    public function initializeArguments()
-    {
-        $this->registerArgument('uids', 'string', '', false, '');
-    }
-
-    /**
-     * Render unordered list for sys_language
-     *
-     * @param array $arguments
-     * @param \Closure $renderChildrenClosure
-     * @param RenderingContextInterface $renderingContext
-     *
-     * @return string
-     */
-    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
-    {
-        $uids = $arguments['uids'];
-        if (!$uids) {
-            return '';
-        }
-
-        $content = '';
-
-        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_language');
-        $queryBuilder->getRestrictions()->removeAll();
-
-        $res = $queryBuilder
-            ->select('uid', 'title', 'flag')
-            ->from('sys_language')
-            ->where(
-                $queryBuilder->expr()->in(
-                    'uid',
-                    $queryBuilder->createNamedParameter(
-                        GeneralUtility::intExplode(',', $uids),
-                        Connection::PARAM_INT_ARRAY
-                    )
-                )
-            )
-            ->orderBy('sorting')
-            ->execute();
-
-        while ($row = $res->fetch()) {
-            $content .= '<li>' . htmlspecialchars($row['title']) . ' [' . htmlspecialchars($row['uid']) . ']</li>';
-        }
-        return '<ul>' . $content . '</ul>';
-    }
-}
diff --git a/typo3/sysext/beuser/Classes/ViewHelpers/Display/TableAccessViewHelper.php b/typo3/sysext/beuser/Classes/ViewHelpers/Display/TableAccessViewHelper.php
new file mode 100644
index 000000000000..86f306c2be21
--- /dev/null
+++ b/typo3/sysext/beuser/Classes/ViewHelpers/Display/TableAccessViewHelper.php
@@ -0,0 +1,35 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Beuser\ViewHelpers\Display;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * 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.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
+
+class TableAccessViewHelper extends AbstractConditionViewHelper
+{
+    public function initializeArguments(): void
+    {
+        parent::initializeArguments();
+        $this->registerArgument('table', 'string', 'Tablename to be checked');
+        $this->registerArgument('select', 'array', 'List of allowed tables to select', false, []);
+        $this->registerArgument('modify', 'array', 'List of allowed tables to modify', false, []);
+    }
+
+    protected static function evaluateCondition($arguments = null): bool
+    {
+        $table = $arguments['table'];
+        return array_key_exists($table, $arguments['select']) || array_key_exists($table, $arguments['modify']);
+    }
+}
diff --git a/typo3/sysext/beuser/Resources/Private/Language/locallang.xlf b/typo3/sysext/beuser/Resources/Private/Language/locallang.xlf
index 35eb4452249b..40badd3844a4 100644
--- a/typo3/sysext/beuser/Resources/Private/Language/locallang.xlf
+++ b/typo3/sysext/beuser/Resources/Private/Language/locallang.xlf
@@ -174,6 +174,51 @@
 			<trans-unit id="visibility.unhide" resname="visibility.unhide">
 				<source>Un-hide</source>
 			</trans-unit>
+			<trans-unit id="information.defaultLanguage" resname="information.defaultLanguage">
+				<source>Default</source>
+			</trans-unit>
+			<trans-unit id="groups" resname="groups">
+				<source>Groups</source>
+			</trans-unit>
+			<trans-unit id="information.groups.direct" resname="information.groups.direct">
+				<source>Directly assigned</source>
+			</trans-unit>
+			<trans-unit id="information.groups.inheritance" resname="information.groups.inheritance">
+				<source>Assigned through inheritance</source>
+			</trans-unit>
+			<trans-unit id="languages" resname="languages">
+				<source>Languages</source>
+			</trans-unit>
+			<trans-unit id="dbMounts" resname="dbMounts">
+				<source>DB Mounts</source>
+			</trans-unit>
+			<trans-unit id="fileMounts" resname="fileMounts">
+				<source>File Mounts</source>
+			</trans-unit>
+			<trans-unit id="categories" resname="categories">
+				<source>Categories</source>
+			</trans-unit>
+			<trans-unit id="permissions" resname="permissions">
+				<source>Permissions</source>
+			</trans-unit>
+			<trans-unit id="modules" resname="modules">
+				<source>Modules</source>
+			</trans-unit>
+			<trans-unit id="tableModes" resname="tableModes">
+				<source>Table select/modify</source>
+			</trans-unit>
+			<trans-unit id="tableModes.select" resname="tableModes.select">
+				<source>Select</source>
+			</trans-unit>
+			<trans-unit id="tableModes.modify" resname="tableModes.modify">
+				<source>Modify</source>
+			</trans-unit>
+			<trans-unit id="information.defaultWorkspace" resname="information.defaultWorkspace">
+				<source>Default workspace</source>
+			</trans-unit>
+			<trans-unit id="backendUser" resname="backendUser">
+				<source>Backend User</source>
+			</trans-unit>
 		</body>
 	</file>
 </xliff>
diff --git a/typo3/sysext/beuser/Resources/Private/Partials/BackendUser/IndexListRow.html b/typo3/sysext/beuser/Resources/Private/Partials/BackendUser/IndexListRow.html
index 3ea508cfea32..047966345a4c 100644
--- a/typo3/sysext/beuser/Resources/Private/Partials/BackendUser/IndexListRow.html
+++ b/typo3/sysext/beuser/Resources/Private/Partials/BackendUser/IndexListRow.html
@@ -71,6 +71,9 @@
             </f:if>
         </div>
         <div class="btn-group" role="group">
+            <f:link.action action="show" arguments="{uid: backendUser.uid}" class="btn btn-default" title="{f:translate(key: 'details')}">
+                <core:icon identifier="actions-system-options-view" size="small"/>
+            </f:link.action>
             <a class="btn btn-default" href="#" title="{f:translate(key:'info')}" onclick="top.TYPO3.InfoWindow.showItem('be_users', '{backendUser.uid}'); return false;"><core:icon identifier="actions-document-info" /></a>
         </div>
         <div class="btn-group" role="group">
diff --git a/typo3/sysext/beuser/Resources/Private/Partials/BackendUser/Information.html b/typo3/sysext/beuser/Resources/Private/Partials/BackendUser/Information.html
new file mode 100644
index 000000000000..8a299e7f876d
--- /dev/null
+++ b/typo3/sysext/beuser/Resources/Private/Partials/BackendUser/Information.html
@@ -0,0 +1,126 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers" xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers" xmlns:bu="http://typo3.org/ns/TYPO3/CMS/Beuser/ViewHelpers">
+
+<f:section name="languages">
+    <ul>
+        <f:for each="{languages}" key="languageUid" as="language">
+            <li>
+                <f:if condition="{languageUid} ==0">
+                    <f:then>
+                        <f:translate key="information.defaultLanguage" />
+                    </f:then>
+                    <f:else>
+                        <a href="#" class="t3js-contextmenutrigger" data-table="sys_language" data-uid="{language.uid}" title="id={language.uid}">
+                            <core:iconForRecord table="sys_language" row="{language}"/>
+                            {language.title} [{language.uid}]
+                        </a>
+                    </f:else>
+                </f:if>
+            </li>
+        </f:for>
+    </ul>
+</f:section>
+
+<f:section name="groups">
+    <f:if condition="{groups.direct}">
+        <strong><f:translate key="information.groups.direct" /></strong>
+
+        <f:for each="{groups.direct}" as="group">
+            <div>
+                <a href="#" class="t3js-contextmenutrigger" data-table="be_groups" data-uid="{group.uid}" title="id={group.uid}">
+                    <core:iconForRecord table="be_groups" row="{group}"/>
+                    {group.title}
+                </a>
+            </div>
+        </f:for>
+    </f:if>
+    <f:if condition="{groups.diff}">
+        <strong><f:translate key="information.groups.inheritance" /></strong>
+
+        <f:for each="{groups.diff}" as="group">
+            <div>
+                <a href="#" class="t3js-contextmenutrigger" data-table="be_groups" data-uid="{group.uid}" title="id={group.uid}">
+                    <core:iconForRecord table="be_groups" row="{group}"/>
+                    {group.title}
+                </a>
+            </div>
+        </f:for>
+    </f:if>
+</f:section>
+
+<f:section name="dbMounts">
+    <f:if condition="{dbMounts}">
+        <ul>
+            <f:for each="{dbMounts}" as="mount">
+                <li>
+                    <core:iconForRecord table="pages" row="{mount}"/>
+                    {mount.title} [{mount.uid}]
+                </li>
+            </f:for>
+        </ul>
+    </f:if>
+</f:section>
+
+<f:section name="fileMounts">
+    <f:if condition="{fileMounts}">
+        <ul>
+            <f:for each="{fileMounts}" as="mount">
+                <li>
+                    <a href="#" class="t3js-contextmenutrigger" data-table="sys_filemounts" data-uid="{mount.uid}" title="id={mount.uid}">
+                        <core:iconForRecord table="sys_filemounts" row="{mount}"/>
+                        {mount.title} [{mount.uid}]
+                    </a>
+                </li>
+            </f:for>
+        </ul>
+    </f:if>
+</f:section>
+
+<f:section name="categories">
+    <f:if condition="{categories}">
+        <ul>
+            <f:for each="{categories}" as="category">
+                <li>
+                    <a href="#" class="t3js-contextmenutrigger" data-table="sys_category" data-uid="{category.uid}" title="id={category.uid}">
+                        <core:iconForRecord table="sys_category" row="{category}"/>
+                        {category.title}
+                    </a>
+                </li>
+            </f:for>
+        </ul>
+    </f:if>
+</f:section>
+
+<f:section name="workspaces">
+    <f:if condition="{workspaces}">
+        <f:if condition="{workspaces.record.uid}">
+            <strong><f:translate key="information.defaultWorkspace" />:</strong>
+            <a href="#" class="t3js-contextmenutrigger" data-table="sys_workspace" data-uid="{workspaces.record.uid}" title="id={workspaces.record.uid}">
+                <core:iconForRecord table="sys_workspaces" row="{workspaces.record}"/>
+                {workspaces.record.title}
+            </a>
+        </f:if>
+    </f:if>
+</f:section>
+
+<f:section name="pageTypes">
+    <f:if condition="{pageTypes}">
+        <ul>
+            <f:for each="{pageTypes}" as="pageType">
+                <li>
+                    <core:icon identifier="{pageType.icon}"/>
+                    {f:translate(key:pageType.label,default:pageType.label)}
+                </li>
+            </f:for>
+        </ul>
+    </f:if>
+</f:section>
+
+
+<f:section name="yesno">
+    <f:if condition="{value}">
+        <f:then><span class="t3-icon change-permission fa fa-check text-success"></span>{f:translate(key:'yes')}</f:then>
+        <f:else><span class="t3-icon change-permission fa fa-times text-danger"></span>{f:translate(key:'no')}</f:else>
+    </f:if>
+</f:section>
+
+</html>
diff --git a/typo3/sysext/beuser/Resources/Private/Templates/BackendUser/Compare.html b/typo3/sysext/beuser/Resources/Private/Templates/BackendUser/Compare.html
index a318e503c5fa..4cfc6fbd955d 100644
--- a/typo3/sysext/beuser/Resources/Private/Templates/BackendUser/Compare.html
+++ b/typo3/sysext/beuser/Resources/Private/Templates/BackendUser/Compare.html
@@ -14,19 +14,19 @@
 </f:section>
 
 <f:section name="Content">
-    <h1><f:translate key="compareBackendUsers">Compare backend users</f:translate></h1>
+    <h1>{f:translate(key:'compareBackendUsers')}</h1>
     <div class="table-fit">
-        <table border="0" cellpadding="0" cellspacing="0" id="tx_beuser_compare" class="table table-striped table-bordered table-hover">
+        <table id="tx_beuser_compare" class="table table-striped table-bordered table-hover">
             <thead>
                 <tr>
                     <th></th>
                     <f:for each="{compareUserList}" as="compareUser">
                         <th>
-                            <a href="#" class="t3js-contextmenutrigger" data-table="be_users" data-uid="{compareUser.uid}" title="id={compareUser.uid}">
-                                <be:avatar backendUser="{compareUser.uid}" showIcon="true" />
+                            <a href="#" class="t3js-contextmenutrigger" data-table="be_users" data-uid="{compareUser.user.uid}" title="id={compareUser.user.uid}">
+                                <be:avatar backendUser="{compareUser.user.uid}" showIcon="true" />
                             </a>
-                            {compareUser.userName}
-                                <be:link.editRecord class="btn btn-default pull-right" table="be_users" uid="{compareUser.uid}" title="edit">
+                            {compareUser.user.username}
+                                <be:link.editRecord class="btn btn-default pull-right" table="be_users" uid="{compareUser.user.uid}" title="edit">
                                 <core:icon identifier="actions-open" />
                                 </be:link.editRecord>
                         </th>
@@ -37,20 +37,10 @@
                 <tr>
                     <th><f:translate key="realName" /></th>
                     <f:for each="{compareUserList}" as="compareUser">
-                        <td>{compareUser.realName}</td>
-                    </f:for>
-                </tr>
-                <tr>
-                    <th><f:translate key="email" /></th>
-                    <f:for each="{compareUserList}" as="compareUser">
-                        <td>
-                            <f:if condition="{compareUser.email}">
-                                <f:then>
-                                    <f:link.email email="{compareUser.email}" />
-                                </f:then>
-                                <f:else>
-                                    -
-                                </f:else>
+                        <td>{compareUser.user.realName}
+
+                            <f:if condition="{compareUser.user.email}">
+                                (<f:link.email email="{compareUser.user.email}" />)
                             </f:if>
                         </td>
                     </f:for>
@@ -59,10 +49,7 @@
                     <th><f:translate key="admin" /></th>
                     <f:for each="{compareUserList}" as="compareUser">
                         <td>
-                            <f:if condition="{compareUser.isAdministrator}">
-                                <f:then><f:translate key="yes" /></f:then>
-                                <f:else><f:translate key="no" /></f:else>
-                            </f:if>
+                            <f:render partial="BackendUser/Information" section="yesno" arguments="{value:compareUser.user.admin}" />
                         </td>
                     </f:for>
                 </tr>
@@ -70,19 +57,17 @@
                     <th><f:translate key="disable_compare" /></th>
                     <f:for each="{compareUserList}" as="compareUser">
                         <td>
-                            <f:if condition="{compareUser.currentlyLoggedIn} == 0">
-                                <f:if condition="{compareUser.isDisabled} == 1">
-                                    <f:then>
-                                        <a class="btn btn-default" href="{be:moduleLink(route:'tce_db', query:'data[be_users][{compareUser.uid}][disable]=0', currentUrlParameterName:'redirect')}" title="{f:translate(key: 'visibility.unhide')}">
-                                            <core:icon identifier="actions-edit-unhide" />
-                                        </a>
-                                    </f:then>
-                                    <f:else>
-                                        <a class="btn btn-default" href="{be:moduleLink(route:'tce_db', query:'data[be_users][{compareUser.uid}][disable]=1', currentUrlParameterName:'redirect')}" title="{f:translate(key: 'visibility.hide')}">
-                                            <core:icon identifier="actions-edit-hide" />
-                                        </a>
-                                    </f:else>
-                                </f:if>
+                            <f:if condition="{compareUser.disable}">
+                                <f:then>
+                                    <a class="btn btn-default" href="{be:moduleLink(route:'tce_db', query:'data[be_users][{compareUser.user.uid}][disable]=0', currentUrlParameterName:'redirect')}" title="{f:translate(key: 'visibility.unhide')}">
+                                        <core:icon identifier="actions-edit-unhide" />
+                                    </a>
+                                </f:then>
+                                <f:else>
+                                    <a class="btn btn-default" href="{be:moduleLink(route:'tce_db', query:'data[be_users][{compareUser.user.uid}][disable]=1', currentUrlParameterName:'redirect')}" title="{f:translate(key: 'visibility.hide')}">
+                                        <core:icon identifier="actions-edit-hide" />
+                                    </a>
+                                </f:else>
                             </f:if>
                         </td>
                     </f:for>
@@ -91,9 +76,9 @@
                     <th><f:translate key="startDateAndTime" /></th>
                     <f:for each="{compareUserList}" as="compareUser">
                         <td>
-                            <f:if condition="{compareUser.startDateAndTime}">
+                            <f:if condition="{compareUser.user.starttime}">
                                 <f:then>
-                                    <f:format.date format="{dateFormat} {timeFormat}">{compareUser.startDateAndTime}</f:format.date>
+                                    <f:format.date format="{dateFormat} {timeFormat}">{compareUser.user.starttime}</f:format.date>
                                 </f:then>
                                 <f:else>
                                     -
@@ -106,9 +91,9 @@
                     <th><f:translate key="endDateAndTime" /></th>
                     <f:for each="{compareUserList}" as="compareUser">
                         <td>
-                            <f:if condition="{compareUser.endDateAndTime}">
+                            <f:if condition="{compareUser.user.endtime}">
                                 <f:then>
-                                    <f:format.date format="{dateFormat} {timeFormat}">{compareUser.endDateAndTime}</f:format.date>
+                                    <f:format.date format="{dateFormat} {timeFormat}">{compareUser.user.endtime}</f:format.date>
                                 </f:then>
                                 <f:else>
                                     -
@@ -121,9 +106,9 @@
                     <th><f:translate key="lastLogin" /></th>
                     <f:for each="{compareUserList}" as="compareUser">
                         <td>
-                            <f:if condition="{compareUser.lastLoginDateAndTime}">
+                            <f:if condition="{compareUser.user.lastlogin}">
                                 <f:then>
-                                    <f:format.date format="{dateFormat} {timeFormat}">{compareUser.lastLoginDateAndTime}</f:format.date>
+                                    <f:format.date format="{dateFormat} {timeFormat}">{compareUser.user.lastlogin}</f:format.date>
                                 </f:then>
                                 <f:else>
                                     <f:translate key="never" />
@@ -136,12 +121,8 @@
                     <th><f:translate key="backendUserGroups" /></th>
                     <f:for each="{compareUserList}" as="compareUser">
                         <td>
-                            <f:for each="{compareUser.BackendUserGroups}" as="backendUserGroup">
-                                <a href="#" class="t3js-contextmenutrigger" data-table="be_groups" data-uid="{backendUserGroup.uid}" title="id={backendUserGroup.uid}">
-                                    <bu:spriteIconForRecord table="be_users" object="{backendUserGroup}" />
-                                </a>
-                                {backendUserGroup.title}<br />
-                            </f:for>
+                            <f:render partial="BackendUser/Information" section="groups" arguments="{groups:compareUser.groups}" />
+
                         </td>
                     </f:for>
                 </tr>
@@ -149,14 +130,7 @@
                     <th><f:translate key="allowedLanguages" /></th>
                     <f:for each="{compareUserList}" as="compareUser">
                         <td>
-                            <f:if condition="{compareUser.allowedLanguages}">
-                                <f:then>
-                                    <bu:display.sysLanguage uids="{compareUser.allowedLanguages}" />
-                                </f:then>
-                                <f:else>
-                                    -
-                                </f:else>
-                            </f:if>
+                            <f:render partial="BackendUser/Information" section="languages" arguments="{languages:compareUser.languages}" />
                         </td>
                     </f:for>
                 </tr>
@@ -164,14 +138,7 @@
                     <th><f:translate key="dbMountPoints" /></th>
                     <f:for each="{compareUserList}" as="compareUser">
                         <td>
-                            <f:if condition="{compareUser.dbMountPoints}">
-                                <f:then>
-                                    <bu:display.pages uids="{compareUser.dbMountPoints}" />
-                                </f:then>
-                                <f:else>
-                                    -
-                                </f:else>
-                            </f:if>
+                            <f:render partial="BackendUser/Information" section="dbMounts" arguments="{dbMounts:compareUser.dbMounts}" />
                         </td>
                     </f:for>
                 </tr>
@@ -179,25 +146,41 @@
                     <th><f:translate key="fileMounts" /></th>
                     <f:for each="{compareUserList}" as="compareUser">
                         <td>
-                            <f:if condition="{compareUser.fileMountPoints}">
-                                <f:then>
-                                    <bu:display.sysFileMounts uids="{compareUser.fileMountPoints}" />
-                                </f:then>
-                                <f:else>
-                                    -
-                                </f:else>
-                            </f:if>
+                            <f:render partial="BackendUser/Information" section="fileMounts" arguments="{fileMounts:compareUser.fileMounts}" />
+                        </td>
+                    </f:for>
+                </tr>
+                <tr>
+                    <th>Page types</th>
+                    <f:for each="{compareUserList}" as="compareUser">
+                        <td>
+                            <f:render partial="BackendUser/Information" section="pageTypes" arguments="{pageTypes:compareUser.pageTypes}" />
+                        </td>
+                    </f:for>
+                </tr>
+                <tr>
+                    <th>Categories</th>
+                    <f:for each="{compareUserList}" as="compareUser">
+                        <td>
+                            <f:render partial="BackendUser/Information" section="categories" arguments="{categories:compareUser.categories}"/>
                         </td>
                     </f:for>
                 </tr>
+                <f:if condition="{compareUserList.0.workspaces}">
+                    <tr>
+                        <th>Workspaces</th>
+                        <f:for each="{compareUserList}" as="compareUser">
+                            <td>
+                                <f:render partial="BackendUser/Information" section="workspaces" arguments="{workspaces:compareUser.workspaces}"/>
+                            </td>
+                        </f:for>
+                    </tr>
+                </f:if>
                 <tr>
                     <th><f:translate key="disableIpLock" /></th>
                     <f:for each="{compareUserList}" as="compareUser">
                         <td>
-                            <f:if condition="{compareUser.ipLockIsDisabled} == 1">
-                                <f:then><f:translate key="yes" /></f:then>
-                                <f:else><f:translate key="no" /></f:else>
-                            </f:if>
+                            <f:render partial="BackendUser/Information" section="yesno" arguments="{value:compareUser.user.disableIPlock}" />
                         </td>
                     </f:for>
                 </tr>
diff --git a/typo3/sysext/beuser/Resources/Private/Templates/BackendUser/Show.html b/typo3/sysext/beuser/Resources/Private/Templates/BackendUser/Show.html
new file mode 100644
index 000000000000..fe4e33b1000c
--- /dev/null
+++ b/typo3/sysext/beuser/Resources/Private/Templates/BackendUser/Show.html
@@ -0,0 +1,169 @@
+<html
+    xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
+    xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers"
+    xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers"
+    xmlns:bu="http://typo3.org/ns/TYPO3/CMS/Beuser/ViewHelpers"
+    data-namespace-typo3-fluid="true">
+
+<f:layout name="Default"/>
+
+<f:section name="Buttons">
+    <be:moduleLayout.button.linkButton
+        icon="actions-add"
+        title="{f:translate(id: 'LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newRecordGeneral')}"
+        link="{be:uri.newRecord(table: 'be_users')}"
+    />
+</f:section>
+
+<f:section name="Content">
+    <h1><f:translate key="backendUser" />: {data.user.username} [{data.user.uid}]</h1>
+
+    <f:if condition="{data.user.description}">
+        <f:be.infobox
+            title="{f:translate(key:'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.recordInformation')}">
+            {data.user.description -> f:format.nl2br()}
+        </f:be.infobox>
+    </f:if>
+
+    <table class="table table-striped table-bordered table-hover">
+        <tr>
+            <th>{f:translate(key:'realName')}</th>
+            <td>
+                <a href="#" class="t3js-contextmenutrigger" data-table="be_users" data-uid="{data.user.uid}" title="id={data.user.uid}">
+                    <be:avatar backendUser="{data.user.uid}" showIcon="true"/>
+                </a>
+                {data.user.userName}
+                <be:link.editRecord class="btn btn-default pull-right" table="be_users" uid="{data.user.uid}"
+                                    title="edit">
+                    <core:icon identifier="actions-open"/>
+                </be:link.editRecord>
+            </td>
+        </tr>
+        <tr>
+            <th>{f:translate(key:'email')}</th>
+            <td>
+                <f:if condition="{data.user.email}">
+                    <f:link.email email="{data.user.email}"/>
+                </f:if>
+            </td>
+        </tr>
+        <tr>
+            <th>{f:translate(key:'startDateAndTime')}</th>
+            <td>
+                <f:if condition="{data.user.starttime}">
+                    <f:format.date format="{dateFormat} {timeFormat}">{data.user.starttime}</f:format.date>
+                </f:if>
+            </td>
+        </tr>
+    </table>
+
+    <div class="row">
+        <div class="col-md-4">
+            <h4><f:translate key="groups" /></h4>
+            <f:render partial="BackendUser/Information" section="groups" arguments="{groups:data.groups}"/>
+        </div>
+        <div class="col-md-4">
+            <h4><f:translate key="languages" /></h4>
+            <f:render partial="BackendUser/Information" section="languages" arguments="{languages:data.languages}"/>
+        </div>
+        <div class="col-md-4">
+
+            <h4><f:translate key="dbMounts" /></h4>
+            <f:render partial="BackendUser/Information" section="dbMounts" arguments="{dbMounts:data.dbMounts}"/>
+
+            <h4><f:translate key="fileMounts" /></h4>
+            <f:render partial="BackendUser/Information" section="fileMounts" arguments="{fileMounts:data.fileMounts}"/>
+
+            <h4><f:translate key="categories" /></h4>
+            <f:render partial="BackendUser/Information" section="categories" arguments="{categories:data.categories}"/>
+        </div>
+    </div>
+
+
+    <div class="row">
+        <div class="col-md-6">
+            <h2><f:translate key="permissions" /></h2>
+            <table class="table table-striped table-bordered table-hover">
+                <thead>
+                <tr>
+                    <th><f:translate key="modules" /></th>
+                </tr>
+                </thead>
+                <tbody>
+                <f:for each="{data.modules}" as="module">
+                    <tr>
+                        <td>
+                            <core:icon identifier="{module.iconIdentifier}"></core:icon>
+                            {f:translate(key:'{module.labels}:mlang_tabs_tab')} <code>{module.name}</code>
+                        </td>
+                    </tr>
+                </f:for>
+                </tbody>
+            </table>
+            <table class="table table-striped table-bordered table-hover">
+                <thead>
+                <tr>
+                    <th><f:translate key="tableModes" /></th>
+                    <th class="text-center"><f:translate key="tableModes.select" /></th>
+                    <th class="text-center"><f:translate key="tableModes.modify" /></th>
+                </tr>
+                </thead>
+                <tbody>
+                <f:for each="{data.tables.all}" key="table" as="label">
+                    <tr>
+                        <td>
+                            <f:if condition="{label}">
+                                <f:then>
+                                    {f:translate(key:label)}<code>{table}</code>
+                                </f:then>
+                                <f:else>
+                                    <code>{table}</code>
+                                </f:else>
+                            </f:if>
+                        </td>
+                        <td class="text-center">
+                            <bu:display.tableAccess table="{table}" select="{data.tables.tables_select}">
+                                <f:then><span class="t3-icon change-permission fa fa-check text-success"></span>
+                                </f:then>
+                                <f:else><span class="t3-icon change-permission fa fa-times text-danger"></span></f:else>
+                            </bu:display.tableAccess>
+                        </td>
+                        <td class="text-center">
+                            <bu:display.tableAccess table="{table}" select="{data.tables.tables_select}"
+                                                    modify="{data.tables.tables_modify}">
+                                <f:then><span class="t3-icon change-permission fa fa-check text-success"></span>
+                                </f:then>
+                                <f:else><span class="t3-icon change-permission fa fa-times text-danger"></span></f:else>
+                            </bu:display.tableAccess>
+                        </td>
+                    </tr>
+                </f:for>
+                </tbody>
+            </table>
+        </div>
+        <div class="col-md-6">
+            <h3>ACL</h3>
+            <f:for each="{data.non_exclude_fields}" key="tableName" as="table">
+                <table class="table table-striped table-bordered table-hover">
+                    <thead>
+                    <tr>
+                        <th>{f:translate(key:table.label)} <code>{tableName}</code></th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <f:for each="{table.fields}" as="label" key="field">
+                        <tr>
+                            <td>
+                                {f:translate(key:label)}
+                                <code>{field}</code>
+                            </td>
+                        </tr>
+                    </f:for>
+                    </tbody>
+                </table>
+            </f:for>
+        </div>
+    </div>
+</f:section>
+
+</html>
diff --git a/typo3/sysext/beuser/ext_tables.php b/typo3/sysext/beuser/ext_tables.php
index ebffebde1d9c..b66597199104 100644
--- a/typo3/sysext/beuser/ext_tables.php
+++ b/typo3/sysext/beuser/ext_tables.php
@@ -8,7 +8,7 @@ defined('TYPO3_MODE') or die();
     'tx_Beuser',
     'top',
     [
-        \TYPO3\CMS\Beuser\Controller\BackendUserController::class => 'index, addToCompareList, removeFromCompareList, compare, online, terminateBackendUserSession',
+        \TYPO3\CMS\Beuser\Controller\BackendUserController::class => 'index, show, addToCompareList, removeFromCompareList, compare, online, terminateBackendUserSession',
         \TYPO3\CMS\Beuser\Controller\BackendUserGroupController::class => 'index'
     ],
     [
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-90298-ImproveUserInfoInBeuserModule.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-90298-ImproveUserInfoInBeuserModule.rst
new file mode 100644
index 000000000000..09b0b1bcf9cd
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-90298-ImproveUserInfoInBeuserModule.rst
@@ -0,0 +1,27 @@
+.. include:: ../../Includes.txt
+
+=====================================================
+Feature: #90298 - Improve user info in BE User module
+=====================================================
+
+See :issue:`90298`
+
+Description
+===========
+
+The *Backend users* module has been improved by showing more details of TYPO3
+Administrators and Editors:
+
+- All assigned groups, including subgroups, are now evaluated
+- All data which can be set in the backend user or a assigned group are now shown including allowed page types, read & write access to tables
+- A new "detail view" for a TYPO3 Backend user has been added
+
+
+Impact
+======
+
+Comparing users is more powerful now. It is now easier for TYPO3 Administrators
+to check backend user permissions without the need to switch to the actual user
+and test the behaviour.
+
+.. index:: Backend, ext:beuser
-- 
GitLab