From 6b9619a3a73dd8b15e1891d1294056f258e7536d Mon Sep 17 00:00:00 2001 From: MGChecker Date: Sat, 30 Apr 2016 19:01:04 +0200 Subject: [PATCH] Split off permission to delete tags from managechangetags permission Every permission included in managechangetags is really harmless and can be reverted in short time, except of the permission to irriversibly delete tags. That's why this should be excluded in an additional permission that other wikis can restrict deletechangetags more than other tag management actions. Bug: T133811 Change-Id: Ieb9199f2c6997316ae3468ff5a92b2d2456c012f --- includes/DefaultSettings.php | 1 + includes/api/ApiManageTags.php | 10 ++++++++-- includes/changetags/ChangeTags.php | 4 ++-- includes/specials/SpecialTags.php | 31 ++++++++++++++++-------------- includes/user/User.php | 1 + languages/i18n/en.json | 7 +++++-- languages/i18n/qqq.json | 3 +++ 7 files changed, 37 insertions(+), 20 deletions(-) diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 1474ad4621..343659737e 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -4904,6 +4904,7 @@ $wgGroupPermissions['sysop']['suppressredirect'] = true; # $wgGroupPermissions['sysop']['upload_by_url'] = true; $wgGroupPermissions['sysop']['mergehistory'] = true; $wgGroupPermissions['sysop']['managechangetags'] = true; +$wgGroupPermissions['sysop']['deletechangetags'] = true; // Permission to change users' group assignments $wgGroupPermissions['bureaucrat']['userrights'] = true; diff --git a/includes/api/ApiManageTags.php b/includes/api/ApiManageTags.php index 60fb4dc1c3..617db227df 100644 --- a/includes/api/ApiManageTags.php +++ b/includes/api/ApiManageTags.php @@ -29,8 +29,14 @@ class ApiManageTags extends ApiBase { $params = $this->extractRequestParams(); // make sure the user is allowed - if ( !$this->getUser()->isAllowed( 'managechangetags' ) ) { - $this->dieUsage( "You don't have permission to manage change tags", 'permissiondenied' ); + if ( $params['operation'] !== 'delete' + && !$this->getUser()->isAllowed( 'managechangetags' ) + ) { + $this->dieUsage( "You don't have permission to manage change tags", + 'permissiondenied' ); + } elseif ( !$this->getUser()->isAllowed( 'deletechangetags' ) ) { + $this->dieUsage( "You don't have permission to delete change tags", + 'permissiondenied' ); } $result = $this->getResult(); diff --git a/includes/changetags/ChangeTags.php b/includes/changetags/ChangeTags.php index 2d4d20f931..a2945afb61 100644 --- a/includes/changetags/ChangeTags.php +++ b/includes/changetags/ChangeTags.php @@ -1055,8 +1055,8 @@ class ChangeTags { $tagUsage = self::tagUsageStatistics(); if ( !is_null( $user ) ) { - if ( !$user->isAllowed( 'managechangetags' ) ) { - return Status::newFatal( 'tags-manage-no-permission' ); + if ( !$user->isAllowed( 'deletechangetags' ) ) { + return Status::newFatal( 'tags-delete-no-permission' ); } elseif ( $user->isBlocked() ) { return Status::newFatal( 'tags-manage-blocked' ); } diff --git a/includes/specials/SpecialTags.php b/includes/specials/SpecialTags.php index e79fd6ee0f..521f0cee16 100644 --- a/includes/specials/SpecialTags.php +++ b/includes/specials/SpecialTags.php @@ -77,6 +77,7 @@ class SpecialTags extends SpecialPage { $user = $this->getUser(); $userCanManage = $user->isAllowed( 'managechangetags' ); + $userCanDelete = $user->isAllowed( 'deletechangetags' ); $userCanEditInterface = $user->isAllowed( 'editinterface' ); // Show form to create a tag @@ -154,12 +155,13 @@ class SpecialTags extends SpecialPage { // Insert tags that have been applied at least once foreach ( $tagStats as $tag => $hitcount ) { - $html .= $this->doTagRow( $tag, $hitcount, $userCanManage, $userCanEditInterface ); + $html .= $this->doTagRow( $tag, $hitcount, $userCanManage, + $userCanDelete, $userCanEditInterface ); } // Insert tags defined somewhere but never applied foreach ( $definedTags as $tag ) { if ( !isset( $tagStats[$tag] ) ) { - $html .= $this->doTagRow( $tag, 0, $userCanManage, $userCanEditInterface ); + $html .= $this->doTagRow( $tag, 0, $userCanManage, $userCanDelete, $userCanEditInterface ); } } @@ -170,7 +172,7 @@ class SpecialTags extends SpecialPage { ) ); } - function doTagRow( $tag, $hitcount, $showActions, $showEditLinks ) { + function doTagRow( $tag, $hitcount, $showManageActions, $showDeleteActions, $showEditLinks ) { $newRow = ''; $newRow .= Xml::tags( 'td', null, Xml::element( 'code', null, $tag ) ); @@ -229,16 +231,17 @@ class SpecialTags extends SpecialPage { $newRow .= Xml::tags( 'td', [ 'data-sort-value' => $hitcount ], $hitcountLabel ); // actions - if ( $showActions ) { // we've already checked that the user had the requisite userright - $actionLinks = []; + $actionLinks = []; - // delete - if ( ChangeTags::canDeleteTag( $tag )->isOK() ) { - $actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'delete' ), - $this->msg( 'tags-delete' )->escaped(), - [], - [ 'tag' => $tag ] ); - } + // delete + if ( $showDeleteActions && ChangeTags::canDeleteTag( $tag )->isOK() ) { + $actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'delete' ), + $this->msg( 'tags-delete' )->escaped(), + [], + [ 'tag' => $tag ] ); + } + + if ( $showManageActions ) { // we've already checked that the user had the requisite userright // activate if ( ChangeTags::canActivateTag( $tag )->isOK() ) { @@ -319,8 +322,8 @@ class SpecialTags extends SpecialPage { protected function showDeleteTagForm( $tag ) { $user = $this->getUser(); - if ( !$user->isAllowed( 'managechangetags' ) ) { - throw new PermissionsError( 'managechangetags' ); + if ( !$user->isAllowed( 'deletechangetags' ) ) { + throw new PermissionsError( 'deletechangetags' ); } $out = $this->getOutput(); diff --git a/includes/user/User.php b/includes/user/User.php index 7d1b940e79..fb4168f089 100644 --- a/includes/user/User.php +++ b/includes/user/User.php @@ -127,6 +127,7 @@ class User implements IDBAccessObject { 'createpage', 'createtalk', 'delete', + 'deletechangetags', 'deletedhistory', 'deletedtext', 'deletelogentry', diff --git a/languages/i18n/en.json b/languages/i18n/en.json index a42020a141..ca60b205ab 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -1226,9 +1226,10 @@ "right-override-export-depth": "Export pages including linked pages up to a depth of 5", "right-sendemail": "Send email to other users", "right-passwordreset": "View password reset emails", - "right-managechangetags": "Create and delete [[Special:Tags|tags]] from the database", + "right-managechangetags": "Create and (de)activate [[Special:Tags|tags]]", "right-applychangetags": "Apply [[Special:Tags|tags]] along with one's changes", "right-changetags": "Add and remove arbitrary [[Special:Tags|tags]] on individual revisions and log entries", + "right-deletechangetags": "Delete [[Special:Tags|tags]] from the database", "grant-generic": "\"$1\" rights bundle", "grant-group-page-interaction": "Interact with pages", "grant-group-file-interaction": "Interact with media", @@ -1306,9 +1307,10 @@ "action-viewmyprivateinfo": "view your private information", "action-editmyprivateinfo": "edit your private information", "action-editcontentmodel": "edit the content model of a page", - "action-managechangetags": "create and delete tags from the database", + "action-managechangetags": "create and (de)activate tags", "action-applychangetags": "apply tags along with your changes", "action-changetags": "add and remove arbitrary tags on individual revisions and log entries", + "action-deletechangetags": "delete tags from the database", "nchanges": "$1 {{PLURAL:$1|change|changes}}", "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|since last visit}}", "enhancedrc-history": "history", @@ -3663,6 +3665,7 @@ "tags-delete-not-found": "The tag \"$1\" does not exist.", "tags-delete-too-many-uses": "The tag \"$1\" is applied to more than $2 {{PLURAL:$2|revision|revisions}}, which means it cannot be deleted.", "tags-delete-warnings-after-delete": "The tag \"$1\" was deleted, but the following {{PLURAL:$2|warning was|warnings were}} encountered:", + "tags-delete-no-permission": "You do not have permission to delete change tags.", "tags-activate-title": "Activate tag", "tags-activate-question": "You are about to activate the tag \"$1\".", "tags-activate-reason": "Reason:", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index 3c0cc894d0..2b893bff3d 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -1407,6 +1407,7 @@ "right-managechangetags": "{{doc-right|managechangetags}}", "right-applychangetags": "{{doc-right|applychangetags}}", "right-changetags": "{{doc-right|changetags}}", + "right-deletechangetags": "{{doc-right|deletechangetags}}", "grant-generic": "Used if the grant name is not defined. Parameters:\n* $1 - grant name\n\nDefined grants (grant name refers: blockusers, createeditmovepage, ...):\n* {{msg-mw|grant-checkuser}}\n* {{msg-mw|grant-blockusers}}\n* {{msg-mw|grant-createaccount}}\n* {{msg-mw|grant-createeditmovepage}}\n* {{msg-mw|grant-delete}}\n* {{msg-mw|grant-editinterface}}\n* {{msg-mw|grant-editmycssjs}}\n* {{msg-mw|grant-editmyoptions}}\n* {{msg-mw|grant-editmywatchlist}}\n* {{msg-mw|grant-editpage}}\n* {{msg-mw|grant-editprotected}}\n* {{msg-mw|grant-highvolume}}\n* {{msg-mw|grant-oversight}}\n* {{msg-mw|grant-patrol}}\n* {{msg-mw|grant-protect}}\n* {{msg-mw|grant-rollback}}\n* {{msg-mw|grant-sendemail}}\n* {{msg-mw|grant-uploadeditmovefile}}\n* {{msg-mw|grant-uploadfile}}\n* {{msg-mw|grant-basic}}\n* {{msg-mw|grant-viewdeleted}}\n* {{msg-mw|grant-viewmywatchlist}}", "grant-group-page-interaction": "{{Related|grant-group}}", "grant-group-file-interaction": "{{Related|grant-group}}", @@ -1487,6 +1488,7 @@ "action-managechangetags": "{{doc-action|managechangetags}}", "action-applychangetags": "{{doc-action|applychangetags}}", "action-changetags": "{{doc-action|changetags}}", + "action-deletechangetags": "{{doc-action|deletechangetags}}", "nchanges": "Appears on enhanced watchlist and recent changes when page has more than one change on given date, linking to a diff of the changes.\n\nParameters:\n* $1 - the number of changes on that day (2 or more)\nThree messages are shown side-by-side: ({{msg-mw|Nchanges}} | {{msg-mw|Enhancedrc-since-last-visit}} | {{msg-mw|Enhancedrc-history}}).", "enhancedrc-since-last-visit": "Appears on enhanced watchlist and recent changes when page has more than one change on given date and at least one that the user hasn't seen yet, linking to a diff of the unviewed changes.\n\nParameters:\n* $1 - the number of unviewed changes (1 or more)\nThree messages are shown side-by-side: ({{msg-mw|nchanges}} | {{msg-mw|enhancedrc-since-last-visit}} | {{msg-mw|enhancedrc-history}}).", "enhancedrc-history": "Appears on enhanced watchlist and recent changes when page has more than one change on given date, linking to its history.\n\nThis is the same as {{msg-mw|hist}}, but not abbreviated.\n\nThree messages are shown side-by-side: ({{msg-mw|nchanges}} | {{msg-mw|enhancedrc-since-last-visit}} | {{msg-mw|enhancedrc-history}}).\n{{Identical|History}}", @@ -3841,6 +3843,7 @@ "tags-delete-not-found": "Error message on [[Special:Tags]]", "tags-delete-too-many-uses": "Error message on [[Special:Tags]]", "tags-delete-warnings-after-delete": "Warning shown after deleting a tag.\n\nParameters:\n* $1 - the code name of the tag that was deleted\n* $2 - the number of warnings", + "tags-delete-no-permission": "Error message on [[Special:Tags]]", "tags-activate-title": "The title of a page used to activate a tag. For more information on tags see [[mw:Manual:Tags|MediaWiki]].", "tags-activate-question": "An explanation to tell users what they are about to do.\n\nParameters:\n* $1 - the code name of the tag that is about to be activated", "tags-activate-reason": "{{Identical|Reason}}", -- 2.20.1