Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
PopulateListOfUsersToRename
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 3
306
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 doQuery
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
240
1<?php
2
3use MediaWiki\Extension\CentralAuth\CentralAuthServices;
4use MediaWiki\Extension\CentralAuth\User\CentralAuthUser;
5use MediaWiki\Extension\CentralAuth\UsersToRename\UsersToRenameDatabaseUpdates;
6use Wikimedia\Rdbms\IResultWrapper;
7
8$IP = getenv( 'MW_INSTALL_PATH' );
9if ( $IP === false ) {
10    $IP = __DIR__ . '/../../..';
11}
12require_once "$IP/maintenance/Maintenance.php";
13
14/**
15 * Populates the users_to_rename table.
16 *
17 * Before running this, you should run migratePass0,
18 * checkLocalNames, and checkLocalUser to make sure
19 * all of your tables are in sync.
20 *
21 * The expectation is the table is populated at some determined
22 * point in time, at which point you can start sending out
23 * notifications to users who are going to lose their accounts.
24 */
25class PopulateListOfUsersToRename extends Maintenance {
26    /** @var string|null */
27    private $lName = '';
28    /** @var string|null */
29    private $lWiki = '';
30
31    public function __construct() {
32        parent::__construct();
33        $this->requireExtension( 'CentralAuth' );
34        $this->setBatchSize( 1000 );
35    }
36
37    /**
38     * Fetches unattached accounts and attempts to continue.
39     *
40     * @return IResultWrapper
41     */
42    private function doQuery() {
43        $dbr = CentralAuthServices::getDatabaseManager()->getCentralReplicaDB();
44        $rows = $dbr->newSelectQueryBuilder()
45            ->select( [ 'name' => 'ln_name', 'wiki' => 'ln_wiki' ] )
46            ->from( 'localnames' )
47            ->leftJoin( 'localuser', null, [ 'ln_name=lu_name', 'ln_wiki=lu_wiki' ] )
48            ->where( [
49                $dbr->buildComparison( '>', [
50                    'ln_name' => $this->lName,
51                    'ln_wiki' => $this->lWiki,
52                ] ),
53                'lu_attached_method' => null,
54            ] )
55            ->orderBy( [ 'ln_name', 'ln_wiki' ] )
56            ->limit( $this->mBatchSize )
57            ->caller( __METHOD__ )
58            ->fetchResultSet();
59
60        return $rows;
61    }
62
63    public function execute() {
64        $dbw = CentralAuthServices::getDatabaseManager()->getCentralPrimaryDB();
65        $databaseUpdates = new UsersToRenameDatabaseUpdates( $dbw );
66        // CentralAuthUser::chooseHomeWiki is expensive and called
67        // multiple times, so lets cache it.
68        $cache = new HashBagOStuff( [ 'maxKeys' => $this->mBatchSize ] );
69        do {
70            $rows = $this->doQuery();
71            $insertRows = [];
72            foreach ( $rows as $row ) {
73                $this->lName = $row->name;
74                $this->lWiki = $row->wiki;
75                $attachableWikis = $cache->get( $row->name );
76                if ( !$attachableWikis ) {
77                    $ca = new CentralAuthUser( $row->name, IDBAccessObject::READ_LATEST );
78                    $attachableWikis = [];
79                    $unattached = $ca->queryUnattached();
80                    if ( $ca->exists() ) {
81                        $home = $ca->getHomeWiki();
82                        $attachableWikis[] = $home;
83                        foreach ( $unattached as $wiki => $info ) {
84                            if ( $ca->getEmailAuthenticationTimestamp() &&
85                                $info['email'] === $ca->getEmail() &&
86                                $info['emailAuthenticated'] !== null
87                            ) {
88                                $attachableWikis[] = $wiki;
89                            }
90                        }
91                    } else {
92                        $home = $ca->chooseHomeWiki( $unattached );
93                        $attachableWikis[] = $home;
94                        if ( $unattached[$home]['email'] &&
95                            isset( $unattached[$home]['emailAuthenticated'] )
96                        ) {
97                            foreach ( $unattached as $wiki => $info ) {
98                                if ( $wiki !== $home &&
99                                    $unattached[$home]['email'] === $info['email'] &&
100                                    isset( $info['emailAuthenticated'] )
101                                ) {
102                                    $attachableWikis[] = $wiki;
103                                }
104                            }
105                        }
106                    }
107                    $cache->set( $row->name, $attachableWikis );
108                }
109
110                if ( !in_array( $row->wiki, $attachableWikis ) ) {
111                    // Unattached account which is not attachable,
112                    // so they're getting renamed :(
113                    $this->output( "{$row->name}@{$row->wiki} is going to be renamed.\n" );
114                    $insertRows[] = (array)$row;
115                }
116            }
117            $databaseUpdates->batchInsert( $insertRows );
118            $count = $dbw->affectedRows();
119            $this->output( "Inserted $count users who we will rename\n" );
120
121            $this->output( "Waiting for replicas...\n" );
122            CentralAuthServices::getDatabaseManager()->waitForReplication();
123
124        } while ( $count !== 0 );
125    }
126}
127
128$maintClass = PopulateListOfUsersToRename::class;
129require_once RUN_MAINTENANCE_IF_MAIN;