From: eikes Date: Thu, 12 Jun 2014 22:18:51 +0000 (+0200) Subject: Split "suppressrevision" into two user rights X-Git-Tag: 1.31.0-rc.0~14878 X-Git-Url: http://git.cyclocoop.org/url?a=commitdiff_plain;h=2f002458d5e905e6a84015344b0530d792d7fe0b;p=lhc%2Fweb%2Fwiklou.git Split "suppressrevision" into two user rights In this change, a new passive user right named "viewsuppressed" which can be used in order to view suppressed page content was added to MediaWiki core. Furthermore, this right was also added to the list of available rights, to qqq.json and to en.json where also the description of the "suppressrevision" right was adjusted in order to reflect reality. Bug: 20476 Change-Id: Id1baacb9c782763db5e05ef8b5c1b761997efcc9 --- diff --git a/RELEASE-NOTES-1.24 b/RELEASE-NOTES-1.24 index fcef78d337..9c4be8bb07 100644 --- a/RELEASE-NOTES-1.24 +++ b/RELEASE-NOTES-1.24 @@ -116,6 +116,8 @@ production. * Upgrade Sinon.JS to 1.10.3. * Added the es5-shim polyfill for older or non-compliant javascript engines. * Upgrade jQuery Cookie to v1.2.0. +* (bug 20476) Add a "viewsuppressed" user right to be able to view + suppressed content but not suppress it ("suppressrevision" right). === Bug fixes in 1.24 === * (bug 49116) Footer copyright notice is now always displayed in user language diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 7785c7e0e2..0e1f944efe 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -4400,6 +4400,8 @@ $wgGroupPermissions['bureaucrat']['noratelimit'] = true; #$wgGroupPermissions['suppress']['hideuser'] = true; // To hide revisions/log items from users and Sysops #$wgGroupPermissions['suppress']['suppressrevision'] = true; +// To view revisions/log items hidden from users and Sysops +#$wgGroupPermissions['suppress']['viewsuppressed'] = true; // For private suppression log access #$wgGroupPermissions['suppress']['suppressionlog'] = true; diff --git a/includes/Revision.php b/includes/Revision.php index de69827416..e0789d55d6 100644 --- a/includes/Revision.php +++ b/includes/Revision.php @@ -1658,19 +1658,19 @@ class Revision implements IDBAccessObject { */ public static function userCanBitfield( $bitfield, $field, User $user = null ) { if ( $bitfield & $field ) { // aspect is deleted - if ( $bitfield & self::DELETED_RESTRICTED ) { - $permission = 'suppressrevision'; - } elseif ( $field & self::DELETED_TEXT ) { - $permission = 'deletedtext'; - } else { - $permission = 'deletedhistory'; - } - wfDebug( "Checking for $permission due to $field match on $bitfield\n" ); if ( $user === null ) { global $wgUser; $user = $wgUser; } - return $user->isAllowed( $permission ); + if ( $bitfield & self::DELETED_RESTRICTED ) { + $permissions = array( 'suppressrevision', 'viewsuppressed' ); + } elseif ( $field & self::DELETED_TEXT ) { + $permissions = array( 'deletedtext' ); + } else { + $permissions = array( 'deletedhistory' ); + } + wfDebug( "Checking for " . implode( ', ', $permissions ) . " due to $field match on $bitfield\n" ); + return call_user_func_array( array( $user, 'isAllowedAny' ), $permissions ); } else { return true; } diff --git a/includes/User.php b/includes/User.php index fc2b351119..7a642c608c 100644 --- a/includes/User.php +++ b/includes/User.php @@ -175,6 +175,7 @@ class User implements IDBAccessObject { 'userrights-interwiki', 'viewmyprivateinfo', 'viewmywatchlist', + 'viewsuppressed', 'writeapi', ); diff --git a/includes/api/ApiQueryBase.php b/includes/api/ApiQueryBase.php index fb882017b4..ebfd8b28e2 100644 --- a/includes/api/ApiQueryBase.php +++ b/includes/api/ApiQueryBase.php @@ -610,7 +610,12 @@ abstract class ApiQueryBase extends ApiBase { * @return bool */ public function userCanSeeRevDel() { - return $this->getUser()->isAllowedAny( 'deletedhistory', 'deletedtext', 'suppressrevision' ); + return $this->getUser()->isAllowedAny( + 'deletedhistory', + 'deletedtext', + 'suppressrevision', + 'viewsuppressed' + ); } } diff --git a/includes/api/ApiQueryDeletedrevs.php b/includes/api/ApiQueryDeletedrevs.php index 6994cd4319..4f77078440 100644 --- a/includes/api/ApiQueryDeletedrevs.php +++ b/includes/api/ApiQueryDeletedrevs.php @@ -210,7 +210,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase { // check it again just in case) if ( !$user->isAllowed( 'deletedhistory' ) ) { $bitmask = Revision::DELETED_USER; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED; } else { $bitmask = 0; diff --git a/includes/api/ApiQueryFilearchive.php b/includes/api/ApiQueryFilearchive.php index 25e1f38652..a94b4fac6d 100644 --- a/includes/api/ApiQueryFilearchive.php +++ b/includes/api/ApiQueryFilearchive.php @@ -129,7 +129,7 @@ class ApiQueryFilearchive extends ApiQueryBase { // Exclude files this user can't view. if ( !$user->isAllowed( 'deletedtext' ) ) { $bitmask = File::DELETED_FILE; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $bitmask = File::DELETED_FILE | File::DELETED_RESTRICTED; } else { $bitmask = 0; diff --git a/includes/api/ApiQueryLogEvents.php b/includes/api/ApiQueryLogEvents.php index 3aad785dec..d79deec3dc 100644 --- a/includes/api/ApiQueryLogEvents.php +++ b/includes/api/ApiQueryLogEvents.php @@ -204,7 +204,7 @@ class ApiQueryLogEvents extends ApiQueryBase { if ( !$this->getUser()->isAllowed( 'deletedhistory' ) ) { $titleBits = LogPage::DELETED_ACTION; $userBits = LogPage::DELETED_USER; - } elseif ( !$this->getUser()->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$this->getUser()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $titleBits = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED; $userBits = LogPage::DELETED_USER | LogPage::DELETED_RESTRICTED; } else { diff --git a/includes/api/ApiQueryRecentChanges.php b/includes/api/ApiQueryRecentChanges.php index c35d39bc05..44d287be1a 100644 --- a/includes/api/ApiQueryRecentChanges.php +++ b/includes/api/ApiQueryRecentChanges.php @@ -329,7 +329,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase { if ( !is_null( $params['user'] ) || !is_null( $params['excludeuser'] ) ) { if ( !$user->isAllowed( 'deletedhistory' ) ) { $bitmask = Revision::DELETED_USER; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED; } else { $bitmask = 0; @@ -342,7 +342,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase { // LogPage::DELETED_ACTION hides the affected page, too. if ( !$user->isAllowed( 'deletedhistory' ) ) { $bitmask = LogPage::DELETED_ACTION; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $bitmask = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED; } else { $bitmask = 0; diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php index 3ff68059a3..582f61e33b 100644 --- a/includes/api/ApiQueryRevisions.php +++ b/includes/api/ApiQueryRevisions.php @@ -318,7 +318,7 @@ class ApiQueryRevisions extends ApiQueryBase { // Paranoia: avoid brute force searches (bug 17342) if ( !$this->getUser()->isAllowed( 'deletedhistory' ) ) { $bitmask = Revision::DELETED_USER; - } elseif ( !$this->getUser()->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$this->getUser()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED; } else { $bitmask = 0; diff --git a/includes/api/ApiQueryUserContributions.php b/includes/api/ApiQueryUserContributions.php index 5f93071fd2..29d03001c7 100644 --- a/includes/api/ApiQueryUserContributions.php +++ b/includes/api/ApiQueryUserContributions.php @@ -193,7 +193,7 @@ class ApiQueryContributions extends ApiQueryBase { // see the username. if ( !$user->isAllowed( 'deletedhistory' ) ) { $bitmask = Revision::DELETED_USER; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED; } else { $bitmask = 0; diff --git a/includes/api/ApiQueryWatchlist.php b/includes/api/ApiQueryWatchlist.php index 506fb591bd..b1b84d87b1 100644 --- a/includes/api/ApiQueryWatchlist.php +++ b/includes/api/ApiQueryWatchlist.php @@ -224,7 +224,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase { if ( !is_null( $params['user'] ) || !is_null( $params['excludeuser'] ) ) { if ( !$user->isAllowed( 'deletedhistory' ) ) { $bitmask = Revision::DELETED_USER; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED; } else { $bitmask = 0; @@ -238,7 +238,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase { // entirely from the watchlist, or someone could guess the title. if ( !$user->isAllowed( 'deletedhistory' ) ) { $bitmask = LogPage::DELETED_ACTION; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $bitmask = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED; } else { $bitmask = 0; diff --git a/includes/logging/LogEventsList.php b/includes/logging/LogEventsList.php index 4ce80704e5..71dc2584a3 100644 --- a/includes/logging/LogEventsList.php +++ b/includes/logging/LogEventsList.php @@ -437,20 +437,18 @@ class LogEventsList extends ContextSource { */ public static function userCanBitfield( $bitfield, $field, User $user = null ) { if ( $bitfield & $field ) { - if ( $bitfield & LogPage::DELETED_RESTRICTED ) { - $permission = 'suppressrevision'; - } else { - $permission = 'deletedhistory'; - } - wfDebug( "Checking for $permission due to $field match on $bitfield\n" ); if ( $user === null ) { global $wgUser; $user = $wgUser; } - - return $user->isAllowed( $permission ); + if ( $bitfield & LogPage::DELETED_RESTRICTED ) { + $permissions = array( 'suppressrevision', 'viewsuppressed' ); + } else { + $permissions = array( 'deletedhistory' ); + } + wfDebug( "Checking for " . implode( ', ', $permissions ) . " due to $field match on $bitfield\n" ); + return call_user_func_array( array( $user, 'isAllowedAny' ), $permissions ); } - return true; } diff --git a/includes/logging/LogPager.php b/includes/logging/LogPager.php index 399c7993ff..082dd5a54a 100644 --- a/includes/logging/LogPager.php +++ b/includes/logging/LogPager.php @@ -175,7 +175,7 @@ class LogPager extends ReverseChronologicalPager { $user = $this->getUser(); if ( !$user->isAllowed( 'deletedhistory' ) ) { $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::DELETED_USER ) . ' = 0'; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $this->mConds[] = $this->mDb->bitAnd( 'log_deleted', LogPage::SUPPRESSED_USER ) . ' != ' . LogPage::SUPPRESSED_USER; } diff --git a/includes/specials/SpecialContributions.php b/includes/specials/SpecialContributions.php index 05bbb5ab2b..fefd3b593a 100644 --- a/includes/specials/SpecialContributions.php +++ b/includes/specials/SpecialContributions.php @@ -790,7 +790,7 @@ class ContribsPager extends ReverseChronologicalPager { // Paranoia: avoid brute force searches (bug 17342) if ( !$user->isAllowed( 'deletedhistory' ) ) { $conds[] = $this->mDb->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0'; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $conds[] = $this->mDb->bitAnd( 'rev_deleted', Revision::SUPPRESSED_USER ) . ' != ' . Revision::SUPPRESSED_USER; } diff --git a/includes/specials/SpecialDeletedContributions.php b/includes/specials/SpecialDeletedContributions.php index 4df5b2b55f..b69eb6347a 100644 --- a/includes/specials/SpecialDeletedContributions.php +++ b/includes/specials/SpecialDeletedContributions.php @@ -62,7 +62,7 @@ class DeletedContribsPager extends IndexPager { // Paranoia: avoid brute force searches (bug 17792) if ( !$user->isAllowed( 'deletedhistory' ) ) { $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::DELETED_USER ) . ' = 0'; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::SUPPRESSED_USER ) . ' != ' . Revision::SUPPRESSED_USER; } diff --git a/includes/specials/SpecialRevisiondelete.php b/includes/specials/SpecialRevisiondelete.php index b90026afa5..9cec8473e6 100644 --- a/includes/specials/SpecialRevisiondelete.php +++ b/includes/specials/SpecialRevisiondelete.php @@ -161,7 +161,14 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { throw new ErrorPageError( 'revdelete-nooldid-title', 'revdelete-nooldid-text' ); } $this->typeLabels = self::$UILabels[$this->typeName]; + $list = $this->getList(); + $list->reset(); + $bitfield = $list->current()->getBits(); $this->mIsAllowed = $user->isAllowed( RevisionDeleter::getRestriction( $this->typeName ) ); + $canViewSuppressedOnly = $this->getUser()->isAllowed( 'viewsuppressed' ) && + !$this->getUser()->isAllowed( 'suppressrevision' ); + $pageIsSuppressed = $bitfield & Revision::DELETED_RESTRICTED; + $this->mIsAllowed = $this->mIsAllowed && !( $canViewSuppressedOnly && $pageIsSuppressed ); # Allow the list type to adjust the passed target $this->targetObj = RevisionDeleter::suggestTarget( @@ -444,12 +451,8 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { Html::hidden( 'target', $this->targetObj->getPrefixedText() ) . Html::hidden( 'type', $this->typeName ) . Html::hidden( 'ids', implode( ',', $this->ids ) ) . - Xml::closeElement( 'fieldset' ) . "\n"; - } else { - $out = ''; - } - if ( $this->mIsAllowed ) { - $out .= Xml::closeElement( 'form' ) . "\n"; + Xml::closeElement( 'fieldset' ) . "\n" . + Xml::closeElement( 'form' ) . "\n"; // Show link to edit the dropdown reasons if ( $this->getUser()->isAllowed( 'editinterface' ) ) { $title = Title::makeTitle( NS_MEDIAWIKI, 'Revdelete-reason-dropdown' ); @@ -461,6 +464,8 @@ class SpecialRevisionDelete extends UnlistedSpecialPage { ); $out .= Xml::tags( 'p', array( 'class' => 'mw-revdel-editreasons' ), $link ) . "\n"; } + } else { + $out = ''; } $this->getOutput()->addHTML( $out ); } diff --git a/includes/specials/SpecialWatchlist.php b/includes/specials/SpecialWatchlist.php index 57659e7289..94de5ce376 100644 --- a/includes/specials/SpecialWatchlist.php +++ b/includes/specials/SpecialWatchlist.php @@ -258,7 +258,7 @@ class SpecialWatchlist extends ChangesListSpecialPage { // the necessary rights. if ( !$user->isAllowed( 'deletedhistory' ) ) { $bitmask = LogPage::DELETED_ACTION; - } elseif ( !$user->isAllowed( 'suppressrevision' ) ) { + } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) { $bitmask = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED; } else { $bitmask = 0; diff --git a/languages/i18n/en.json b/languages/i18n/en.json index bc2dbdbd63..e42d716df6 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -1087,7 +1087,8 @@ "right-deletedtext": "View deleted text and changes between deleted revisions", "right-browsearchive": "Search deleted pages", "right-undelete": "Undelete a page", - "right-suppressrevision": "Review and restore revisions hidden from administrators", + "right-suppressrevision": "View, hide and unhide specific revisions of pages from any user", + "right-viewsuppressed": "View revisions hidden from any user", "right-suppressionlog": "View private logs", "right-block": "Block other users from editing", "right-blockemail": "Block a user from sending email", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index 62837d202c..ad5b28880b 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -1249,7 +1249,8 @@ "right-deletedtext": "{{doc-right|deletedtext}}", "right-browsearchive": "{{doc-right|browsearchive}}", "right-undelete": "{{doc-right|undelete}}", - "right-suppressrevision": "{{doc-right|suppressrevision}}\nThis user right is part of the [[mw:RevisionDelete|RevisionDelete]] feature.\nIt can be given to the group {{msg-mw|group-suppress}}, although that group is disabled by default.\n\nSee also:\n* {{msg-mw|right-suppressionlog}}\n* {{msg-mw|right-hideuser}}\n* {{msg-mw|right-deletelogentry}}\n* {{msg-mw|right-deleterevision}}", + "right-suppressrevision": "{{doc-right|suppressrevision}}\nThis user right is part of the [[mw:RevisionDelete|RevisionDelete]] feature.\nIt can be given to the group {{msg-mw|group-suppress}}, although that group is disabled by default.\n\nSee also:\n* {{msg-mw|right-suppressionlog}}\n* {{msg-mw|right-viewsuppressed}}\n* {{msg-mw|right-hideuser}}\n* {{msg-mw|right-deletelogentry}}\n* {{msg-mw|right-deleterevision}}", + "right-viewsuppressed": "{{doc-right|viewsuppressed}}\nThis user right is part of the [[mw:RevisionDelete|RevisionDelete]] feature.\nIt can be given to any group for observation of suppression activities.\n\nSee also:\n* {{msg-mw|right-suppressrevision}}", "right-suppressionlog": "{{doc-right|suppressionlog}}\nThis user right is part of the [[mw:RevisionDelete|RevisionDelete]] feature.\nIt can be given to the group {{msg-mw|group-suppress}}, although that group is disabled by default.\n\nSee also\n* {{msg-mw|right-suppressrevision}}\n* {{msg-mw|right-hideuser}}\n* {{msg-mw|right-deletelogentry}}\n* {{msg-mw|right-deleterevision}}", "right-block": "{{doc-right|block}}", "right-blockemail": "{{doc-right|blockemail}}",