Split off permission to delete tags from managechangetags permission
authorMGChecker <hgasuser@gmail.com>
Sat, 30 Apr 2016 17:01:04 +0000 (19:01 +0200)
committerMGChecker <hgasuser@gmail.com>
Thu, 12 May 2016 21:11:04 +0000 (21:11 +0000)
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
includes/api/ApiManageTags.php
includes/changetags/ChangeTags.php
includes/specials/SpecialTags.php
includes/user/User.php
languages/i18n/en.json
languages/i18n/qqq.json

index 1474ad4..3436597 100644 (file)
@@ -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;
index 60fb4dc..617db22 100644 (file)
@@ -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();
index 2d4d20f..a2945af 100644 (file)
@@ -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' );
                        }
index e79fd6e..521f0ce 100644 (file)
@@ -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();
index 7d1b940..fb4168f 100644 (file)
@@ -127,6 +127,7 @@ class User implements IDBAccessObject {
                'createpage',
                'createtalk',
                'delete',
+               'deletechangetags',
                'deletedhistory',
                'deletedtext',
                'deletelogentry',
index a42020a..ca60b20 100644 (file)
        "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",
        "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",
        "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:",
index 3c0cc89..2b893bf 100644 (file)
        "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}}",
        "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}}",
        "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}}",