Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.28% covered (success)
98.28%
114 / 116
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
BlockUsers
98.28% covered (success)
98.28%
114 / 116
50.00% covered (danger)
50.00%
1 / 2
11
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
70 / 70
100.00% covered (success)
100.00%
1 / 1
1
 execute
95.65% covered (success)
95.65%
44 / 46
0.00% covered (danger)
0.00%
0 / 1
10
1<?php
2
3/**
4 * @license GPL-2.0-or-later
5 * @file
6 * @ingroup Maintenance
7 */
8
9// @codeCoverageIgnoreStart
10require_once __DIR__ . '/Maintenance.php';
11// @codeCoverageIgnoreEnd
12
13use MediaWiki\Maintenance\Maintenance;
14use MediaWiki\User\User;
15
16class BlockUsers extends Maintenance {
17
18    public function __construct() {
19        parent::__construct();
20
21        $this->addDescription(
22            "Blocks a list of usernames. Can use STDIN or the file argument.\n\n" .
23            'Note, this is probably most useful when dealing with spammers, with a ' .
24            "list you've generated with an SQL query or similar.\n\n" .
25            'By default, all users are hard blocked, auto blocked from any current and subsequent ' .
26            'IP addresses, email disabled, unable to write to their user page and unable to ' .
27            'create further accounts with no expiry to this block. You can change the expiry ' .
28            'with --expiry parameter.'
29        );
30
31        $this->addArg(
32            'file',
33            'File with list of users to block',
34            false
35        );
36
37        $this->addOption(
38            'performer',
39            'User to make the blocks',
40            false,
41            true
42        );
43
44        $this->addOption(
45            'reason',
46            'Reason for the blocks',
47            false,
48            true
49        );
50
51        $this->addOption(
52            'reblock',
53            'Reblock users who are already blocked',
54            false,
55            false
56        );
57
58        $this->addOption(
59            'expiry',
60            'Expiry of your block',
61            false,
62            true
63        );
64
65        $this->addOption(
66            'unblock',
67            'Should this unblock?',
68            false,
69            false
70        );
71
72        $this->addOption(
73            'allow-createaccount',
74            'Allow account creation for blocked IPs',
75            false
76        );
77
78        $this->addOption(
79            'allow-email',
80            'Allow blocked accounts to send emails',
81            false
82        );
83
84        $this->addOption(
85            'allow-talkedit',
86            'Allow blocked accounts to edit their own talk page',
87            false
88        );
89
90        $this->addOption(
91            'disable-hardblock',
92            'Don\'t block logged in accounts from a blocked IP address (will still block temporary accounts)',
93            false
94        );
95
96        $this->addOption(
97            'disable-autoblock',
98            'Don\'t autoblock IP addresses used by the accounts',
99            false
100        );
101    }
102
103    public function execute() {
104        $performerName = $this->getOption( 'performer', false );
105        $reason = $this->getOption( 'reason', '' );
106        $unblocking = $this->getOption( 'unblock', false );
107        $reblock = $this->hasOption( 'reblock' );
108        $expiry = $this->getOption( 'expiry', 'indefinite' );
109
110        if ( $performerName ) {
111            $performer = $this->getServiceContainer()->getUserFactory()->newFromName( $performerName );
112        } else {
113            $performer = User::newSystemUser( User::MAINTENANCE_SCRIPT_USER, [ 'steal' => true ] );
114        }
115
116        if ( $performer === null ) {
117            $this->fatalError( "Unable to parse performer's username" );
118        }
119
120        if ( $this->hasArg( 0 ) ) {
121            $file = fopen( $this->getArg( 0 ), 'r' );
122        } else {
123            $file = $this->getStdin();
124        }
125
126        # Setup
127        if ( !$file ) {
128            $this->fatalError( "Unable to read file, exiting" );
129        }
130
131        # Handle each entry
132        $blockUserFactory = $this->getServiceContainer()->getBlockUserFactory();
133        $unblockUserFactory = $this->getServiceContainer()->getUnblockUserFactory();
134        $action = $unblocking ? "Unblocking" : "Blocking";
135        for ( $linenum = 1; !feof( $file ); $linenum++ ) {
136            $line = trim( fgets( $file ) );
137            if ( $line == '' ) {
138                continue;
139            }
140
141            if ( $unblocking ) {
142                $res = $unblockUserFactory->newUnblockUser(
143                    $line,
144                    $performer,
145                    $reason
146                )->unblockUnsafe();
147            } else {
148                $res = $blockUserFactory->newBlockUser(
149                    $line,
150                    $performer,
151                    $expiry,
152                    $reason,
153                    [
154                        'isCreateAccountBlocked' => !$this->hasOption( 'allow-createaccount' ),
155                        'isEmailBlocked' => !$this->hasOption( 'allow-email' ),
156                        'isUserTalkEditBlocked' => !$this->hasOption( 'allow-talkedit' ),
157                        'isHardBlock' => !$this->hasOption( 'disable-hardblock' ),
158                        'isAutoblocking' => !$this->hasOption( 'disable-autoblock' ),
159                    ]
160                )->placeBlockUnsafe( $reblock );
161            }
162
163            if ( $res->isOK() ) {
164                $this->output( "{$action} '{$line}' succeeded.\n" );
165            } else {
166                $errorsText = $res->getMessage()->text();
167                $this->output( "{$action} '{$line}' failed ({$errorsText}).\n" );
168            }
169
170            $this->waitForReplication();
171        }
172    }
173}
174
175// @codeCoverageIgnoreStart
176$maintClass = BlockUsers::class;
177require_once RUN_MAINTENANCE_IF_MAIN;
178// @codeCoverageIgnoreEnd