Page MenuHomeWickedGov Phorge

LocalRenameUserJob.php
No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None

LocalRenameUserJob.php

<?php
namespace MediaWiki\Extension\CentralAuth\GlobalRename\LocalRenameJob;
use LogicException;
use MediaWiki\Extension\CentralAuth\GlobalRename\GlobalRenameRequest;
use MediaWiki\Extension\CentralAuth\User\CentralAuthUser;
use MediaWiki\MediaWikiServices;
use MediaWiki\RenameUser\RenameuserSQL;
use MediaWiki\Title\Title;
use MediaWiki\User\User;
use MediaWiki\WikiMap\WikiMap;
use Wikimedia\Rdbms\IExpression;
use Wikimedia\Rdbms\LikeValue;
/**
* Job class to rename a user locally
* This is intended to be run on each wiki individually
*/
class LocalRenameUserJob extends LocalRenameJob {
/**
* @param Title $title
* @param array $params An associative array of options:
* from - old username
* to - new username
* force - try to do the rename even if the old username is invalid
* renamer - whom the renaming should be attributed in logs
* reason - reason to use in the rename log
* movepages - move user / user talk pages and their subpages
* suppressredirects - when moving pages, suppress redirects
* reattach - after rename, attach the local account. When used, should be set to
* [ wiki ID => [ 'attachedMethod' => method, 'attachedTimestamp' => timestamp ].
* See CentralAuthUser::queryAttached. (default: false)
* promotetoglobal - globalize the new user account (default: false)
* session - session data from RequestContext::exportSession, for checkuser data
* ignorestatus - ignore update status, run the job even if it seems like another job
* is already working on it
*/
public function __construct( $title, $params ) {
$this->command = 'LocalRenameUserJob';
// For back-compat
if ( !isset( $params['promotetoglobal'] ) ) {
$params['promotetoglobal'] = false;
}
if ( !isset( $params['reason'] ) ) {
$params['reason'] = '';
}
if ( !isset( $params['reattach'] ) ) {
$params['reattach'] = false;
}
if ( !isset( $params['type'] ) ) {
$params['type'] = GlobalRenameRequest::RENAME;
}
parent::__construct( $title, $params );
}
/** @inheritDoc */
public function doRun( $fnameTrxOwner ) {
$from = $this->params['from'];
$to = $this->params['to'];
$this->updateStatus( 'inprogress' );
$services = MediaWikiServices::getInstance();
// Make the status update visible to all other transactions immediately
$factory = $services->getDBLoadBalancerFactory();
$factory->commitPrimaryChanges( $fnameTrxOwner );
if ( isset( $this->params['force'] ) && $this->params['force'] ) {
// If we're dealing with an invalid username, load the data ourselves to avoid
// any normalization at all done by User or Title.
$userQuery = User::getQueryInfo();
$row = $services->getConnectionProvider()->getPrimaryDatabase()->newSelectQueryBuilder()
->tables( $userQuery['tables'] )
->select( $userQuery['fields'] )
->where( [ 'user_name' => $from ] )
->joinConds( $userQuery['joins'] )
->caller( __METHOD__ )
->fetchRow();
$oldUser = User::newFromRow( $row );
} else {
$oldUser = User::newFromName( $from );
}
$rename = new RenameuserSQL(
$from,
$to,
$oldUser->getId(),
$this->getRenameUser(),
[
'checkIfUserExists' => false,
'debugPrefix' => 'GlobalRename',
'reason' => $this->params['reason'],
]
);
if ( !$rename->rename() ) {
// This should never happen!
// If it does happen, the user will be locked out of their account
// until a sysadmin intervenes...
throw new LogicException( 'RenameuserSQL::rename returned false.' );
}
if ( $this->params['type'] === GlobalRenameRequest::VANISH ) {
// $renamedUser should always be truthy, otherwise the exception
// above would be thrown
$renamedUser = $services->getUserFactory()->newFromName( $to );
if ( $renamedUser ) {
User::newSystemUser( $renamedUser->getName(), [ 'steal' => true ] );
}
}
if ( $this->params['reattach'] ) {
$caUser = CentralAuthUser::getInstanceByName( $this->params['to'] );
$wikiId = WikiMap::getCurrentWikiId();
$details = $this->params['reattach'][$wikiId];
$caUser->attach(
$wikiId,
$details['attachedMethod'],
false,
$details['attachedTimestamp']
);
}
if ( $this->params['movepages'] ) {
$this->movePages( $oldUser );
}
if ( $this->params['promotetoglobal'] ) {
$this->promoteToGlobal();
}
$this->done();
}
private function promoteToGlobal() {
$newName = $this->params['to'];
$caUser = CentralAuthUser::getPrimaryInstanceByName( $newName );
$status = $caUser->promoteToGlobal( WikiMap::getCurrentWikiId() );
if ( !$status->isOK() ) {
if ( $status->hasMessage( 'promote-not-on-wiki' ) ) {
// Eh, what?
throw new LogicException( "Tried to promote '$newName' to a global account except it " .
"doesn't exist locally" );
} elseif ( $status->hasMessage( 'promote-already-exists' ) ) {
// Even more wtf.
throw new LogicException( "Tried to prommote '$newName' to a global account except it " .
"already exists" );
}
}
$caUser->quickInvalidateCache();
}
/**
* Queue up jobs to move pages
* @param User $oldUser
*/
public function movePages( User $oldUser ) {
$from = $this->params['from'];
$to = $this->params['to'];
$fromDBkey = $oldUser->getUserPage()->getDBkey();
$toDBkey = Title::makeTitleSafe( NS_USER, $to )->getDBkey();
$dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
$rows = $dbr->newSelectQueryBuilder()
->select( [ 'page_namespace', 'page_title' ] )
->from( 'page' )
->where( [
'page_namespace' => [ NS_USER, NS_USER_TALK ],
$dbr->expr( 'page_title', IExpression::LIKE, new LikeValue( $fromDBkey . '/', $dbr->anyString() ) )
->or( 'page_title', '=', $fromDBkey )
] )
->caller( __METHOD__ )
->fetchResultSet();
$jobParams = [
'to' => $to,
'from' => $from,
'renamer' => $this->getRenameUser()->getName(),
'suppressredirects' => $this->params['suppressredirects'],
];
if ( isset( $this->params['session'] ) ) {
$jobParams['session'] = $this->params['session'];
}
$jobs = [];
$toReplace = static::escapeReplacement( $toDBkey );
foreach ( $rows as $row ) {
$oldPage = Title::newFromRow( $row );
$newPage = Title::makeTitleSafe( $row->page_namespace,
preg_replace( '!^[^/]+!', $toReplace, $row->page_title ) );
$jobs[] = new LocalPageMoveJob(
Title::newFromText( 'LocalRenameUserJob' ),
$jobParams + [
'old' => [ $oldPage->getNamespace(), $oldPage->getDBkey() ],
'new' => [ $newPage->getNamespace(), $newPage->getDBkey() ],
]
);
}
MediaWikiServices::getInstance()->getJobQueueGroup()->push( $jobs );
}
protected function done() {
parent::done();
$caOld = CentralAuthUser::getInstanceByName( $this->params['from'] );
$caOld->quickInvalidateCache();
}
/**
* Escape a string to be used as a replacement by preg_replace so that
* anything in it that looks like a backreference is treated as a literal
* substitution.
*
* @param string $str String to escape
* @return string
*/
protected static function escapeReplacement( $str ) {
// T188171: escape any occurrence of '$n' or '\n' in the replacement
// string passed to preg_replace so that it will not be treated as
// a backreference.
return preg_replace(
// find $n, ${n}, and \n
'/[$\\\\]{?\d+}?/',
// prepend with a literal '\\'
'\\\\${0}',
$str
);
}
}

File Metadata

Mime Type
text/x-php
Expires
Aug 17 2026, 12:18 (10 w, 6 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ab/88/06ca3022b138295152879da93a51
Default Alt Text
LocalRenameUserJob.php (7 KB)

Event Timeline