Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4146026
LocalRenameJob.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
LocalRenameJob.php
View Options
<?php
namespace
MediaWiki\Extension\CentralAuth\GlobalRename\LocalRenameJob
;
use
Exception
;
use
Job
;
use
MediaWiki\Context\RequestContext
;
use
MediaWiki\Extension\CentralAuth\CentralAuthServices
;
use
MediaWiki\Extension\CentralAuth\GlobalRename\GlobalRenameUserStatus
;
use
MediaWiki\Extension\CentralAuth\User\CentralAuthUser
;
use
MediaWiki\Logger\LoggerFactory
;
use
MediaWiki\MediaWikiServices
;
use
MediaWiki\Title\Title
;
use
MediaWiki\User\User
;
use
MediaWiki\WikiMap\WikiMap
;
use
Wikimedia\Rdbms\IDBAccessObject
;
use
Wikimedia\ScopedCallback
;
/**
* Base class for jobs that change a user's
* name. Intended to be run on local wikis
* indvidually.
*
* Parameters:
* - from: current username
* - to: new username to rename to
* - renamer: username of the performer
* - ignorestatus: when true, the rename will be done even if another job is supposed to be
* already doing it. This should only be used for stuck renames.
* - session: array of session data from RequestContext::exportSession()
*/
abstract
class
LocalRenameJob
extends
Job
{
/**
* @var GlobalRenameUserStatus
*/
private
$renameuserStatus
;
/**
* @param Title $title
* @param array $params
*/
public
function
__construct
(
Title
$title
,
$params
)
{
parent
::
__construct
(
$this
->
command
,
$title
,
$params
);
}
/**
* @throws Exception
*/
public
function
run
():
bool
{
$this
->
setRenameUserStatus
(
CentralAuthServices
::
getGlobalRenameFactory
()
->
newGlobalRenameUserStatus
(
$this
->
params
[
'to'
]
)
);
// Bail if it's already done or in progress. Use a locking read to block until the
// transaction adding this job is done, so we can see its changes. This is similar to
// the trick that the RenameUser extension does.
$status
=
$this
->
renameuserStatus
->
getStatus
(
IDBAccessObject
::
READ_LOCKING
);
// Clear any REPEATABLE-READ snapshot in case the READ_LOCKING blocked above. We want
// regular non-locking SELECTs to see all the changes from that transaction we waited on.
// Making a new transaction also reduces deadlocks from the locking read.
// T145596
$fnameTrxOwner
=
get_class
(
$this
)
.
'::'
.
__FUNCTION__
;
$factory
=
MediaWikiServices
::
getInstance
()->
getDBLoadBalancerFactory
();
$factory
->
commitPrimaryChanges
(
$fnameTrxOwner
);
if
(
empty
(
$this
->
params
[
'ignorestatus'
]
)
)
{
if
(
$status
!==
'queued'
&&
$status
!==
'failed'
)
{
$logger
=
LoggerFactory
::
getInstance
(
'CentralAuth'
);
$logger
->
info
(
'Skipping duplicate rename from {oldName} to {newName}'
,
[
'oldName'
=>
$this
->
params
[
'from'
],
'newName'
=>
$this
->
params
[
'to'
],
'component'
=>
'GlobalRename'
,
'status'
=>
$status
,
]
);
return
true
;
}
}
if
(
isset
(
$this
->
params
[
'session'
]
)
)
{
// Don't carry over users or sessions because it's going to be wrong
// across wikis
$this
->
params
[
'session'
][
'userId'
]
=
0
;
$this
->
params
[
'session'
][
'sessionId'
]
=
''
;
$callback
=
RequestContext
::
importScopedSession
(
$this
->
params
[
'session'
]
);
$this
->
addTeardownCallback
(
static
function
()
use
(
&
$callback
)
{
ScopedCallback
::
consume
(
$callback
);
}
);
}
try
{
$this
->
doRun
(
$fnameTrxOwner
);
$this
->
addTeardownCallback
(
[
$this
,
'scheduleNextWiki'
]
);
}
catch
(
Exception
$e
)
{
// This will lock the user out of their account until a sysadmin intervenes
$factory
->
rollbackPrimaryChanges
(
$fnameTrxOwner
);
$this
->
updateStatus
(
'failed'
);
$factory
->
commitPrimaryChanges
(
$fnameTrxOwner
);
// Record job failure in CentralAuth channel (T217211)
$logger
=
LoggerFactory
::
getInstance
(
'CentralAuth'
);
$logger
->
error
(
'Failed to rename {oldName} to {newName} ({error})'
,
[
'oldName'
=>
$this
->
params
[
'from'
],
'newName'
=>
$this
->
params
[
'to'
],
'component'
=>
'GlobalRename'
,
'error'
=>
$e
->
getMessage
()
]
);
throw
$e
;
}
return
true
;
}
/**
* Actually do the work for the job class
* @param string $fnameTrxOwner Caller name
*/
abstract
protected
function
doRun
(
$fnameTrxOwner
);
/**
* @param GlobalRenameUserStatus $status
*/
protected
function
setRenameUserStatus
(
GlobalRenameUserStatus
$status
)
{
$this
->
renameuserStatus
=
$status
;
}
/**
* Get the user object for the user who is doing the renaming
* "Auto-create" if it doesn't exist yet.
* @return User
*/
protected
function
getRenameUser
()
{
$user
=
User
::
newFromName
(
$this
->
params
[
'renamer'
]
);
$userNameUtils
=
MediaWikiServices
::
getInstance
()->
getUserNameUtils
();
// If the username is a reserved name, don't worry about the account
// existing, just use it.
if
(
!
$userNameUtils
->
isUsable
(
$user
->
getName
()
)
)
{
return
$user
;
}
$caUser
=
CentralAuthUser
::
getPrimaryInstance
(
$user
);
// Race condition where the renamer isn't attached here, but
// someone creates an account in the meantime and then bad
// stuff could happen...
// For the meantime, just use a system account
if
(
!
$caUser
->
attachedOn
(
WikiMap
::
getCurrentWikiId
()
)
&&
$user
->
getId
()
!==
0
)
{
return
User
::
newSystemUser
(
'Global rename script'
,
[
'steal'
=>
true
]
);
}
if
(
$user
->
getId
()
==
0
)
{
// No local user, lets "auto-create" one
if
(
CentralAuthServices
::
getUtilityService
()->
autoCreateUser
(
$user
)->
isGood
()
)
{
// So the internal cache is reloaded
return
User
::
newFromName
(
$user
->
getName
()
);
}
// Auto-creation didn't work, fallback on the system account.
return
User
::
newSystemUser
(
'Global rename script'
,
[
'steal'
=>
true
]
);
}
// Account is attached and exists, just use it :)
return
$user
;
}
protected
function
done
()
{
$this
->
renameuserStatus
->
done
(
WikiMap
::
getCurrentWikiId
()
);
$caNew
=
CentralAuthUser
::
getInstanceByName
(
$this
->
params
[
'to'
]
);
$caNew
->
quickInvalidateCache
();
}
/**
* @param string $status
*/
protected
function
updateStatus
(
$status
)
{
$this
->
renameuserStatus
->
updateStatus
(
WikiMap
::
getCurrentWikiId
(),
$status
);
}
/**
* @param bool $status See Job::addTeardownCallback
*/
protected
function
scheduleNextWiki
(
$status
)
{
if
(
$status
===
false
)
{
// This will lock the user out of their account until a sysadmin intervenes.
$this
->
updateStatus
(
'failed'
);
// Bail out just in case the error would affect all renames and continuing would
// just put all wikis of the user in failure state. Running the rename for this
// wiki again (e.g. with fixStuckGlobalRename.php) will resume the job chain.
return
;
}
$job
=
new
static
(
$this
->
getTitle
(),
$this
->
getParams
()
);
$nextWiki
=
null
;
$statuses
=
$this
->
renameuserStatus
->
getStatuses
(
IDBAccessObject
::
READ_LATEST
);
foreach
(
$statuses
as
$wiki
=>
$status
)
{
if
(
$status
===
'queued'
&&
$wiki
!==
WikiMap
::
getCurrentWikiId
()
)
{
$nextWiki
=
$wiki
;
break
;
}
}
if
(
$nextWiki
)
{
MediaWikiServices
::
getInstance
()->
getJobQueueGroupFactory
()->
makeJobQueueGroup
(
$nextWiki
)->
push
(
$job
);
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Aug 19 2026, 17:52 (5 w, 5 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ce/b5/7726abd1eca8891aae4b0b40f574
Default Alt Text
LocalRenameJob.php (6 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment