mediawiki-skins-MinervaNeue/includes/menu/AuthMenuEntry.php
Derick Alangi a9ead1938b menu: Add system generated logoutToken on logout action in Minerva
Upon building the menu components for logged in users, the logoutToken
was not properly appended to the logout URL. The URL is supposed to be

`?title=Special:UserLogout&returnto=...&logoutToken=...`

and not what was rendered previously, see below

`?title=Special:UserLogout&<token>`

The absense of the 'logoutToken' param prompted an intermediate step asking
users to confirm the logout action. We don't need this in Minerva if users want
to logout from their accounts and asking users to confirm this action is annoying.

We want the user to be able to logout when the "Logout" button is clicked
and the system would have generated a logout token and appended to the logout
URL in the format specified above. This patch has been tested locally and
everything works just fine.

Bug: T225220
Change-Id: I20f30db707915179a0604a1dc9061d8db225a230
2019-06-11 12:54:37 +01:00

209 lines
5.9 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
namespace MediaWiki\Minerva\Menu;
use MessageLocalizer;
use MinervaUI;
use SpecialPage;
use Title;
use User;
use WebRequest;
/**
* Model for a menu entry that represents log-in / profile+logout pair of links
*/
class AuthMenuEntry implements IMenuEntry {
/**
* Default tracking code for clicks on profile menu link
*/
const DEFAULT_PROFILE_TRACKING_CODE = 'profile';
/**
* @var User
*/
private $user;
/**
* @var WebRequest
*/
private $request;
/**
* @var Title
*/
private $title;
/**
* @var MessageLocalizer
*/
private $messageLocalizer;
/**
* Code used to track clicks on the link to profile page
* @var string
*/
private $profileTrackingCode = 'profile';
/**
* Custom profile URL, can be used to override where the profile link href
* @var string|null
*/
private $customProfileURL = null;
/**
* Custom profile label, can be used to override the profile label
* @var string|null
*/
private $customProfileLabel = null;
/**
* Initialize the Auth menu entry
*
* @param User $user Currently logged in user/anon
* @param WebRequest $request Request to load the returnToQuery values
* @param MessageLocalizer $messageLocalizer used for text translation
* @param Title|null $currentTitle The current title, will be used as returnTo
*/
public function __construct( User $user, WebRequest $request,
\MessageLocalizer $messageLocalizer, Title $currentTitle = null ) {
$this->user = $user;
$this->request = $request;
$this->title = $currentTitle;
$this->messageLocalizer = $messageLocalizer;
}
/**
* @inheritDoc
*/
public function getName() {
return 'auth';
}
/**
* Override the href for the profile component for logged in users
* @param string $customURL A new href for profile entry
* @param string|null $customLabel A new label for profile entry. Null if you don't want to
* override it
* @param string $trackingCode new tracking code
*/
public function overrideProfileURL( $customURL, $customLabel = null,
$trackingCode = self::DEFAULT_PROFILE_TRACKING_CODE ) {
$this->customProfileURL = $customURL;
$this->customProfileLabel = $customLabel;
$this->profileTrackingCode = $trackingCode;
}
/**
* @inheritDoc
*/
public function getCSSClasses(): array {
return [];
}
/**
* @inheritDoc
*/
public function getComponents(): array {
$authLinksQuery = [];
$returnToQuery = $this->getReturnToQuery();
// Don't ever redirect back to the login page (bug 55379)
if ( $this->title && !$this->title->isSpecial( 'Userlogin' ) ) {
$authLinksQuery[ 'returnto' ] = $this->title->getPrefixedText();
}
return $this->user->isLoggedIn()
? $this->buildComponentsForLoggedIn( $returnToQuery, $authLinksQuery )
: $this->buildComponentsForAnon( $returnToQuery, $authLinksQuery );
}
/**
* Retrieve current query parameters from Request object so system can pass those
* to the Login/logout links
* Some parameters are disabled (like title), as the returnto will be replaced with
* the current page.
* @return array
*/
private function getReturnToQuery(): array {
$returnToQuery = [];
if ( !$this->request->wasPosted() ) {
$returnToQuery = $this->request->getValues();
unset( $returnToQuery['title'] );
unset( $returnToQuery['returnto'] );
unset( $returnToQuery['returntoquery'] );
}
return $returnToQuery;
}
/**
* @param array $returnToQuery
* @param array $authLinksQuery
* @return array
* @throws \MWException
*/
private function buildComponentsForLoggedIn( array $returnToQuery, array $authLinksQuery ): array {
if ( !empty( $returnToQuery ) ) {
$authLinksQuery['returntoquery'] = wfArrayToCgi( $returnToQuery );
}
$authLinksQuery['logoutToken'] = $this->user->getEditToken( 'logoutToken', $this->request );
$logoutURL = SpecialPage::getTitleFor( 'Userlogout' )->getLocalURL( $authLinksQuery );
$username = $this->user->getName();
$profileUrl = $this->customProfileURL ??
Title::newFromText( $username, NS_USER )->getLocalURL();
$profileLabel = $this->customProfileLabel ?? $username;
return [
[
'text' => $profileLabel,
'href' => $profileUrl,
'class' => MinervaUI::iconClass( 'profile', 'before',
'truncated-text primary-action' ),
'data-event-name' => $this->profileTrackingCode
],
[
'text' => $this->messageLocalizer->msg( 'mobile-frontend-main-menu-logout' )->escaped(),
'href' => $logoutURL,
'class' => MinervaUI::iconClass( 'logout', 'element',
'truncated-text secondary-action' ),
'data-event-name' => 'logout'
]
];
}
/**
* @param array $returnToQuery
* @param $authLinksQuery
* @return array
*/
private function buildComponentsForAnon( array $returnToQuery, $authLinksQuery ): array {
// unset campaign on login link so as not to interfere with A/B tests
unset( $returnToQuery['campaign'] );
if ( !empty( $returnToQuery ) ) {
$authLinksQuery['returntoquery'] = wfArrayToCgi( $returnToQuery );
}
return [
'text' => $this->messageLocalizer->msg( 'mobile-frontend-main-menu-login' )->escaped(),
'href' => SpecialPage::getTitleFor( 'Userlogin' )->getLocalURL( $authLinksQuery ),
'class' => MinervaUI::iconClass( 'login', 'before' ),
'data-event-name' => 'login'
];
}
}