use MediaWiki\Block\BlockRestriction;
use MediaWiki\Block\Restriction\PageRestriction;
+use MediaWiki\Block\Restriction\NamespaceRestriction;
/**
* A special page that allows users with 'block' right to block users from
'type' => 'user',
'ipallowed' => true,
'iprange' => true,
- 'label-message' => 'ipaddressorusername',
'id' => 'mw-bi-target',
'size' => '45',
'autofocus' => true,
'required' => true,
'validation-callback' => [ __CLASS__, 'validateTargetField' ],
+ 'section' => 'target',
+ ];
+
+ $a['Editing'] = [
+ 'type' => 'check',
+ 'label-message' => 'block-prevent-edit',
+ 'default' => true,
+ 'section' => 'actions',
+ 'disabled' => $enablePartialBlocks ? false : true,
];
if ( $enablePartialBlocks ) {
$a['EditingRestriction'] = [
'type' => 'radio',
- 'label' => $this->msg( 'ipb-type-label' )->text(),
+ 'cssclass' => 'mw-block-editing-restriction',
'options' => [
$this->msg( 'ipb-sitewide' )->text() => 'sitewide',
$this->msg( 'ipb-partial' )->text() => 'partial',
],
+ 'section' => 'actions',
];
$a['PageRestrictions'] = [
'type' => 'titlesmultiselect',
'label' => $this->msg( 'ipb-pages-label' )->text(),
'exists' => true,
'max' => 10,
- 'cssclass' => 'mw-block-page-restrictions',
+ 'cssclass' => 'mw-block-restriction',
'showMissing' => false,
'input' => [
'autocomplete' => false
],
+ 'section' => 'actions',
+ ];
+ $a['NamespaceRestrictions'] = [
+ 'type' => 'namespacesmultiselect',
+ 'label' => $this->msg( 'ipb-namespaces-label' )->text(),
+ 'exists' => true,
+ 'cssclass' => 'mw-block-restriction',
+ 'input' => [
+ 'autocomplete' => false
+ ],
+ 'section' => 'actions',
];
}
- $a['Expiry'] = [
- 'type' => 'expiry',
- 'label-message' => 'ipbexpiry',
- 'required' => true,
- 'options' => $suggestedDurations,
- 'default' => $this->msg( 'ipb-default-expiry' )->inContentLanguage()->text(),
- ];
-
- $a['Reason'] = [
- 'type' => 'selectandother',
- // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP
- // (e.g. emojis) count for two each. This limit is overridden in JS to instead count
- // Unicode codepoints (or 255 UTF-8 bytes for old schema).
- 'maxlength' => $oldCommentSchema ? 255 : CommentStore::COMMENT_CHARACTER_LIMIT,
- 'maxlength-unit' => 'codepoints',
- 'label-message' => 'ipbreason',
- 'options-message' => 'ipbreason-dropdown',
- ];
-
$a['CreateAccount'] = [
'type' => 'check',
'label-message' => 'ipbcreateaccount',
'default' => true,
+ 'section' => 'actions',
];
if ( self::canBlockEmail( $user ) ) {
$a['DisableEmail'] = [
'type' => 'check',
'label-message' => 'ipbemailban',
+ 'section' => 'actions',
];
}
'type' => 'check',
'label-message' => 'ipb-disableusertalk',
'default' => false,
+ 'section' => 'actions',
];
}
+ $a['Expiry'] = [
+ 'type' => 'expiry',
+ 'required' => true,
+ 'options' => $suggestedDurations,
+ 'default' => $this->msg( 'ipb-default-expiry' )->inContentLanguage()->text(),
+ 'section' => 'expiry',
+ ];
+
+ $a['Reason'] = [
+ 'type' => 'selectandother',
+ // HTML maxlength uses "UTF-16 code units", which means that characters outside BMP
+ // (e.g. emojis) count for two each. This limit is overridden in JS to instead count
+ // Unicode codepoints (or 255 UTF-8 bytes for old schema).
+ 'maxlength' => $oldCommentSchema ? 255 : CommentStore::COMMENT_CHARACTER_LIMIT,
+ 'maxlength-unit' => 'codepoints',
+ 'options-message' => 'ipbreason-dropdown',
+ 'section' => 'reason',
+ ];
+
$a['AutoBlock'] = [
'type' => 'check',
'label-message' => 'ipbenableautoblock',
'default' => true,
+ 'section' => 'options',
];
# Allow some users to hide name from block log, blocklist and listusers
'type' => 'check',
'label-message' => 'ipbhidename',
'cssclass' => 'mw-block-hideuser',
+ 'section' => 'options',
];
}
$a['Watch'] = [
'type' => 'check',
'label-message' => 'ipbwatchuser',
+ 'section' => 'options',
];
}
'type' => 'check',
'label-message' => 'ipb-hardblock',
'default' => false,
+ 'section' => 'options',
];
# This is basically a copy of the Target field, but the user can't change it, so we
if ( $block instanceof Block ) {
$pageRestrictions = [];
+ $namespaceRestrictions = [];
foreach ( $block->getRestrictions() as $restriction ) {
- if ( $restriction->getType() !== 'page' ) {
- continue;
+ switch ( $restriction->getType() ) {
+ case PageRestriction::TYPE:
+ $pageRestrictions[] = $restriction->getTitle()->getPrefixedText();
+ break;
+ case NamespaceRestriction::TYPE:
+ $namespaceRestrictions[] = $restriction->getValue();
+ break;
}
+ }
- $pageRestrictions[] = $restriction->getTitle()->getPrefixedText();
+ if (
+ !$block->isSitewide() &&
+ empty( $pageRestrictions ) &&
+ empty( $namespaceRestrictions )
+ ) {
+ $fields['Editing']['default'] = false;
}
// Sort the restrictions so they are in alphabetical order.
sort( $pageRestrictions );
$fields['PageRestrictions']['default'] = implode( "\n", $pageRestrictions );
+ sort( $namespaceRestrictions );
+ $fields['NamespaceRestrictions']['default'] = implode( "\n", $namespaceRestrictions );
}
}
}
* @return string
*/
protected function preText() {
- $this->getOutput()->addModuleStyles( 'mediawiki.widgets.TitlesMultiselectWidget.styles' );
+ $this->getOutput()->addModuleStyles( [
+ 'mediawiki.widgets.TagMultiselectWidget.styles',
+ 'mediawiki.special',
+ ] );
$this->getOutput()->addModules( [ 'mediawiki.special.block' ] );
$blockCIDRLimit = $this->getConfig()->get( 'BlockCIDRLimit' );
return $reason;
}
- $restrictions = [];
+ $pageRestrictions = [];
+ $namespaceRestrictions = [];
if ( $enablePartialBlocks ) {
- if ( !empty( $data['PageRestrictions'] ) ) {
- $restrictions = array_map( function ( $text ) {
+ if ( $data['PageRestrictions'] !== '' ) {
+ $pageRestrictions = array_map( function ( $text ) {
$title = Title::newFromText( $text );
// Use the link cache since the title has already been loaded when
// the field was validated.
return $restriction;
}, explode( "\n", $data['PageRestrictions'] ) );
}
+ if ( $data['NamespaceRestrictions'] !== '' ) {
+ $namespaceRestrictions = array_map( function ( $id ) {
+ return new NamespaceRestriction( 0, $id );
+ }, explode( "\n", $data['NamespaceRestrictions'] ) );
+ }
+ $restrictions = ( array_merge( $pageRestrictions, $namespaceRestrictions ) );
$block->setRestrictions( $restrictions );
}
}
$status = $currentBlock->update();
+ // TODO handle failure
$logaction = 'reblock';
if ( (bool)$currentBlock->mHideName ) {
$data['HideUser'] = true;
}
+
+ $block = $currentBlock;
}
} else {
$logaction = 'block';
$logParams['6::flags'] = self::blockLogFlags( $data, $type );
$logParams['sitewide'] = $block->isSitewide();
- if ( $enablePartialBlocks && !empty( $data['PageRestrictions'] ) ) {
- $logParams['7::restrictions'] = [
- 'pages' => explode( "\n", $data['PageRestrictions'] ),
- ];
+ if ( $enablePartialBlocks && !$block->isSitewide() ) {
+ if ( $data['PageRestrictions'] !== '' ) {
+ $logParams['7::restrictions']['pages'] = explode( "\n", $data['PageRestrictions'] );
+ }
+
+ if ( $data['NamespaceRestrictions'] !== '' ) {
+ $logParams['7::restrictions']['namespaces'] = explode( "\n", $data['NamespaceRestrictions'] );
+ }
}
# Make log entry, if the name is hidden, put it in the suppression log
$logEntry->setComment( $data['Reason'][0] );
$logEntry->setPerformer( $performer );
$logEntry->setParameters( $logParams );
- # Relate log ID to block IDs (T27763)
- $blockIds = array_merge( [ $status['id'] ], $status['autoIds'] );
- $logEntry->setRelations( [ 'ipb_id' => $blockIds ] );
+ # Relate log ID to block ID (T27763)
+ $logEntry->setRelations( [ 'ipb_id' => $block->getId() ] );
$logId = $logEntry->insert();
if ( !empty( $data['Tags'] ) ) {
* Exception: Users can block the user who blocked them, to reduce
* advantage of a malicious account blocking all admins (T150826)
*
- * @param User|int|string $user Target to block or unblock
+ * @param User|int|string|null $target Target to block or unblock; could be a User object,
+ * or a user ID or username, or null when the target is not known yet (e.g. when
+ * displaying Special:Block)
* @param User $performer User doing the request
* @return bool|string True or error message key
*/
- public static function checkUnblockSelf( $user, User $performer ) {
- if ( is_int( $user ) ) {
- $user = User::newFromId( $user );
- } elseif ( is_string( $user ) ) {
- $user = User::newFromName( $user );
+ public static function checkUnblockSelf( $target, User $performer ) {
+ if ( is_int( $target ) ) {
+ $target = User::newFromId( $target );
+ } elseif ( is_string( $target ) ) {
+ $target = User::newFromName( $target );
}
if ( $performer->isBlocked() ) {
- if ( $user instanceof User && $user->getId() == $performer->getId() ) {
+ if ( $target instanceof User && $target->getId() == $performer->getId() ) {
# User is trying to unblock themselves
if ( $performer->isAllowed( 'unblockself' ) ) {
return true;
return 'ipbnounblockself';
}
} elseif (
- $user instanceof User &&
+ $target instanceof User &&
$performer->getBlock() instanceof Block &&
$performer->getBlock()->getBy() &&
- $performer->getBlock()->getBy() === $user->getId()
+ $performer->getBlock()->getBy() === $target->getId()
) {
// Allow users to block the user that blocked them.
// This is to prevent a situation where a malicious user
* @return bool|array True for success, false for didn't-try, array of errors on failure
*/
public function onSubmit( array $data, HTMLForm $form = null ) {
+ // If "Editing" checkbox is unchecked, the block must be a partial block affecting
+ // actions other than editing, and there must be no restrictions.
+ if ( isset( $data['Editing'] ) && $data['Editing'] === false ) {
+ $data['EditingRestriction'] = 'partial';
+ $data['PageRestrictions'] = '';
+ $data['NamespaceRestrictions'] = '';
+ }
return self::processForm( $data, $form->getContext() );
}