Localisation updates from https://translatewiki.net.
[mediawiki.git] / includes / specials / SpecialBlockList.php
blob1f6f3e6189e749bfdea544b879e7d63306014156
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.
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.
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
18 * @file
21 namespace MediaWiki\Specials;
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 MediaWiki\User\TempUser\TempUserConfig;
37 use Wikimedia\IPUtils;
38 use Wikimedia\Rdbms\IConnectionProvider;
39 use Wikimedia\Rdbms\IExpression;
40 use Wikimedia\Rdbms\IReadableDatabase;
42 /**
43 * List of existing blocks
45 * @see SpecialBlock
46 * @see SpecialAutoblockList
47 * @ingroup SpecialPage
49 class SpecialBlockList extends SpecialPage {
50 /** @var string */
51 protected $target;
53 /** @var array */
54 protected $options;
56 /** @var string|null */
57 protected $blockType;
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;
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' );
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;
96 /**
97 * @param string|null $par Title fragment
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' ] );
107 $request = $this->getRequest();
108 $par = $request->getVal( 'ip', $par ?? '' );
109 $this->target = trim( $request->getVal( 'wpTarget', $par ) );
111 $this->options = $request->getArray( 'wpOptions', [] );
112 $this->blockType = $request->getVal( 'blockType' );
114 $action = $request->getText( 'action' );
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() );
121 return;
124 // Setup BlockListPager here to get the actual default Limit
125 $pager = $this->getBlockListPager();
127 $blockFilterOptions = [
128 'blocklist-tempblocks' => 'tempblocks',
129 'blocklist-indefblocks' => 'indefblocks',
130 'blocklist-autoblocks' => 'autoblocks',
131 'blocklist-addressblocks' => 'addressblocks',
132 'blocklist-rangeblocks' => 'rangeblocks',
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';
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,
152 'Options' => [
153 'type' => 'multiselect',
154 'options-messages' => $blockFilterOptions,
155 'flatlist' => true,
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',
167 'name' => 'blockType',
168 'cssclass' => 'mw-field-block-type',
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',
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 );
190 $this->showList( $pager );
194 * Setup a new BlockListPager instance.
195 * @return BlockListPager
197 protected function getBlockListPager() {
198 $conds = [];
199 $db = $this->getDB();
201 if ( $this->target !== '' ) {
202 [ $target, $type ] = $this->blockUtils->parseBlockTarget( $this->target );
204 switch ( $type ) {
205 case DatabaseBlock::TYPE_ID:
206 case DatabaseBlock::TYPE_AUTO:
207 $conds['bl_id'] = $target;
208 break;
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;
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';
225 break;
229 // Apply filters
230 if ( in_array( 'userblocks', $this->options ) ) {
231 $namedUserConds = $db->expr( 'bt_user', '=', null );
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 )
241 $conds[] = $namedUserConds;
243 if ( in_array( 'autoblocks', $this->options ) ) {
244 $conds['bl_parent_block_id'] = null;
246 if ( in_array( 'addressblocks', $this->options )
247 && in_array( 'rangeblocks', $this->options )
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;
257 if (
258 in_array( 'tempuserblocks', $this->options ) &&
259 $this->tempUserConfig->isKnown()
261 $conds[] = $db->expr( 'bt_user', '=', null )
262 ->orExpr(
263 $this->tempUserConfig->getMatchCondition( $db, 'bt_user_text', IExpression::NOT_LIKE )
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() );
278 if ( $this->blockType === 'sitewide' ) {
279 $conds['bl_sitewide'] = 1;
280 } elseif ( $this->blockType === 'partial' ) {
281 $conds['bl_sitewide'] = 0;
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
301 * Show the list of blocked accounts matching the actual filter.
302 * @param BlockListPager $pager The BlockListPager instance for this page
304 protected function showList( BlockListPager $pager ) {
305 $out = $this->getOutput();
307 // Check for other blocks, i.e. global/tor blocks
308 $otherBlockLink = [];
309 $this->getHookRunner()->onOtherBlockLogLink( $otherBlockLink, $this->target );
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"
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' );
327 if ( count( $otherBlockLink ) ) {
328 $out->addHTML(
329 Html::rawElement(
330 'h2',
332 $this->msg( 'ipblocklist-otherblocks', count( $otherBlockLink ) )->parse()
333 ) . "\n"
335 $list = '';
336 foreach ( $otherBlockLink as $link ) {
337 $list .= Html::rawElement( 'li', [], $link ) . "\n";
339 $out->addHTML( Html::rawElement(
340 'ul',
341 [ 'class' => 'mw-ipblocklist-otherblocks' ],
342 $list
343 ) . "\n" );
347 protected function getGroupName() {
348 return 'users';
352 * Return a IDatabase object for reading
354 * @return IReadableDatabase
356 protected function getDB() {
357 return $this->dbProvider->getReplicaDatabase();
361 /** @deprecated class alias since 1.41 */
362 class_alias( SpecialBlockList::class, 'SpecialBlockList' );