public function execute() { $dbw = CentralAuthUser::getCentralDB(); $databaseUpdates = new UsersToRenameDatabaseUpdates($dbw); // CentralAuthUser::chooseHomeWiki is expensive and called // multiple times, so lets cache it. $cache = new MapCacheLRU($this->mBatchSize); do { $rows = $this->doQuery(); $insertRows = array(); foreach ($rows as $row) { $this->lName = $row->name; $this->lWiki = $row->wiki; if ($cache->has($row->name)) { $attachableWikis = $cache->get($row->name); } else { $ca = new CentralAuthUser($row->name); $attachableWikis = array(); $unattached = $ca->queryUnattached(); if ($ca->exists()) { $home = $ca->getHomeWiki(); $attachableWikis[] = $home; foreach ($unattached as $wiki => $info) { if ($ca->getEmailAuthenticationTimestamp() && $info['email'] === $ca->getEmail() && !is_null($info['emailAuthenticated'])) { $attachableWikis[] = $wiki; } } } else { $home = $ca->chooseHomeWiki($unattached); $attachableWikis[] = $home; if ($unattached[$home]['email'] && isset($unattached[$home]['emailAuthenticated'])) { foreach ($unattached as $wiki => $info) { if ($wiki !== $home && $unattached[$home]['email'] === $info['email'] && isset($info['emailAuthenticated'])) { $attachableWikis[] = $wiki; } } } } $cache->set($row->name, $attachableWikis); } if (!in_array($row->wiki, $attachableWikis)) { // Unattached account which is not attachable, // so they're getting renamed :( $this->output("{$row->name}@{$row->wiki} is going to be renamed.\n"); $insertRows[] = (array) $row; } } $databaseUpdates->batchInsert($insertRows); $count = $dbw->affectedRows(); $this->output("Inserted {$count} users who we will rename\n"); $this->output("Waiting for slaves...\n"); CentralAuthUser::waitForSlaves(); } while ($count !== 0); }
function migrate($username, $homewiki = null) { $this->total++; $this->output("CentralAuth account migration for: " . $username . "\n"); $central = new CentralAuthUser($username); 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; } /** * Migration with an existing global account */ if ($central->exists()) { $this->output("INFO: A global account already exists for: {$username}\n"); if ($this->getOption('attachmissing', false) && !is_null($central->getEmailAuthenticationTimestamp())) { foreach ($unattached as $wiki => $local) { if ($central->getEmail() === $local['email'] && !is_null($local['emailAuthenticated'])) { $this->output("ATTACHING: {$username}@{$wiki}\n"); $central->attach($wiki, 'mail', !$this->suppressRC); } } } if ($this->getOption('attachbroken', false)) { // This option is for bug 61876 / bug 39996 where the account has // an empty password and email set, and became unattached. // Since there is no way an account can have an empty password manually // it has to be due to a CentralAuth bug. So just attach it then. // But just to be on the safe side, check that it also has 0 edits. foreach ($unattached as $wiki => $local) { if ($local['email'] === '' && $local['password'] === '' && $local['editCount'] === '0') { $this->output("ATTACHING: {$username}@{$wiki}\n"); // Ironically, the attachment is made due to lack of a password. $central->attach($wiki, 'password', !$this->suppressRC); } } } } else { if (count($unattached) == 0) { $this->output("ERROR: No local accounts found for: {$username}\n"); return; } if ($this->safe && count($unattached) !== 1) { $this->output("ERROR: More than 1 local user account found for username: {$username}\n"); foreach ($unattached as $local) { $this->output("\t" . $central->getName() . "@" . $local['wiki'] . "\n"); } return; } if ($homewiki !== null) { if (!array_key_exists($homewiki, $unattached)) { $this->output("ERROR: Unattached user not found for {$username}@{$homewiki}\n"); return; } $this->output("INFO: Setting homewiki for '{$username}' to {$homewiki}\n"); $central->mHomeWiki = $homewiki; } // Check that all unattached (i.e. ALL) accounts have a confirmed email // address and that the addresses are all the same. We are using this // to match accounts to the same user, since we can't use the password. $emailMatch = true; $email = null; foreach ($unattached as $local) { if (is_null($email)) { $email = $local['email']; } if ($local['email'] === $email && !is_null($local['emailAuthenticated'])) { continue; } $emailMatch = false; break; } // All of the emails are the same and confirmed? Merge all the accounts. // They aren't? Skip, or merge the winner if --auto was specified. if ($emailMatch) { $this->output("Email addresses match and are confirmed for: {$username}\n"); $central->storeAndMigrate(array(), !$this->suppressRC); } else { if (isset($central->mHomeWiki) || $this->autoMigrate) { $central->storeAndMigrate(array(), !$this->suppressRC); } else { $this->output("ERROR: Auto migration is disabled and email addresses do not match for: {$username}\n"); } } } $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"); } if ($this->resetToken) { $this->output("INFO: Resetting CentralAuth auth token for '{$username}'\n"); $central->resetAuthToken(); } }