26$IP = getenv(
'MW_INSTALL_PATH' );
28 $IP = __DIR__ .
'/../../..';
30require_once
"$IP/maintenance/Maintenance.php";
34 parent::__construct();
35 $this->
addDescription(
'Maintenance script to finish incomplete rename user,'
36 .
' in particular to reassign edits that were missed' );
37 $this->
addOption(
'olduser',
'Old user name',
true,
true );
38 $this->
addOption(
'newuser',
'New user name',
true,
true );
39 $this->
addOption(
'olduid',
'Old user id in revision records (DANGEROUS)',
false,
true );
47 $this->
output(
"Core xx_user_text fields are no longer used, no updates should be needed.\n" );
51 $this->
output(
"Rename User Cleanup starting...\n\n" );
52 $olduser = User::newFromName( $this->
getOption(
'olduser' ) );
53 $newuser = User::newFromName( $this->
getOption(
'newuser' ) );
60 $this->
doUpdates( $olduser, $newuser, $olduid );
62 $this->
doUpdates( $olduser, $newuser, $newuser->getId() );
63 $this->
doUpdates( $olduser, $newuser, 0 );
65 $this->
output(
"Done!\n" );
73 if ( !$newuser->getId() ) {
74 $this->
error(
'No such user: ' . $this->
getOption(
'newuser' ),
true );
76 if ( $olduser->getId() ) {
77 $this->
output(
'WARNING!!: Old user still exists: ' . $this->
getOption(
'olduser' ) .
"\n" );
78 $this->
output(
'We\'ll only re-attribute edits that have the new user uid (or 0) ' );
79 $this->
output(
'or the uid specified by the caller, and the old user name.' );
80 $this->
output(
'Proceed anyway? [N/y] ' );
82 $stdin = fopen(
'php://stdin',
'rt' );
83 $line = fgets( $stdin );
87 $this->
output(
"Exiting at users request\n" );
99 $oldTitle = Title::makeTitle(
NS_USER, $olduser->getName() );
101 $result =
$dbr->select(
'logging',
'*',
102 [
'log_type' =>
'renameuser',
103 'log_action' =>
'renameuser',
105 'log_title' => $oldTitle->getDBkey(),
106 'log_params' => $newuser->getName()
110 if ( !$result || !$result->numRows() ) {
112 if ( class_exists( CommentStore::class ) ) {
113 $commentStore = CommentStore::getStore();
114 $commentQuery = $commentStore->getJoin(
'log_comment' );
116 $commentStore =
null;
119 'fields' => [
'log_comment' =>
'log_comment' ],
123 $result =
$dbr->select(
124 [
'logging' ] + $commentQuery[
'tables'],
125 [
'log_title',
'log_timestamp' ] + $commentQuery[
'fields'],
127 'log_type' =>
'renameuser',
128 'log_action' =>
'renameuser',
130 'log_title' => $olduser->getName(),
134 $commentQuery[
'joins']
136 if ( !$result || !$result->numRows() ) {
137 $this->
output(
'No log entry found for a rename of ' . $olduser->getName() .
138 ' to ' . $newuser->getName() .
', proceed anyways? [N/y] ' );
140 $stdin = fopen(
'php://stdin',
'rt' );
141 $line = fgets( $stdin );
145 $this->
output(
"Exiting at user's request\n" );
149 foreach ( $result as $row ) {
150 $comment = $commentStore
151 ? $commentStore->getComment(
'log_comment', $row )->text
153 $this->
output(
'Found possible log entry of the rename, please check: ' .
154 $row->log_title .
' with comment ' . $comment .
155 " on $row->log_timestamp\n" );
159 foreach ( $result as $row ) {
160 $this->
output(
'Found log entry of the rename: ' . $olduser->getName() .
161 ' to ' . $newuser->getName() .
" on $row->log_timestamp\n" );
164 if ( $result && $result->numRows() > 1 ) {
165 print 'More than one rename entry found in the log, not sure ' .
166 'what to do. Proceed anyways? [N/y] ';
168 $stdin = fopen(
'php://stdin',
'rt' );
169 $line = fgets( $stdin );
173 $this->
output(
"Exiting at users request\n" );
250 public function updateTable( $table, $usernamefield, $useridfield,
251 $timestampfield, $olduser, $newuser, $uid
255 $contribs = $dbw->selectField(
259 $usernamefield => $olduser->getName(),
265 if ( $contribs === 0 ) {
266 $this->
output(
"No edits to be re-attributed from table $table for uid $uid\n" );
271 $this->
output(
"Found $contribs edits to be re-attributed from table $table for uid $uid\n" );
272 if ( $uid !== $newuser->getId() ) {
273 $this->
output(
'If you proceed, the uid field will be set to that ' .
274 'of the new user name (i.e. ' . $newuser->getId() .
") in these rows.\n" );
277 $this->
output(
'Proceed? [N/y] ' );
279 $stdin = fopen(
'php://stdin',
'rt' );
280 $line = fgets( $stdin );
284 $this->
output(
"Skipping at user's request\n" );
288 $selectConds = [ $usernamefield => $olduser->getName(), $useridfield => $uid ];
289 $updateFields = [ $usernamefield => $newuser->getName(), $useridfield => $newuser->getId() ];
291 while ( $contribs > 0 ) {
292 $this->
output(
'Doing batch of up to approximately ' . $this->mBatchSize .
"\n" );
293 $this->
output(
'Do this batch? [N/y] ' );
295 $stdin = fopen(
'php://stdin',
'rt' );
296 $line = fgets( $stdin );
300 $this->
output(
"Skipping at user's request\n" );
305 $result = $dbw->select(
311 'ORDER BY' => $timestampfield .
' DESC',
312 'LIMIT' => $this->mBatchSize
317 $this->
output(
"There were rows for updating but now they are gone. Skipping.\n" );
323 $result->seek( $result->numRows() - 1 );
324 $row = $result->fetchObject();
325 $timestamp = $dbw->addQuotes( $row->$timestampfield );
326 $updateCondsWithTime = array_merge( $selectConds, [
"$timestampfield >= $timestamp" ] );
330 $updateCondsWithTime,
335 $rowsDone = $dbw->affectedRows();
339 $this->
error(
"Problem with the update, rolling back and exiting\n",
true );
343 $contribs = $dbw->selectField( $table,
'count(*)', $selectConds, __METHOD__ );
344 $this->
output(
"Updated $rowsDone edits; $contribs edits remaining to be re-attributed\n" );
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
const RUN_MAINTENANCE_IF_MAIN
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
error( $err, $die=0)
Throw an error to the user.
requireExtension( $name)
Indicate that the specified extension must be loaded before the script can run.
beginTransaction(IDatabase $dbw, $fname)
Begin a transcation on a DB.
commitTransaction(IDatabase $dbw, $fname)
Commit the transcation on a DB handle and wait for replica DBs to catch up.
output( $out, $channel=null)
Throw some output to the user.
addDescription( $text)
Set the description text.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
getOption( $name, $default=null)
Get an option, or return the default.
rollbackTransaction(IDatabase $dbw, $fname)
Rollback the transcation on a DB handle.
setBatchSize( $s=0)
Set the batch size.
__construct()
Default constructor.
checkUserExistence( $olduser, $newuser)
doUpdates( $olduser, $newuser, $uid)
updateTable( $table, $usernamefield, $useridfield, $timestampfield, $olduser, $newuser, $uid)
execute()
Do the actual work.
checkRenameLog( $olduser, $newuser)
static actorMigrationWriteOld()
Indicate whether we should still write old user fields.
while(( $__line=Maintenance::readconsole()) !==false) print
$IP
Maintenance script to clean up after incomplete user renames Sometimes user edits are left lying arou...