From 8fcd3b444f1fb7343939b69d6c215bb83dbb4614 Mon Sep 17 00:00:00 2001
From: Andreas Fernandez <a.fernandez@scripting-base.de>
Date: Tue, 28 Mar 2017 22:53:14 +0200
Subject: [PATCH] =?UTF-8?q?[FEATURE]=20Store=20recent=20su=E2=80=99ed=20us?=
 =?UTF-8?q?ers=20and=20render=20quicklinks=20in=20user=20menu?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When a backend user with admin privileges switches to another user, the
entered user is now stored in the uc. The users stored in this list will
be rendered into the user menu to allow quick switching to the recent
users.

Resolves: #80581
Releases: master
Change-Id: I1a2128828d994f9de221d1615ded10683f4ce790
Reviewed-on: https://review.typo3.org/52225
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Henrik Elsner <helsner@dfau.de>
Tested-by: Henrik Elsner <helsner@dfau.de>
Reviewed-by: Tymoteusz Motylewski <t.motylewski@gmail.com>
Tested-by: Tymoteusz Motylewski <t.motylewski@gmail.com>
---
 .../Backend/ToolbarItems/UserToolbarItem.php  | 24 +++++++
 .../Resources/Private/Language/locallang.xlf  |  6 ++
 .../ToolbarItems/UserToolbarItemDropDown.html | 29 +++++++-
 .../Controller/BackendUserController.php      | 33 ++++++++++
 .../Controller/BackendUserControllerTest.php  | 66 +++++++++++++++++++
 ...rListOfRecentlyUsersThatWereSwitchedTo.rst | 21 ++++++
 6 files changed, 177 insertions(+), 2 deletions(-)
 create mode 100644 typo3/sysext/beuser/Tests/Unit/Controller/BackendUserControllerTest.php
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-80581-RenderListOfRecentlyUsersThatWereSwitchedTo.rst

diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php
index 4783beb300e9..0a4c44fb580b 100644
--- a/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
 use TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository;
 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
 
@@ -58,13 +59,36 @@ class UserToolbarItem implements ToolbarItemInterface
      */
     public function getDropDown()
     {
+        $backendUser = $this->getBackendUser();
+
         /** @var BackendModuleRepository $backendModuleRepository */
         $backendModuleRepository = GeneralUtility::makeInstance(BackendModuleRepository::class);
+
+        $mostRecentUsers = [];
+        if (ExtensionManagementUtility::isLoaded('beuser')
+            && $backendUser->isAdmin()
+            && (int)$backendUser->user['ses_backuserid'] === 0
+            && isset($backendUser->uc['recentSwitchedToUsers'])
+            && is_array($backendUser->uc['recentSwitchedToUsers'])
+        ) {
+            foreach ($backendUser->uc['recentSwitchedToUsers'] as $userUid) {
+                $backendUserRecord = BackendUtility::getRecord('be_users', $userUid);
+                $backendUserRecord['switchUserLink'] = BackendUtility::getModuleUrl(
+                    'system_BeuserTxBeuser',
+                        [
+                            'SwitchUser' => $backendUserRecord['uid']
+                        ]
+                );
+                $mostRecentUsers[] = $backendUserRecord;
+            }
+        }
+
         $view = $this->getFluidTemplateObject('UserToolbarItemDropDown.html');
         $view->assignMultiple([
             'modules' => $backendModuleRepository->findByModuleName('user')->getChildren(),
             'logoutUrl' => BackendUtility::getModuleUrl('logout'),
             'switchUserMode' => $this->getBackendUser()->user['ses_backuserid'],
+            'recentUsers' => $mostRecentUsers,
         ]);
         return $view->render();
     }
diff --git a/typo3/sysext/backend/Resources/Private/Language/locallang.xlf b/typo3/sysext/backend/Resources/Private/Language/locallang.xlf
index 5387089f5e1b..98dc8f1aee31 100644
--- a/typo3/sysext/backend/Resources/Private/Language/locallang.xlf
+++ b/typo3/sysext/backend/Resources/Private/Language/locallang.xlf
@@ -19,6 +19,12 @@
 				<source>Your system is fully operational.
 Have a nice day.</source>
 			</trans-unit>
+			<trans-unit id="usermodule.su.list">
+				<source>Recently 'switched to' users</source>
+			</trans-unit>
+			<trans-unit id="usermodule.su.tooltip">
+				<source>Switch to user %s</source>
+			</trans-unit>
 			<trans-unit id="config.loginLogo">
 				<source>Logo: If set, this logo will be used instead of the TYPO3 logo above the login credential fields (e.g. fileadmin/images/login-logo.png or EXT:my_theme/Resources/Public/Images/login-logo.png or //domain.tld/login-logo.png)</source>
 			</trans-unit>
diff --git a/typo3/sysext/backend/Resources/Private/Templates/ToolbarItems/UserToolbarItemDropDown.html b/typo3/sysext/backend/Resources/Private/Templates/ToolbarItems/UserToolbarItemDropDown.html
index 475be8c2b1d5..c7e28c39b27d 100644
--- a/typo3/sysext/backend/Resources/Private/Templates/ToolbarItems/UserToolbarItemDropDown.html
+++ b/typo3/sysext/backend/Resources/Private/Templates/ToolbarItems/UserToolbarItemDropDown.html
@@ -1,4 +1,4 @@
-<html xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers" data-namespace-typo3-fluid="true">
+<html xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers" xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers" data-namespace-typo3-fluid="true">
 <h3 class="dropdown-headline">
 	{f:translate(key: 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.user')}
 </h3>
@@ -24,6 +24,31 @@
 	</div>
 	<hr>
 </f:if>
+<f:if condition="{f:count(subject: recentUsers)} > 0">
+	<h3 class="dropdown-headline"><f:translate key="usermodule.su.list" /></h3>
+	<div class="dropdown-table">
+		<f:for each="{recentUsers}" as="user">
+			<div class="dropdown-table-row">
+				<div class="dropdown-table-column dropdown-table-icon">
+					<be:avatar backendUser="{user.uid}" size="32" />
+				</div>
+				<div class="dropdown-table-column dropdown-table-title">
+					<a href="{user.switchUserLink}" title="{f:translate(key: 'usermodule.su.tooltip', arguments: {0: user.username})}">
+						<f:if condition="{user.realName}">
+							<f:then>
+								{user.realName}
+							</f:then>
+							<f:else>
+								{user.username}
+							</f:else>
+						</f:if>
+					</a>
+				</div>
+			</div>
+		</f:for>
+	</div>
+	<hr>
+</f:if>
 <a href="{logoutUrl}" class="btn btn-danger pull-left" target="_top">
 	<core:icon identifier="actions-logout" size="small" alternativeMarkupIdentifier="inline"/>
 	<f:if condition="{switchUserMode}">
@@ -35,4 +60,4 @@
 		</f:else>
 	</f:if>
 </a>
-</html>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/beuser/Classes/Controller/BackendUserController.php b/typo3/sysext/beuser/Classes/Controller/BackendUserController.php
index 56c1793d8e5c..1a6a4fd0f8a9 100644
--- a/typo3/sysext/beuser/Classes/Controller/BackendUserController.php
+++ b/typo3/sysext/beuser/Classes/Controller/BackendUserController.php
@@ -27,6 +27,11 @@ use TYPO3\CMS\Lang\LanguageService;
  */
 class BackendUserController extends BackendUserActionController
 {
+    /**
+     * @var int
+     */
+    const RECENT_USERS_LIMIT = 3;
+
     /**
      * @var \TYPO3\CMS\Beuser\Domain\Model\ModuleData
      */
@@ -243,6 +248,7 @@ class BackendUserController extends BackendUserActionController
         if (is_array($targetUser) && $this->getBackendUserAuthentication()->isAdmin()) {
             // Set backend user listing module as starting module for switchback
             $this->getBackendUserAuthentication()->uc['startModuleOnFirstLogin'] = 'system_BeuserTxBeuser';
+            $this->getBackendUserAuthentication()->uc['recentSwitchedToUsers'] = $this->generateListOfMostRecentSwitchedUsers($targetUser['uid']);
             $this->getBackendUserAuthentication()->writeUC();
 
             $sessionBackend = $this->getSessionBackend();
@@ -259,6 +265,33 @@ class BackendUserController extends BackendUserActionController
         }
     }
 
+    /**
+     * Generates a list of users to whom where switched in the past. This is limited by RECENT_USERS_LIMIT.
+     *
+     * @param int $targetUserUid
+     * @return int[]
+     */
+    protected function generateListOfMostRecentSwitchedUsers(int $targetUserUid): array
+    {
+        $latestUserUids = [];
+        $backendUser = $this->getBackendUserAuthentication();
+
+        if (isset($backendUser->uc['recentSwitchedToUsers']) && is_array($backendUser->uc['recentSwitchedToUsers'])) {
+            $latestUserUids = $backendUser->uc['recentSwitchedToUsers'];
+        }
+
+        // Remove potentially existing user in that list
+        $index = array_search($targetUserUid, $latestUserUids, true);
+        if ($index !== false) {
+            unset($latestUserUids[$index]);
+        }
+
+        array_unshift($latestUserUids, $targetUserUid);
+        $latestUserUids = array_slice($latestUserUids, 0, static::RECENT_USERS_LIMIT);
+
+        return $latestUserUids;
+    }
+
     /**
      * @return BackendUserAuthentication
      */
diff --git a/typo3/sysext/beuser/Tests/Unit/Controller/BackendUserControllerTest.php b/typo3/sysext/beuser/Tests/Unit/Controller/BackendUserControllerTest.php
new file mode 100644
index 000000000000..aa62f8c42fa8
--- /dev/null
+++ b/typo3/sysext/beuser/Tests/Unit/Controller/BackendUserControllerTest.php
@@ -0,0 +1,66 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Beuser\Tests\Unit\Controller;
+
+/*
+ * 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\Beuser\Controller\BackendUserController;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+
+/**
+ * Test case
+ */
+class BackendUserControllerTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
+{
+    /**
+     * @var BackendUserController|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface
+     */
+    protected $subject;
+
+    protected function setUp()
+    {
+        $GLOBALS['BE_USER'] = $this->createMock(BackendUserAuthentication::class);
+        $GLOBALS['BE_USER']->uc = [
+            'recentSwitchedToUsers' => []
+        ];
+
+        $this->subject = $this->getAccessibleMock(BackendUserController::class, ['dummy'], [], '', false);
+    }
+
+    /**
+     * @test
+     */
+    public function generateListOfLatestSwitchedUsersReturnsCorrectAmountAndOrder()
+    {
+        $items = range(1, BackendUserController::RECENT_USERS_LIMIT + 5);
+        $expected = array_reverse(array_slice($items, -BackendUserController::RECENT_USERS_LIMIT));
+        foreach ($items as $id) {
+            $GLOBALS['BE_USER']->uc['recentSwitchedToUsers'] = $this->subject->_call('generateListOfMostRecentSwitchedUsers', $id);
+        }
+
+        static::assertCount(BackendUserController::RECENT_USERS_LIMIT, $GLOBALS['BE_USER']->uc['recentSwitchedToUsers']);
+        static::assertSame($expected, $GLOBALS['BE_USER']->uc['recentSwitchedToUsers']);
+    }
+
+    /**
+     * @test
+     */
+    public function listOfLatestSwitchedUsersDoesNotContainTheSameUserTwice()
+    {
+        $GLOBALS['BE_USER']->uc['recentSwitchedToUsers'] = $this->subject->_call('generateListOfMostRecentSwitchedUsers', 100);
+        $GLOBALS['BE_USER']->uc['recentSwitchedToUsers'] = $this->subject->_call('generateListOfMostRecentSwitchedUsers', 100);
+
+        static::assertCount(1, $GLOBALS['BE_USER']->uc['recentSwitchedToUsers']);
+    }
+}
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-80581-RenderListOfRecentlyUsersThatWereSwitchedTo.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-80581-RenderListOfRecentlyUsersThatWereSwitchedTo.rst
new file mode 100644
index 000000000000..101296ebe08d
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-80581-RenderListOfRecentlyUsersThatWereSwitchedTo.rst
@@ -0,0 +1,21 @@
+.. include:: ../../Includes.txt
+
+=====================================================================
+Feature: #80581 - Render list of recently users that were switched to
+=====================================================================
+
+See :issue:`80581`
+
+Description
+===========
+
+When a backend user with admin privileges switches to another user, the entered user is now stored in the uc. The users
+stored in this list will be rendered into the user menu to allow quick switching to the recent users.
+
+
+Impact
+======
+
+The user menu renders up to three users to which the currently logged in admin switched to.
+
+.. index:: Backend
\ No newline at end of file
-- 
GitLab