Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 160 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
SpecialBlockList | |
0.00% |
0 / 159 |
|
0.00% |
0 / 6 |
1122 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 67 |
|
0.00% |
0 / 1 |
20 | |||
getBlockListPager | |
0.00% |
0 / 52 |
|
0.00% |
0 / 1 |
420 | |||
showList | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
42 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getDB | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | */ |
20 | |
21 | namespace MediaWiki\Specials; |
22 | |
23 | use MediaWiki\Block\BlockActionInfo; |
24 | use MediaWiki\Block\BlockRestrictionStore; |
25 | use MediaWiki\Block\BlockUtils; |
26 | use MediaWiki\Block\DatabaseBlock; |
27 | use MediaWiki\Block\DatabaseBlockStore; |
28 | use MediaWiki\Block\HideUserUtils; |
29 | use MediaWiki\Cache\LinkBatchFactory; |
30 | use MediaWiki\CommentFormatter\RowCommentFormatter; |
31 | use MediaWiki\CommentStore\CommentStore; |
32 | use MediaWiki\Html\Html; |
33 | use MediaWiki\HTMLForm\HTMLForm; |
34 | use MediaWiki\Pager\BlockListPager; |
35 | use MediaWiki\SpecialPage\SpecialPage; |
36 | use Wikimedia\IPUtils; |
37 | use Wikimedia\Rdbms\IConnectionProvider; |
38 | use Wikimedia\Rdbms\IReadableDatabase; |
39 | |
40 | /** |
41 | * List of existing blocks |
42 | * |
43 | * @see SpecialBlock |
44 | * @see SpecialAutoblockList |
45 | * @ingroup SpecialPage |
46 | */ |
47 | class SpecialBlockList extends SpecialPage { |
48 | /** @var string */ |
49 | protected $target; |
50 | |
51 | /** @var array */ |
52 | protected $options; |
53 | |
54 | /** @var string|null */ |
55 | protected $blockType; |
56 | |
57 | private LinkBatchFactory $linkBatchFactory; |
58 | private DatabaseBlockStore $blockStore; |
59 | private BlockRestrictionStore $blockRestrictionStore; |
60 | private IConnectionProvider $dbProvider; |
61 | private CommentStore $commentStore; |
62 | private BlockUtils $blockUtils; |
63 | private HideUserUtils $hideUserUtils; |
64 | private BlockActionInfo $blockActionInfo; |
65 | private RowCommentFormatter $rowCommentFormatter; |
66 | |
67 | public function __construct( |
68 | LinkBatchFactory $linkBatchFactory, |
69 | DatabaseBlockStore $blockStore, |
70 | BlockRestrictionStore $blockRestrictionStore, |
71 | IConnectionProvider $dbProvider, |
72 | CommentStore $commentStore, |
73 | BlockUtils $blockUtils, |
74 | HideUserUtils $hideUserUtils, |
75 | BlockActionInfo $blockActionInfo, |
76 | RowCommentFormatter $rowCommentFormatter |
77 | ) { |
78 | parent::__construct( 'BlockList' ); |
79 | |
80 | $this->linkBatchFactory = $linkBatchFactory; |
81 | $this->blockStore = $blockStore; |
82 | $this->blockRestrictionStore = $blockRestrictionStore; |
83 | $this->dbProvider = $dbProvider; |
84 | $this->commentStore = $commentStore; |
85 | $this->blockUtils = $blockUtils; |
86 | $this->hideUserUtils = $hideUserUtils; |
87 | $this->blockActionInfo = $blockActionInfo; |
88 | $this->rowCommentFormatter = $rowCommentFormatter; |
89 | } |
90 | |
91 | /** |
92 | * @param string|null $par Title fragment |
93 | */ |
94 | public function execute( $par ) { |
95 | $this->setHeaders(); |
96 | $this->outputHeader(); |
97 | $this->addHelpLink( 'Help:Blocking_users' ); |
98 | $out = $this->getOutput(); |
99 | $out->setPageTitleMsg( $this->msg( 'ipblocklist' ) ); |
100 | $out->addModuleStyles( [ 'mediawiki.special' ] ); |
101 | |
102 | $request = $this->getRequest(); |
103 | $par = $request->getVal( 'ip', $par ?? '' ); |
104 | $this->target = trim( $request->getVal( 'wpTarget', $par ) ); |
105 | |
106 | $this->options = $request->getArray( 'wpOptions', [] ); |
107 | $this->blockType = $request->getVal( 'blockType' ); |
108 | |
109 | $action = $request->getText( 'action' ); |
110 | |
111 | if ( $action == 'unblock' || ( $action == 'submit' && $request->wasPosted() ) ) { |
112 | // B/C @since 1.18: Unblock interface is now at Special:Unblock |
113 | $title = $this->getSpecialPageFactory()->getTitleForAlias( 'Unblock/' . $this->target ); |
114 | $out->redirect( $title->getFullURL() ); |
115 | |
116 | return; |
117 | } |
118 | |
119 | // Setup BlockListPager here to get the actual default Limit |
120 | $pager = $this->getBlockListPager(); |
121 | |
122 | // Just show the block list |
123 | $fields = [ |
124 | 'Target' => [ |
125 | 'type' => 'user', |
126 | 'label-message' => 'ipaddressorusername', |
127 | 'tabindex' => '1', |
128 | 'size' => '45', |
129 | 'default' => $this->target, |
130 | ], |
131 | 'Options' => [ |
132 | 'type' => 'multiselect', |
133 | 'options-messages' => [ |
134 | 'blocklist-tempblocks' => 'tempblocks', |
135 | 'blocklist-indefblocks' => 'indefblocks', |
136 | 'blocklist-autoblocks' => 'autoblocks', |
137 | 'blocklist-userblocks' => 'userblocks', |
138 | 'blocklist-addressblocks' => 'addressblocks', |
139 | 'blocklist-rangeblocks' => 'rangeblocks', |
140 | ], |
141 | 'flatlist' => true, |
142 | ], |
143 | ]; |
144 | |
145 | $fields['BlockType'] = [ |
146 | 'type' => 'select', |
147 | 'label-message' => 'blocklist-type', |
148 | 'options' => [ |
149 | $this->msg( 'blocklist-type-opt-all' )->escaped() => '', |
150 | $this->msg( 'blocklist-type-opt-sitewide' )->escaped() => 'sitewide', |
151 | $this->msg( 'blocklist-type-opt-partial' )->escaped() => 'partial', |
152 | ], |
153 | 'name' => 'blockType', |
154 | 'cssclass' => 'mw-field-block-type', |
155 | ]; |
156 | |
157 | $fields['Limit'] = [ |
158 | 'type' => 'limitselect', |
159 | 'label-message' => 'table_pager_limit_label', |
160 | 'options' => $pager->getLimitSelectList(), |
161 | 'name' => 'limit', |
162 | 'default' => $pager->getLimit(), |
163 | 'cssclass' => 'mw-field-limit mw-has-field-block-type', |
164 | ]; |
165 | |
166 | $form = HTMLForm::factory( 'ooui', $fields, $this->getContext() ); |
167 | $form |
168 | ->setMethod( 'get' ) |
169 | ->setTitle( $this->getPageTitle() ) // Remove subpage |
170 | ->setFormIdentifier( 'blocklist' ) |
171 | ->setWrapperLegendMsg( 'ipblocklist-legend' ) |
172 | ->setSubmitTextMsg( 'ipblocklist-submit' ) |
173 | ->prepareForm() |
174 | ->displayForm( false ); |
175 | |
176 | $this->showList( $pager ); |
177 | } |
178 | |
179 | /** |
180 | * Setup a new BlockListPager instance. |
181 | * @return BlockListPager |
182 | */ |
183 | protected function getBlockListPager() { |
184 | $conds = []; |
185 | $db = $this->getDB(); |
186 | |
187 | if ( $this->target !== '' ) { |
188 | [ $target, $type ] = $this->blockUtils->parseBlockTarget( $this->target ); |
189 | |
190 | switch ( $type ) { |
191 | case DatabaseBlock::TYPE_ID: |
192 | case DatabaseBlock::TYPE_AUTO: |
193 | $conds['bl_id'] = $target; |
194 | break; |
195 | |
196 | case DatabaseBlock::TYPE_IP: |
197 | case DatabaseBlock::TYPE_RANGE: |
198 | [ $start, $end ] = IPUtils::parseRange( $target ); |
199 | $conds[] = $this->blockStore->getRangeCond( $start, $end ); |
200 | $conds['bt_auto'] = 0; |
201 | break; |
202 | |
203 | case DatabaseBlock::TYPE_USER: |
204 | if ( $target->getId() ) { |
205 | $conds['bt_user'] = $target->getId(); |
206 | $conds['bt_auto'] = 0; |
207 | } else { |
208 | // No such user |
209 | $conds[] = '1=0'; |
210 | } |
211 | break; |
212 | } |
213 | } |
214 | |
215 | // Apply filters |
216 | if ( in_array( 'userblocks', $this->options ) ) { |
217 | $conds['bt_user'] = null; |
218 | } |
219 | if ( in_array( 'autoblocks', $this->options ) ) { |
220 | $conds['bl_parent_block_id'] = null; |
221 | } |
222 | if ( in_array( 'addressblocks', $this->options ) |
223 | && in_array( 'rangeblocks', $this->options ) |
224 | ) { |
225 | // Simpler conditions for only user blocks (T360864) |
226 | $conds[] = $db->expr( 'bt_user', '!=', null ); |
227 | } elseif ( in_array( 'addressblocks', $this->options ) ) { |
228 | $conds[] = $db->expr( 'bt_user', '!=', null )->or( 'bt_range_start', '!=', null ); |
229 | } elseif ( in_array( 'rangeblocks', $this->options ) ) { |
230 | $conds['bt_range_start'] = null; |
231 | } |
232 | |
233 | $hideTemp = in_array( 'tempblocks', $this->options ); |
234 | $hideIndef = in_array( 'indefblocks', $this->options ); |
235 | if ( $hideTemp && $hideIndef ) { |
236 | // If both types are hidden, ensure query doesn't produce any results |
237 | $conds[] = '1=0'; |
238 | } elseif ( $hideTemp ) { |
239 | $conds['bl_expiry'] = $db->getInfinity(); |
240 | } elseif ( $hideIndef ) { |
241 | $conds[] = $db->expr( 'bl_expiry', '!=', $db->getInfinity() ); |
242 | } |
243 | |
244 | if ( $this->blockType === 'sitewide' ) { |
245 | $conds['bl_sitewide'] = 1; |
246 | } elseif ( $this->blockType === 'partial' ) { |
247 | $conds['bl_sitewide'] = 0; |
248 | } |
249 | |
250 | return new BlockListPager( |
251 | $this->getContext(), |
252 | $this->blockActionInfo, |
253 | $this->blockRestrictionStore, |
254 | $this->blockUtils, |
255 | $this->hideUserUtils, |
256 | $this->commentStore, |
257 | $this->linkBatchFactory, |
258 | $this->getLinkRenderer(), |
259 | $this->dbProvider, |
260 | $this->rowCommentFormatter, |
261 | $this->getSpecialPageFactory(), |
262 | $conds |
263 | ); |
264 | } |
265 | |
266 | /** |
267 | * Show the list of blocked accounts matching the actual filter. |
268 | * @param BlockListPager $pager The BlockListPager instance for this page |
269 | */ |
270 | protected function showList( BlockListPager $pager ) { |
271 | $out = $this->getOutput(); |
272 | |
273 | // Check for other blocks, i.e. global/tor blocks |
274 | $otherBlockLink = []; |
275 | $this->getHookRunner()->onOtherBlockLogLink( $otherBlockLink, $this->target ); |
276 | |
277 | // Show additional header for the local block only when other blocks exists. |
278 | // Not necessary in a standard installation without such extensions enabled |
279 | if ( count( $otherBlockLink ) ) { |
280 | $out->addHTML( |
281 | Html::element( 'h2', [], $this->msg( 'ipblocklist-localblock' )->text() ) . "\n" |
282 | ); |
283 | } |
284 | |
285 | if ( $pager->getNumRows() ) { |
286 | $out->addParserOutputContent( $pager->getFullOutput() ); |
287 | } elseif ( $this->target ) { |
288 | $out->addWikiMsg( 'ipblocklist-no-results' ); |
289 | } else { |
290 | $out->addWikiMsg( 'ipblocklist-empty' ); |
291 | } |
292 | |
293 | if ( count( $otherBlockLink ) ) { |
294 | $out->addHTML( |
295 | Html::rawElement( |
296 | 'h2', |
297 | [], |
298 | $this->msg( 'ipblocklist-otherblocks', count( $otherBlockLink ) )->parse() |
299 | ) . "\n" |
300 | ); |
301 | $list = ''; |
302 | foreach ( $otherBlockLink as $link ) { |
303 | $list .= Html::rawElement( 'li', [], $link ) . "\n"; |
304 | } |
305 | $out->addHTML( Html::rawElement( |
306 | 'ul', |
307 | [ 'class' => 'mw-ipblocklist-otherblocks' ], |
308 | $list |
309 | ) . "\n" ); |
310 | } |
311 | } |
312 | |
313 | protected function getGroupName() { |
314 | return 'users'; |
315 | } |
316 | |
317 | /** |
318 | * Return a IDatabase object for reading |
319 | * |
320 | * @return IReadableDatabase |
321 | */ |
322 | protected function getDB() { |
323 | return $this->dbProvider->getReplicaDatabase(); |
324 | } |
325 | } |
326 | |
327 | /** @deprecated class alias since 1.41 */ |
328 | class_alias( SpecialBlockList::class, 'SpecialBlockList' ); |