MediaWiki master
SpecialBlockList.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Specials;
22
37use Wikimedia\IPUtils;
41
51 protected $target;
52
54 protected $options;
55
57 protected $blockType;
58
59 private LinkBatchFactory $linkBatchFactory;
60 private DatabaseBlockStore $blockStore;
61 private BlockRestrictionStore $blockRestrictionStore;
62 private IConnectionProvider $dbProvider;
63 private CommentStore $commentStore;
64 private BlockUtils $blockUtils;
65 private HideUserUtils $hideUserUtils;
66 private BlockActionInfo $blockActionInfo;
67 private RowCommentFormatter $rowCommentFormatter;
68 private TempUserConfig $tempUserConfig;
69
70 public function __construct(
71 LinkBatchFactory $linkBatchFactory,
72 DatabaseBlockStore $blockStore,
73 BlockRestrictionStore $blockRestrictionStore,
74 IConnectionProvider $dbProvider,
75 CommentStore $commentStore,
76 BlockUtils $blockUtils,
77 HideUserUtils $hideUserUtils,
78 BlockActionInfo $blockActionInfo,
79 RowCommentFormatter $rowCommentFormatter,
80 TempUserConfig $tempUserConfig
81 ) {
82 parent::__construct( 'BlockList' );
83
84 $this->linkBatchFactory = $linkBatchFactory;
85 $this->blockStore = $blockStore;
86 $this->blockRestrictionStore = $blockRestrictionStore;
87 $this->dbProvider = $dbProvider;
88 $this->commentStore = $commentStore;
89 $this->blockUtils = $blockUtils;
90 $this->hideUserUtils = $hideUserUtils;
91 $this->blockActionInfo = $blockActionInfo;
92 $this->rowCommentFormatter = $rowCommentFormatter;
93 $this->tempUserConfig = $tempUserConfig;
94 }
95
99 public function execute( $par ) {
100 $this->setHeaders();
101 $this->outputHeader();
102 $this->addHelpLink( 'Help:Blocking_users' );
103 $out = $this->getOutput();
104 $out->setPageTitleMsg( $this->msg( 'ipblocklist' ) );
105 $out->addModuleStyles( [ 'mediawiki.special' ] );
106
107 $request = $this->getRequest();
108 $par = $request->getVal( 'ip', $par ?? '' );
109 $this->target = trim( $request->getVal( 'wpTarget', $par ) );
110
111 $this->options = $request->getArray( 'wpOptions', [] );
112 $this->blockType = $request->getVal( 'blockType' );
113
114 $action = $request->getText( 'action' );
115
116 if ( $action == 'unblock' || ( $action == 'submit' && $request->wasPosted() ) ) {
117 // B/C @since 1.18: Unblock interface is now at Special:Unblock
118 $title = $this->getSpecialPageFactory()->getTitleForAlias( 'Unblock/' . $this->target );
119 $out->redirect( $title->getFullURL() );
120
121 return;
122 }
123
124 // Setup BlockListPager here to get the actual default Limit
125 $pager = $this->getBlockListPager();
126
127 $blockFilterOptions = [
128 'blocklist-tempblocks' => 'tempblocks',
129 'blocklist-indefblocks' => 'indefblocks',
130 'blocklist-autoblocks' => 'autoblocks',
131 'blocklist-addressblocks' => 'addressblocks',
132 'blocklist-rangeblocks' => 'rangeblocks',
133 ];
134
135 if ( $this->tempUserConfig->isKnown() ) {
136 // Clarify that "userblocks" excludes named users only if temporary accounts are known (T380266)
137 $blockFilterOptions['blocklist-nameduserblocks'] = 'userblocks';
138 $blockFilterOptions['blocklist-tempuserblocks'] = 'tempuserblocks';
139 } else {
140 $blockFilterOptions['blocklist-userblocks'] = 'userblocks';
141 }
142
143 // Just show the block list
144 $fields = [
145 'Target' => [
146 'type' => 'user',
147 'label-message' => 'ipaddressorusername',
148 'tabindex' => '1',
149 'size' => '45',
150 'default' => $this->target,
151 ],
152 'Options' => [
153 'type' => 'multiselect',
154 'options-messages' => $blockFilterOptions,
155 'flatlist' => true,
156 ],
157 ];
158
159 $fields['BlockType'] = [
160 'type' => 'select',
161 'label-message' => 'blocklist-type',
162 'options' => [
163 $this->msg( 'blocklist-type-opt-all' )->escaped() => '',
164 $this->msg( 'blocklist-type-opt-sitewide' )->escaped() => 'sitewide',
165 $this->msg( 'blocklist-type-opt-partial' )->escaped() => 'partial',
166 ],
167 'name' => 'blockType',
168 'cssclass' => 'mw-field-block-type',
169 ];
170
171 $fields['Limit'] = [
172 'type' => 'limitselect',
173 'label-message' => 'table_pager_limit_label',
174 'options' => $pager->getLimitSelectList(),
175 'name' => 'limit',
176 'default' => $pager->getLimit(),
177 'cssclass' => 'mw-field-limit mw-has-field-block-type',
178 ];
179
180 $form = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
181 $form
182 ->setMethod( 'get' )
183 ->setTitle( $this->getPageTitle() ) // Remove subpage
184 ->setFormIdentifier( 'blocklist' )
185 ->setWrapperLegendMsg( 'ipblocklist-legend' )
186 ->setSubmitTextMsg( 'ipblocklist-submit' )
187 ->prepareForm()
188 ->displayForm( false );
189
190 $this->showList( $pager );
191 }
192
197 protected function getBlockListPager() {
198 $conds = [];
199 $db = $this->getDB();
200
201 if ( $this->target !== '' ) {
202 [ $target, $type ] = $this->blockUtils->parseBlockTarget( $this->target );
203
204 switch ( $type ) {
205 case DatabaseBlock::TYPE_ID:
206 case DatabaseBlock::TYPE_AUTO:
207 $conds['bl_id'] = $target;
208 break;
209
210 case DatabaseBlock::TYPE_IP:
211 case DatabaseBlock::TYPE_RANGE:
212 [ $start, $end ] = IPUtils::parseRange( $target );
213 $conds[] = $this->blockStore->getRangeCond( $start, $end );
214 $conds['bt_auto'] = 0;
215 break;
216
217 case DatabaseBlock::TYPE_USER:
218 if ( $target->getId() ) {
219 $conds['bt_user'] = $target->getId();
220 $conds['bt_auto'] = 0;
221 } else {
222 // No such user
223 $conds[] = '1=0';
224 }
225 break;
226 }
227 }
228
229 // Apply filters
230 if ( in_array( 'userblocks', $this->options ) ) {
231 $namedUserConds = $db->expr( 'bt_user', '=', null );
232
233 // If temporary accounts are a known concept on this wiki,
234 // have the "Hide account blocks" filter exclude only named users (T380266).
235 if ( $this->tempUserConfig->isKnown() ) {
236 $namedUserConds = $namedUserConds->orExpr(
237 $this->tempUserConfig->getMatchCondition( $db, 'bt_user_text', IExpression::LIKE )
238 );
239 }
240
241 $conds[] = $namedUserConds;
242 }
243 if ( in_array( 'autoblocks', $this->options ) ) {
244 $conds['bl_parent_block_id'] = null;
245 }
246 if ( in_array( 'addressblocks', $this->options )
247 && in_array( 'rangeblocks', $this->options )
248 ) {
249 // Simpler conditions for only user blocks (T360864)
250 $conds[] = $db->expr( 'bt_user', '!=', null );
251 } elseif ( in_array( 'addressblocks', $this->options ) ) {
252 $conds[] = $db->expr( 'bt_user', '!=', null )->or( 'bt_range_start', '!=', null );
253 } elseif ( in_array( 'rangeblocks', $this->options ) ) {
254 $conds['bt_range_start'] = null;
255 }
256
257 if (
258 in_array( 'tempuserblocks', $this->options ) &&
259 $this->tempUserConfig->isKnown()
260 ) {
261 $conds[] = $db->expr( 'bt_user', '=', null )
262 ->orExpr(
263 $this->tempUserConfig->getMatchCondition( $db, 'bt_user_text', IExpression::NOT_LIKE )
264 );
265 }
266
267 $hideTemp = in_array( 'tempblocks', $this->options );
268 $hideIndef = in_array( 'indefblocks', $this->options );
269 if ( $hideTemp && $hideIndef ) {
270 // If both types are hidden, ensure query doesn't produce any results
271 $conds[] = '1=0';
272 } elseif ( $hideTemp ) {
273 $conds['bl_expiry'] = $db->getInfinity();
274 } elseif ( $hideIndef ) {
275 $conds[] = $db->expr( 'bl_expiry', '!=', $db->getInfinity() );
276 }
277
278 if ( $this->blockType === 'sitewide' ) {
279 $conds['bl_sitewide'] = 1;
280 } elseif ( $this->blockType === 'partial' ) {
281 $conds['bl_sitewide'] = 0;
282 }
283
284 return new BlockListPager(
285 $this->getContext(),
286 $this->blockActionInfo,
287 $this->blockRestrictionStore,
288 $this->blockUtils,
289 $this->hideUserUtils,
290 $this->commentStore,
291 $this->linkBatchFactory,
292 $this->getLinkRenderer(),
293 $this->dbProvider,
294 $this->rowCommentFormatter,
295 $this->getSpecialPageFactory(),
296 $conds
297 );
298 }
299
304 protected function showList( BlockListPager $pager ) {
305 $out = $this->getOutput();
306
307 // Check for other blocks, i.e. global/tor blocks
308 $otherBlockLink = [];
309 $this->getHookRunner()->onOtherBlockLogLink( $otherBlockLink, $this->target );
310
311 // Show additional header for the local block only when other blocks exists.
312 // Not necessary in a standard installation without such extensions enabled
313 if ( count( $otherBlockLink ) ) {
314 $out->addHTML(
315 Html::element( 'h2', [], $this->msg( 'ipblocklist-localblock' )->text() ) . "\n"
316 );
317 }
318
319 if ( $pager->getNumRows() ) {
320 $out->addParserOutputContent( $pager->getFullOutput() );
321 } elseif ( $this->target ) {
322 $out->addWikiMsg( 'ipblocklist-no-results' );
323 } else {
324 $out->addWikiMsg( 'ipblocklist-empty' );
325 }
326
327 if ( count( $otherBlockLink ) ) {
328 $out->addHTML(
329 Html::rawElement(
330 'h2',
331 [],
332 $this->msg( 'ipblocklist-otherblocks', count( $otherBlockLink ) )->parse()
333 ) . "\n"
334 );
335 $list = '';
336 foreach ( $otherBlockLink as $link ) {
337 $list .= Html::rawElement( 'li', [], $link ) . "\n";
338 }
339 $out->addHTML( Html::rawElement(
340 'ul',
341 [ 'class' => 'mw-ipblocklist-otherblocks' ],
342 $list
343 ) . "\n" );
344 }
345 }
346
347 protected function getGroupName() {
348 return 'users';
349 }
350
356 protected function getDB() {
357 return $this->dbProvider->getReplicaDatabase();
358 }
359}
360
362class_alias( SpecialBlockList::class, 'SpecialBlockList' );
Defines the actions that can be blocked by a partial block.
Backend class for blocking utils.
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Helpers for building queries that determine whether a user is hidden.
This is basically a CommentFormatter with a CommentStore dependency, allowing it to retrieve comment ...
Handle database storage of comments such as edit summaries and log reasons.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:209
This class is a collection of static functions that serve two purposes:
Definition Html.php:56
getNumRows()
Get the number of rows in the result set.
getFullOutput()
Get the formatted result list, with navigation bars.
Parent class for all special pages.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getPageTitle( $subpage=false)
Get a self-referential title object.
getContext()
Gets the context this SpecialPage is executed in.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages By default the message key is the canonical name of...
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
showList(BlockListPager $pager)
Show the list of blocked accounts matching the actual filter.
getDB()
Return a IDatabase object for reading.
__construct(LinkBatchFactory $linkBatchFactory, DatabaseBlockStore $blockStore, BlockRestrictionStore $blockRestrictionStore, IConnectionProvider $dbProvider, CommentStore $commentStore, BlockUtils $blockUtils, HideUserUtils $hideUserUtils, BlockActionInfo $blockActionInfo, RowCommentFormatter $rowCommentFormatter, TempUserConfig $tempUserConfig)
getBlockListPager()
Setup a new BlockListPager instance.
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Interface for temporary user creation config and name matching.
Provide primary and replica IDatabase connections.
A database connection without write operations.
element(SerializerNode $parent, SerializerNode $node, $contents)