MediaWiki REL1_37
SpecialBlock.php
Go to the documentation of this file.
1<?php
40use Wikimedia\IPUtils;
41
49
51 private $blockUtils;
52
55
58
61
64
67
70
74 protected $target;
75
77 protected $type;
78
80 protected $previousTarget;
81
84
86 protected $alreadyBlocked;
87
89 protected $preErrors = [];
90
93
104 public function __construct(
105 BlockUtils $blockUtils,
106 BlockPermissionCheckerFactory $blockPermissionCheckerFactory,
107 BlockUserFactory $blockUserFactory,
108 UserNameUtils $userNameUtils,
109 UserNamePrefixSearch $userNamePrefixSearch,
110 BlockActionInfo $blockActionInfo,
111 TitleFormatter $titleFormatter,
112 NamespaceInfo $namespaceInfo
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 ) {
196 $form->addHeaderText( Html::rawElement(
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['Editing'] = [
251 'type' => 'check',
252 'label-message' => 'block-prevent-edit',
253 'default' => true,
254 'section' => 'actions',
255 ];
256
257 $a['EditingRestriction'] = [
258 'type' => 'radio',
259 'cssclass' => 'mw-block-editing-restriction',
260 'default' => 'sitewide',
261 'options' => [
262 $this->msg( 'ipb-sitewide' )->escaped() .
263 new \OOUI\LabelWidget( [
264 'classes' => [ 'oo-ui-inline-help' ],
265 'label' => $this->msg( 'ipb-sitewide-help' )->text(),
266 ] ) => 'sitewide',
267 $this->msg( 'ipb-partial' )->escaped() .
268 new \OOUI\LabelWidget( [
269 'classes' => [ 'oo-ui-inline-help' ],
270 'label' => $this->msg( 'ipb-partial-help' )->text(),
271 ] ) => 'partial',
272 ],
273 'section' => 'actions',
274 ];
275
276 $a['PageRestrictions'] = [
277 'type' => 'titlesmultiselect',
278 'label' => $this->msg( 'ipb-pages-label' )->text(),
279 'exists' => true,
280 'max' => 10,
281 'cssclass' => 'mw-block-restriction',
282 'default' => '',
283 'showMissing' => false,
284 'excludeDynamicNamespaces' => true,
285 'input' => [
286 'autocomplete' => false
287 ],
288 'section' => 'actions',
289 ];
290
291 $a['NamespaceRestrictions'] = [
292 'type' => 'namespacesmultiselect',
293 'label' => $this->msg( 'ipb-namespaces-label' )->text(),
294 'exists' => true,
295 'cssclass' => 'mw-block-restriction',
296 'default' => '',
297 'input' => [
298 'autocomplete' => false
299 ],
300 'section' => 'actions',
301 ];
302
303 $a['CreateAccount'] = [
304 'type' => 'check',
305 'label-message' => 'ipbcreateaccount',
306 'default' => true,
307 'section' => 'actions',
308 ];
309
310 if ( $this->blockPermissionCheckerFactory
311 ->newBlockPermissionChecker( null, $user )
312 ->checkEmailPermissions()
313 ) {
314 $a['DisableEmail'] = [
315 'type' => 'check',
316 'label-message' => 'ipbemailban',
317 'section' => 'actions',
318 ];
319 }
320
321 if ( $blockAllowsUTEdit ) {
322 $a['DisableUTEdit'] = [
323 'type' => 'check',
324 'label-message' => 'ipb-disableusertalk',
325 'default' => false,
326 'section' => 'actions',
327 ];
328 }
329
330 if ( $conf->get( 'EnablePartialActionBlocks' ) ) {
331 $blockActions = $this->blockActionInfo->getAllBlockActions();
332 $a['ActionRestrictions'] = [
333 'type' => 'multiselect',
334 'cssclass' => 'mw-block-action-restriction',
335 'options-messages' => array_combine(
336 array_map( static function ( $action ) {
337 return "ipb-action-$action";
338 }, array_keys( $blockActions ) ),
339 $blockActions
340 ),
341 'section' => 'actions',
342 ];
343 }
344
345 $defaultExpiry = $this->msg( 'ipb-default-expiry' )->inContentLanguage();
346 if ( $this->type === DatabaseBlock::TYPE_RANGE || $this->type === DatabaseBlock::TYPE_IP ) {
347 $defaultExpiryIP = $this->msg( 'ipb-default-expiry-ip' )->inContentLanguage();
348 if ( !$defaultExpiryIP->isDisabled() ) {
349 $defaultExpiry = $defaultExpiryIP;
350 }
351 }
352
353 $a['Expiry'] = [
354 'type' => 'expiry',
355 'required' => true,
356 'options' => $suggestedDurations,
357 'default' => $defaultExpiry->text(),
358 'section' => 'expiry',
359 ];
360
361 $a['Reason'] = [
362 'type' => 'selectandother',
363 // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP
364 // (e.g. emojis) count for two each. This limit is overridden in JS to instead count
365 // Unicode codepoints.
366 'maxlength' => CommentStore::COMMENT_CHARACTER_LIMIT,
367 'maxlength-unit' => 'codepoints',
368 'options-message' => 'ipbreason-dropdown',
369 'section' => 'reason',
370 ];
371
372 $a['AutoBlock'] = [
373 'type' => 'check',
374 'label-message' => 'ipbenableautoblock',
375 'default' => true,
376 'section' => 'options',
377 ];
378
379 # Allow some users to hide name from block log, blocklist and listusers
380 if ( $this->getAuthority()->isAllowed( 'hideuser' ) ) {
381 $a['HideUser'] = [
382 'type' => 'check',
383 'label-message' => 'ipbhidename',
384 'cssclass' => 'mw-block-hideuser',
385 'section' => 'options',
386 ];
387 }
388
389 # Watchlist their user page? (Only if user is logged in)
390 if ( $user->isRegistered() ) {
391 $a['Watch'] = [
392 'type' => 'check',
393 'label-message' => 'ipbwatchuser',
394 'section' => 'options',
395 ];
396 }
397
398 $a['HardBlock'] = [
399 'type' => 'check',
400 'label-message' => 'ipb-hardblock',
401 'default' => false,
402 'section' => 'options',
403 ];
404
405 # This is basically a copy of the Target field, but the user can't change it, so we
406 # can see if the warnings we maybe showed to the user before still apply
407 $a['PreviousTarget'] = [
408 'type' => 'hidden',
409 'default' => false,
410 ];
411
412 # We'll turn this into a checkbox if we need to
413 $a['Confirm'] = [
414 'type' => 'hidden',
415 'default' => '',
416 'label-message' => 'ipb-confirm',
417 'cssclass' => 'mw-block-confirm',
418 ];
419
420 $this->maybeAlterFormDefaults( $a );
421
422 // Allow extensions to add more fields
423 $this->getHookRunner()->onSpecialBlockModifyFormFields( $this, $a );
424
425 return $a;
426 }
427
433 protected function maybeAlterFormDefaults( &$fields ) {
434 # This will be overwritten by request data
435 $fields['Target']['default'] = (string)$this->target;
436
437 if ( $this->target ) {
438 $status = $this->blockUtils->validateTarget( $this->target );
439 if ( !$status->isOK() ) {
440 $errors = $status->getErrorsArray();
441 $this->preErrors = array_merge( $this->preErrors, $errors );
442 }
443 }
444
445 # This won't be
446 $fields['PreviousTarget']['default'] = (string)$this->target;
447
448 $block = DatabaseBlock::newFromTarget( $this->target );
449
450 // Populate fields if there is a block that is not an autoblock; if it is a range
451 // block, only populate the fields if the range is the same as $this->target
452 if ( $block instanceof DatabaseBlock && $block->getType() !== DatabaseBlock::TYPE_AUTO
453 && ( $this->type != DatabaseBlock::TYPE_RANGE
454 || ( $this->target && $block->isBlocking( $this->target ) ) )
455 ) {
456 $fields['HardBlock']['default'] = $block->isHardblock();
457 $fields['CreateAccount']['default'] = $block->isCreateAccountBlocked();
458 $fields['AutoBlock']['default'] = $block->isAutoblocking();
459
460 if ( isset( $fields['DisableEmail'] ) ) {
461 $fields['DisableEmail']['default'] = $block->isEmailBlocked();
462 }
463
464 if ( isset( $fields['HideUser'] ) ) {
465 $fields['HideUser']['default'] = $block->getHideName();
466 }
467
468 if ( isset( $fields['DisableUTEdit'] ) ) {
469 $fields['DisableUTEdit']['default'] = !$block->isUsertalkEditAllowed();
470 }
471
472 // If the username was hidden (ipb_deleted == 1), don't show the reason
473 // unless this user also has rights to hideuser: T37839
474 if ( !$block->getHideName() || $this->getAuthority()->isAllowed( 'hideuser' ) ) {
475 $fields['Reason']['default'] = $block->getReasonComment()->text;
476 } else {
477 $fields['Reason']['default'] = '';
478 }
479
480 if ( $this->getRequest()->wasPosted() ) {
481 # Ok, so we got a POST submission asking us to reblock a user. So show the
482 # confirm checkbox; the user will only see it if they haven't previously
483 $fields['Confirm']['type'] = 'check';
484 } else {
485 # We got a target, but it wasn't a POST request, so the user must have gone
486 # to a link like [[Special:Block/User]]. We don't need to show the checkbox
487 # as long as they go ahead and block *that* user
488 $fields['Confirm']['default'] = 1;
489 }
490
491 if ( $block->getExpiry() == 'infinity' ) {
492 $fields['Expiry']['default'] = 'infinite';
493 } else {
494 $fields['Expiry']['default'] = wfTimestamp( TS_RFC2822, $block->getExpiry() );
495 }
496
497 if ( !$block->isSitewide() ) {
498 $fields['EditingRestriction']['default'] = 'partial';
499
500 $pageRestrictions = [];
501 $namespaceRestrictions = [];
502 foreach ( $block->getRestrictions() as $restriction ) {
503 if ( $restriction instanceof PageRestriction && $restriction->getTitle() ) {
504 $pageRestrictions[] = $restriction->getTitle()->getPrefixedText();
505 } elseif ( $restriction instanceof NamespaceRestriction &&
506 $this->namespaceInfo->exists( $restriction->getValue() )
507 ) {
508 $namespaceRestrictions[] = $restriction->getValue();
509 }
510 }
511
512 // Sort the restrictions so they are in alphabetical order.
513 sort( $pageRestrictions );
514 $fields['PageRestrictions']['default'] = implode( "\n", $pageRestrictions );
515 sort( $namespaceRestrictions );
516 $fields['NamespaceRestrictions']['default'] = implode( "\n", $namespaceRestrictions );
517
518 if (
519 empty( $pageRestrictions ) &&
520 empty( $namespaceRestrictions )
521 ) {
522 $fields['Editing']['default'] = false;
523 }
524
525 if ( $this->getConfig()->get( 'EnablePartialActionBlocks' ) ) {
526 $actionRestrictions = [];
527 foreach ( $block->getRestrictions() as $restriction ) {
528 if ( $restriction instanceof ActionRestriction ) {
529 $actionRestrictions[] = $restriction->getValue();
530 }
531 }
532 $fields['ActionRestrictions']['default'] = $actionRestrictions;
533 }
534 }
535
536 $this->alreadyBlocked = true;
537 $this->preErrors[] = [ 'ipb-needreblock', wfEscapeWikiText( $block->getTargetName() ) ];
538 }
539
540 if ( $this->alreadyBlocked || $this->getRequest()->wasPosted()
541 || $this->getRequest()->getCheck( 'wpCreateAccount' )
542 ) {
543 $this->getOutput()->addJsConfigVars( 'wgCreateAccountDirty', true );
544 }
545
546 # We always need confirmation to do HideUser
547 if ( $this->requestedHideUser ) {
548 $fields['Confirm']['type'] = 'check';
549 unset( $fields['Confirm']['default'] );
550 $this->preErrors[] = [ 'ipb-confirmhideuser', 'ipb-confirmaction' ];
551 }
552
553 # Or if the user is trying to block themselves
554 if ( (string)$this->target === $this->getUser()->getName() ) {
555 $fields['Confirm']['type'] = 'check';
556 unset( $fields['Confirm']['default'] );
557 $this->preErrors[] = [ 'ipb-blockingself', 'ipb-confirmaction' ];
558 }
559 }
560
565 protected function preText() {
566 $this->getOutput()->addModuleStyles( [
567 'mediawiki.widgets.TagMultiselectWidget.styles',
568 'mediawiki.special',
569 ] );
570 $this->getOutput()->addModules( [ 'mediawiki.special.block' ] );
571
572 $blockCIDRLimit = $this->getConfig()->get( 'BlockCIDRLimit' );
573 $text = $this->msg( 'blockiptext', $blockCIDRLimit['IPv4'], $blockCIDRLimit['IPv6'] )->parse();
574
575 $otherBlockMessages = [];
576 if ( $this->target !== null ) {
577 $targetName = $this->target;
578 if ( $this->target instanceof UserIdentity ) {
579 $targetName = $this->target->getName();
580 }
581 # Get other blocks, i.e. from GlobalBlocking or TorBlock extension
582 $this->getHookRunner()->onOtherBlockLogLink(
583 $otherBlockMessages, $targetName );
584
585 if ( count( $otherBlockMessages ) ) {
586 $s = Html::rawElement(
587 'h2',
588 [],
589 $this->msg( 'ipb-otherblocks-header', count( $otherBlockMessages ) )->parse()
590 ) . "\n";
591
592 $list = '';
593
594 foreach ( $otherBlockMessages as $link ) {
595 $list .= Html::rawElement( 'li', [], $link ) . "\n";
596 }
597
598 $s .= Html::rawElement(
599 'ul',
600 [ 'class' => 'mw-blockip-alreadyblocked' ],
601 $list
602 ) . "\n";
603
604 $text .= $s;
605 }
606 }
607
608 return $text;
609 }
610
615 protected function postText() {
616 $links = [];
617
618 $this->getOutput()->addModuleStyles( 'mediawiki.special' );
619
621 # Link to the user's contributions, if applicable
622 if ( $this->target instanceof UserIdentity ) {
623 $contribsPage = SpecialPage::getTitleFor( 'Contributions', $this->target->getName() );
624 $links[] = $linkRenderer->makeLink(
625 $contribsPage,
626 $this->msg( 'ipb-blocklist-contribs', $this->target->getName() )->text()
627 );
628 }
629
630 # Link to unblock the specified user, or to a blank unblock form
631 if ( $this->target instanceof UserIdentity ) {
632 $message = $this->msg(
633 'ipb-unblock-addr',
634 wfEscapeWikiText( $this->target->getName() )
635 )->parse();
636 $list = SpecialPage::getTitleFor( 'Unblock', $this->target->getName() );
637 } else {
638 $message = $this->msg( 'ipb-unblock' )->parse();
639 $list = SpecialPage::getTitleFor( 'Unblock' );
640 }
641 $links[] = $linkRenderer->makeKnownLink(
642 $list,
643 new HtmlArmor( $message )
644 );
645
646 # Link to the block list
647 $links[] = $linkRenderer->makeKnownLink(
648 SpecialPage::getTitleFor( 'BlockList' ),
649 $this->msg( 'ipb-blocklist' )->text()
650 );
651
652 # Link to edit the block dropdown reasons, if applicable
653 if ( $this->getAuthority()->isAllowed( 'editinterface' ) ) {
654 $links[] = $linkRenderer->makeKnownLink(
655 $this->msg( 'ipbreason-dropdown' )->inContentLanguage()->getTitle(),
656 $this->msg( 'ipb-edit-dropdown' )->text(),
657 [],
658 [ 'action' => 'edit' ]
659 );
660 }
661
662 $text = Html::rawElement(
663 'p',
664 [ 'class' => 'mw-ipb-conveniencelinks' ],
665 $this->getLanguage()->pipeList( $links )
666 );
667
668 $userPage = self::getTargetUserTitle( $this->target );
669 if ( $userPage ) {
670 # Get relevant extracts from the block and suppression logs, if possible
671 $out = '';
672
673 LogEventsList::showLogExtract(
674 $out,
675 'block',
676 $userPage,
677 '',
678 [
679 'lim' => 10,
680 'msgKey' => [
681 'blocklog-showlog',
682 $this->titleFormatter->getText( $userPage ),
683 ],
684 'showIfEmpty' => false
685 ]
686 );
687 $text .= $out;
688
689 # Add suppression block entries if allowed
690 if ( $this->getAuthority()->isAllowed( 'suppressionlog' ) ) {
691 LogEventsList::showLogExtract(
692 $out,
693 'suppress',
694 $userPage,
695 '',
696 [
697 'lim' => 10,
698 'conds' => [ 'log_action' => [ 'block', 'reblock', 'unblock' ] ],
699 'msgKey' => [
700 'blocklog-showsuppresslog',
701 $this->titleFormatter->getText( $userPage ),
702 ],
703 'showIfEmpty' => false
704 ]
705 );
706
707 $text .= $out;
708 }
709 }
710
711 return $text;
712 }
713
720 protected static function getTargetUserTitle( $target ): ?PageReference {
721 if ( $target instanceof UserIdentity ) {
722 return PageReferenceValue::localReference( NS_USER, $target->getName() );
723 }
724
725 if ( is_string( $target ) && IPUtils::isIPAddress( $target ) ) {
726 return PageReferenceValue::localReference( NS_USER, $target );
727 }
728
729 return null;
730 }
731
745 public static function getTargetAndType( ?string $par, WebRequest $request = null ) {
746 if ( !$request instanceof WebRequest ) {
747 return MediaWikiServices::getInstance()->getBlockUtils()->parseBlockTarget( $par );
748 }
749
750 $possibleTargets = [
751 $request->getVal( 'wpTarget', null ),
752 $par,
753 $request->getVal( 'ip', null ),
754 // B/C @since 1.18
755 $request->getVal( 'wpBlockAddress', null ),
756 ];
757 foreach ( $possibleTargets as $possibleTarget ) {
758 $targetAndType = MediaWikiServices::getInstance()
759 ->getBlockUtils()
760 ->parseBlockTarget( $possibleTarget );
761 // If type is not null then target is valid
762 if ( $targetAndType[ 1 ] !== null ) {
763 break;
764 }
765 }
766 return $targetAndType;
767 }
768
777 public static function processForm( array $data, IContextSource $context ) {
778 $services = MediaWikiServices::getInstance();
779 return self::processFormInternal(
780 $data,
781 $context->getAuthority(),
782 $services->getBlockUserFactory(),
783 $services->getBlockUtils()
784 );
785 }
786
797 private static function processFormInternal(
798 array $data,
799 Authority $performer,
800 BlockUserFactory $blockUserFactory,
801 BlockUtils $blockUtils
802 ) {
803 // Temporarily access service container until the feature flag is removed: T280532
804 $enablePartialActionBlocks = MediaWikiServices::getInstance()
805 ->getMainConfig()->get( 'EnablePartialActionBlocks' );
806
807 $isPartialBlock = isset( $data['EditingRestriction'] ) &&
808 $data['EditingRestriction'] === 'partial';
809
810 # This might have been a hidden field or a checkbox, so interesting data
811 # can come from it
812 $data['Confirm'] = !in_array( $data['Confirm'], [ '', '0', null, false ], true );
813
814 # If the user has done the form 'properly', they won't even have been given the
815 # option to suppress-block unless they have the 'hideuser' permission
816 if ( !isset( $data['HideUser'] ) ) {
817 $data['HideUser'] = false;
818 }
819
821 list( $target, $type ) = $blockUtils->parseBlockTarget( $data['Target'] );
822 if ( $type == DatabaseBlock::TYPE_USER ) {
823 $user = $target;
824 $target = $user->getName();
825 $userId = $user->getId();
826
827 # Give admins a heads-up before they go and block themselves. Much messier
828 # to do this for IPs, but it's pretty unlikely they'd ever get the 'block'
829 # permission anyway, although the code does allow for it.
830 # Note: Important to use $target instead of $data['Target']
831 # since both $data['PreviousTarget'] and $target are normalized
832 # but $data['target'] gets overridden by (non-normalized) request variable
833 # from previous request.
834 if ( $target === $performer->getUser()->getName() &&
835 ( $data['PreviousTarget'] !== $target || !$data['Confirm'] )
836 ) {
837 return [ 'ipb-blockingself', 'ipb-confirmaction' ];
838 }
839
840 if ( $data['HideUser'] && !$data['Confirm'] ) {
841 return [ 'ipb-confirmhideuser', 'ipb-confirmaction' ];
842 }
843 } elseif ( $type == DatabaseBlock::TYPE_RANGE ) {
844 $user = null;
845 $userId = 0;
846 } elseif ( $type == DatabaseBlock::TYPE_IP ) {
847 $user = null;
848 $target = $target->getName();
849 $userId = 0;
850 } else {
851 # This should have been caught in the form field validation
852 return [ 'badipaddress' ];
853 }
854
855 // Reason, to be passed to the block object. For default values of reason, see
856 // HTMLSelectAndOtherField::getDefault
857 $blockReason = $data['Reason'][0] ?? '';
858
859 $pageRestrictions = [];
860 $namespaceRestrictions = [];
861 $actionRestrictions = [];
862 if ( $isPartialBlock ) {
863 if ( isset( $data['PageRestrictions'] ) && $data['PageRestrictions'] !== '' ) {
864 $titles = explode( "\n", $data['PageRestrictions'] );
865 foreach ( $titles as $title ) {
866 $pageRestrictions[] = PageRestriction::newFromTitle( $title );
867 }
868 }
869 if ( isset( $data['NamespaceRestrictions'] ) && $data['NamespaceRestrictions'] !== '' ) {
870 $namespaceRestrictions = array_map( static function ( $id ) {
871 return new NamespaceRestriction( 0, $id );
872 }, explode( "\n", $data['NamespaceRestrictions'] ) );
873 }
874 if (
875 $enablePartialActionBlocks &&
876 isset( $data['ActionRestrictions'] ) &&
877 $data['ActionRestrictions'] !== ''
878 ) {
879 $actionRestrictions = array_map( static function ( $id ) {
880 return new ActionRestriction( 0, $id );
881 }, $data['ActionRestrictions'] );
882 }
883 }
884 $restrictions = array_merge( $pageRestrictions, $namespaceRestrictions, $actionRestrictions );
885
886 if ( !isset( $data['Tags'] ) ) {
887 $data['Tags'] = [];
888 }
889
890 $blockOptions = [
891 'isCreateAccountBlocked' => $data['CreateAccount'],
892 'isHardBlock' => $data['HardBlock'],
893 'isAutoblocking' => $data['AutoBlock'],
894 'isHideUser' => $data['HideUser'],
895 'isPartial' => $isPartialBlock,
896 ];
897
898 if ( isset( $data['DisableUTEdit'] ) ) {
899 $blockOptions['isUserTalkEditBlocked'] = $data['DisableUTEdit'];
900 }
901 if ( isset( $data['DisableEmail'] ) ) {
902 $blockOptions['isEmailBlocked'] = $data['DisableEmail'];
903 }
904
905 $blockUser = $blockUserFactory->newBlockUser(
906 $target,
907 $performer,
908 $data['Expiry'],
909 $blockReason,
910 $blockOptions,
911 $restrictions,
912 $data['Tags']
913 );
914
915 # Indicates whether the user is confirming the block and is aware of
916 # the conflict (did not change the block target in the meantime)
917 $blockNotConfirmed = !$data['Confirm'] || ( array_key_exists( 'PreviousTarget', $data )
918 && $data['PreviousTarget'] !== $target );
919
920 # Special case for API - T34434
921 $reblockNotAllowed = ( array_key_exists( 'Reblock', $data ) && !$data['Reblock'] );
922
923 $doReblock = !$blockNotConfirmed && !$reblockNotAllowed;
924
925 $status = $blockUser->placeBlock( $doReblock );
926 if ( !$status->isOK() ) {
927 return $status;
928 }
929
930 if (
931 // Can't watch a rangeblock
932 $type != DatabaseBlock::TYPE_RANGE
933
934 // Technically a wiki can be configured to allow anonymous users to place blocks,
935 // in which case the 'Watch' field isn't included in the form shown, and we should
936 // not try to access it.
937 && array_key_exists( 'Watch', $data )
938 && $data['Watch']
939 ) {
940 MediaWikiServices::getInstance()->getWatchlistManager()->addWatchIgnoringRights(
941 $performer->getUser(),
942 Title::makeTitle( NS_USER, $target )
943 );
944 }
945
946 return true;
947 }
948
959 public static function getSuggestedDurations( Language $lang = null, $includeOther = true ) {
960 $msg = $lang === null
961 ? wfMessage( 'ipboptions' )->inContentLanguage()->text()
962 : wfMessage( 'ipboptions' )->inLanguage( $lang )->text();
963
964 if ( $msg == '-' ) {
965 return [];
966 }
967
969
970 if ( $a && $includeOther ) {
971 // if options exist, add other to the end instead of the begining (which
972 // is what happens by default).
973 $a[ wfMessage( 'ipbother' )->text() ] = 'other';
974 }
975
976 return $a;
977 }
978
988 public static function parseExpiryInput( $expiry ) {
989 return BlockUser::parseExpiryInput( $expiry );
990 }
991
999 public static function canBlockEmail( UserIdentity $user ) {
1000 return MediaWikiServices::getInstance()
1001 ->getBlockPermissionCheckerFactory()
1002 ->newBlockPermissionChecker( null, User::newFromIdentity( $user ) )
1003 ->checkEmailPermissions();
1004 }
1005
1020 public static function checkUnblockSelf( $target, Authority $performer ) {
1021 wfDeprecated( __METHOD__, '1.36' );
1022 return MediaWikiServices::getInstance()
1023 ->getBlockPermissionCheckerFactory()
1024 ->newBlockPermissionChecker( $target, $performer )
1025 ->checkBlockPermissions();
1026 }
1027
1034 public function onSubmit( array $data, HTMLForm $form = null ) {
1035 // If "Editing" checkbox is unchecked, the block must be a partial block affecting
1036 // actions other than editing, and there must be no restrictions.
1037 if ( isset( $data['Editing'] ) && $data['Editing'] === false ) {
1038 $data['EditingRestriction'] = 'partial';
1039 $data['PageRestrictions'] = '';
1040 $data['NamespaceRestrictions'] = '';
1041 }
1042 return self::processFormInternal(
1043 $data,
1044 $this->getAuthority(),
1045 $this->blockUserFactory,
1046 $this->blockUtils
1047 );
1048 }
1049
1054 public function onSuccess() {
1055 $out = $this->getOutput();
1056 $out->setPageTitle( $this->msg( 'blockipsuccesssub' ) );
1057 $out->addWikiMsg( 'blockipsuccesstext', wfEscapeWikiText( $this->target ) );
1058 }
1059
1068 public function prefixSearchSubpages( $search, $limit, $offset ) {
1069 $search = $this->userNameUtils->getCanonical( $search );
1070 if ( !$search ) {
1071 // No prefix suggestion for invalid user
1072 return [];
1073 }
1074 // Autocomplete subpage as user list - public to allow caching
1075 return $this->userNamePrefixSearch
1076 ->search( UserNamePrefixSearch::AUDIENCE_PUBLIC, $search, $limit, $offset );
1077 }
1078
1079 protected function getGroupName() {
1080 return 'users';
1081 }
1082}
getAuthority()
const NS_USER
Definition Defines.php:66
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
if(ini_get('mbstring.func_overload')) if(!defined('MW_ENTRY_POINT'))
Pre-config setup: Before loading LocalSettings.php.
Definition Setup.php:88
An error page which can definitely be safely rendered using the OutputPage.
Special page which uses an HTMLForm to handle processing.
string null $par
The sub-page of the special page.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:143
setHeaderText( $msg, $section=null)
Set header text, inside the form.
Definition HTMLForm.php:852
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
formatErrors( $errors)
Format a stack of error messages into a single HTML string.
setSubmitDestructive()
Identify that the submit button in the form has a destructive action.
addHeaderText( $msg, $section=null)
Add HTML to the header, inside the form.
Definition HTMLForm.php:830
Marks HTML that shouldn't be escaped.
Definition HtmlArmor.php:30
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition Language.php:42
Defines the actions that can be blocked by a partial block.
Handles the backend logic of blocking users.
Definition BlockUser.php:51
Backend class for blocking utils.
parseBlockTarget( $target)
From an existing block, get the target and the type of target.
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
getType()
Get the type of target for this particular block.int|null AbstractBlock::TYPE_ constant,...
Restriction for partial blocks of actions.
makeKnownLink( $target, $text=null, array $extraAttribs=[], array $query=[])
makeLink( $target, $text=null, array $extraAttribs=[], array $query=[])
MediaWikiServices is the service locator for the application scope of MediaWiki.
Immutable value object representing a page reference.
Handles searching prefixes of user names.
UserNameUtils service.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
A special page that allows users with 'block' right to block users from editing pages and other actio...
int $type
DatabaseBlock::TYPE_ constant.
requiresUnblock()
We allow certain special cases where user is blocked.
NamespaceInfo $namespaceInfo
BlockPermissionCheckerFactory $blockPermissionCheckerFactory
preText()
Add header elements like block log entries, etc.
static processForm(array $data, IContextSource $context)
Given the form data, actually implement a block.
UserNameUtils $userNameUtils
BlockActionInfo $blockActionInfo
onSuccess()
Do something exciting on successful processing of the form, most likely to show a confirmation messag...
static parseExpiryInput( $expiry)
Convert a submitted expiry time, which may be relative ("2 weeks", etc) or absolute ("24 May 2034",...
BlockUtils $blockUtils
TitleFormatter $titleFormatter
bool $requestedHideUser
Whether the previous submission of the form asked for HideUser.
maybeAlterFormDefaults(&$fields)
If the user has already been blocked with similar settings, load that block and change the defaults f...
getFormFields()
Get the HTMLForm descriptor array for the block form.
postText()
Add footer elements to the form.
BlockUserFactory $blockUserFactory
__construct(BlockUtils $blockUtils, BlockPermissionCheckerFactory $blockPermissionCheckerFactory, BlockUserFactory $blockUserFactory, UserNameUtils $userNameUtils, UserNamePrefixSearch $userNamePrefixSearch, BlockActionInfo $blockActionInfo, TitleFormatter $titleFormatter, NamespaceInfo $namespaceInfo)
static checkUnblockSelf( $target, Authority $performer)
T17810: Sitewide blocked admins should not be able to block/unblock others with one exception; they c...
getDisplayFormat()
Get display format for the form.
UserNamePrefixSearch $userNamePrefixSearch
setParameter( $par)
Handle some magic here.
User string $previousTarget
The previous block target.
checkExecutePermissions(User $user)
Checks that the user can unblock themselves if they are trying to do so.
alterForm(HTMLForm $form)
Customizes the HTMLForm a bit.
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...
static getTargetUserTitle( $target)
Get a user page target for things like logs.
static canBlockEmail(UserIdentity $user)
Can we do an email block?
doesWrites()
Indicates whether this special page may perform database writes.
onSubmit(array $data, HTMLForm $form=null)
Process the form on POST submission.
static getSuggestedDurations(Language $lang=null, $includeOther=true)
Get an array of suggested block durations from MediaWiki:Ipboptions.
prefixSearchSubpages( $search, $limit, $offset)
Return an array of subpages beginning with $search that this special page will accept.
static getTargetAndType(?string $par, WebRequest $request=null)
Get the target and type, given the request and the subpage parameter.
UserIdentity string null $target
User to be blocked, as passed either by parameter (url?wpTarget=Foo) or as subpage (Special:Block/Foo...
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
getName()
Get the name of this Special Page.
getOutput()
Get the OutputPage being used for this instance.
getUser()
Shortcut to get the User executing this instance.
getSkin()
Shortcut to get the skin being used for this instance.
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,...
LinkRenderer null $linkRenderer
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getConfig()
Shortcut to get main config object.
getRequest()
Get the WebRequest being used for this instance.
getLanguage()
Shortcut to get user's language.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:69
static newFromIdentity(UserIdentity $identity)
Returns a User object corresponding to the given UserIdentity.
Definition User.php:684
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
static parseOptionsMessage(string $msg)
Parse labels and values out of a comma- and colon-separated list of options, such as is used for expi...
Interface for objects which can provide a MediaWiki context on request.
newBlockUser( $target, Authority $performer, string $expiry, string $reason='', array $blockOptions=[], array $blockRestrictions=[], $tags=[])
Create BlockUser.
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.
This interface represents the authority associated the current execution context, such as a web reque...
Definition Authority.php:37
getUser()
Returns the performer of the actions associated with this authority.
Interface for objects representing user identity.
A title formatter service for MediaWiki.
foreach( $mmfl['setupFiles'] as $fileName) if($queue) if(empty( $mmfl['quiet'])) $s
if(!isset( $args[0])) $lang