MediaWiki  master
SpecialBlock.php
Go to the documentation of this file.
1 <?php
37 use Wikimedia\IPUtils;
38 
50 
52  private $blockUtils;
53 
56 
59 
61  private $userNameUtils;
62 
65 
69  protected $target;
70 
72  protected $type;
73 
75  protected $previousTarget;
76 
78  protected $requestedHideUser;
79 
81  protected $alreadyBlocked;
82 
84  protected $preErrors = [];
85 
94  public function __construct(
101  ) {
102  parent::__construct( 'Block', 'block' );
103 
104  $this->permissionManager = $permissionManager;
105  $this->blockUtils = $blockUtils;
106  $this->blockPermissionCheckerFactory = $blockPermissionCheckerFactory;
107  $this->blockUserFactory = $blockUserFactory;
108  $this->userNameUtils = $userNameUtils;
109  $this->userNamePrefixSearch = $userNamePrefixSearch;
110  }
111 
112  public function doesWrites() {
113  return true;
114  }
115 
122  protected function checkExecutePermissions( User $user ) {
123  parent::checkExecutePermissions( $user );
124  # T17810: blocked admins should have limited access here
125  $status = $this->blockPermissionCheckerFactory
126  ->newBlockPermissionChecker( $this->target, $user )
127  ->checkBlockPermissions();
128  if ( $status !== true ) {
129  throw new ErrorPageError( 'badaccess', $status );
130  }
131  }
132 
138  public function requiresUnblock() {
139  return false;
140  }
141 
147  protected function setParameter( $par ) {
148  # Extract variables from the request. Try not to get into a situation where we
149  # need to extract *every* variable from the form just for processing here, but
150  # there are legitimate uses for some variables
151  $request = $this->getRequest();
152  list( $this->target, $this->type ) = self::getTargetAndType( $par, $request );
153  if ( $this->target instanceof User ) {
154  # Set the 'relevant user' in the skin, so it displays links like Contributions,
155  # User logs, UserRights, etc.
156  $this->getSkin()->setRelevantUser( $this->target );
157  }
158 
159  list( $this->previousTarget, /*...*/ ) =
160  DatabaseBlock::parseTarget( $request->getVal( 'wpPreviousTarget' ) );
161  $this->requestedHideUser = $request->getBool( 'wpHideUser' );
162  }
163 
169  protected function alterForm( HTMLForm $form ) {
170  $form->setHeaderText( '' );
171  $form->setSubmitDestructive();
172 
173  $msg = $this->alreadyBlocked ? 'ipb-change-block' : 'ipbsubmit';
174  $form->setSubmitTextMsg( $msg );
175 
176  $this->addHelpLink( 'Help:Blocking users' );
177 
178  # Don't need to do anything if the form has been posted
179  if ( !$this->getRequest()->wasPosted() && $this->preErrors ) {
180  $s = $form->formatErrors( $this->preErrors );
181  if ( $s ) {
183  'div',
184  [ 'class' => 'error' ],
185  $s
186  ) );
187  }
188  }
189  }
190 
191  protected function getDisplayFormat() {
192  return 'ooui';
193  }
194 
199  protected function getFormFields() {
200  $conf = $this->getConfig();
201  $blockAllowsUTEdit = $conf->get( 'BlockAllowsUTEdit' );
202 
203  $this->getOutput()->enableOOUI();
204 
205  $user = $this->getUser();
206 
207  $suggestedDurations = self::getSuggestedDurations();
208 
209  $a = [];
210 
211  $a['Target'] = [
212  'type' => 'user',
213  'ipallowed' => true,
214  'iprange' => true,
215  'id' => 'mw-bi-target',
216  'size' => '45',
217  'autofocus' => true,
218  'required' => true,
219  'validation-callback' => function ( $value, $alldata, $form ) {
220  $status = $this->blockUtils->validateTarget( $value );
221  if ( !$status->isOK() ) {
222  $errors = $status->getErrorsArray();
223 
224  return $form->msg( ...$errors[0] );
225  }
226  return true;
227  },
228  'section' => 'target',
229  ];
230 
231  $a['Editing'] = [
232  'type' => 'check',
233  'label-message' => 'block-prevent-edit',
234  'default' => true,
235  'section' => 'actions',
236  ];
237 
238  $a['EditingRestriction'] = [
239  'type' => 'radio',
240  'cssclass' => 'mw-block-editing-restriction',
241  'default' => 'sitewide',
242  'options' => [
243  $this->msg( 'ipb-sitewide' )->escaped() .
244  new \OOUI\LabelWidget( [
245  'classes' => [ 'oo-ui-inline-help' ],
246  'label' => $this->msg( 'ipb-sitewide-help' )->text(),
247  ] ) => 'sitewide',
248  $this->msg( 'ipb-partial' )->escaped() .
249  new \OOUI\LabelWidget( [
250  'classes' => [ 'oo-ui-inline-help' ],
251  'label' => $this->msg( 'ipb-partial-help' )->text(),
252  ] ) => 'partial',
253  ],
254  'section' => 'actions',
255  ];
256 
257  $a['PageRestrictions'] = [
258  'type' => 'titlesmultiselect',
259  'label' => $this->msg( 'ipb-pages-label' )->text(),
260  'exists' => true,
261  'max' => 10,
262  'cssclass' => 'mw-block-restriction',
263  'showMissing' => false,
264  'excludeDynamicNamespaces' => true,
265  'input' => [
266  'autocomplete' => false
267  ],
268  'section' => 'actions',
269  ];
270 
271  $a['NamespaceRestrictions'] = [
272  'type' => 'namespacesmultiselect',
273  'label' => $this->msg( 'ipb-namespaces-label' )->text(),
274  'exists' => true,
275  'cssclass' => 'mw-block-restriction',
276  'input' => [
277  'autocomplete' => false
278  ],
279  'section' => 'actions',
280  ];
281 
282  $a['CreateAccount'] = [
283  'type' => 'check',
284  'label-message' => 'ipbcreateaccount',
285  'default' => true,
286  'section' => 'actions',
287  ];
288 
289  if ( $this->blockPermissionCheckerFactory
290  ->newBlockPermissionChecker( null, $user )
291  ->checkEmailPermissions()
292  ) {
293  $a['DisableEmail'] = [
294  'type' => 'check',
295  'label-message' => 'ipbemailban',
296  'section' => 'actions',
297  ];
298  }
299 
300  if ( $blockAllowsUTEdit ) {
301  $a['DisableUTEdit'] = [
302  'type' => 'check',
303  'label-message' => 'ipb-disableusertalk',
304  'default' => false,
305  'section' => 'actions',
306  ];
307  }
308 
309  $defaultExpiry = $this->msg( 'ipb-default-expiry' )->inContentLanguage();
310  if ( $this->type === DatabaseBlock::TYPE_RANGE || $this->type === DatabaseBlock::TYPE_IP ) {
311  $defaultExpiryIP = $this->msg( 'ipb-default-expiry-ip' )->inContentLanguage();
312  if ( !$defaultExpiryIP->isDisabled() ) {
313  $defaultExpiry = $defaultExpiryIP;
314  }
315  }
316 
317  $a['Expiry'] = [
318  'type' => 'expiry',
319  'required' => true,
320  'options' => $suggestedDurations,
321  'default' => $defaultExpiry->text(),
322  'section' => 'expiry',
323  ];
324 
325  $a['Reason'] = [
326  'type' => 'selectandother',
327  // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP
328  // (e.g. emojis) count for two each. This limit is overridden in JS to instead count
329  // Unicode codepoints.
331  'maxlength-unit' => 'codepoints',
332  'options-message' => 'ipbreason-dropdown',
333  'section' => 'reason',
334  ];
335 
336  $a['AutoBlock'] = [
337  'type' => 'check',
338  'label-message' => 'ipbenableautoblock',
339  'default' => true,
340  'section' => 'options',
341  ];
342 
343  # Allow some users to hide name from block log, blocklist and listusers
344  if ( $this->permissionManager->userHasRight( $user, 'hideuser' ) ) {
345  $a['HideUser'] = [
346  'type' => 'check',
347  'label-message' => 'ipbhidename',
348  'cssclass' => 'mw-block-hideuser',
349  'section' => 'options',
350  ];
351  }
352 
353  # Watchlist their user page? (Only if user is logged in)
354  if ( $user->isLoggedIn() ) {
355  $a['Watch'] = [
356  'type' => 'check',
357  'label-message' => 'ipbwatchuser',
358  'section' => 'options',
359  ];
360  }
361 
362  $a['HardBlock'] = [
363  'type' => 'check',
364  'label-message' => 'ipb-hardblock',
365  'default' => false,
366  'section' => 'options',
367  ];
368 
369  # This is basically a copy of the Target field, but the user can't change it, so we
370  # can see if the warnings we maybe showed to the user before still apply
371  $a['PreviousTarget'] = [
372  'type' => 'hidden',
373  'default' => false,
374  ];
375 
376  # We'll turn this into a checkbox if we need to
377  $a['Confirm'] = [
378  'type' => 'hidden',
379  'default' => '',
380  'label-message' => 'ipb-confirm',
381  'cssclass' => 'mw-block-confirm',
382  ];
383 
384  $this->maybeAlterFormDefaults( $a );
385 
386  // Allow extensions to add more fields
387  $this->getHookRunner()->onSpecialBlockModifyFormFields( $this, $a );
388 
389  return $a;
390  }
391 
397  protected function maybeAlterFormDefaults( &$fields ) {
398  # This will be overwritten by request data
399  $fields['Target']['default'] = (string)$this->target;
400 
401  if ( $this->target ) {
402  $status = $this->blockUtils->validateTarget( $this->target );
403  if ( !$status->isOK() ) {
404  $errors = $status->getErrorsArray();
405  $this->preErrors = array_merge( $this->preErrors, $errors );
406  }
407  }
408 
409  # This won't be
410  $fields['PreviousTarget']['default'] = (string)$this->target;
411 
412  $block = DatabaseBlock::newFromTarget( $this->target );
413 
414  // Populate fields if there is a block that is not an autoblock; if it is a range
415  // block, only populate the fields if the range is the same as $this->target
416  if ( $block instanceof DatabaseBlock && $block->getType() !== DatabaseBlock::TYPE_AUTO
417  && ( $this->type != DatabaseBlock::TYPE_RANGE
418  || $block->getTarget() == $this->target )
419  ) {
420  $fields['HardBlock']['default'] = $block->isHardblock();
421  $fields['CreateAccount']['default'] = $block->isCreateAccountBlocked();
422  $fields['AutoBlock']['default'] = $block->isAutoblocking();
423 
424  if ( isset( $fields['DisableEmail'] ) ) {
425  $fields['DisableEmail']['default'] = $block->isEmailBlocked();
426  }
427 
428  if ( isset( $fields['HideUser'] ) ) {
429  $fields['HideUser']['default'] = $block->getHideName();
430  }
431 
432  if ( isset( $fields['DisableUTEdit'] ) ) {
433  $fields['DisableUTEdit']['default'] = !$block->isUsertalkEditAllowed();
434  }
435 
436  // If the username was hidden (ipb_deleted == 1), don't show the reason
437  // unless this user also has rights to hideuser: T37839
438  if ( !$block->getHideName() || $this->permissionManager
439  ->userHasRight( $this->getUser(), 'hideuser' )
440  ) {
441  $fields['Reason']['default'] = $block->getReasonComment()->text;
442  } else {
443  $fields['Reason']['default'] = '';
444  }
445 
446  if ( $this->getRequest()->wasPosted() ) {
447  # Ok, so we got a POST submission asking us to reblock a user. So show the
448  # confirm checkbox; the user will only see it if they haven't previously
449  $fields['Confirm']['type'] = 'check';
450  } else {
451  # We got a target, but it wasn't a POST request, so the user must have gone
452  # to a link like [[Special:Block/User]]. We don't need to show the checkbox
453  # as long as they go ahead and block *that* user
454  $fields['Confirm']['default'] = 1;
455  }
456 
457  if ( $block->getExpiry() == 'infinity' ) {
458  $fields['Expiry']['default'] = 'infinite';
459  } else {
460  $fields['Expiry']['default'] = wfTimestamp( TS_RFC2822, $block->getExpiry() );
461  }
462 
463  if ( !$block->isSitewide() ) {
464  $fields['EditingRestriction']['default'] = 'partial';
465 
466  $pageRestrictions = [];
467  $namespaceRestrictions = [];
468  foreach ( $block->getRestrictions() as $restriction ) {
469  if ( $restriction instanceof PageRestriction && $restriction->getTitle() ) {
470  $pageRestrictions[] = $restriction->getTitle()->getPrefixedText();
471  } elseif ( $restriction instanceof NamespaceRestriction ) {
472  $namespaceRestrictions[] = $restriction->getValue();
473  }
474  }
475 
476  // Sort the restrictions so they are in alphabetical order.
477  sort( $pageRestrictions );
478  $fields['PageRestrictions']['default'] = implode( "\n", $pageRestrictions );
479  sort( $namespaceRestrictions );
480  $fields['NamespaceRestrictions']['default'] = implode( "\n", $namespaceRestrictions );
481 
482  if (
483  // @phan-suppress-next-line PhanImpossibleCondition
484  empty( $pageRestrictions ) &&
485  // @phan-suppress-next-line PhanImpossibleCondition
486  empty( $namespaceRestrictions )
487  ) {
488  $fields['Editing']['default'] = false;
489  }
490  }
491 
492  $this->alreadyBlocked = true;
493  $this->preErrors[] = [ 'ipb-needreblock', wfEscapeWikiText( (string)$block->getTarget() ) ];
494  }
495 
496  if ( $this->alreadyBlocked || $this->getRequest()->wasPosted()
497  || $this->getRequest()->getCheck( 'wpCreateAccount' )
498  ) {
499  $this->getOutput()->addJsConfigVars( 'wgCreateAccountDirty', true );
500  }
501 
502  # We always need confirmation to do HideUser
503  if ( $this->requestedHideUser ) {
504  $fields['Confirm']['type'] = 'check';
505  unset( $fields['Confirm']['default'] );
506  $this->preErrors[] = [ 'ipb-confirmhideuser', 'ipb-confirmaction' ];
507  }
508 
509  # Or if the user is trying to block themselves
510  if ( (string)$this->target === $this->getUser()->getName() ) {
511  $fields['Confirm']['type'] = 'check';
512  unset( $fields['Confirm']['default'] );
513  $this->preErrors[] = [ 'ipb-blockingself', 'ipb-confirmaction' ];
514  }
515  }
516 
521  protected function preText() {
522  $this->getOutput()->addModuleStyles( [
523  'mediawiki.widgets.TagMultiselectWidget.styles',
524  'mediawiki.special',
525  ] );
526  $this->getOutput()->addModules( [ 'mediawiki.special.block' ] );
527 
528  $blockCIDRLimit = $this->getConfig()->get( 'BlockCIDRLimit' );
529  $text = $this->msg( 'blockiptext', $blockCIDRLimit['IPv4'], $blockCIDRLimit['IPv6'] )->parse();
530 
531  $otherBlockMessages = [];
532  if ( $this->target !== null ) {
533  $targetName = $this->target;
534  if ( $this->target instanceof User ) {
535  $targetName = $this->target->getName();
536  }
537  # Get other blocks, i.e. from GlobalBlocking or TorBlock extension
538  $this->getHookRunner()->onOtherBlockLogLink(
539  $otherBlockMessages, $targetName );
540 
541  if ( count( $otherBlockMessages ) ) {
543  'h2',
544  [],
545  $this->msg( 'ipb-otherblocks-header', count( $otherBlockMessages ) )->parse()
546  ) . "\n";
547 
548  $list = '';
549 
550  foreach ( $otherBlockMessages as $link ) {
551  $list .= Html::rawElement( 'li', [], $link ) . "\n";
552  }
553 
554  $s .= Html::rawElement(
555  'ul',
556  [ 'class' => 'mw-blockip-alreadyblocked' ],
557  $list
558  ) . "\n";
559 
560  $text .= $s;
561  }
562  }
563 
564  return $text;
565  }
566 
571  protected function postText() {
572  $links = [];
573 
574  $this->getOutput()->addModuleStyles( 'mediawiki.special' );
575 
576  $linkRenderer = $this->getLinkRenderer();
577  # Link to the user's contributions, if applicable
578  if ( $this->target instanceof User ) {
579  $contribsPage = SpecialPage::getTitleFor( 'Contributions', $this->target->getName() );
580  $links[] = $linkRenderer->makeLink(
581  $contribsPage,
582  $this->msg( 'ipb-blocklist-contribs', $this->target->getName() )->text()
583  );
584  }
585 
586  # Link to unblock the specified user, or to a blank unblock form
587  if ( $this->target instanceof User ) {
588  $message = $this->msg(
589  'ipb-unblock-addr',
590  wfEscapeWikiText( $this->target->getName() )
591  )->parse();
592  $list = SpecialPage::getTitleFor( 'Unblock', $this->target->getName() );
593  } else {
594  $message = $this->msg( 'ipb-unblock' )->parse();
595  $list = SpecialPage::getTitleFor( 'Unblock' );
596  }
597  $links[] = $linkRenderer->makeKnownLink(
598  $list,
599  new HtmlArmor( $message )
600  );
601 
602  # Link to the block list
603  $links[] = $linkRenderer->makeKnownLink(
604  SpecialPage::getTitleFor( 'BlockList' ),
605  $this->msg( 'ipb-blocklist' )->text()
606  );
607 
608  $user = $this->getUser();
609 
610  # Link to edit the block dropdown reasons, if applicable
611  if ( $this->permissionManager->userHasRight( $user, 'editinterface' ) ) {
612  $links[] = $linkRenderer->makeKnownLink(
613  $this->msg( 'ipbreason-dropdown' )->inContentLanguage()->getTitle(),
614  $this->msg( 'ipb-edit-dropdown' )->text(),
615  [],
616  [ 'action' => 'edit' ]
617  );
618  }
619 
620  $text = Html::rawElement(
621  'p',
622  [ 'class' => 'mw-ipb-conveniencelinks' ],
623  $this->getLanguage()->pipeList( $links )
624  );
625 
626  $userTitle = self::getTargetUserTitle( $this->target );
627  if ( $userTitle ) {
628  # Get relevant extracts from the block and suppression logs, if possible
629  $out = '';
630 
632  $out,
633  'block',
634  $userTitle,
635  '',
636  [
637  'lim' => 10,
638  'msgKey' => [ 'blocklog-showlog', $userTitle->getText() ],
639  'showIfEmpty' => false
640  ]
641  );
642  $text .= $out;
643 
644  # Add suppression block entries if allowed
645  if ( $this->permissionManager->userHasRight( $user, 'suppressionlog' ) ) {
647  $out,
648  'suppress',
649  $userTitle,
650  '',
651  [
652  'lim' => 10,
653  'conds' => [ 'log_action' => [ 'block', 'reblock', 'unblock' ] ],
654  'msgKey' => [ 'blocklog-showsuppresslog', $userTitle->getText() ],
655  'showIfEmpty' => false
656  ]
657  );
658 
659  $text .= $out;
660  }
661  }
662 
663  return $text;
664  }
665 
672  protected static function getTargetUserTitle( $target ) {
673  if ( $target instanceof User ) {
674  return $target->getUserPage();
675  } elseif ( IPUtils::isIPAddress( $target ) ) {
677  }
678 
679  return null;
680  }
681 
695  public static function getTargetAndType( ?string $par, WebRequest $request = null ) {
696  if ( !$request instanceof WebRequest ) {
697  return AbstractBlock::parseTarget( $par );
698  }
699 
700  $possibleTargets = [
701  $request->getVal( 'wpTarget', null ),
702  $par,
703  $request->getVal( 'ip', null ),
704  // B/C @since 1.18
705  $request->getVal( 'wpBlockAddress', null ),
706  ];
707  foreach ( $possibleTargets as $possibleTarget ) {
708  $targetAndType = AbstractBlock::parseTarget( $possibleTarget );
709  // If type is not null then target is valid
710  if ( $targetAndType[ 1 ] !== null ) {
711  break;
712  }
713  }
714  return $targetAndType;
715  }
716 
727  public static function validateTarget( $value, User $user ) {
728  wfDeprecated( __METHOD__, '1.36' );
729 
730  $status = MediaWikiServices::getInstance()->getBlockUtils()->validateTarget( $value );
731 
732  // This is here to make validateTarget to not change its behavior
733  // BlockUtils does not check checkUnblockSelf.
734  list( $target, $type ) = self::getTargetAndType( $value );
735  if ( $type === AbstractBlock::TYPE_USER ) {
736  $unblockStatus = self::checkUnblockSelf( $target, $user );
737  if ( $unblockStatus !== true ) {
738  $status->fatal( 'badaccess', $unblockStatus );
739  }
740  }
741 
742  return $status;
743  }
744 
753  public static function processForm( array $data, IContextSource $context ) {
754  $services = MediaWikiServices::getInstance();
756  $data,
757  $context->getUser(),
758  $services->getBlockUserFactory(),
759  $services->getBlockUtils()
760  );
761  }
762 
773  private static function processFormInternal(
774  array $data,
775  User $performer,
778  ) {
779  $isPartialBlock = isset( $data['EditingRestriction'] ) &&
780  $data['EditingRestriction'] === 'partial';
781 
782  # This might have been a hidden field or a checkbox, so interesting data
783  # can come from it
784  $data['Confirm'] = !in_array( $data['Confirm'], [ '', '0', null, false ], true );
785 
786  # If the user has done the form 'properly', they won't even have been given the
787  # option to suppress-block unless they have the 'hideuser' permission
788  if ( !isset( $data['HideUser'] ) ) {
789  $data['HideUser'] = false;
790  }
791 
793  list( $target, $type ) = $blockUtils->parseBlockTarget( $data['Target'] );
794  if ( $type == DatabaseBlock::TYPE_USER ) {
795  $user = $target;
796  $target = $user->getName();
797  $userId = $user->getId();
798 
799  # Give admins a heads-up before they go and block themselves. Much messier
800  # to do this for IPs, but it's pretty unlikely they'd ever get the 'block'
801  # permission anyway, although the code does allow for it.
802  # Note: Important to use $target instead of $data['Target']
803  # since both $data['PreviousTarget'] and $target are normalized
804  # but $data['target'] gets overridden by (non-normalized) request variable
805  # from previous request.
806  if ( $target === $performer->getName() &&
807  ( $data['PreviousTarget'] !== $target || !$data['Confirm'] )
808  ) {
809  return [ 'ipb-blockingself', 'ipb-confirmaction' ];
810  }
811 
812  if ( $data['HideUser'] && !$data['Confirm'] ) {
813  return [ 'ipb-confirmhideuser', 'ipb-confirmaction' ];
814  }
815  } elseif ( $type == DatabaseBlock::TYPE_RANGE ) {
816  $user = null;
817  $userId = 0;
818  } elseif ( $type == DatabaseBlock::TYPE_IP ) {
819  $user = null;
820  $target = $target->getName();
821  $userId = 0;
822  } else {
823  # This should have been caught in the form field validation
824  return [ 'badipaddress' ];
825  }
826 
827  // Reason, to be passed to the block object. For default values of reason, see
828  // HTMLSelectAndOtherField::getDefault
829  // @phan-suppress-next-line PhanPluginDuplicateConditionalNullCoalescing
830  $blockReason = isset( $data['Reason'][0] ) ? $data['Reason'][0] : '';
831 
832  $pageRestrictions = [];
833  $namespaceRestrictions = [];
834  if ( $isPartialBlock ) {
835  if ( isset( $data['PageRestrictions'] ) && $data['PageRestrictions'] !== '' ) {
836  $pageRestrictions = array_map( function ( $text ) {
837  $title = Title::newFromText( $text );
838  // Use the link cache since the title has already been loaded when
839  // the field was validated.
840  $restriction = new PageRestriction( 0, $title->getArticleID() );
841  $restriction->setTitle( $title );
842  return $restriction;
843  }, explode( "\n", $data['PageRestrictions'] ) );
844  }
845  if ( isset( $data['NamespaceRestrictions'] ) && $data['NamespaceRestrictions'] !== '' ) {
846  $namespaceRestrictions = array_map( function ( $id ) {
847  return new NamespaceRestriction( 0, $id );
848  }, explode( "\n", $data['NamespaceRestrictions'] ) );
849  }
850  }
851  $restrictions = ( array_merge( $pageRestrictions, $namespaceRestrictions ) );
852 
853  if ( !isset( $data['Tags'] ) ) {
854  $data['Tags'] = [];
855  }
856 
857  $blockOptions = [
858  'isCreateAccountBlocked' => $data['CreateAccount'],
859  'isHardBlock' => $data['HardBlock'],
860  'isAutoblocking' => $data['AutoBlock'],
861  'isHideUser' => $data['HideUser'],
862  'isPartial' => $isPartialBlock,
863  ];
864 
865  if ( isset( $data['DisableUTEdit'] ) ) {
866  $blockOptions['isUserTalkEditBlocked'] = $data['DisableUTEdit'];
867  }
868  if ( isset( $data['DisableEmail'] ) ) {
869  $blockOptions['isEmailBlocked'] = $data['DisableEmail'];
870  }
871 
872  $blockUser = $blockUserFactory->newBlockUser(
873  $target,
874  $performer,
875  $data['Expiry'],
876  $blockReason,
877  $blockOptions,
878  $restrictions,
879  $data['Tags']
880  );
881 
882  # Indicates whether the user is confirming the block and is aware of
883  # the conflict (did not change the block target in the meantime)
884  $blockNotConfirmed = !$data['Confirm'] || ( array_key_exists( 'PreviousTarget', $data )
885  && $data['PreviousTarget'] !== $target );
886 
887  # Special case for API - T34434
888  $reblockNotAllowed = ( array_key_exists( 'Reblock', $data ) && !$data['Reblock'] );
889 
890  $doReblock = !$blockNotConfirmed && !$reblockNotAllowed;
891 
892  $status = $blockUser->placeBlock( $doReblock );
893  if ( !$status->isOK() ) {
894  return $status;
895  }
896 
897  # Can't watch a rangeblock
898  if ( $type != DatabaseBlock::TYPE_RANGE && $data['Watch'] ) {
901  $performer,
903  );
904  }
905 
906  return true;
907  }
908 
919  public static function getSuggestedDurations( Language $lang = null, $includeOther = true ) {
920  $msg = $lang === null
921  ? wfMessage( 'ipboptions' )->inContentLanguage()->text()
922  : wfMessage( 'ipboptions' )->inLanguage( $lang )->text();
923 
924  if ( $msg == '-' ) {
925  return [];
926  }
927 
928  $a = XmlSelect::parseOptionsMessage( $msg );
929 
930  if ( $a && $includeOther ) {
931  // if options exist, add other to the end instead of the begining (which
932  // is what happens by default).
933  $a[ wfMessage( 'ipbother' )->text() ] = 'other';
934  }
935 
936  return $a;
937  }
938 
948  public static function parseExpiryInput( $expiry ) {
949  return BlockUser::parseExpiryInput( $expiry );
950  }
951 
959  public static function canBlockEmail( UserIdentity $user ) {
960  return MediaWikiServices::getInstance()
961  ->getBlockPermissionCheckerFactory()
962  ->newBlockPermissionChecker( null, User::newFromIdentity( $user ) )
963  ->checkEmailPermissions();
964  }
965 
980  public static function checkUnblockSelf( $target, User $performer ) {
981  return MediaWikiServices::getInstance()
982  ->getBlockPermissionCheckerFactory()
983  ->newBlockPermissionChecker( $target, $performer )
984  ->checkBlockPermissions();
985  }
986 
993  public function onSubmit( array $data, HTMLForm $form = null ) {
994  // If "Editing" checkbox is unchecked, the block must be a partial block affecting
995  // actions other than editing, and there must be no restrictions.
996  if ( isset( $data['Editing'] ) && $data['Editing'] === false ) {
997  $data['EditingRestriction'] = 'partial';
998  $data['PageRestrictions'] = '';
999  $data['NamespaceRestrictions'] = '';
1000  }
1002  $data,
1003  $this->getUser(),
1004  $this->blockUserFactory,
1005  $this->blockUtils
1006  );
1007  }
1008 
1013  public function onSuccess() {
1014  $out = $this->getOutput();
1015  $out->setPageTitle( $this->msg( 'blockipsuccesssub' ) );
1016  $out->addWikiMsg( 'blockipsuccesstext', wfEscapeWikiText( $this->target ) );
1017  }
1018 
1027  public function prefixSearchSubpages( $search, $limit, $offset ) {
1028  $search = $this->userNameUtils->getCanonical( $search );
1029  if ( !$search ) {
1030  // No prefix suggestion for invalid user
1031  return [];
1032  }
1033  // Autocomplete subpage as user list - public to allow caching
1034  return $this->userNamePrefixSearch
1035  ->search( UserNamePrefixSearch::AUDIENCE_PUBLIC, $search, $limit, $offset );
1036  }
1037 
1038  protected function getGroupName() {
1039  return 'users';
1040  }
1041 }
SpecialPage\$linkRenderer
LinkRenderer null $linkRenderer
Definition: SpecialPage.php:79
SpecialPage\msg
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:900
SpecialBlock\$blockUserFactory
BlockUserFactory $blockUserFactory
Definition: SpecialBlock.php:58
MediaWiki\Block\Restriction\PageRestriction\getTitle
getTitle()
Definition: PageRestriction.php:68
MediaWiki\Block\BlockPermissionCheckerFactory
Factory class for BlockPermissionChecker.
Definition: BlockPermissionCheckerFactory.php:34
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:328
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:959
MediaWiki\Block\BlockUserFactory
Definition: BlockUserFactory.php:30
SpecialBlock\$permissionManager
PermissionManager $permissionManager
Definition: SpecialBlock.php:49
SpecialBlock\onSuccess
onSuccess()
Do something exciting on successful processing of the form, most likely to show a confirmation messag...
Definition: SpecialBlock.php:1013
SpecialBlock\$userNamePrefixSearch
UserNamePrefixSearch $userNamePrefixSearch
Definition: SpecialBlock.php:64
WatchAction\doWatch
static doWatch(Title $title, User $user, $checkRights=User::CHECK_USER_RIGHTS, ?string $expiry=null)
Watch a page.
Definition: WatchAction.php:289
SpecialBlock\$type
int $type
DatabaseBlock::TYPE_ constant.
Definition: SpecialBlock.php:72
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:788
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:165
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
SpecialBlock\checkUnblockSelf
static checkUnblockSelf( $target, User $performer)
T17810: Sitewide blocked admins should not be able to block/unblock others with one exception; they c...
Definition: SpecialBlock.php:980
SpecialBlock\$preErrors
array $preErrors
Definition: SpecialBlock.php:84
HTMLForm\addHeaderText
addHeaderText( $msg, $section=null)
Add HTML to the header, inside the form.
Definition: HTMLForm.php:820
SpecialBlock\$requestedHideUser
bool $requestedHideUser
Whether the previous submission of the form asked for HideUser.
Definition: SpecialBlock.php:78
SpecialBlock\processForm
static processForm(array $data, IContextSource $context)
Given the form data, actually implement a block.
Definition: SpecialBlock.php:753
SpecialBlock\preText
preText()
Add header elements like block log entries, etc.
Definition: SpecialBlock.php:521
MediaWiki\Block\BlockUser
Handles the backend logic of blocking users.
Definition: BlockUser.php:45
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1815
MediaWiki\Block\BlockUtils
Backend class for blocking utils.
Definition: BlockUtils.php:44
HTMLForm\setHeaderText
setHeaderText( $msg, $section=null)
Set header text, inside the form.
Definition: HTMLForm.php:842
HTMLForm\formatErrors
formatErrors( $errors)
Format a stack of error messages into a single HTML string.
Definition: HTMLForm.php:1365
MediaWiki\Block\DatabaseBlock\getType
getType()
Get the type of target for this particular block.int|null AbstractBlock::TYPE_ constant,...
Definition: DatabaseBlock.php:1078
SpecialBlock\$blockPermissionCheckerFactory
BlockPermissionCheckerFactory $blockPermissionCheckerFactory
Definition: SpecialBlock.php:55
SpecialBlock\$target
User string null $target
User to be blocked, as passed either by parameter (url?wpTarget=Foo) or as subpage (Special:Block/Foo...
Definition: SpecialBlock.php:69
SpecialBlock\$previousTarget
User string $previousTarget
The previous block target.
Definition: SpecialBlock.php:75
SpecialBlock\getTargetAndType
static getTargetAndType(?string $par, WebRequest $request=null)
Get the target and type, given the request and the subpage parameter.
Definition: SpecialBlock.php:695
SpecialBlock\onSubmit
onSubmit(array $data, HTMLForm $form=null)
Process the form on POST submission.
Definition: SpecialBlock.php:993
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:1220
User\getUserPage
getUserPage()
Get this user's personal page title.
Definition: User.php:3702
$s
$s
Definition: mergeMessageFileList.php:184
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:106
SpecialPage\getSkin
getSkin()
Shortcut to get the skin being used for this instance.
Definition: SpecialPage.php:808
SpecialBlock\__construct
__construct(PermissionManager $permissionManager, BlockUtils $blockUtils, BlockPermissionCheckerFactory $blockPermissionCheckerFactory, BlockUserFactory $blockUserFactory, UserNameUtils $userNameUtils, UserNamePrefixSearch $userNamePrefixSearch)
Definition: SpecialBlock.php:94
User\newFromIdentity
static newFromIdentity(UserIdentity $identity)
Returns a User object corresponding to the given UserIdentity.
Definition: User.php:616
SpecialBlock\doesWrites
doesWrites()
Indicates whether this special page may perform database writes.
Definition: SpecialBlock.php:112
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:818
SpecialBlock\checkExecutePermissions
checkExecutePermissions(User $user)
Checks that the user can unblock themselves if they are trying to do so.
Definition: SpecialBlock.php:122
SpecialPage\getName
getName()
Get the name of this Special Page.
Definition: SpecialPage.php:178
SpecialBlock\setParameter
setParameter( $par)
Handle some magic here.
Definition: SpecialBlock.php:147
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:145
MediaWiki\User\UserIdentity
Interface for objects representing user identity.
Definition: UserIdentity.php:32
SpecialBlock\postText
postText()
Add footer elements to the form.
Definition: SpecialBlock.php:571
MediaWiki\Block\DatabaseBlock
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Definition: DatabaseBlock.php:50
SpecialPage\addHelpLink
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition: SpecialPage.php:936
SpecialPage\getHookRunner
getHookRunner()
Definition: SpecialPage.php:1083
SpecialPage\getConfig
getConfig()
Shortcut to get main config object.
Definition: SpecialPage.php:866
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that $function is deprecated.
Definition: GlobalFunctions.php:1027
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:397
SpecialBlock\alterForm
alterForm(HTMLForm $form)
Customizes the HTMLForm a bit.
Definition: SpecialBlock.php:169
SpecialBlock
A special page that allows users with 'block' right to block users from editing pages and other actio...
Definition: SpecialBlock.php:45
MediaWiki\Block\BlockUserFactory\newBlockUser
newBlockUser( $target, User $performer, string $expiry, string $reason='', array $blockOptions=[], array $blockRestrictions=[], $tags=[])
Create BlockUser.
MediaWiki\User\UserNamePrefixSearch
Handles searching prefixes of user names.
Definition: UserNamePrefixSearch.php:39
SpecialBlock\$blockUtils
BlockUtils $blockUtils
Definition: SpecialBlock.php:52
SpecialBlock\getTargetUserTitle
static getTargetUserTitle( $target)
Get a user page target for things like logs.
Definition: SpecialBlock.php:672
$title
$title
Definition: testCompression.php:38
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:798
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:591
LogEventsList\showLogExtract
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
Definition: LogEventsList.php:618
SpecialBlock\prefixSearchSubpages
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
Definition: SpecialBlock.php:1027
FormSpecialPage\$par
string null $par
The sub-page of the special page.
Definition: FormSpecialPage.php:36
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:617
MediaWiki\Permissions\PermissionManager
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
Definition: PermissionManager.php:50
SpecialBlock\processFormInternal
static processFormInternal(array $data, User $performer, BlockUserFactory $blockUserFactory, BlockUtils $blockUtils)
Implementation details for processForm Own function to allow sharing the deprecated code with non-dep...
Definition: SpecialBlock.php:773
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:778
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1494
SpecialBlock\getFormFields
getFormFields()
Get the HTMLForm descriptor array for the block form.
Definition: SpecialBlock.php:199
IContextSource\getUser
getUser()
HTMLForm\setSubmitDestructive
setSubmitDestructive()
Identify that the submit button in the form has a destructive action.
Definition: HTMLForm.php:1400
SpecialBlock\$userNameUtils
UserNameUtils $userNameUtils
Definition: SpecialBlock.php:61
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:55
WebRequest
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
Definition: WebRequest.php:42
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:1414
SpecialPage\getLinkRenderer
getLinkRenderer()
Definition: SpecialPage.php:1016
MediaWiki\Block\Restriction\PageRestriction
Definition: PageRestriction.php:25
SpecialBlock\$alreadyBlocked
bool $alreadyBlocked
Definition: SpecialBlock.php:81
MediaWiki\User\UserNameUtils
UserNameUtils service.
Definition: UserNameUtils.php:42
SpecialBlock\validateTarget
static validateTarget( $value, User $user)
Validate a block target.
Definition: SpecialBlock.php:727
SpecialBlock\getDisplayFormat
getDisplayFormat()
Get display format for the form.
Definition: SpecialBlock.php:191
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:212
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:948
SpecialBlock\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialBlock.php:1038
NS_USER
const NS_USER
Definition: Defines.php:71
SpecialBlock\getSuggestedDurations
static getSuggestedDurations(Language $lang=null, $includeOther=true)
Get an array of suggested block durations from MediaWiki:Ipboptions.
Definition: SpecialBlock.php:919
MediaWiki\Block\AbstractBlock
Definition: AbstractBlock.php:37
User\IGNORE_USER_RIGHTS
const IGNORE_USER_RIGHTS
Definition: User.php:90
MediaWiki\Block\BlockUtils\parseBlockTarget
parseBlockTarget( $target)
From an existing block, get the target and the type of target.
Definition: BlockUtils.php:83
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:56
User\getName
getName()
Get the user name, or the IP of an anonymous user.
Definition: User.php:2053
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:42
SpecialBlock\requiresUnblock
requiresUnblock()
We allow certain special cases where user is blocked.
Definition: SpecialBlock.php:138
HTMLForm
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition: HTMLForm.php:135