Index: trunk/CentralAuth/TestPlugin.php |
— | — | @@ -224,66 +224,84 @@ |
225 | 225 | } |
226 | 226 | |
227 | 227 | /** |
228 | | - * Try to auto-migrate this account, possibly using a given |
229 | | - * password plaintext for additional oomph. |
| 228 | + * Pick a winning master account and try to auto-merge as many as possible. |
230 | 229 | * @fixme add some locking or something |
231 | 230 | */ |
232 | 231 | function attemptAutoMigration( $password='' ) { |
233 | | - $dbw = wfGetDB( DB_MASTER, 'CentralAuth' ); |
234 | | - $attached = array(); |
235 | | - $unattached = array(); |
236 | | - $migrated = array(); |
| 232 | + $rows = $this->fetchUnattached(); |
237 | 233 | |
238 | | - $result = $dbw->select( 'localuser', |
239 | | - array( |
240 | | - 'lu_dbname', |
241 | | - 'lu_id', |
242 | | - 'lu_name', |
243 | | - 'lu_password', |
244 | | - 'lu_email', |
245 | | - 'lu_email_authenticated', |
246 | | - 'lu_editcount', |
247 | | - 'lu_attached', |
248 | | - ), |
249 | | - array( 'lu_name' => $this->mName ), |
250 | | - __METHOD__ ); |
251 | | - while( $row = $dbw->fetchObject( $result ) ) { |
252 | | - if( $row->lu_attached ) { |
253 | | - $attached[] = $row; |
254 | | - } else { |
255 | | - $unattached[] = $row; |
| 234 | + $winner = false; |
| 235 | + $max = -1; |
| 236 | + $attach = array(); |
| 237 | + $unattach = array(); |
| 238 | + |
| 239 | + // We have to pick a master account |
| 240 | + // The winner is the one with the most edits, usually |
| 241 | + foreach( $rows as $row ) { |
| 242 | + if( $row->lu_editcount > $max ) { |
| 243 | + $winner = $row; |
| 244 | + $max = $row->lu_editcount; |
256 | 245 | } |
257 | 246 | } |
258 | | - $dbw->freeResult( $result ); |
| 247 | + assert( isset( $winner ) ); |
259 | 248 | |
260 | | - if( count( $unattached ) == 0 ) { |
261 | | - wfDebugLog( 'CentralAuth', |
262 | | - "All accounts already migrated for '$this->mName'" ); |
263 | | - return false; |
264 | | - // Or... should this return true ? |
| 249 | + // Do they all match? |
| 250 | + $allMatch = true; |
| 251 | + $allMatchOrEmpty = true; |
| 252 | + $allMatchOrUnused = true; |
| 253 | + $isConflict = false; |
| 254 | + $winningMail = ($winner->lu_email == '' ? false : $winner->lu_email); |
| 255 | + |
| 256 | + foreach( $rows as $row ) { |
| 257 | + if( $row->lu_dbname == $winner->lu_dbname ) { |
| 258 | + $attach[] = $row; |
| 259 | + } else { |
| 260 | + if( $row->lu_email !== $winningMail ) { |
| 261 | + $allMatch = false; |
| 262 | + if( $row->lu_email !== '' ) { |
| 263 | + $allMatchOrEmpty = false; |
| 264 | + } |
| 265 | + if( $row->lu_editcount == 0 ) { |
| 266 | + // Unused accounts are fair game for reclaiming |
| 267 | + $attach[] = $row; |
| 268 | + } else { |
| 269 | + $allMatchOrUnused = false; |
| 270 | + $unattach[] = $row; |
| 271 | + $isConflict = true; |
| 272 | + } |
| 273 | + } else { |
| 274 | + $attach[] = $row; |
| 275 | + } |
| 276 | + } |
265 | 277 | } |
266 | 278 | |
267 | | - if( count( $attached ) == 0 ) { |
268 | | - if( count( $unattached ) == 1 ) { |
269 | | - // convenient special case |
270 | | - $row = $unattached[0]; |
271 | | - $db = $row->lu_dbname; |
| 279 | + if( $allMatch ) { |
| 280 | + if( count( $rows ) == 1 ) { |
272 | 281 | wfDebugLog( 'CentralAuth', |
273 | | - "Attaching '$this->mName' on $db as singleton" ); |
274 | | - $this->storeGlobalData( |
275 | | - $row->lu_id, |
276 | | - $row->lu_password, |
277 | | - $row->lu_email, |
278 | | - $row->lu_email_authenticated ); |
279 | | - $this->attach( $db ); |
280 | | - |
281 | | - $dbw->commit(); |
282 | | - return true; |
| 282 | + "Singleton migration for '$this->mName'" ); |
283 | 283 | } else { |
284 | | - // We have to pick a winner... |
| 284 | + wfDebugLog( 'CentralAuth', |
| 285 | + "Full automatic migration for '$this->mName'" ); |
285 | 286 | } |
| 287 | + } else { |
| 288 | + wfDebugLog( 'CentralAuth', |
| 289 | + "Incomplete migration for '$this->mName'" ); |
286 | 290 | } |
| 291 | + |
| 292 | + $this->storeGlobalData( |
| 293 | + $winner->lu_id, |
| 294 | + $winner->lu_password, |
| 295 | + $winner->lu_email, |
| 296 | + $winner->lu_email_authenticated ); |
287 | 297 | |
| 298 | + foreach( $attach as $row ) { |
| 299 | + $this->attach( $row->lu_dbname ); |
| 300 | + } |
| 301 | + |
| 302 | + } |
| 303 | + |
| 304 | + function attemptPasswordMigration( $password ) { |
| 305 | + |
288 | 306 | // Look for accounts we can match by password |
289 | 307 | foreach( $unattached as $key => $row ) { |
290 | 308 | if( $this->matchHash( $password, $row->lu_id, $row->lu_password ) ) { |
— | — | @@ -434,19 +452,37 @@ |
435 | 453 | * @return array of database name strings |
436 | 454 | */ |
437 | 455 | function listUnattached() { |
438 | | - $dbr = wfGetDB( DB_MASTER, 'CentralAuth' ); |
439 | | - $res = $dbr->select( |
440 | | - array( 'globaluser', 'localuser' ), |
441 | | - array( 'lu_database' ), |
| 456 | + $rows = $this->fetchUnattached; |
| 457 | + $dbs = array(); |
| 458 | + foreach( $rows as $row ) { |
| 459 | + $dbs[] = $row->lu_dbname; |
| 460 | + } |
| 461 | + return $dbs; |
| 462 | + } |
| 463 | + |
| 464 | + function fetchUnattached() { |
| 465 | + $dbw = wfGetDB( DB_MASTER, 'CentralAuth' ); |
| 466 | + $result = $dbw->select( 'localuser', |
442 | 467 | array( |
443 | | - 'lu_name' => $this->mName, |
444 | | - 'lu_attached' => 0 ) ); |
445 | | - $list = array(); |
446 | | - while( $row = $db->fetchObject( $res ) ) { |
447 | | - $list[] = $row->lu_database; |
| 468 | + 'lu_dbname', |
| 469 | + 'lu_id', |
| 470 | + 'lu_name', |
| 471 | + 'lu_password', |
| 472 | + 'lu_email', |
| 473 | + 'lu_email_authenticated', |
| 474 | + 'lu_editcount', |
| 475 | + 'lu_attached', |
| 476 | + ), |
| 477 | + array( |
| 478 | + 'lu_name' => $this->mName, |
| 479 | + 'lu_attached' => 0, |
| 480 | + ), |
| 481 | + __METHOD__ ); |
| 482 | + while( $row = $dbw->fetchObject( $result ) ) { |
| 483 | + $rows[] = $row; |
448 | 484 | } |
449 | | - $db->freeResult( $res ); |
450 | | - return $list; |
| 485 | + $dbw->freeResult( $result ); |
| 486 | + return $rows; |
451 | 487 | } |
452 | 488 | |
453 | 489 | function getEmail() { |