MediaWiki  master
SpecialBlock.php
Go to the documentation of this file.
1 <?php
40 use Wikimedia\IPUtils;
41 
49 
51  private $blockUtils;
52 
55 
58 
60  private $userNameUtils;
61 
64 
67 
69  private $titleFormatter;
70 
74  protected $target;
75 
77  protected $type;
78 
80  protected $previousTarget;
81 
83  protected $requestedHideUser;
84 
86  protected $alreadyBlocked;
87 
89  protected $preErrors = [];
90 
92  private $namespaceInfo;
93 
104  public function __construct(
113  ) {
114  parent::__construct( 'Block', 'block' );
115 
116  $this->blockUtils = $blockUtils;
117  $this->blockPermissionCheckerFactory = $blockPermissionCheckerFactory;
118  $this->blockUserFactory = $blockUserFactory;
119  $this->userNameUtils = $userNameUtils;
120  $this->userNamePrefixSearch = $userNamePrefixSearch;
121  $this->blockActionInfo = $blockActionInfo;
122  $this->titleFormatter = $titleFormatter;
123  $this->namespaceInfo = $namespaceInfo;
124  }
125 
126  public function doesWrites() {
127  return true;
128  }
129 
136  protected function checkExecutePermissions( User $user ) {
137  parent::checkExecutePermissions( $user );
138  # T17810: blocked admins should have limited access here
139  $status = $this->blockPermissionCheckerFactory
140  ->newBlockPermissionChecker( $this->target, $user )
141  ->checkBlockPermissions();
142  if ( $status !== true ) {
143  throw new ErrorPageError( 'badaccess', $status );
144  }
145  }
146 
152  public function requiresUnblock() {
153  return false;
154  }
155 
161  protected function setParameter( $par ) {
162  # Extract variables from the request. Try not to get into a situation where we
163  # need to extract *every* variable from the form just for processing here, but
164  # there are legitimate uses for some variables
165  $request = $this->getRequest();
166  list( $this->target, $this->type ) = self::getTargetAndType( $par, $request );
167  if ( $this->target instanceof UserIdentity ) {
168  # Set the 'relevant user' in the skin, so it displays links like Contributions,
169  # User logs, UserRights, etc.
170  $this->getSkin()->setRelevantUser( $this->target );
171  }
172 
173  list( $this->previousTarget, /*...*/ ) = $this->blockUtils
174  ->parseBlockTarget( $request->getVal( 'wpPreviousTarget' ) );
175  $this->requestedHideUser = $request->getBool( 'wpHideUser' );
176  }
177 
183  protected function alterForm( HTMLForm $form ) {
184  $form->setHeaderText( '' );
185  $form->setSubmitDestructive();
186 
187  $msg = $this->alreadyBlocked ? 'ipb-change-block' : 'ipbsubmit';
188  $form->setSubmitTextMsg( $msg );
189 
190  $this->addHelpLink( 'Help:Blocking users' );
191 
192  # Don't need to do anything if the form has been posted
193  if ( !$this->getRequest()->wasPosted() && $this->preErrors ) {
194  $s = $form->formatErrors( $this->preErrors );
195  if ( $s ) {
197  'div',
198  [ 'class' => 'error' ],
199  $s
200  ) );
201  }
202  }
203  }
204 
205  protected function getDisplayFormat() {
206  return 'ooui';
207  }
208 
213  protected function getFormFields() {
214  $conf = $this->getConfig();
215  $blockAllowsUTEdit = $conf->get( 'BlockAllowsUTEdit' );
216  $this->getOutput()->addJsConfigVars(
217  'wgEnablePartialActionBlocks',
218  $conf->get( 'EnablePartialActionBlocks' )
219  );
220 
221  $this->getOutput()->enableOOUI();
222 
223  $user = $this->getUser();
224 
225  $suggestedDurations = self::getSuggestedDurations();
226 
227  $a = [];
228 
229  $a['Target'] = [
230  'type' => 'user',
231  'ipallowed' => true,
232  'iprange' => true,
233  'id' => 'mw-bi-target',
234  'size' => '45',
235  'autofocus' => true,
236  'required' => true,
237  'placeholder' => $this->msg( 'block-target-placeholder' )->text(),
238  'validation-callback' => function ( $value, $alldata, $form ) {
239  $status = $this->blockUtils->validateTarget( $value );
240  if ( !$status->isOK() ) {
241  $errors = $status->getErrorsArray();
242 
243  return $form->msg( ...$errors[0] );
244  }
245  return true;
246  },
247  'section' => 'target',
248  ];
249 
250  $a['EditingRestriction'] = [
251  'type' => 'radio',
252  'cssclass' => 'mw-block-editing-restriction',
253  'default' => 'sitewide',
254  'options' => [
255  $this->msg( 'ipb-sitewide' )->escaped() .
256  new \OOUI\LabelWidget( [
257  'classes' => [ 'oo-ui-inline-help' ],
258  'label' => new \OOUI\HtmlSnippet( $this->msg( 'ipb-sitewide-help' )->parse() ),
259  ] ) => 'sitewide',
260  $this->msg( 'ipb-partial' )->escaped() .
261  new \OOUI\LabelWidget( [
262  'classes' => [ 'oo-ui-inline-help' ],
263  'label' => $this->msg( 'ipb-partial-help' )->text(),
264  ] ) => 'partial',
265  ],
266  'section' => 'actions',
267  ];
268 
269  $a['PageRestrictions'] = [
270  'type' => 'titlesmultiselect',
271  'label' => $this->msg( 'ipb-pages-label' )->text(),
272  'exists' => true,
273  'max' => 10,
274  'cssclass' => 'mw-block-partial-restriction',
275  'showMissing' => false,
276  'excludeDynamicNamespaces' => true,
277  'input' => [
278  'autocomplete' => false
279  ],
280  'section' => 'actions',
281  ];
282 
283  $a['NamespaceRestrictions'] = [
284  'type' => 'namespacesmultiselect',
285  'label' => $this->msg( 'ipb-namespaces-label' )->text(),
286  'exists' => true,
287  'cssclass' => 'mw-block-partial-restriction',
288  'input' => [
289  'autocomplete' => false
290  ],
291  'section' => 'actions',
292  ];
293 
294  if ( $conf->get( 'EnablePartialActionBlocks' ) ) {
295  $blockActions = $this->blockActionInfo->getAllBlockActions();
296  $a['ActionRestrictions'] = [
297  'type' => 'multiselect',
298  'cssclass' => 'mw-block-partial-restriction mw-block-action-restriction',
299  'options-messages' => array_combine(
300  array_map( static function ( $action ) {
301  return "ipb-action-$action";
302  }, array_keys( $blockActions ) ),
303  $blockActions
304  ),
305  'section' => 'actions',
306  ];
307  }
308 
309  $a['CreateAccount'] = [
310  'type' => 'check',
311  'cssclass' => 'mw-block-restriction',
312  'label-message' => 'ipbcreateaccount',
313  'default' => true,
314  'section' => 'details',
315  ];
316 
317  if ( $this->blockPermissionCheckerFactory
318  ->newBlockPermissionChecker( null, $user )
319  ->checkEmailPermissions()
320  ) {
321  $a['DisableEmail'] = [
322  'type' => 'check',
323  'cssclass' => 'mw-block-restriction',
324  'label-message' => 'ipbemailban',
325  'section' => 'details',
326  ];
327  }
328 
329  if ( $blockAllowsUTEdit ) {
330  $a['DisableUTEdit'] = [
331  'type' => 'check',
332  'cssclass' => 'mw-block-restriction',
333  'label-message' => 'ipb-disableusertalk',
334  'default' => false,
335  'section' => 'details',
336  ];
337  }
338 
339  $defaultExpiry = $this->msg( 'ipb-default-expiry' )->inContentLanguage();
340  if ( $this->type === DatabaseBlock::TYPE_RANGE || $this->type === DatabaseBlock::TYPE_IP ) {
341  $defaultExpiryIP = $this->msg( 'ipb-default-expiry-ip' )->inContentLanguage();
342  if ( !$defaultExpiryIP->isDisabled() ) {
343  $defaultExpiry = $defaultExpiryIP;
344  }
345  }
346 
347  $a['Expiry'] = [
348  'type' => 'expiry',
349  'required' => true,
350  'options' => $suggestedDurations,
351  'default' => $defaultExpiry->text(),
352  'section' => 'expiry',
353  ];
354 
355  $a['Reason'] = [
356  'type' => 'selectandother',
357  // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP
358  // (e.g. emojis) count for two each. This limit is overridden in JS to instead count
359  // Unicode codepoints.
361  'maxlength-unit' => 'codepoints',
362  'options-message' => 'ipbreason-dropdown',
363  'section' => 'reason',
364  ];
365 
366  $a['AutoBlock'] = [
367  'type' => 'check',
368  'label-message' => [
369  'ipbenableautoblock',
370  Message::durationParam( $conf->get( 'AutoblockExpiry' ) )
371  ],
372  'default' => true,
373  'section' => 'options',
374  ];
375 
376  # Allow some users to hide name from block log, blocklist and listusers
377  if ( $this->getAuthority()->isAllowed( 'hideuser' ) ) {
378  $a['HideUser'] = [
379  'type' => 'check',
380  'label-message' => 'ipbhidename',
381  'cssclass' => 'mw-block-hideuser',
382  'section' => 'options',
383  ];
384  }
385 
386  # Watchlist their user page? (Only if user is logged in)
387  if ( $user->isRegistered() ) {
388  $a['Watch'] = [
389  'type' => 'check',
390  'label-message' => 'ipbwatchuser',
391  'section' => 'options',
392  ];
393  }
394 
395  $a['HardBlock'] = [
396  'type' => 'check',
397  'label-message' => 'ipb-hardblock',
398  'default' => false,
399  'section' => 'options',
400  ];
401 
402  # This is basically a copy of the Target field, but the user can't change it, so we
403  # can see if the warnings we maybe showed to the user before still apply
404  $a['PreviousTarget'] = [
405  'type' => 'hidden',
406  'default' => false,
407  ];
408 
409  # We'll turn this into a checkbox if we need to
410  $a['Confirm'] = [
411  'type' => 'hidden',
412  'default' => '',
413  'label-message' => 'ipb-confirm',
414  'cssclass' => 'mw-block-confirm',
415  ];
416 
417  $this->maybeAlterFormDefaults( $a );
418 
419  // Allow extensions to add more fields
420  $this->getHookRunner()->onSpecialBlockModifyFormFields( $this, $a );
421 
422  return $a;
423  }
424 
430  protected function maybeAlterFormDefaults( &$fields ) {
431  # This will be overwritten by request data
432  $fields['Target']['default'] = (string)$this->target;
433 
434  if ( $this->target ) {
435  $status = $this->blockUtils->validateTarget( $this->target );
436  if ( !$status->isOK() ) {
437  $errors = $status->getErrorsArray();
438  $this->preErrors = array_merge( $this->preErrors, $errors );
439  }
440  }
441 
442  # This won't be
443  $fields['PreviousTarget']['default'] = (string)$this->target;
444 
445  $block = DatabaseBlock::newFromTarget( $this->target );
446 
447  // Populate fields if there is a block that is not an autoblock; if it is a range
448  // block, only populate the fields if the range is the same as $this->target
449  if ( $block instanceof DatabaseBlock && $block->getType() !== DatabaseBlock::TYPE_AUTO
450  && ( $this->type != DatabaseBlock::TYPE_RANGE
451  || ( $this->target && $block->isBlocking( $this->target ) ) )
452  ) {
453  $fields['HardBlock']['default'] = $block->isHardblock();
454  $fields['CreateAccount']['default'] = $block->isCreateAccountBlocked();
455  $fields['AutoBlock']['default'] = $block->isAutoblocking();
456 
457  if ( isset( $fields['DisableEmail'] ) ) {
458  $fields['DisableEmail']['default'] = $block->isEmailBlocked();
459  }
460 
461  if ( isset( $fields['HideUser'] ) ) {
462  $fields['HideUser']['default'] = $block->getHideName();
463  }
464 
465  if ( isset( $fields['DisableUTEdit'] ) ) {
466  $fields['DisableUTEdit']['default'] = !$block->isUsertalkEditAllowed();
467  }
468 
469  // If the username was hidden (ipb_deleted == 1), don't show the reason
470  // unless this user also has rights to hideuser: T37839
471  if ( !$block->getHideName() || $this->getAuthority()->isAllowed( 'hideuser' ) ) {
472  $fields['Reason']['default'] = $block->getReasonComment()->text;
473  } else {
474  $fields['Reason']['default'] = '';
475  }
476 
477  if ( $this->getRequest()->wasPosted() ) {
478  # Ok, so we got a POST submission asking us to reblock a user. So show the
479  # confirm checkbox; the user will only see it if they haven't previously
480  $fields['Confirm']['type'] = 'check';
481  } else {
482  # We got a target, but it wasn't a POST request, so the user must have gone
483  # to a link like [[Special:Block/User]]. We don't need to show the checkbox
484  # as long as they go ahead and block *that* user
485  $fields['Confirm']['default'] = 1;
486  }
487 
488  if ( $block->getExpiry() == 'infinity' ) {
489  $fields['Expiry']['default'] = 'infinite';
490  } else {
491  $fields['Expiry']['default'] = wfTimestamp( TS_RFC2822, $block->getExpiry() );
492  }
493 
494  if ( !$block->isSitewide() ) {
495  $fields['EditingRestriction']['default'] = 'partial';
496 
497  $pageRestrictions = [];
498  $namespaceRestrictions = [];
499  foreach ( $block->getRestrictions() as $restriction ) {
500  if ( $restriction instanceof PageRestriction && $restriction->getTitle() ) {
501  $pageRestrictions[] = $restriction->getTitle()->getPrefixedText();
502  } elseif ( $restriction instanceof NamespaceRestriction &&
503  $this->namespaceInfo->exists( $restriction->getValue() )
504  ) {
505  $namespaceRestrictions[] = $restriction->getValue();
506  }
507  }
508 
509  // Sort the restrictions so they are in alphabetical order.
510  sort( $pageRestrictions );
511  $fields['PageRestrictions']['default'] = implode( "\n", $pageRestrictions );
512  sort( $namespaceRestrictions );
513  $fields['NamespaceRestrictions']['default'] = implode( "\n", $namespaceRestrictions );
514 
515  if ( $this->getConfig()->get( 'EnablePartialActionBlocks' ) ) {
516  $actionRestrictions = [];
517  foreach ( $block->getRestrictions() as $restriction ) {
518  if ( $restriction instanceof ActionRestriction ) {
519  $actionRestrictions[] = $restriction->getValue();
520  }
521  }
522  $fields['ActionRestrictions']['default'] = $actionRestrictions;
523  }
524  }
525 
526  $this->alreadyBlocked = true;
527  $this->preErrors[] = [ 'ipb-needreblock', wfEscapeWikiText( $block->getTargetName() ) ];
528  }
529 
530  if ( $this->alreadyBlocked || $this->getRequest()->wasPosted()
531  || $this->getRequest()->getCheck( 'wpCreateAccount' )
532  ) {
533  $this->getOutput()->addJsConfigVars( 'wgCreateAccountDirty', true );
534  }
535 
536  # We always need confirmation to do HideUser
537  if ( $this->requestedHideUser ) {
538  $fields['Confirm']['type'] = 'check';
539  unset( $fields['Confirm']['default'] );
540  $this->preErrors[] = [ 'ipb-confirmhideuser', 'ipb-confirmaction' ];
541  }
542 
543  # Or if the user is trying to block themselves
544  if ( (string)$this->target === $this->getUser()->getName() ) {
545  $fields['Confirm']['type'] = 'check';
546  unset( $fields['Confirm']['default'] );
547  $this->preErrors[] = [ 'ipb-blockingself', 'ipb-confirmaction' ];
548  }
549  }
550 
555  protected function preText() {
556  $this->getOutput()->addModuleStyles( [
557  'mediawiki.widgets.TagMultiselectWidget.styles',
558  'mediawiki.special',
559  ] );
560  $this->getOutput()->addModules( [ 'mediawiki.special.block' ] );
561 
562  $blockCIDRLimit = $this->getConfig()->get( 'BlockCIDRLimit' );
563  $text = $this->msg( 'blockiptext', $blockCIDRLimit['IPv4'], $blockCIDRLimit['IPv6'] )->parse();
564 
565  $otherBlockMessages = [];
566  if ( $this->target !== null ) {
567  $targetName = $this->target;
568  if ( $this->target instanceof UserIdentity ) {
569  $targetName = $this->target->getName();
570  }
571  # Get other blocks, i.e. from GlobalBlocking or TorBlock extension
572  $this->getHookRunner()->onOtherBlockLogLink(
573  $otherBlockMessages, $targetName );
574 
575  if ( count( $otherBlockMessages ) ) {
577  'h2',
578  [],
579  $this->msg( 'ipb-otherblocks-header', count( $otherBlockMessages ) )->parse()
580  ) . "\n";
581 
582  $list = '';
583 
584  foreach ( $otherBlockMessages as $link ) {
585  $list .= Html::rawElement( 'li', [], $link ) . "\n";
586  }
587 
588  $s .= Html::rawElement(
589  'ul',
590  [ 'class' => 'mw-blockip-alreadyblocked' ],
591  $list
592  ) . "\n";
593 
594  $text .= $s;
595  }
596  }
597 
598  return $text;
599  }
600 
605  protected function postText() {
606  $links = [];
607 
608  $this->getOutput()->addModuleStyles( 'mediawiki.special' );
609 
610  $linkRenderer = $this->getLinkRenderer();
611  # Link to the user's contributions, if applicable
612  if ( $this->target instanceof UserIdentity ) {
613  $contribsPage = SpecialPage::getTitleFor( 'Contributions', $this->target->getName() );
614  $links[] = $linkRenderer->makeLink(
615  $contribsPage,
616  $this->msg( 'ipb-blocklist-contribs', $this->target->getName() )->text()
617  );
618  }
619 
620  # Link to unblock the specified user, or to a blank unblock form
621  if ( $this->target instanceof UserIdentity ) {
622  $message = $this->msg(
623  'ipb-unblock-addr',
624  wfEscapeWikiText( $this->target->getName() )
625  )->parse();
626  $list = SpecialPage::getTitleFor( 'Unblock', $this->target->getName() );
627  } else {
628  $message = $this->msg( 'ipb-unblock' )->parse();
629  $list = SpecialPage::getTitleFor( 'Unblock' );
630  }
631  $links[] = $linkRenderer->makeKnownLink(
632  $list,
633  new HtmlArmor( $message )
634  );
635 
636  # Link to the block list
637  $links[] = $linkRenderer->makeKnownLink(
638  SpecialPage::getTitleFor( 'BlockList' ),
639  $this->msg( 'ipb-blocklist' )->text()
640  );
641 
642  # Link to edit the block dropdown reasons, if applicable
643  if ( $this->getAuthority()->isAllowed( 'editinterface' ) ) {
644  $links[] = $linkRenderer->makeKnownLink(
645  $this->msg( 'ipbreason-dropdown' )->inContentLanguage()->getTitle(),
646  $this->msg( 'ipb-edit-dropdown' )->text(),
647  [],
648  [ 'action' => 'edit' ]
649  );
650  }
651 
652  $text = Html::rawElement(
653  'p',
654  [ 'class' => 'mw-ipb-conveniencelinks' ],
655  $this->getLanguage()->pipeList( $links )
656  );
657 
658  $userPage = self::getTargetUserTitle( $this->target );
659  if ( $userPage ) {
660  # Get relevant extracts from the block and suppression logs, if possible
661  $out = '';
662 
664  $out,
665  'block',
666  $userPage,
667  '',
668  [
669  'lim' => 10,
670  'msgKey' => [
671  'blocklog-showlog',
672  $this->titleFormatter->getText( $userPage ),
673  ],
674  'showIfEmpty' => false
675  ]
676  );
677  $text .= $out;
678 
679  # Add suppression block entries if allowed
680  if ( $this->getAuthority()->isAllowed( 'suppressionlog' ) ) {
682  $out,
683  'suppress',
684  $userPage,
685  '',
686  [
687  'lim' => 10,
688  'conds' => [ 'log_action' => [ 'block', 'reblock', 'unblock' ] ],
689  'msgKey' => [
690  'blocklog-showsuppresslog',
691  $this->titleFormatter->getText( $userPage ),
692  ],
693  'showIfEmpty' => false
694  ]
695  );
696 
697  $text .= $out;
698  }
699  }
700 
701  return $text;
702  }
703 
710  protected static function getTargetUserTitle( $target ): ?PageReference {
711  if ( $target instanceof UserIdentity ) {
712  return PageReferenceValue::localReference( NS_USER, $target->getName() );
713  } elseif ( IPUtils::isIPAddress( $target ) ) {
714  return PageReferenceValue::localReference( NS_USER, $target );
715  }
716  return null;
717  }
718 
732  public static function getTargetAndType( ?string $par, WebRequest $request = null ) {
733  if ( !$request instanceof WebRequest ) {
734  return MediaWikiServices::getInstance()->getBlockUtils()->parseBlockTarget( $par );
735  }
736 
737  $possibleTargets = [
738  $request->getVal( 'wpTarget', null ),
739  $par,
740  $request->getVal( 'ip', null ),
741  // B/C @since 1.18
742  $request->getVal( 'wpBlockAddress', null ),
743  ];
744  foreach ( $possibleTargets as $possibleTarget ) {
745  $targetAndType = MediaWikiServices::getInstance()
746  ->getBlockUtils()
747  ->parseBlockTarget( $possibleTarget );
748  // If type is not null then target is valid
749  if ( $targetAndType[ 1 ] !== null ) {
750  break;
751  }
752  }
753  return $targetAndType;
754  }
755 
764  public static function processForm( array $data, IContextSource $context ) {
765  $services = MediaWikiServices::getInstance();
767  $data,
768  $context->getAuthority(),
769  $services->getBlockUserFactory(),
770  $services->getBlockUtils()
771  );
772  }
773 
784  private static function processFormInternal(
785  array $data,
786  Authority $performer,
789  ) {
790  // Temporarily access service container until the feature flag is removed: T280532
791  $enablePartialActionBlocks = MediaWikiServices::getInstance()
792  ->getMainConfig()->get( 'EnablePartialActionBlocks' );
793 
794  $isPartialBlock = isset( $data['EditingRestriction'] ) &&
795  $data['EditingRestriction'] === 'partial';
796 
797  # This might have been a hidden field or a checkbox, so interesting data
798  # can come from it
799  $data['Confirm'] = !in_array( $data['Confirm'], [ '', '0', null, false ], true );
800 
801  # If the user has done the form 'properly', they won't even have been given the
802  # option to suppress-block unless they have the 'hideuser' permission
803  if ( !isset( $data['HideUser'] ) ) {
804  $data['HideUser'] = false;
805  }
806 
808  list( $target, $type ) = $blockUtils->parseBlockTarget( $data['Target'] );
809  if ( $type == DatabaseBlock::TYPE_USER ) {
810  $user = $target;
811  $target = $user->getName();
812  $userId = $user->getId();
813 
814  # Give admins a heads-up before they go and block themselves. Much messier
815  # to do this for IPs, but it's pretty unlikely they'd ever get the 'block'
816  # permission anyway, although the code does allow for it.
817  # Note: Important to use $target instead of $data['Target']
818  # since both $data['PreviousTarget'] and $target are normalized
819  # but $data['target'] gets overridden by (non-normalized) request variable
820  # from previous request.
821  if ( $target === $performer->getUser()->getName() &&
822  ( $data['PreviousTarget'] !== $target || !$data['Confirm'] )
823  ) {
824  return [ 'ipb-blockingself', 'ipb-confirmaction' ];
825  }
826 
827  if ( $data['HideUser'] && !$data['Confirm'] ) {
828  return [ 'ipb-confirmhideuser', 'ipb-confirmaction' ];
829  }
830  } elseif ( $type == DatabaseBlock::TYPE_RANGE ) {
831  $user = null;
832  $userId = 0;
833  } elseif ( $type == DatabaseBlock::TYPE_IP ) {
834  $user = null;
835  $target = $target->getName();
836  $userId = 0;
837  } else {
838  # This should have been caught in the form field validation
839  return [ 'badipaddress' ];
840  }
841 
842  // Reason, to be passed to the block object. For default values of reason, see
843  // HTMLSelectAndOtherField::getDefault
844  $blockReason = $data['Reason'][0] ?? '';
845 
846  $pageRestrictions = [];
847  $namespaceRestrictions = [];
848  $actionRestrictions = [];
849  if ( $isPartialBlock ) {
850  if ( isset( $data['PageRestrictions'] ) && $data['PageRestrictions'] !== '' ) {
851  $titles = explode( "\n", $data['PageRestrictions'] );
852  foreach ( $titles as $title ) {
853  $pageRestrictions[] = PageRestriction::newFromTitle( $title );
854  }
855  }
856  if ( isset( $data['NamespaceRestrictions'] ) && $data['NamespaceRestrictions'] !== '' ) {
857  $namespaceRestrictions = array_map( static function ( $id ) {
858  return new NamespaceRestriction( 0, $id );
859  }, explode( "\n", $data['NamespaceRestrictions'] ) );
860  }
861  if (
862  $enablePartialActionBlocks &&
863  isset( $data['ActionRestrictions'] ) &&
864  $data['ActionRestrictions'] !== ''
865  ) {
866  $actionRestrictions = array_map( static function ( $id ) {
867  return new ActionRestriction( 0, $id );
868  }, $data['ActionRestrictions'] );
869  }
870  }
871  $restrictions = array_merge( $pageRestrictions, $namespaceRestrictions, $actionRestrictions );
872 
873  if ( !isset( $data['Tags'] ) ) {
874  $data['Tags'] = [];
875  }
876 
877  $blockOptions = [
878  'isCreateAccountBlocked' => $data['CreateAccount'],
879  'isHardBlock' => $data['HardBlock'],
880  'isAutoblocking' => $data['AutoBlock'],
881  'isHideUser' => $data['HideUser'],
882  'isPartial' => $isPartialBlock,
883  ];
884 
885  if ( isset( $data['DisableUTEdit'] ) ) {
886  $blockOptions['isUserTalkEditBlocked'] = $data['DisableUTEdit'];
887  }
888  if ( isset( $data['DisableEmail'] ) ) {
889  $blockOptions['isEmailBlocked'] = $data['DisableEmail'];
890  }
891 
892  $blockUser = $blockUserFactory->newBlockUser(
893  $target,
894  $performer,
895  $data['Expiry'],
896  $blockReason,
897  $blockOptions,
898  $restrictions,
899  $data['Tags']
900  );
901 
902  # Indicates whether the user is confirming the block and is aware of
903  # the conflict (did not change the block target in the meantime)
904  $blockNotConfirmed = !$data['Confirm'] || ( array_key_exists( 'PreviousTarget', $data )
905  && $data['PreviousTarget'] !== $target );
906 
907  # Special case for API - T34434
908  $reblockNotAllowed = ( array_key_exists( 'Reblock', $data ) && !$data['Reblock'] );
909 
910  $doReblock = !$blockNotConfirmed && !$reblockNotAllowed;
911 
912  $status = $blockUser->placeBlock( $doReblock );
913  if ( !$status->isOK() ) {
914  return $status;
915  }
916 
917  if (
918  // Can't watch a rangeblock
919  $type != DatabaseBlock::TYPE_RANGE
920 
921  // Technically a wiki can be configured to allow anonymous users to place blocks,
922  // in which case the 'Watch' field isn't included in the form shown, and we should
923  // not try to access it.
924  && array_key_exists( 'Watch', $data )
925  && $data['Watch']
926  ) {
927  MediaWikiServices::getInstance()->getWatchlistManager()->addWatchIgnoringRights(
928  $performer->getUser(),
930  );
931  }
932 
933  return true;
934  }
935 
946  public static function getSuggestedDurations( Language $lang = null, $includeOther = true ) {
947  $msg = $lang === null
948  ? wfMessage( 'ipboptions' )->inContentLanguage()->text()
949  : wfMessage( 'ipboptions' )->inLanguage( $lang )->text();
950 
951  if ( $msg == '-' ) {
952  return [];
953  }
954 
955  $a = XmlSelect::parseOptionsMessage( $msg );
956 
957  if ( $a && $includeOther ) {
958  // if options exist, add other to the end instead of the begining (which
959  // is what happens by default).
960  $a[ wfMessage( 'ipbother' )->text() ] = 'other';
961  }
962 
963  return $a;
964  }
965 
975  public static function parseExpiryInput( $expiry ) {
976  return BlockUser::parseExpiryInput( $expiry );
977  }
978 
986  public static function canBlockEmail( UserIdentity $user ) {
987  return MediaWikiServices::getInstance()
988  ->getBlockPermissionCheckerFactory()
989  ->newBlockPermissionChecker( null, User::newFromIdentity( $user ) )
990  ->checkEmailPermissions();
991  }
992 
1007  public static function checkUnblockSelf( $target, Authority $performer ) {
1008  wfDeprecated( __METHOD__, '1.36' );
1009  return MediaWikiServices::getInstance()
1010  ->getBlockPermissionCheckerFactory()
1011  ->newBlockPermissionChecker( $target, $performer )
1012  ->checkBlockPermissions();
1013  }
1014 
1021  public function onSubmit( array $data, HTMLForm $form = null ) {
1023  $data,
1024  $this->getAuthority(),
1025  $this->blockUserFactory,
1026  $this->blockUtils
1027  );
1028  }
1029 
1034  public function onSuccess() {
1035  $out = $this->getOutput();
1036  $out->setPageTitle( $this->msg( 'blockipsuccesssub' ) );
1037  $out->addWikiMsg( 'blockipsuccesstext', wfEscapeWikiText( $this->target ) );
1038  }
1039 
1048  public function prefixSearchSubpages( $search, $limit, $offset ) {
1049  $search = $this->userNameUtils->getCanonical( $search );
1050  if ( !$search ) {
1051  // No prefix suggestion for invalid user
1052  return [];
1053  }
1054  // Autocomplete subpage as user list - public to allow caching
1055  return $this->userNamePrefixSearch
1056  ->search( UserNamePrefixSearch::AUDIENCE_PUBLIC, $search, $limit, $offset );
1057  }
1058 
1059  protected function getGroupName() {
1060  return 'users';
1061  }
1062 }
SpecialPage\$linkRenderer
LinkRenderer null $linkRenderer
Definition: SpecialPage.php:80
SpecialBlock\checkUnblockSelf
static checkUnblockSelf( $target, Authority $performer)
T17810: Sitewide blocked admins should not be able to block/unblock others with one exception; they c...
Definition: SpecialBlock.php:1007
SpecialPage\msg
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:912
SpecialBlock\$blockUserFactory
BlockUserFactory $blockUserFactory
Definition: SpecialBlock.php:57
MediaWiki\Block\Restriction\PageRestriction\getTitle
getTitle()
Definition: PageRestriction.php:68
MediaWiki\Block\BlockPermissionCheckerFactory
Factory class for BlockPermissionChecker.
Definition: BlockPermissionCheckerFactory.php:33
HtmlArmor
Marks HTML that shouldn't be escaped.
Definition: HtmlArmor.php:30
SpecialBlock\canBlockEmail
static canBlockEmail(UserIdentity $user)
Can we do an email block?
Definition: SpecialBlock.php:986
MediaWiki\Block\BlockUserFactory
Definition: BlockUserFactory.php:30
SpecialBlock\onSuccess
onSuccess()
Do something exciting on successful processing of the form, most likely to show a confirmation messag...
Definition: SpecialBlock.php:1034
SpecialBlock\$userNamePrefixSearch
UserNamePrefixSearch $userNamePrefixSearch
Definition: SpecialBlock.php:63
SpecialBlock\$type
int $type
DatabaseBlock::TYPE_ constant.
Definition: SpecialBlock.php:77
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:790
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:193
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
SpecialBlock\$preErrors
array $preErrors
Definition: SpecialBlock.php:89
HTMLForm\addHeaderText
addHeaderText( $msg, $section=null)
Add HTML to the header, inside the form.
Definition: HTMLForm.php:830
SpecialBlock\$requestedHideUser
bool $requestedHideUser
Whether the previous submission of the form asked for HideUser.
Definition: SpecialBlock.php:83
SpecialBlock\processForm
static processForm(array $data, IContextSource $context)
Given the form data, actually implement a block.
Definition: SpecialBlock.php:764
SpecialBlock\preText
preText()
Add header elements like block log entries, etc.
Definition: SpecialBlock.php:555
MediaWiki\Block\BlockUser
Handles the backend logic of blocking users.
Definition: BlockUser.php:51
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1691
MediaWiki\Block\BlockUtils
Backend class for blocking utils.
Definition: BlockUtils.php:45
HTMLForm\setHeaderText
setHeaderText( $msg, $section=null)
Set header text, inside the form.
Definition: HTMLForm.php:852
HTMLForm\formatErrors
formatErrors( $errors)
Format a stack of error messages into a single HTML string.
Definition: HTMLForm.php:1371
MediaWiki\Block\DatabaseBlock\getType
getType()
Get the type of target for this particular block.int|null AbstractBlock::TYPE_ constant,...
Definition: DatabaseBlock.php:1006
SpecialBlock\$blockPermissionCheckerFactory
BlockPermissionCheckerFactory $blockPermissionCheckerFactory
Definition: SpecialBlock.php:54
SpecialBlock\$previousTarget
User string $previousTarget
The previous block target.
Definition: SpecialBlock.php:80
SpecialBlock\getTargetAndType
static getTargetAndType(?string $par, WebRequest $request=null)
Get the target and type, given the request and the subpage parameter.
Definition: SpecialBlock.php:732
SpecialBlock\onSubmit
onSubmit(array $data, HTMLForm $form=null)
Process the form on POST submission.
Definition: SpecialBlock.php:1021
FormSpecialPage
Special page which uses an HTMLForm to handle processing.
Definition: FormSpecialPage.php:31
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1182
SpecialPage\getTitleFor
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Definition: SpecialPage.php:107
SpecialPage\getSkin
getSkin()
Shortcut to get the skin being used for this instance.
Definition: SpecialPage.php:820
User\newFromIdentity
static newFromIdentity(UserIdentity $identity)
Returns a User object corresponding to the given UserIdentity.
Definition: User.php:683
SpecialPage\getAuthority
getAuthority()
Shortcut to get the Authority executing this instance.
Definition: SpecialPage.php:810
SpecialBlock\doesWrites
doesWrites()
Indicates whether this special page may perform database writes.
Definition: SpecialBlock.php:126
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:830
SpecialBlock\checkExecutePermissions
checkExecutePermissions(User $user)
Checks that the user can unblock themselves if they are trying to do so.
Definition: SpecialBlock.php:136
IContextSource\getAuthority
getAuthority()
SpecialPage\getName
getName()
Get the name of this Special Page.
Definition: SpecialPage.php:179
SpecialBlock\setParameter
setParameter( $par)
Handle some magic here.
Definition: SpecialBlock.php:161
XmlSelect\parseOptionsMessage
static parseOptionsMessage(string $msg)
Parse labels and values out of a comma- and colon-separated list of options, such as is used for expi...
Definition: XmlSelect.php:146
MediaWiki\Permissions\Authority\getUser
getUser()
Returns the performer of the actions associated with this authority.
Page\PageReference
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.
Definition: PageReference.php:49
MediaWiki\User\UserIdentity
Interface for objects representing user identity.
Definition: UserIdentity.php:39
SpecialBlock\$blockActionInfo
BlockActionInfo $blockActionInfo
Definition: SpecialBlock.php:66
SpecialBlock\postText
postText()
Add footer elements to the form.
Definition: SpecialBlock.php:605
MediaWiki\Block\DatabaseBlock
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Definition: DatabaseBlock.php:52
SpecialPage\addHelpLink
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition: SpecialPage.php:948
SpecialPage\getHookRunner
getHookRunner()
Definition: SpecialPage.php:1095
SpecialPage\getConfig
getConfig()
Shortcut to get main config object.
Definition: SpecialPage.php:878
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
Definition: GlobalFunctions.php:997
SpecialBlock\maybeAlterFormDefaults
maybeAlterFormDefaults(&$fields)
If the user has already been blocked with similar settings, load that block and change the defaults f...
Definition: SpecialBlock.php:430
SpecialBlock\alterForm
alterForm(HTMLForm $form)
Customizes the HTMLForm a bit.
Definition: SpecialBlock.php:183
SpecialBlock
A special page that allows users with 'block' right to block users from editing pages and other actio...
Definition: SpecialBlock.php:48
MediaWiki\User\UserNamePrefixSearch
Handles searching prefixes of user names.
Definition: UserNamePrefixSearch.php:39
SpecialBlock\$blockUtils
BlockUtils $blockUtils
Definition: SpecialBlock.php:51
SpecialBlock\getTargetUserTitle
static getTargetUserTitle( $target)
Get a user page target for things like logs.
Definition: SpecialBlock.php:710
MediaWiki\User\UserIdentity\getName
getName()
$title
$title
Definition: testCompression.php:38
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:800
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:651
LogEventsList\showLogExtract
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Definition: LogEventsList.php:597
SpecialBlock\prefixSearchSubpages
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
Definition: SpecialBlock.php:1048
FormSpecialPage\$par
string null $par
The sub-page of the special page.
Definition: FormSpecialPage.php:36
MediaWiki\Permissions\Authority
This interface represents the authority associated the current execution context, such as a web reque...
Definition: Authority.php:37
$s
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
Definition: mergeMessageFileList.php:206
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:780
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1455
SpecialBlock\getFormFields
getFormFields()
Get the HTMLForm descriptor array for the block form.
Definition: SpecialBlock.php:213
SpecialBlock\$target
UserIdentity string null $target
User to be blocked, as passed either by parameter (url?wpTarget=Foo) or as subpage (Special:Block/Foo...
Definition: SpecialBlock.php:74
MediaWiki\Block\BlockActionInfo
Defines the actions that can be blocked by a partial block.
Definition: BlockActionInfo.php:40
NS_USER
const NS_USER
Definition: Defines.php:66
HTMLForm\setSubmitDestructive
setSubmitDestructive()
Identify that the submit button in the form has a destructive action.
Definition: HTMLForm.php:1406
SpecialBlock\$userNameUtils
UserNameUtils $userNameUtils
Definition: SpecialBlock.php:60
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:58
WebRequest
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
Definition: WebRequest.php:43
MediaWiki\Block\Restriction\NamespaceRestriction
Definition: NamespaceRestriction.php:25
CommentStore\COMMENT_CHARACTER_LIMIT
const COMMENT_CHARACTER_LIMIT
Maximum length of a comment in UTF-8 characters.
Definition: CommentStore.php:48
HTMLForm\setSubmitTextMsg
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
Definition: HTMLForm.php:1420
SpecialPage\getLinkRenderer
getLinkRenderer()
Definition: SpecialPage.php:1028
SpecialBlock\$titleFormatter
TitleFormatter $titleFormatter
Definition: SpecialBlock.php:69
MediaWiki\Block\Restriction\PageRestriction
Definition: PageRestriction.php:25
SpecialBlock\$alreadyBlocked
bool $alreadyBlocked
Definition: SpecialBlock.php:86
Page\PageReferenceValue
Immutable value object representing a page reference.
Definition: PageReferenceValue.php:42
MediaWiki\Block\BlockUserFactory\newBlockUser
newBlockUser( $target, Authority $performer, string $expiry, string $reason='', array $blockOptions=[], array $blockRestrictions=[], $tags=[])
Create BlockUser.
MediaWiki\User\UserNameUtils
UserNameUtils service.
Definition: UserNameUtils.php:42
TitleFormatter
A title formatter service for MediaWiki.
Definition: TitleFormatter.php:35
SpecialBlock\processFormInternal
static processFormInternal(array $data, Authority $performer, BlockUserFactory $blockUserFactory, BlockUtils $blockUtils)
Implementation details for processForm Own function to allow sharing the deprecated code with non-dep...
Definition: SpecialBlock.php:784
SpecialBlock\getDisplayFormat
getDisplayFormat()
Get display format for the form.
Definition: SpecialBlock.php:205
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:210
getTitle
getTitle()
Definition: RevisionSearchResultTrait.php:81
SpecialBlock\parseExpiryInput
static parseExpiryInput( $expiry)
Convert a submitted expiry time, which may be relative ("2 weeks", etc) or absolute ("24 May 2034",...
Definition: SpecialBlock.php:975
SpecialBlock\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialBlock.php:1059
SpecialBlock\getSuggestedDurations
static getSuggestedDurations(Language $lang=null, $includeOther=true)
Get an array of suggested block durations from MediaWiki:Ipboptions.
Definition: SpecialBlock.php:946
NamespaceInfo
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Definition: NamespaceInfo.php:35
MediaWiki\Block\BlockUtils\parseBlockTarget
parseBlockTarget( $target)
From an existing block, get the target and the type of target.
Definition: BlockUtils.php:91
ErrorPageError
An error page which can definitely be safely rendered using the OutputPage.
Definition: ErrorPageError.php:30
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:68
MediaWiki\Block\Restriction\ActionRestriction
Restriction for partial blocks of actions.
Definition: ActionRestriction.php:30
Message\durationParam
static durationParam( $duration)
Definition: Message.php:1096
SpecialBlock\$namespaceInfo
NamespaceInfo $namespaceInfo
Definition: SpecialBlock.php:92
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:42
SpecialBlock\__construct
__construct(BlockUtils $blockUtils, BlockPermissionCheckerFactory $blockPermissionCheckerFactory, BlockUserFactory $blockUserFactory, UserNameUtils $userNameUtils, UserNamePrefixSearch $userNamePrefixSearch, BlockActionInfo $blockActionInfo, TitleFormatter $titleFormatter, NamespaceInfo $namespaceInfo)
Definition: SpecialBlock.php:104
SpecialBlock\requiresUnblock
requiresUnblock()
We allow certain special cases where user is blocked.
Definition: SpecialBlock.php:152
HTMLForm
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition: HTMLForm.php:143