Page MenuHomeWickedGov Phorge

SpecialGlobalRenameQueue.php
No OneTemporary

Size
30 KB
Referenced Files
None
Subscribers
None

SpecialGlobalRenameQueue.php

<?php
/**
* @section LICENSE
* 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.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup SpecialPage
*/
namespace MediaWiki\Extension\CentralAuth\Special;
use Exception;
use LogEventsList;
use MailAddress;
use MediaWiki\Extension\CentralAuth\CentralAuthDatabaseManager;
use MediaWiki\Extension\CentralAuth\CentralAuthUIService;
use MediaWiki\Extension\CentralAuth\GlobalRename\GlobalRenameFactory;
use MediaWiki\Extension\CentralAuth\GlobalRename\GlobalRenameRequest;
use MediaWiki\Extension\CentralAuth\GlobalRename\GlobalRenameRequestStore;
use MediaWiki\Extension\CentralAuth\GlobalRename\GlobalRenameUserLogger;
use MediaWiki\Extension\CentralAuth\GlobalRename\LocalRenameJob\LocalRenameUserJob;
use MediaWiki\Extension\CentralAuth\User\CentralAuthAntiSpoofManager;
use MediaWiki\Extension\CentralAuth\User\CentralAuthUser;
use MediaWiki\Extension\TitleBlacklist\TitleBlacklist;
use MediaWiki\Extension\TitleBlacklist\TitleBlacklistEntry;
use MediaWiki\HTMLForm\HTMLForm;
use MediaWiki\JobQueue\JobQueueGroupFactory;
use MediaWiki\Logger\LoggerFactory;
use MediaWiki\Registration\ExtensionRegistry;
use MediaWiki\SpecialPage\SpecialPage;
use MediaWiki\Status\Status;
use MediaWiki\Title\Title;
use MediaWiki\User\User;
use MediaWiki\User\UserIdentityLookup;
use MediaWiki\User\UserNameUtils;
use MediaWiki\WikiMap\WikiMap;
use MediaWiki\Xml\Xml;
use OOUI\MessageWidget;
use Psr\Log\LoggerInterface;
use RuntimeException;
use UserMailer;
use Wikimedia\Rdbms\LBFactory;
/**
* Process account rename requests made via [[Special:GlobalRenameRequest]].
*
* @author Bryan Davis <bd808@wikimedia.org>
* @copyright © 2014 Bryan Davis and Wikimedia Foundation.
* @ingroup SpecialPage
*/
class SpecialGlobalRenameQueue extends SpecialPage {
private UserNameUtils $userNameUtils;
private LBFactory $lbFactory;
private CentralAuthDatabaseManager $databaseManager;
private CentralAuthUIService $uiService;
private GlobalRenameRequestStore $globalRenameRequestStore;
private JobQueueGroupFactory $jobQueueGroupFactory;
private CentralAuthAntiSpoofManager $caAntiSpoofManager;
private GlobalRenameFactory $globalRenameFactory;
private UserIdentityLookup $userIdentityLookup;
private LoggerInterface $logger;
public const PAGE_OPEN_QUEUE = 'open';
public const PAGE_PROCESS_REQUEST = 'request';
public const PAGE_CLOSED_QUEUE = 'closed';
private const ACTION_CANCEL = 'cancel';
public const ACTION_VIEW = 'view';
public function __construct(
UserNameUtils $userNameUtils,
LBFactory $lbFactory,
CentralAuthDatabaseManager $databaseManager,
CentralAuthUIService $uiService,
GlobalRenameRequestStore $globalRenameRequestStore,
JobQueueGroupFactory $jobQueueGroupFactory,
CentralAuthAntiSpoofManager $caAntiSpoofManager,
GlobalRenameFactory $globalRenameFactory,
UserIdentityLookup $userIdentityLookup
) {
parent::__construct( 'GlobalRenameQueue', 'centralauth-rename' );
$this->userNameUtils = $userNameUtils;
$this->lbFactory = $lbFactory;
$this->databaseManager = $databaseManager;
$this->uiService = $uiService;
$this->globalRenameRequestStore = $globalRenameRequestStore;
$this->jobQueueGroupFactory = $jobQueueGroupFactory;
$this->caAntiSpoofManager = $caAntiSpoofManager;
$this->globalRenameFactory = $globalRenameFactory;
$this->userIdentityLookup = $userIdentityLookup;
$this->logger = LoggerFactory::getInstance( 'CentralAuth' );
}
public function doesWrites() {
return true;
}
/**
* @param string|null $par Subpage string if one was specified
*/
public function execute( $par ) {
$navigation = explode( '/', $par );
$action = array_shift( $navigation );
$this->outputHeader();
$this->addSubtitleLinks();
switch ( $action ) {
case self::PAGE_OPEN_QUEUE:
$this->handleOpenQueue();
break;
case self::PAGE_CLOSED_QUEUE:
$this->handleClosedQueue();
break;
case self::PAGE_PROCESS_REQUEST:
$this->handleProcessRequest( $navigation );
break;
default:
$this->doRedirectToOpenQueue();
break;
}
}
/**
* @param string $titleMessage Message name for page title
* @param array $titleParams Params for page title
*/
protected function commonPreamble( $titleMessage, $titleParams = [] ) {
$out = $this->getOutput();
$this->setHeaders();
$this->checkPermissions();
$out->setPageTitleMsg( $this->msg( $titleMessage, $titleParams ) );
}
/**
* @inheritDoc
*/
public function getAssociatedNavigationLinks() {
return [
$this->getPageTitle( self::PAGE_OPEN_QUEUE )->getPrefixedText(),
$this->getPageTitle( self::PAGE_CLOSED_QUEUE )->getPrefixedText(),
];
}
/**
* @inheritDoc
*/
public function getShortDescription( string $path = '' ): string {
switch ( $path ) {
case $this->getPageTitle( self::PAGE_OPEN_QUEUE )->getText():
return $this->msg( 'globalrenamequeue-nav-openqueue' )->text();
case $this->getPageTitle( self::PAGE_CLOSED_QUEUE )->getText():
return $this->msg( 'globalrenamequeue-nav-closedqueue' )->text();
default:
return '';
}
}
private function addSubtitleLinks() {
if ( $this->getSkin()->supportsMenu( 'associated-pages' ) ) {
// Already shown by the skin
return;
}
$links = [];
foreach ( $this->getAssociatedNavigationLinks() as $titleText ) {
$title = Title::newFromText( $titleText );
$links[] = $this->getLinkRenderer()->makeKnownLink(
$title,
$this->getShortDescription( $title->getText() )
);
}
$this->getOutput()->addSubtitle( $this->getLanguage()->pipeList( $links ) );
}
/**
* Get an array of fields for use by the HTMLForm shown above the pager.
*
* @return array[]
*/
private function getCommonFormFieldsArray() {
$lang = $this->getLanguage();
return [
'username' => [
'type' => 'text',
'name' => 'username',
'label-message' => 'globalrenamequeue-form-username',
'size' => 30,
],
'newname' => [
'type' => 'text',
'name' => 'newname',
'size' => 30,
'label-message' => 'globalrenamequeue-form-newname',
],
'limit' => [
'type' => 'limitselect',
'name' => 'limit',
'label-message' => 'table_pager_limit_label',
'options' => [
$lang->formatNum( 25 ) => 25,
$lang->formatNum( 50 ) => 50,
$lang->formatNum( 75 ) => 75,
$lang->formatNum( 100 ) => 100,
],
],
'type' => [
'type' => 'select',
'name' => 'type',
'label-message' => 'globalrenamequeue-form-type',
'options-messages' => [
'globalrenamequeue-form-type-all' => 'all',
'globalrenamequeue-form-type-rename' => GlobalRenameRequest::RENAME,
'globalrenamequeue-form-type-vanish' => GlobalRenameRequest::VANISH,
],
'default' => 'all',
],
];
}
/**
* Initialize and output the HTMLForm used for filtering.
*
* @param array $formDescriptor
*/
private function outputFilterForm( array $formDescriptor ) {
$htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() );
$htmlForm
->setMethod( 'get' )
->setWrapperLegendMsg( 'search' )
->prepareForm()->displayForm( false );
}
/**
* Handle requests to display the open request queue
*/
protected function handleOpenQueue() {
$this->commonPreamble( 'globalrenamequeue' );
$this->outputFilterForm( $this->getCommonFormFieldsArray() );
$pager = new RenameQueueTablePager(
$this->getContext(),
$this->getLinkRenderer(),
$this->databaseManager,
$this->userNameUtils,
self::PAGE_OPEN_QUEUE
);
$this->getOutput()->addParserOutputContent( $pager->getFullOutput() );
}
/**
* Handle requests to display the closed request queue
*/
protected function handleClosedQueue() {
$this->commonPreamble( 'globalrenamequeue' );
$formDescriptor = array_merge(
$this->getCommonFormFieldsArray(),
[
'status' => [
'type' => 'select',
'name' => 'status',
'label-message' => 'globalrenamequeue-form-status',
'options-messages' => [
'globalrenamequeue-form-status-all' => 'all',
'globalrenamequeue-view-approved' => GlobalRenameRequest::APPROVED,
'globalrenamequeue-view-rejected' => GlobalRenameRequest::REJECTED,
],
'default' => 'all',
]
]
);
$this->outputFilterForm( $formDescriptor );
$pager = new RenameQueueTablePager(
$this->getContext(),
$this->getLinkRenderer(),
$this->databaseManager,
$this->userNameUtils,
self::PAGE_CLOSED_QUEUE
);
$this->getOutput()->addParserOutputContent( $pager->getFullOutput() );
}
/**
* Handle requests related to processing a request.
*
* @param array $pathArgs Extra path arguments
*/
protected function handleProcessRequest( array $pathArgs ) {
if ( !$pathArgs ) {
$this->doRedirectToOpenQueue();
return;
}
$rqId = array_shift( $pathArgs );
if ( !is_numeric( $rqId ) ) {
$this->showUnkownRequest();
return;
}
$req = $this->globalRenameRequestStore->newFromId( $rqId );
if ( !$req->exists() ) {
$this->showUnkownRequest();
return;
}
$action = array_shift( $pathArgs );
if ( !$req->isPending() ) {
$action = self::ACTION_VIEW;
}
switch ( $action ) {
case self::ACTION_CANCEL:
$this->doRedirectToOpenQueue();
break;
case self::ACTION_VIEW:
$this->doViewRequest( $req );
break;
default:
$this->doShowProcessForm( $req );
break;
}
}
private function showUnkownRequest() {
$this->commonPreamble( 'globalrenamequeue-request-unknown-title' );
$this->getOutput()->addWikiMsg(
'globalrenamequeue-request-unknown-body'
);
}
protected function doRedirectToOpenQueue() {
$this->getOutput()->redirect(
$this->getPageTitle( self::PAGE_OPEN_QUEUE )->getFullURL()
);
}
/**
* Display a request.
*
* @param GlobalRenameRequest $req
*/
protected function doViewRequest( GlobalRenameRequest $req ) {
$isVanishRequest = $req->getType() === GlobalRenameRequest::VANISH;
if ( $isVanishRequest ) {
$this->commonPreamble(
'globalrenamequeue-request-vanish-status-title',
[ $req->getName() ]
);
} else {
$this->commonPreamble(
'globalrenamequeue-request-status-title',
[ $req->getName(), $req->getNewName() ]
);
}
$reason = $req->getReason() ?: '';
$renamer = CentralAuthUser::newFromId( $req->getPerformer() );
if ( $renamer === false ) {
throw new RuntimeException(
"The performer's global user id ({$req->getPerformer()}) " .
"does not exist in the database"
);
}
$homewiki = $renamer->getHomeWiki();
if ( $renamer->isAttached() || $homewiki === null ) {
$renamerLink = Title::makeTitleSafe( NS_USER, $renamer->getName() )->getFullURL();
} else {
$renamerLink = WikiMap::getForeignURL( $homewiki, 'User:' . $renamer->getName() );
}
if ( strpos( $reason, "\n" ) !== false ) {
$reason = "<dl><dd>" . str_replace( "\n", "</dd><dd>", $reason ) . "</dd></dl>";
} else {
$reason = ': ' . $reason;
}
$status = $req->getStatus();
$causerName = $status === GlobalRenameRequest::APPROVED
? $req->getNewName()
: $req->getName();
$causer = CentralAuthUser::getInstanceByName( $causerName );
$attachedWikis = $causer->exists() && $causer->isAttached()
? implode( ', ', array_keys( $causer->queryAttachedBasic() ) )
: '';
// Done as one big message so that admins can create a local
// translation to customize the output as they see fit.
// @TODO: Do that actually in here... this is not how we do interfaces in 2015.
if ( $isVanishRequest ) {
$viewMsg = $this->msg( 'globalrenamequeue-vanish-view',
$req->getName(),
$reason,
$this->msg( 'globalrenamequeue-view-' . $status )->text(),
$this->getLanguage()->userTimeAndDate(
$req->getRequested(), $this->getUser()
),
$this->getLanguage()->userTimeAndDate(
$req->getCompleted(), $this->getUser()
),
$attachedWikis,
$renamerLink,
$renamer->getName(),
$req->getComments()
)->parseAsBlock();
} else {
$viewMsg = $this->msg( 'globalrenamequeue-view',
$req->getName(),
$req->getNewName(),
$reason,
$this->msg( 'globalrenamequeue-view-' . $status )->text(),
$this->getLanguage()->userTimeAndDate(
$req->getRequested(), $this->getUser()
),
$this->getLanguage()->userTimeAndDate(
$req->getCompleted(), $this->getUser()
),
$renamerLink,
$renamer->getName(),
$req->getComments()
)->parseAsBlock();
}
$this->getOutput()->addHtml( '<div class="plainlinks">' . $viewMsg . '</div>' );
}
/**
* Display form for approving/denying request or process form submission.
*
* @param GlobalRenameRequest $req Pending request
*/
protected function doShowProcessForm( GlobalRenameRequest $req ) {
$isVanishRequest = $req->getType() === GlobalRenameRequest::VANISH;
// Set up message keys according to request type (rename/vanish)
if ( $isVanishRequest ) {
$commonPreambleMsg = 'globalrenamequeue-request-vanish-title';
$approveButtonMsg = 'globalrenamequeue-request-vanish-approve-text';
$denyButtonMsg = 'globalrenamequeue-request-vanish-deny-text';
$globalUserInfoMsg = 'globalrenamequeue-request-vanish-userinfo';
$headerMsgKey = 'globalrenamequeue-request-vanish-header';
$reasonMsg = 'globalrenamequeue-request-vanish-reason';
$approveConfirmation = 'mw-renamequeue-approve-vanish';
} else {
$commonPreambleMsg = 'globalrenamequeue-request-title';
$approveButtonMsg = 'globalrenamequeue-request-approve-text';
$denyButtonMsg = 'globalrenamequeue-request-deny-text';
$globalUserInfoMsg = 'globalrenamequeue-request-userinfo-global';
$headerMsgKey = 'globalrenamequeue-request-header';
$reasonMsg = 'globalrenamequeue-request-reason';
$approveConfirmation = 'mw-renamequeue-approve';
}
$this->commonPreamble( $commonPreambleMsg, [ $req->getName() ] );
$htmlForm = HTMLForm::factory( 'ooui',
[
'rid' => [
'default' => $req->getId(),
'name' => 'rid',
'type' => 'hidden',
],
'comments' => [
'default' => $this->getRequest()->getVal( 'comments' ),
'id' => 'mw-renamequeue-comments',
'label-message' => 'globalrenamequeue-request-comments-label',
'name' => 'comments',
'type' => 'textarea',
'rows' => 5,
],
],
$this->getContext(),
'globalrenamequeue'
);
// Show tools to approve only when user is not reviewing own request.
if ( $req->getName() !== $this->getUser()->getName() ) {
$htmlForm
->addFields( [
// The following fields need to have their names stay in
// sync with the expectations of GlobalRenameUser::rename()
'reason' => [
'id' => 'mw-renamequeue-reason',
'label-message' => 'globalrenamequeue-request-reason-label',
'name' => 'reason',
'type' => 'text',
],
'movepages' => [
'id' => 'mw-renamequeue-movepages',
'name' => 'movepages',
'label-message' => 'globalrenamequeue-request-movepages',
'type' => 'check',
'default' => 1,
],
'suppressredirects' => [
'id' => 'mw-renamequeue-suppressredirects',
'name' => 'suppressredirects',
'label-message' => 'globalrenamequeue-request-suppressredirects',
'type' => 'check',
'default' => $isVanishRequest ? 1 : 0,
'disabled' => $isVanishRequest ? 1 : 0,
],
] )
->addButton( [
'name' => 'approve',
'value' => $this->msg( $approveButtonMsg )->text(),
'id' => $approveConfirmation,
'flags' => [ 'primary', 'progressive' ],
'framed' => true
] );
}
$htmlForm
->suppressDefaultSubmit()
->addButton( [
'name' => 'deny',
'value' => $this->msg( $denyButtonMsg )->text(),
'id' => 'mw-renamequeue-deny',
'flags' => [ 'destructive' ],
'framed' => true
] )
->addButton( [
'name' => 'cancel',
'value' => $this->msg( 'globalrenamequeue-request-cancel-text' )->text(),
'id' => 'mw-renamequeue-cancel',
] )
->setId( 'mw-globalrenamequeue-request' );
if ( $req->userIsGlobal() ) {
$globalUser = CentralAuthUser::getInstanceByName( $req->getName() );
$homeWiki = $globalUser->getHomeWiki();
$infoMsgKey = $globalUserInfoMsg;
} else {
$homeWiki = $req->getWiki();
$infoMsgKey = 'globalrenamequeue-request-userinfo-local';
}
if ( $homeWiki === null ) {
$homeLink = Title::makeTitleSafe( NS_USER, $req->getName() )->getFullURL();
} else {
$homeLink = WikiMap::getForeignURL( $homeWiki, 'User:' . $req->getName() );
}
$headerMsg = $this->msg(
$headerMsgKey,
$homeLink,
$req->getName(),
$req->getNewName()
);
$htmlForm->addHeaderHtml( '<span class="plainlinks">' . $headerMsg->parseAsBlock() .
'</span>' );
$homeWikiWiki = $homeWiki ? WikiMap::getWiki( $homeWiki ) : null;
$infoMsgArgs = [
$infoMsgKey,
$req->getName(),
// homeWikiWiki shouldn't ever be null except in
// a development/testing environment.
( $homeWikiWiki ? $homeWikiWiki->getDisplayName() : $homeWiki ),
];
// Rename requests need the new username into the info message
if ( !$isVanishRequest ) {
$infoMsgArgs[] = $req->getNewName();
}
$infoMsg = $this->msg( ...$infoMsgArgs );
if ( isset( $globalUser ) ) {
$infoMsg->numParams( $globalUser->getGlobalEditCount() );
$infoMsg->params( $this->msg(
$globalUser->isBlocked() ?
'globalrenamequeue-request-vanish-user-blocked' :
'globalrenamequeue-request-vanish-user-not-blocked'
) );
}
$htmlForm->addHeaderHtml( $infoMsg->parseAsBlock() );
// Handle AntiSpoof integration
$spoofUser = $this->caAntiSpoofManager->getSpoofUser( $req->getNewName() );
$conflicts = $this->uiService->processAntiSpoofConflicts(
$this->getContext(),
$req->getName(),
$spoofUser->getConflicts()
);
$renamedUser = $this->caAntiSpoofManager->getOldRenamedUserName( $req->getNewName() );
if ( $renamedUser !== null ) {
$conflicts[] = $renamedUser;
}
if ( $conflicts ) {
$htmlForm->addHeaderHtml(
$this->msg(
'globalrenamequeue-request-antispoof-conflicts',
$this->getLanguage()->commaList( $conflicts )
)->numParams( count( $conflicts ) )->parseAsBlock()
);
}
// Show a message if the new username matches the title blacklist.
if ( ExtensionRegistry::getInstance()->isLoaded( 'TitleBlacklist' ) ) {
$titleBlacklist = TitleBlacklist::singleton()->isBlacklisted(
Title::makeTitleSafe( NS_USER, $req->getNewName() ),
'new-account'
);
if ( $titleBlacklist instanceof TitleBlacklistEntry ) {
$htmlForm->addHeaderHtml(
$this->msg( 'globalrenamequeue-request-titleblacklist' )
->params( wfEscapeWikiText( $titleBlacklist->getRegex() ) )->parseAsBlock()
);
}
}
// Show a log entry of previous renames under the requesting user's username
$caTitle = SpecialPage::getTitleFor( 'CentralAuth', $req->getName() );
$extract = '';
$extractCount = LogEventsList::showLogExtract( $extract, 'gblrename', $caTitle, '', [
'showIfEmpty' => false,
] );
if ( $extractCount ) {
$htmlForm->addHeaderHtml(
Xml::fieldset( $this->msg( 'globalrenamequeue-request-previous-renames' )
->numParams( $extractCount )
->text(), $extract )
);
}
$reason = $req->getReason() ?: '';
$htmlForm->addHeaderHtml( $this->msg( $reasonMsg,
"<dl><dd>" . str_replace( "\n", "</dd><dd>", $reason ) . "</dd></dl>"
)->parseAsBlock() );
// Show warning when reviewing own request
if ( $req->getName() === $this->getUser()->getName() ) {
$message = new MessageWidget( [
'label' => $this->msg( 'globalrenamerequest-self-warning' )->text(),
'type' => 'warning',
'inline' => true
] );
$htmlForm->addHeaderHtml( $message->toString() );
}
$htmlForm->setSubmitCallback( [ $this, 'onProcessSubmit' ] );
$out = $this->getOutput();
$out->addModuleStyles( 'ext.centralauth.globalrenamequeue.styles' );
$out->addModules( 'ext.centralauth.globalrenamequeue' );
$status = $htmlForm->show();
if ( $status instanceof Status && $status->isOK() ) {
$this->getOutput()->redirect(
$this->getPageTitle(
self::PAGE_PROCESS_REQUEST . "/{$req->getId()}/{$status->value}"
)->getFullURL()
);
}
}
/**
* @param array $data
* @return Status
*/
public function onProcessSubmit( array $data ) {
$request = $this->getContext()->getRequest();
$status = new Status;
if ( $request->getCheck( 'approve' ) ) {
$status = $this->doResolveRequest( true, $data );
} elseif ( $request->getCheck( 'deny' ) ) {
$status = $this->doResolveRequest( false, $data );
} else {
$status->setResult( true, 'cancel' );
}
return $status;
}
/**
* @param bool $approved
* @param array $data
*
* @return Status
*/
protected function doResolveRequest( $approved, $data ) {
$request = $this->globalRenameRequestStore->newFromId( $data['rid'] );
$oldUser = User::newFromName( $request->getName() );
$newUser = User::newFromName( $request->getNewName(), 'creatable' );
$status = new Status;
$session = $this->getContext()->exportSession();
if ( $approved ) {
// Disallow self-renaming
if ( $request->getName() === $this->getUser()->getName() ) {
return Status::newFatal( 'globalrenamerequest-self-error' );
}
if ( $request->userIsGlobal() ) {
$data['type'] = $request->getType();
$globalRenameUser = $this->globalRenameFactory
->newGlobalRenameUser(
$this->getUser(),
CentralAuthUser::getInstanceByName( $request->getName() ),
$request->getNewName()
)
->withSession( $session );
// Credit the vanish performer with account locking logs for
// vanish requests. Renamers cannot normally perform locks and
// thus should not be associated with them.
if ( $request->getType() === GlobalRenameRequest::VANISH ) {
$vanishPerformerName = $this->getConfig()->get( 'CentralAuthAutomaticVanishPerformer' );
if ( isset( $vanishPerformerName ) ) {
$localVanishPerformer = $this->userIdentityLookup
->getUserIdentityByName( $vanishPerformerName );
if ( isset( $localVanishPerformer ) ) {
$globalRenameUser = $globalRenameUser->withLockPerformingUser( $localVanishPerformer );
}
}
}
// Trigger a global rename job
$status = $globalRenameUser->rename( $data );
} else {
// If the user is local-only:
// * rename the local user using LocalRenameUserJob
// * create a global user attached only to the local wiki
$job = new LocalRenameUserJob(
Title::newFromText( 'Global rename job' ),
[
'from' => $oldUser->getName(),
'to' => $newUser->getName(),
'renamer' => $this->getUser()->getName(),
'movepages' => true,
'suppressredirects' => true,
'promotetoglobal' => true,
'reason' => $data['reason'],
'session' => $session,
'type' => $request->getType(),
]
);
$this->jobQueueGroupFactory->makeJobQueueGroup( $request->getWiki() )->push( $job );
// Now log it
$this->logPromotionRename(
$oldUser->getName(),
$request->getWiki(),
$newUser->getName(),
$data['reason']
);
$status = Status::newGood();
}
}
if ( $status->isGood() ) {
$request->setStatus(
$approved ? GlobalRenameRequest::APPROVED : GlobalRenameRequest::REJECTED
);
$request->setCompleted( wfTimestampNow() );
$request->setPerformer(
CentralAuthUser::getInstance( $this->getUser() )->getId()
);
$request->setComments( $data['comments'] );
if ( $this->globalRenameRequestStore->save( $request ) ) {
if ( $request->getType() === GlobalRenameRequest::VANISH ) {
$emailSubjectApprovedMsg = 'globalrenamequeue-vanish-email-subject-approved';
$emailBodyApprovedMsg = 'globalrenamequeue-vanish-email-body-approved';
$emailBodyApprovedWithNoteMsg = 'globalrenamequeue-vanish-email-body-approved-with-note';
$emailSubjectRejectedMsg = 'globalrenamequeue-vanish-email-subject-rejected';
$emailBodyRejectedMsg = 'globalrenamequeue-vanish-email-body-rejected';
$emailBodyMsgArgs = [
$oldUser->getName(),
$request->getComments()
];
} else {
$emailSubjectApprovedMsg = 'globalrenamequeue-email-subject-approved';
$emailBodyApprovedMsg = 'globalrenamequeue-email-body-approved';
$emailBodyApprovedWithNoteMsg = 'globalrenamequeue-email-body-approved-with-note';
$emailSubjectRejectedMsg = 'globalrenamequeue-email-subject-rejected';
$emailBodyRejectedMsg = 'globalrenamequeue-email-body-rejected';
$emailBodyMsgArgs = [
$oldUser->getName(),
$newUser->getName(),
$request->getComments(),
];
}
// Send email to the user about the change in status.
if ( $approved ) {
$subject = $this->msg(
$emailSubjectApprovedMsg
)->inContentLanguage()->text();
if ( $request->getComments() === '' ) {
$msgKey = $emailBodyApprovedMsg;
} else {
$msgKey = $emailBodyApprovedWithNoteMsg;
}
$body = $this->msg(
$msgKey, $emailBodyMsgArgs
)->inContentLanguage()->text();
} else {
$recipientConfig = $this->getConfig()->get( 'CentralAuthRejectVanishUserNotification' );
if ( $recipientConfig ) {
$status = $this->sendEmailForRejectionOfVanishRequest( $request, $recipientConfig );
}
$subject = $this->msg(
$emailSubjectRejectedMsg
)->inContentLanguage()->text();
$body = $this->msg(
$emailBodyRejectedMsg, $emailBodyMsgArgs
)->inContentLanguage()->text();
}
if ( $request->userIsGlobal() || $request->getWiki() === WikiMap::getCurrentWikiId() ) {
$notifyEmail = MailAddress::newFromUser( $oldUser );
} else {
$notifyEmail = $this->getRemoteUserMailAddress(
$request->getWiki(), $request->getName()
);
}
if ( $notifyEmail !== null && $notifyEmail->address ) {
$type = $approved ? 'approval' : 'rejection';
$this->logger->info( "Send $type email to User:{oldName}", [
'oldName' => $oldUser->getName(),
'component' => 'GlobalRename',
] );
$this->sendNotificationEmail( $notifyEmail, $subject, $body );
}
} else {
$status->fatal( 'globalrenamequeue-request-savefailed' );
}
}
return $status;
}
/**
* Log a promotion to global rename in the global rename log
*
* @param string $oldName
* @param string $wiki
* @param string $newName
* @param string $reason
*/
protected function logPromotionRename( $oldName, $wiki, $newName, $reason ) {
$logger = new GlobalRenameUserLogger( $this->getUser() );
$logger->logPromotion( $oldName, $wiki, $newName, $reason );
}
/**
* Get a MailAddress for a user on a remote wiki
*
* @param string $wiki
* @param string $username
* @return MailAddress|null
*/
protected function getRemoteUserMailAddress( $wiki, $username ) {
$lb = $this->lbFactory->getMainLB( $wiki );
$remoteDB = $lb->getConnection( DB_REPLICA, [], $wiki );
$row = $remoteDB->newSelectQueryBuilder()
->select( [ 'user_email', 'user_name', 'user_real_name' ] )
->from( 'user' )
->where( [
'user_name' => $this->userNameUtils->getCanonical( $username ),
] )
->caller( __METHOD__ )
->fetchRow();
if ( $row === false ) {
$address = null;
} else {
$address = new MailAddress(
$row->user_email, $row->user_name, $row->user_real_name
);
}
return $address;
}
/**
* Send an email notifying the user of the result of their request.
*
* @param MailAddress $to
* @param string $subject
* @param string $body
* @return Status
*/
protected function sendNotificationEmail( MailAddress $to, $subject, $body ) {
$from = new MailAddress(
$this->getConfig()->get( 'PasswordSender' ),
$this->msg( 'emailsender' )->inContentLanguage()->text()
);
return UserMailer::send( $to, $from, $subject, $body );
}
/**
* Send an email on account vanishing rejection to the provided recipient.
*
* @param GlobalRenameRequest $request
* @param string $recipientUserName
* @return Status
*/
protected function sendEmailForRejectionOfVanishRequest( GlobalRenameRequest $request, $recipientUserName ) {
// Email to legal is only sent when it's a vanish request
if ( $request->getType() !== GlobalRenameRequest::VANISH ) {
return Status::newGood();
}
if ( $request->userIsGlobal() ) {
$globalUser = CentralAuthUser::getInstanceByName( $request->getName() );
$homeWiki = $globalUser->getHomeWiki();
$globalEditCount = $globalUser->getGlobalEditCount();
$isBlocked = $globalUser->isBlocked() ?
'globalrenamequeue-request-vanish-user-blocked' :
'globalrenamequeue-request-vanish-user-not-blocked';
} else {
$homeWiki = $request->getWiki();
$globalEditCount = '';
$isBlocked = 'globalrenamequeue-request-vanish-user-not-blocked';
}
// This should never be null except in dev/testing environment.
$homeWikiWiki = $homeWiki ? WikiMap::getWiki( $homeWiki ) : null;
$rejector = CentralAuthUser::newFromId( $request->getPerformer() );
$rejectorName = $rejector ? $rejector->getName() : $request->getPerformer();
$subject = $this->msg(
'globalvanishrequest-rejected-subject-notification',
$request->getName(),
)->inContentLanguage()->text();
$isBlockedMsg = $this->msg( $isBlocked )->inContentLanguage()->text();
$bodyMessage = $this->msg(
'globalvanishrequest-rejected-body-notification',
$request->getName(),
( $homeWikiWiki ? $homeWikiWiki->getDisplayName() : $homeWiki ),
$globalEditCount,
$isBlockedMsg,
$request->getReason(),
$rejectorName,
$request->getComments(),
$this->getLanguage()->userTimeAndDate(
$request->getRequested(), $this->getUser()
),
$this->getLanguage()->userTimeAndDate(
$request->getCompleted(), $this->getUser()
),
)->inContentLanguage()->text();
try {
$contactRecipientUser = User::newFromName( $recipientUserName );
$contactRecipientAddress = MailAddress::newFromUser( $contactRecipientUser );
$contactSenderAddress = new MailAddress(
$this->getConfig()->get( 'PasswordSender' ),
$this->msg( 'emailsender' )->inContentLanguage()->text()
);
$userMailerStatus = UserMailer::send(
$contactRecipientAddress,
$contactSenderAddress,
$subject,
$bodyMessage,
);
if ( $userMailerStatus->isGood() ) {
return Status::newGood();
} else {
return Status::newFatal( 'globalvanishrequest-rejected-notification-error' );
}
} catch ( Exception $e ) {
return Status::newFatal( 'globalvanishrequest-rejected-notification-error' );
}
}
/** @inheritDoc */
protected function getGroupName() {
return 'users';
}
/** @inheritDoc */
public function getSubpagesForPrefixSearch() {
return [
self::PAGE_OPEN_QUEUE,
self::PAGE_PROCESS_REQUEST,
self::PAGE_CLOSED_QUEUE
];
}
}

File Metadata

Mime Type
text/x-php
Expires
Fri, Jul 3, 17:32 (16 h, 50 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
dd/44/ee79dfac66f30b4234f48b9b52c7
Default Alt Text
SpecialGlobalRenameQueue.php (30 KB)

Event Timeline