From: Brad Jorsch Date: Fri, 28 Jun 2013 20:49:47 +0000 (-0400) Subject: Improve UI for page protection with $wgNamespaceProtection X-Git-Tag: 1.31.0-rc.0~17803 X-Git-Url: https://git.cyclocoop.org/%28%28?a=commitdiff_plain;h=8862991ce1b125f22a094399868d192c15a2115a;p=lhc%2Fweb%2Fwiklou.git Improve UI for page protection with $wgNamespaceProtection Right now, if you set $wgNamespaceProtection, the protection interface is confusing: it will allow you to apply "useless" protection levels for any namespace except MediaWiki, where it will refuse to let you set any protection at all. The fix is to find which restriction levels are more restrictive than the $wgNamespaceProtection restriction (i.e. where there is at least one group that can pass $wgNamespaceProtection but not the level from $wgRestrictionLevels), and use only those in the protection form. If there are no such levels, we can skip showing the "protect" tab entirely. Change-Id: I9e2b29ade566abcd008ea2ad1e2f9818e315bb32 --- diff --git a/RELEASE-NOTES-1.23 b/RELEASE-NOTES-1.23 index cf1678efcc..4697b4d78b 100644 --- a/RELEASE-NOTES-1.23 +++ b/RELEASE-NOTES-1.23 @@ -39,6 +39,11 @@ production. hide their (unrelated) log entries. * Added $wgOpenSearchDefaultLimit defining the default number of entries to show on action=opensearch API call. +* For namespaces with $wgNamespaceProtection (including the MediaWiki + namespace), the "protect" tab will be shown only if there are restriction + levels available that would restrict editing beyond what + $wgNamespaceProtection already applies. The protection form will offer only + those protection levels. === Bug fixes in 1.23 === * (bug 41759) The "updated since last visit" markers (on history pages, recent diff --git a/includes/EditPage.php b/includes/EditPage.php index c0e7ed2870..f86cae46f4 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -2476,7 +2476,9 @@ class EditPage { } } - if ( $this->mTitle->getNamespace() != NS_MEDIAWIKI && $this->mTitle->isProtected( 'edit' ) ) { + if ( $this->mTitle->isProtected( 'edit' ) && + MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace() ) !== array( '' ) + ) { # Is the title semi-protected? if ( $this->mTitle->isSemiProtected() ) { $noticeMsg = 'semiprotectedpagewarning'; @@ -2678,7 +2680,9 @@ HTML $attribs = array( 'style' => 'display:none;' ); } else { $classes = array(); // Textarea CSS - if ( $this->mTitle->getNamespace() != NS_MEDIAWIKI && $this->mTitle->isProtected( 'edit' ) ) { + if ( $this->mTitle->isProtected( 'edit' ) && + MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace() ) !== array( '' ) + ) { # Is the title semi-protected? if ( $this->mTitle->isSemiProtected() ) { $classes[] = 'mw-textarea-sprotected'; diff --git a/includes/Namespace.php b/includes/Namespace.php index 5c8e63b74d..ce585cec2f 100644 --- a/includes/Namespace.php +++ b/includes/Namespace.php @@ -433,4 +433,74 @@ class MWNamespace { ? $wgNamespaceContentModels[$index] : null; } + + /** + * Determine which restriction levels it makes sense to use in a namespace, + * optionally filtered by a user's rights. + * + * @since 1.23 + * @param int $index Index to check + * @param User $user User to check + * @return array + */ + public static function getRestrictionLevels( $index, User $user = null ) { + global $wgNamespaceProtection, $wgRestrictionLevels; + + if ( !isset( $wgNamespaceProtection[$index] ) ) { + // All levels are valid if there's no namespace restriction. + // But still filter by user, if necessary + $levels = $wgRestrictionLevels; + if ( $user ) { + $levels = array_values( array_filter( $levels, function ( $level ) use ( $user ) { + $right = $level; + if ( $right == 'sysop' ) { + $right = 'editprotected'; // BC + } + if ( $right == 'autoconfirmed' ) { + $right = 'editsemiprotected'; // BC + } + return ( $right == '' || $user->isAllowed( $right ) ); + } ) ); + } + return $levels; + } + + // First, get the list of groups that can edit this namespace. + $namespaceGroups = array(); + $combine = 'array_merge'; + foreach ( (array)$wgNamespaceProtection[$index] as $right ) { + if ( $right == 'sysop' ) { + $right = 'editprotected'; // BC + } + if ( $right == 'autoconfirmed' ) { + $right = 'editsemiprotected'; // BC + } + if ( $right != '' ) { + $namespaceGroups = call_user_func( $combine, $namespaceGroups, + User::getGroupsWithPermission( $right ) ); + $combine = 'array_intersect'; + } + } + + // Now, keep only those restriction levels where there is at least one + // group that can edit the namespace but would be blocked by the + // restriction. + $usableLevels = array( '' ); + foreach ( $wgRestrictionLevels as $level ) { + $right = $level; + if ( $right == 'sysop' ) { + $right = 'editprotected'; // BC + } + if ( $right == 'autoconfirmed' ) { + $right = 'editsemiprotected'; // BC + } + if ( $right != '' && ( !$user || $user->isAllowed( $right ) ) && + array_diff( $namespaceGroups, User::getGroupsWithPermission( $right ) ) + ) { + $usableLevels[] = $level; + } + } + + return $usableLevels; + } } diff --git a/includes/ProtectionForm.php b/includes/ProtectionForm.php index f10317a9e5..d6cc8a3835 100644 --- a/includes/ProtectionForm.php +++ b/includes/ProtectionForm.php @@ -83,8 +83,8 @@ class ProtectionForm { */ function loadData() { global $wgRequest, $wgUser; - global $wgRestrictionLevels; + $levels = MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace(), $wgUser ); $this->mCascade = $this->mTitle->areRestrictionsCascading(); $this->mReason = $wgRequest->getText( 'mwProtect-reason' ); @@ -132,21 +132,7 @@ class ProtectionForm { } $val = $wgRequest->getVal( "mwProtect-level-$action" ); - if ( isset( $val ) && in_array( $val, $wgRestrictionLevels ) ) { - // Prevent users from setting levels that they cannot later unset - if ( $val == 'sysop' ) { - // Special case, rewrite sysop to editprotected - if ( !$wgUser->isAllowed( 'editprotected' ) ) { - continue; - } - } elseif ( $val == 'autoconfirmed' ) { - // Special case, rewrite autoconfirmed to editsemiprotected - if ( !$wgUser->isAllowed( 'editsemiprotected' ) ) { - continue; - } - } elseif ( !$wgUser->isAllowed( $val ) ) { - continue; - } + if ( isset( $val ) && in_array( $val, $levels ) ) { $this->mRestrictions[$action] = $val; } } @@ -189,7 +175,7 @@ class ProtectionForm { function execute() { global $wgRequest, $wgOut; - if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { + if ( MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace() ) === array( '' ) ) { throw new ErrorPageError( 'protect-badnamespace-title', 'protect-badnamespace-text' ); } @@ -556,28 +542,13 @@ class ProtectionForm { * @return String: HTML fragment */ function buildSelector( $action, $selected ) { - global $wgRestrictionLevels, $wgUser; - - $levels = array(); - foreach ( $wgRestrictionLevels as $key ) { - //don't let them choose levels above their own (aka so they can still unprotect and edit the page). but only when the form isn't disabled - if ( $key == 'sysop' ) { - //special case, rewrite sysop to editprotected - if ( !$wgUser->isAllowed( 'editprotected' ) && !$this->disabled ) { - continue; - } - } elseif ( $key == 'autoconfirmed' ) { - //special case, rewrite autoconfirmed to editsemiprotected - if ( !$wgUser->isAllowed( 'editsemiprotected' ) && !$this->disabled ) { - continue; - } - } else { - if ( !$wgUser->isAllowed( $key ) && !$this->disabled ) { - continue; - } - } - $levels[] = $key; - } + global $wgUser; + + // If the form is disabled, display all relevant levels. Otherwise, + // just show the ones this user can use. + $levels = MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace(), + $this->disabled ? null : $wgUser + ); $id = 'mwProtect-level-' . $action; $attribs = array( diff --git a/includes/SkinTemplate.php b/includes/SkinTemplate.php index dde3f3725d..da4c376aa7 100644 --- a/includes/SkinTemplate.php +++ b/includes/SkinTemplate.php @@ -1039,7 +1039,9 @@ class SkinTemplate extends Skin { } } - if ( $title->getNamespace() !== NS_MEDIAWIKI && $title->quickUserCan( 'protect', $user ) && $title->getRestrictionTypes() ) { + if ( $title->quickUserCan( 'protect', $user ) && $title->getRestrictionTypes() && + MWNamespace::getRestrictionLevels( $title->getNamespace(), $user ) !== array( '' ) + ) { $mode = $title->isProtected() ? 'unprotect' : 'protect'; $content_navigation['actions'][$mode] = array( 'class' => ( $onPage && $action == $mode ) ? 'selected' : false,