[FEATURE] Store recent su’ed users and render quicklinks in user menu 25/52225/10
authorAndreas Fernandez <a.fernandez@scripting-base.de>
Tue, 28 Mar 2017 20:53:14 +0000 (22:53 +0200)
committerTymoteusz Motylewski <t.motylewski@gmail.com>
Mon, 8 May 2017 08:38:40 +0000 (10:38 +0200)
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>
typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php
typo3/sysext/backend/Resources/Private/Language/locallang.xlf
typo3/sysext/backend/Resources/Private/Templates/ToolbarItems/UserToolbarItemDropDown.html
typo3/sysext/beuser/Classes/Controller/BackendUserController.php
typo3/sysext/beuser/Tests/Unit/Controller/BackendUserControllerTest.php [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Feature-80581-RenderListOfRecentlyUsersThatWereSwitchedTo.rst [new file with mode: 0644]

index 4783beb..0a4c44f 100644 (file)
@@ -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();
     }
index 5387089..98dc8f1 100644 (file)
                                <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>
index 475be8c..c7e28c3 100644 (file)
@@ -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>
        </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
index 56c1793..1a6a4fd 100644 (file)
@@ -28,6 +28,11 @@ use TYPO3\CMS\Lang\LanguageService;
 class BackendUserController extends BackendUserActionController
 {
     /**
+     * @var int
+     */
+    const RECENT_USERS_LIMIT = 3;
+
+    /**
      * @var \TYPO3\CMS\Beuser\Domain\Model\ModuleData
      */
     protected $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();
@@ -260,6 +266,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
      */
     protected function getBackendUserAuthentication()
diff --git a/typo3/sysext/beuser/Tests/Unit/Controller/BackendUserControllerTest.php b/typo3/sysext/beuser/Tests/Unit/Controller/BackendUserControllerTest.php
new file mode 100644 (file)
index 0000000..aa62f8c
--- /dev/null
@@ -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 (file)
index 0000000..101296e
--- /dev/null
@@ -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