MediaWiki REL1_34
renameUserCleanup.php
Go to the documentation of this file.
1<?php
26$IP = getenv( 'MW_INSTALL_PATH' );
27if ( $IP === false ) {
28 $IP = __DIR__ . '/../../..';
29}
30require_once "$IP/maintenance/Maintenance.php";
31
33 public function __construct() {
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 );
40 $this->setBatchSize( 1000 );
41
42 $this->requireExtension( 'Renameuser' );
43 }
44
45 public function execute() {
47 $this->output( "Core xx_user_text fields are no longer used, no updates should be needed.\n" );
48 return;
49 }
50
51 $this->output( "Rename User Cleanup starting...\n\n" );
52 $olduser = User::newFromName( $this->getOption( 'olduser' ) );
53 $newuser = User::newFromName( $this->getOption( 'newuser' ) );
54 $olduid = $this->getOption( 'olduid' );
55
56 $this->checkUserExistence( $olduser, $newuser );
57 $this->checkRenameLog( $olduser, $newuser );
58
59 if ( $olduid ) {
60 $this->doUpdates( $olduser, $newuser, $olduid );
61 }
62 $this->doUpdates( $olduser, $newuser, $newuser->getId() );
63 $this->doUpdates( $olduser, $newuser, 0 );
64
65 $this->output( "Done!\n" );
66 }
67
72 public function checkUserExistence( $olduser, $newuser ) {
73 if ( !$newuser->getId() ) {
74 $this->error( 'No such user: ' . $this->getOption( 'newuser' ), true );
75 }
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] ' );
81
82 $stdin = fopen( 'php://stdin', 'rt' );
83 $line = fgets( $stdin );
84 fclose( $stdin );
85
86 if ( $line[0] !== 'Y' && $line[0] !== 'y' ) {
87 $this->output( "Exiting at users request\n" );
88 }
89 }
90 }
91
96 public function checkRenameLog( $olduser, $newuser ) {
98
99 $oldTitle = Title::makeTitle( NS_USER, $olduser->getName() );
100
101 $result = $dbr->select( 'logging', '*',
102 [ 'log_type' => 'renameuser',
103 'log_action' => 'renameuser',
104 'log_namespace' => NS_USER,
105 'log_title' => $oldTitle->getDBkey(),
106 'log_params' => $newuser->getName()
107 ],
108 __METHOD__
109 );
110 if ( !$result || !$result->numRows() ) {
111 // try the old format
112 if ( class_exists( CommentStore::class ) ) {
113 $commentStore = CommentStore::getStore();
114 $commentQuery = $commentStore->getJoin( 'log_comment' );
115 } else {
116 $commentStore = null;
117 $commentQuery = [
118 'tables' => [],
119 'fields' => [ 'log_comment' => 'log_comment' ],
120 'joins' => [],
121 ];
122 }
123 $result = $dbr->select(
124 [ 'logging' ] + $commentQuery['tables'],
125 [ 'log_title', 'log_timestamp' ] + $commentQuery['fields'],
126 [
127 'log_type' => 'renameuser',
128 'log_action' => 'renameuser',
129 'log_namespace' => NS_USER,
130 'log_title' => $olduser->getName(),
131 ],
132 __METHOD__,
133 [],
134 $commentQuery['joins']
135 );
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] ' );
139
140 $stdin = fopen( 'php://stdin', 'rt' );
141 $line = fgets( $stdin );
142 fclose( $stdin );
143
144 if ( $line[0] !== 'Y' && $line[0] !== 'y' ) {
145 $this->output( "Exiting at user's request\n" );
146 exit( 1 );
147 }
148 } else {
149 foreach ( $result as $row ) {
150 $comment = $commentStore
151 ? $commentStore->getComment( 'log_comment', $row )->text
152 : $row->log_comment;
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" );
156 }
157 }
158 } else {
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" );
162 }
163 }
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] ';
167
168 $stdin = fopen( 'php://stdin', 'rt' );
169 $line = fgets( $stdin );
170 fclose( $stdin );
171
172 if ( $line[0] !== 'Y' && $line[0] !== 'y' ) {
173 $this->output( "Exiting at users request\n" );
174 exit( 1 );
175 }
176 }
177 }
178
184 public function doUpdates( $olduser, $newuser, $uid ) {
185 $this->updateTable(
186 'revision',
187 'rev_user_text',
188 'rev_user',
189 'rev_timestamp',
190 $olduser,
191 $newuser,
192 $uid
193 );
194 $this->updateTable(
195 'archive',
196 'ar_user_text',
197 'ar_user',
198 'ar_timestamp',
199 $olduser,
200 $newuser,
201 $uid
202 );
203 $this->updateTable(
204 'logging',
205 'log_user_text',
206 'log_user',
207 'log_timestamp',
208 $olduser,
209 $newuser,
210 $uid
211 );
212 $this->updateTable(
213 'image',
214 'img_user_text',
215 'img_user',
216 'img_timestamp',
217 $olduser,
218 $newuser,
219 $uid
220 );
221 $this->updateTable(
222 'oldimage',
223 'oi_user_text',
224 'oi_user',
225 'oi_timestamp',
226 $olduser,
227 $newuser,
228 $uid
229 );
230 $this->updateTable(
231 'filearchive',
232 'fa_user_text',
233 'fa_user',
234 'fa_timestamp',
235 $olduser,
236 $newuser,
237 $uid
238 );
239 }
240
250 public function updateTable( $table, $usernamefield, $useridfield,
251 $timestampfield, $olduser, $newuser, $uid
252 ) {
253 $dbw = wfGetDB( DB_MASTER );
254
255 $contribs = $dbw->selectField(
256 $table,
257 'count(*)',
258 [
259 $usernamefield => $olduser->getName(),
260 $useridfield => $uid
261 ],
262 __METHOD__
263 );
264
265 if ( $contribs === 0 ) {
266 $this->output( "No edits to be re-attributed from table $table for uid $uid\n" );
267
268 return;
269 }
270
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" );
275 }
276
277 $this->output( 'Proceed? [N/y] ' );
278
279 $stdin = fopen( 'php://stdin', 'rt' );
280 $line = fgets( $stdin );
281 fclose( $stdin );
282
283 if ( $line[0] !== 'Y' && $line[0] !== 'y' ) {
284 $this->output( "Skipping at user's request\n" );
285 return;
286 }
287
288 $selectConds = [ $usernamefield => $olduser->getName(), $useridfield => $uid ];
289 $updateFields = [ $usernamefield => $newuser->getName(), $useridfield => $newuser->getId() ];
290
291 while ( $contribs > 0 ) {
292 $this->output( 'Doing batch of up to approximately ' . $this->mBatchSize . "\n" );
293 $this->output( 'Do this batch? [N/y] ' );
294
295 $stdin = fopen( 'php://stdin', 'rt' );
296 $line = fgets( $stdin );
297 fclose( $stdin );
298
299 if ( $line[0] !== 'Y' && $line[0] !== 'y' ) {
300 $this->output( "Skipping at user's request\n" );
301 return;
302 }
303
304 $this->beginTransaction( $dbw, __METHOD__ );
305 $result = $dbw->select(
306 $table,
307 $timestampfield,
308 $selectConds,
309 __METHOD__,
310 [
311 'ORDER BY' => $timestampfield . ' DESC',
312 'LIMIT' => $this->mBatchSize
313 ]
314 );
315
316 if ( !$result ) {
317 $this->output( "There were rows for updating but now they are gone. Skipping.\n" );
318 $this->rollbackTransaction( $dbw, __METHOD__ );
319
320 return;
321 }
322
323 $result->seek( $result->numRows() - 1 );
324 $row = $result->fetchObject();
325 $timestamp = $dbw->addQuotes( $row->$timestampfield );
326 $updateCondsWithTime = array_merge( $selectConds, [ "$timestampfield >= $timestamp" ] );
327 $success = $dbw->update(
328 $table,
329 $updateFields,
330 $updateCondsWithTime,
331 __METHOD__
332 );
333
334 if ( $success ) {
335 $rowsDone = $dbw->affectedRows();
336 $this->commitTransaction( $dbw, __METHOD__ );
337 } else {
338 $this->rollbackTransaction( $dbw, __METHOD__ );
339 $this->error( "Problem with the update, rolling back and exiting\n", true );
340 }
341
342 // $contribs = User::edits( $olduser->getId() );
343 $contribs = $dbw->selectField( $table, 'count(*)', $selectConds, __METHOD__ );
344 $this->output( "Updated $rowsDone edits; $contribs edits remaining to be re-attributed\n" );
345 }
346 }
347}
348
349$maintClass = RenameUserCleanup::class;
350require_once RUN_MAINTENANCE_IF_MAIN;
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
const RUN_MAINTENANCE_IF_MAIN
$line
Definition cdb.php:59
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
Definition eval.php:64
const NS_USER
Definition Defines.php:71
$IP
Maintenance script to clean up after incomplete user renames Sometimes user edits are left lying arou...
const DB_REPLICA
Definition defines.php:25
const DB_MASTER
Definition defines.php:26