<?php
$IP = getenv( 'MW_INSTALL_PATH' );
if ( $IP === false ) {
$IP = __DIR__ . '/../../..';
}
require_once( "$IP/maintenance/Maintenance.php" );
class AttachAccount extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Attaches the specified usernames to a global account";
$this->start = microtime( true );
$this->partial = 0;
$this->migrated = 0;
$this->total = 0;
$this->dbBackground = null;
$this->batchSize = 1000;
$this->addOption( 'userlist', 'List of usernames to migrate', false, true );
}
public function execute() {
$this->dbBackground = CentralAuthUtils::getCentralSlaveDB();
if ( $this->getOption( 'userlist', false ) === false ) {
$this->output( "ERROR - No list of usernames given\n" );
exit( 1 );
}
$list = $this->getOption( 'userlist' );
if ( !is_file( $list ) ) {
$this->output( "ERROR - File not found: $list" );
exit( 1 );
}
$file = fopen( $list, 'r' );
if ( $file === false ) {
$this->output( "ERROR - Could not open file: $list" );
exit( 1 );
}
while( strlen( $line = trim( fgets( $file ) ) ) ) {
$values = explode( "\t", $line );
switch( count( $values ) ){
case 1:
$this->migrate( $values[0] );
break;
default:
$this->output( "ERROR: Invalid account specification: '$line'\n" );
continue;
}
if ( $this->total % $this->batchSize == 0 ) {
$this->output( "Waiting for slaves to catch up ... " );
CentralAuthUtils::waitForSlaves();
$this->output( "done\n" );
}
}
fclose( $file );
$this->migratePassOneReport();
$this->output( "done.\n" );
}
function migrate( $username ) {
$this->total++;
$this->output( "CentralAuth account attach for: {$username}\n");
$central = new CentralAuthUser( $username, CentralAuthUser::READ_LATEST );
try {
$unattached = $central->queryUnattached();
} catch ( Exception $e ) {
// This might happen due to localnames inconsistencies (bug 67350)
$this->output( "ERROR: Fetching unattached accounts for {$username} failed." );
return;
}
if ( $central->exists() ) {
$tryEmail = !is_null( $central->getEmailAuthenticationTimestamp() );
foreach ( $unattached as $wiki => $local ) {
if ( $tryEmail &&
$central->getEmail() === $local['email'] &&
!is_null( $local['emailAuthenticated'] )
) {
$this->output( "ATTACHING: $username@$wiki\n" );
$central->attach( $wiki, 'mail', false );
} elseif ( $local['password'] === '' ) {
$this->output( "ATTACHING: $username@$wiki\n" );
$central->attach( $wiki, 'password', false );
} else {
$this->output( "ATTACHING: $username@$wiki\n" );
$central->attach( $wiki, 'login', false );
}
}
} else {
$this->output( "ERROR: No CA account found for: $username\n" );
return;
}
$unattachedAfter = $central->queryUnattached();
if ( count( $unattachedAfter ) == 0 ) {
$this->migrated++;
return;
} elseif ( count( $unattachedAfter ) > 0 && count( $unattachedAfter ) < count( $unattached ) ) {
$this->partial++;
$this->output( "INFO: Incomplete migration for '$username'\n" );
}
}
function migratePassOneReport() {
$delta = microtime( true ) - $this->start;
$this->output( sprintf( "%s processed %d usernames (%.1f/sec), %d (%.1f%%) fully migrated, %d (%.1f%%) partially migrated\n",
wfTimestamp( TS_DB ),
$this->total,
$this->total / $delta,
$this->migrated,
$this->total > 0 ? ( $this->migrated / $this->total * 100.0 ) : 0,
$this->partial,
$this->total > 0 ? ( $this->partial / $this->total * 100.0 ) : 0
) );
}
}
$maintClass = "MigrateAccount";
require_once( RUN_MAINTENANCE_IF_MAIN );