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 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
CentralAuthDeleteLocalPasswords
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 6
272
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 initialize
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 getUserBatches
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 getUserDB
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 getWikis
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 getUsers
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3use MediaWiki\Extension\CentralAuth\CentralAuthServices;
4use MediaWiki\MediaWikiServices;
5use MediaWiki\WikiMap\WikiMap;
6use Wikimedia\Rdbms\SelectQueryBuilder;
7
8$IP = getenv( 'MW_INSTALL_PATH' );
9if ( $IP === false ) {
10    $IP = __DIR__ . '/../../..';
11}
12require_once "$IP/maintenance/includes/DeleteLocalPasswords.php";
13
14// @phpcs:ignore MediaWiki.Files.ClassMatchesFilename.NotMatch
15class CentralAuthDeleteLocalPasswords extends DeleteLocalPasswords {
16    /** @var string|null Wiki to run on, or null for all. */
17    protected $wiki;
18
19    /** @var string|null The wiki being currently processed */
20    protected $currentWiki;
21
22    public function __construct() {
23        parent::__construct();
24        $this->requireExtension( 'CentralAuth' );
25        $this->addDescription( 'Deletes local password for users with a central account.' );
26
27        $this->addOption( 'wiki', 'If specified, only runs against local names from this wiki',
28            false, true );
29        $this->addOption( 'allwikis', 'If specified, checks all wikis. This is for the benefit '
30            . "of frameworks which always add a 'wiki' parameter.", false, false );
31    }
32
33    protected function initialize() {
34        parent::initialize();
35        $wiki = $this->getOption( 'wiki', false );
36        if ( $wiki !== false && !$this->getOption( 'allwikis' ) ) {
37            $this->wiki = $wiki;
38        }
39    }
40
41    /** @inheritDoc */
42    protected function getUserBatches() {
43        // since the keys on localnames are not conducive to batch operations and
44        // because of the database shards, grab a list of the wikis and we will
45        // iterate from there
46        foreach ( $this->getWikis() as $wiki ) {
47            $this->output( "Processing users for $wiki ...\n" );
48
49            if ( !WikiMap::getWiki( $wiki ) ) {
50                $this->error( "$wiki does not exist, use checkLocalUser.php to delete invalid records\n" );
51                continue;
52            }
53
54            $this->currentWiki = $wiki;
55            foreach ( $this->getUsers( $wiki ) as $users ) {
56                yield $users;
57            }
58        }
59    }
60
61    /** @inheritDoc */
62    protected function getUserDB() {
63        if ( $this->currentWiki === null ) {
64            throw new LogicException( 'Tried to get wiki DB before wiki was selected' );
65        }
66        return MediaWikiServices::getInstance()->getDBLoadBalancerFactory()
67            ->getMainLB( $this->currentWiki )
68            ->getMaintenanceConnectionRef( DB_PRIMARY, [], $this->currentWiki );
69    }
70
71    /**
72     * @return array|null[]|string[]
73     */
74    protected function getWikis() {
75        $centralReplica = CentralAuthServices::getDatabaseManager()->getCentralReplicaDB();
76
77        if ( $this->wiki !== null ) {
78            return [ $this->wiki ];
79        } else {
80            $conds = [];
81            if ( $this->user !== null ) {
82                $conds['lu_name'] = $this->user;
83            }
84            return $centralReplica->newSelectQueryBuilder()
85                ->select( 'lu_wiki' )
86                ->distinct()
87                ->from( 'localuser' )
88                ->where( $conds )
89                ->orderBy( 'lu_wiki', SelectQueryBuilder::SORT_ASC )
90                ->caller( __METHOD__ )
91                ->fetchFieldValues();
92        }
93    }
94
95    /**
96     * @param string $wiki
97     *
98     * @return Generator
99     */
100    protected function getUsers( $wiki ) {
101        if ( $this->user !== null ) {
102            $this->output( "\t ... querying '$this->user'\n" );
103            yield [ $this->user ];
104            return;
105        }
106
107        $centralReplica = CentralAuthServices::getDatabaseManager()->getCentralReplicaDB();
108        $lastUsername = '';
109        do {
110            $this->output( "\t ... querying from '$lastUsername'\n" );
111            $users = $centralReplica->newSelectQueryBuilder()
112                ->select( 'lu_name' )
113                ->from( 'localuser' )
114                ->where( [
115                    'lu_wiki' => $wiki,
116                    $centralReplica->expr( 'lu_name', '>', $lastUsername ),
117                ] )
118                ->orderBy( 'lu_name', SelectQueryBuilder::SORT_ASC )
119                ->limit( $this->getBatchSize() )
120                ->caller( __METHOD__ )
121                ->fetchFieldValues();
122
123            if ( $users ) {
124                yield $users;
125                $lastUsername = end( $users );
126            }
127        } while ( count( $users ) === $this->getBatchSize() );
128    }
129}
130
131$maintClass = CentralAuthDeleteLocalPasswords::class;
132require_once RUN_MAINTENANCE_IF_MAIN;