From d87a4eaa19aad80e109307eb0088fd6a25dd5f51 Mon Sep 17 00:00:00 2001 From: Jackmcbarn Date: Fri, 19 Dec 2014 00:28:35 -0500 Subject: [PATCH] Allow all users to view Special:UserRights Allow Special:UserRights to always be used in read-only mode, rather than completely locking out users who cannot make modifications with it. Bug: T27319 Change-Id: I57e9ca4f20fe557e4024c4f5a4865170f02ebb45 --- includes/skins/SkinTemplate.php | 14 ++- includes/specials/SpecialUserrights.php | 144 +++++++++--------------- languages/i18n/en.json | 8 +- languages/i18n/qqq.json | 10 +- 4 files changed, 69 insertions(+), 107 deletions(-) diff --git a/includes/skins/SkinTemplate.php b/includes/skins/SkinTemplate.php index 9c5600d0b6..e6763cab47 100644 --- a/includes/skins/SkinTemplate.php +++ b/includes/skins/SkinTemplate.php @@ -1309,12 +1309,14 @@ class SkinTemplate extends Skin { if ( !$user->isAnon() ) { $sur = new UserrightsPage; $sur->setContext( $this->getContext() ); - if ( $sur->userCanExecute( $this->getUser() ) ) { - $nav_urls['userrights'] = [ - 'text' => $this->msg( 'tool-link-userrights', $this->getUser()->getName() )->text(), - 'href' => self::makeSpecialUrlSubpage( 'Userrights', $rootUser ) - ]; - } + $canChange = $sur->userCanChangeRights( $this->getUser(), false ); + $nav_urls['userrights'] = [ + 'text' => $this->msg( + $canChange ? 'tool-link-userrights' : 'tool-link-userrights-readonly', + $this->getUser()->getName() + )->text(), + 'href' => self::makeSpecialUrlSubpage( 'Userrights', $rootUser ) + ]; } } diff --git a/includes/specials/SpecialUserrights.php b/includes/specials/SpecialUserrights.php index 433dcab593..3c28eb594e 100644 --- a/includes/specials/SpecialUserrights.php +++ b/includes/specials/SpecialUserrights.php @@ -48,14 +48,6 @@ class UserrightsPage extends SpecialPage { return true; } - public function isRestricted() { - return true; - } - - public function userCanExecute( User $user ) { - return $this->userCanChangeRights( $user, false ); - } - /** * @param User $user * @param bool $checkIfSelf @@ -82,22 +74,10 @@ class UserrightsPage extends SpecialPage { * @throws UserBlockedError|PermissionsError */ public function execute( $par ) { - // If the visitor doesn't have permissions to assign or remove - // any groups, it's a bit silly to give them the user search prompt. - $user = $this->getUser(); $request = $this->getRequest(); $out = $this->getOutput(); - /* - * If the user is blocked and they only have "partial" access - * (e.g. they don't have the userrights permission), then don't - * allow them to use Special:UserRights. - */ - if ( $user->isBlocked() && !$user->isAllowed( 'userrights' ) ) { - throw new UserBlockedError( $user->getBlock() ); - } - if ( $par !== null ) { $this->mTarget = $par; } else { @@ -108,24 +88,7 @@ class UserrightsPage extends SpecialPage { $this->mTarget = trim( $this->mTarget ); } - $available = $this->changeableGroups(); - - if ( $this->mTarget === null ) { - /* - * If the user specified no target, and they can only - * edit their own groups, automatically set them as the - * target. - */ - if ( !count( $available['add'] ) && !count( $available['remove'] ) ) { - $this->mTarget = $user->getName(); - } - } - - if ( $this->mTarget !== null && User::getCanonicalName( $this->mTarget ) === $user->getName() ) { - $this->isself = true; - } - - $fetchedStatus = $this->fetchUser( $this->mTarget ); + $fetchedStatus = $this->fetchUser( $this->mTarget, true ); if ( $fetchedStatus->isOK() ) { $this->mFetchedUser = $fetchedStatus->value; if ( $this->mFetchedUser instanceof User ) { @@ -135,23 +98,6 @@ class UserrightsPage extends SpecialPage { } } - if ( !$this->userCanChangeRights( $user, true ) ) { - if ( $this->isself && $request->getCheck( 'success' ) ) { - // bug 48609: if the user just removed its own rights, this would - // leads it in a "permissions error" page. In that case, show a - // message that it can't anymore use this page instead of an error - $this->setHeaders(); - $out->wrapWikiMsg( "
\n$1\n
", 'userrights-removed-self' ); - $out->returnToMain(); - - return; - } - - // @todo FIXME: There may be intermediate groups we can mention. - $msg = $user->isAnon() ? 'userrights-nologin' : 'userrights-notallowed'; - throw new PermissionsError( null, [ [ $msg ] ] ); - } - // show a successbox, if the user rights was saved successfully if ( $request->getCheck( 'success' ) && $this->mFetchedUser !== null ) { $out->addModules( [ 'mediawiki.special.userrights' ] ); @@ -173,18 +119,13 @@ class UserrightsPage extends SpecialPage { ); } - $this->checkReadOnly(); - $this->setHeaders(); $this->outputHeader(); $out->addModuleStyles( 'mediawiki.special' ); $this->addHelpLink( 'Help:Assigning permissions' ); - // show the general form - if ( count( $available['add'] ) || count( $available['remove'] ) ) { - $this->switchForm(); - } + $this->switchForm(); if ( $request->wasPosted() && @@ -192,6 +133,17 @@ class UserrightsPage extends SpecialPage { $this->mTarget !== null && $user->matchEditToken( $request->getVal( 'wpEditToken' ), $this->mTarget ) ) { + /* + * If the user is blocked and they only have "partial" access + * (e.g. they don't have the userrights permission), then don't + * allow them to change any user rights. + */ + if ( $user->isBlocked() && !$user->isAllowed( 'userrights' ) ) { + throw new UserBlockedError( $user->getBlock() ); + } + + $this->checkReadOnly(); + // save settings if ( !$fetchedStatus->isOK() ) { $this->getOutput()->addWikiText( $fetchedStatus->getWikiText() ); @@ -352,7 +304,7 @@ class UserrightsPage extends SpecialPage { * @param string $username Name of the user. */ function editUserGroupsForm( $username ) { - $status = $this->fetchUser( $username ); + $status = $this->fetchUser( $username, true ); if ( !$status->isOK() ) { $this->getOutput()->addWikiText( $status->getWikiText() ); @@ -376,9 +328,10 @@ class UserrightsPage extends SpecialPage { * * Side effects: error output for invalid access * @param string $username + * @param bool $writing * @return Status */ - public function fetchUser( $username ) { + public function fetchUser( $username, $writing ) { $parts = explode( $this->getConfig()->get( 'UserrightsInterwikiDelimiter' ), $username ); if ( count( $parts ) < 2 ) { $name = trim( $username ); @@ -389,7 +342,7 @@ class UserrightsPage extends SpecialPage { if ( $database == wfWikiID() ) { $database = ''; } else { - if ( !$this->getUser()->isAllowed( 'userrights-interwiki' ) ) { + if ( $writing && !$this->getUser()->isAllowed( 'userrights-interwiki' ) ) { return Status::newFatal( 'userrights-no-interwiki' ); } if ( !UserRightsProxy::validDatabase( $database ) ) { @@ -578,6 +531,7 @@ class UserrightsPage extends SpecialPage { Linker::TOOL_LINKS_EMAIL /* Add "send e-mail" link */ ); + list( $groupCheckboxes, $canChangeAny ) = $this->groupCheckboxes( $groups, $user ); $this->getOutput()->addHTML( Xml::openElement( 'form', @@ -601,30 +555,38 @@ class UserrightsPage extends SpecialPage { $this->msg( 'userrights-editusergroup', $user->getName() )->text() ) . $this->msg( 'editinguser' )->params( wfEscapeWikiText( $user->getName() ) ) - ->rawParams( $userToolLinks )->parse() . - $this->msg( 'userrights-groups-help', $user->getName() )->parse() . - $grouplist . - $this->groupCheckboxes( $groups, $user ) . - Xml::openElement( 'table', [ 'id' => 'mw-userrights-table-outer' ] ) . - " - " . - Xml::label( $this->msg( 'userrights-reason' )->text(), 'wpReason' ) . - " - " . - Xml::input( 'user-reason', 60, $this->getRequest()->getVal( 'user-reason', false ), - [ 'id' => 'wpReason', 'maxlength' => 255 ] ) . - " - - - - " . - Xml::submitButton( $this->msg( 'saveusergroups', $user->getName() )->text(), - [ 'name' => 'saveusergroups' ] + - Linker::tooltipAndAccesskeyAttribs( 'userrights-set' ) - ) . - " - " . - Xml::closeElement( 'table' ) . "\n" . + ->rawParams( $userToolLinks )->parse() + ); + if ( $canChangeAny ) { + $this->getOutput()->addHTML( + $this->msg( 'userrights-groups-help', $user->getName() )->parse() . + $grouplist . + $groupCheckboxes . + Xml::openElement( 'table', [ 'id' => 'mw-userrights-table-outer' ] ) . + " + " . + Xml::label( $this->msg( 'userrights-reason' )->text(), 'wpReason' ) . + " + " . + Xml::input( 'user-reason', 60, $this->getRequest()->getVal( 'user-reason', false ), + [ 'id' => 'wpReason', 'maxlength' => 255 ] ) . + " + + + + " . + Xml::submitButton( $this->msg( 'saveusergroups', $user->getName() )->text(), + [ 'name' => 'saveusergroups' ] + + Linker::tooltipAndAccesskeyAttribs( 'userrights-set' ) + ) . + " + " . + Xml::closeElement( 'table' ) . "\n" + ); + } else { + $this->getOutput()->addHTML( $grouplist ); + } + $this->getOutput()->addHTML( Xml::closeElement( 'fieldset' ) . Xml::closeElement( 'form' ) . "\n" ); @@ -664,7 +626,8 @@ class UserrightsPage extends SpecialPage { * @todo Just pass the username string? * @param array $usergroups Groups the user belongs to * @param User $user - * @return string XHTML table element with checkboxes + * @return Array with 2 elements: the XHTML table element with checkxboes, and + * whether any groups are changeable */ private function groupCheckboxes( $usergroups, $user ) { $allgroups = $this->getAllGroups(); @@ -739,7 +702,7 @@ class UserrightsPage extends SpecialPage { } $ret .= Xml::closeElement( 'tr' ) . Xml::closeElement( 'table' ); - return $ret; + return [ $ret, (bool)$columns['changeable'] ]; } /** @@ -817,3 +780,4 @@ class UserrightsPage extends SpecialPage { return 'users'; } } + diff --git a/languages/i18n/en.json b/languages/i18n/en.json index 27ac32aa25..37890a91af 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -206,6 +206,7 @@ "views": "Views", "toolbox": "Tools", "tool-link-userrights": "Change {{GENDER:$1|user}} groups", + "tool-link-userrights-readonly": "View {{GENDER:$1|user}} groups", "tool-link-emailuser": "Email this {{GENDER:$1|user}}", "userpage": "View user page", "projectpage": "View project page", @@ -1134,9 +1135,9 @@ "prefs-tabs-navigation-hint": "Tip: You can use the left and right arrow keys to navigate between the tabs in the tabs list.", "userrights": "User rights management", "userrights-summary": "", - "userrights-lookup-user": "Manage user groups", + "userrights-lookup-user": "Select a user", "userrights-user-editname": "Enter a username:", - "editusergroup": "Edit {{GENDER:$1|user}} groups", + "editusergroup": "Load {{GENDER:$1|user}} groups", "editinguser": "Changing user rights of {{GENDER:$1|user}} [[User:$1|$1]] $2", "userrights-editusergroup": "Edit user groups", "saveusergroups": "Save {{GENDER:$1|user}} groups", @@ -1147,13 +1148,10 @@ "userrights-reason": "Reason:", "userrights-no-interwiki": "You do not have permission to edit user rights on other wikis.", "userrights-nodatabase": "Database $1 does not exist or is not local.", - "userrights-nologin": "You must [[Special:UserLogin|log in]] with an administrator account to assign user rights.", - "userrights-notallowed": "You do not have permission to add or remove user rights.", "userrights-changeable-col": "Groups you can change", "userrights-unchangeable-col": "Groups you cannot change", "userrights-irreversible-marker": "$1*", "userrights-conflict": "Conflict of user rights changes! Please review and confirm your changes.", - "userrights-removed-self": "You removed your own rights. As such, you are no longer able to access this page.", "group": "Group:", "group-user": "Users", "group-autoconfirmed": "Autoconfirmed users", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index d6dfc88af9..edf4b852bc 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -389,7 +389,8 @@ "talk": "Used as display name for the tab to all {{msg-mw|Talk}} pages. These pages accompany all content pages and can be used for discussing the content page. Example: [[Talk:Example]].\n\nSee also:\n* {{msg-mw|Talk}}\n* {{msg-mw|Accesskey-ca-talk}}\n* {{msg-mw|Tooltip-ca-talk}}\n{{Identical|Discussion}}", "views": "Subtitle for the list of available views, for the current page. In \"monobook\" skin the list of views are shown as tabs, so this sub-title is not shown. For an example, see [{{canonicalurl:Main_Page|useskin=simple}} Main Page using simple skin].\n\n'''Note:''' This is \"views\" as in \"appearances\"/\"representations\", '''not''' as in \"visits\"/\"accesses\".\n{{Identical|View}}", "toolbox": "The title of the toolbox below the search menu.\n{{Identical|Tool}}", - "tool-link-userrights": "Link to [[Special:UserRights]] (user rights management) in the sidebar toolbox.\n\nParameters:\n* $1 - Name of user for the user group management (usable for GENDER)", + "tool-link-userrights": "Link to [[Special:UserRights]] (user rights management) in the sidebar toolbox, shown if the current user is allowed to change given user's groups.\n\nParameters:\n* $1 - Name of user for the user group management (usable for GENDER)", + "tool-link-userrights-readonly": "Link to [[Special:UserRights]] (user rights management) in the sidebar toolbox, shown if the current user is '''not''' allowed to change given user's groups.\n\nParameters:\n* $1 - Name of user for the user group management (usable for GENDER)", "tool-link-emailuser": "Link to [[Special:EmailUser]] (email user tool) in the sidebar toolbox.\n\nParameters:\n* $1 - Name of user who would receive the email\n\nSee also:\n* {{msg-mw|Emailuser-title-target}}", "userpage": "Used in user talk pages as the text of the link to the user page, with the Cologne Blue skin.", "projectpage": "Used as link text in Talk page of project page with the Cologne Blue skin.", @@ -1320,9 +1321,9 @@ "userrights-summary": "{{doc-specialpagesummary|userrights}}", "userrights-lookup-user": "Label text when managing user rights ([[Special:UserRights]])", "userrights-user-editname": "Displayed on [[Special:UserRights]].", - "editusergroup": "Button name, in page [[Special:Userrights]] (only available to administrators), in the section named {{MediaWiki:userrights-lookup-user}}.\n\n{{Identical|Edit user groups}}.\nParameters:\n* $1 - username, for GENDER support", + "editusergroup": "Button name, in page [[Special:Userrights]], in the section named {{MediaWiki:userrights-lookup-user}}.\nParameters:\n* $1 - username, for GENDER support", "editinguser": "Appears on [[Special:UserRights]]. Parameters:\n* $1 - a plaintext username\n* $2 - user tool links. e.g. \"(Talk | contribs | block | send email)\"", - "userrights-editusergroup": "Parameter:\n* $1 - (Optional) a username, can be used for GENDER\n{{Identical|Edit user groups}}", + "userrights-editusergroup": "Parameter:\n* $1 - (Optional) a username, can be used for GENDER", "saveusergroups": "Button text when editing user groups.\nParameters:\n* $1 - username, for GENDER support", "userrights-groupsmember": "Used when editing user groups in [[Special:Userrights]].\n\nThe message is followed by a list of group names.\n\nParameters:\n* $1 - (Optional) the number of items in the list following the message, for PLURAL\n* $2 - (Optional) the user name, for GENDER", "userrights-groupsmember-auto": "Used when editing user groups in [[Special:Userrights]]. The message is followed by a list of group names.\n\n\"Implicit\" is for groups that the user was automatically added to (such as \"autoconfirmed\"); cf. {{msg-mw|userrights-groupsmember}}\n\nParameters:\n* $1 - (Optional) the number of items in the list following the message, for PLURAL\n* $2 - (Optional) the user name, for GENDER", @@ -1331,13 +1332,10 @@ "userrights-reason": "Text beside log field when editing user groups\n\n{{Identical|Reason}}", "userrights-no-interwiki": "Error message when editing user groups", "userrights-nodatabase": "Error message when editing user groups.\n\n\"Local\" means databases/wikis of the same farm/cluster; that is, meta, enwiki, dewiki, commons, etc are all local databases of the Wikimedia Foundation.\n\nSee [{{canonicalurl:meta:Special:Log|type=rights}} meta:Special:Log?type=rights] for a usage of local databases: username@barwiki\n\nParameters:\n* $1 - database name", - "userrights-nologin": "Error displayed on [[Special:UserRights]] when you aren't logged in.\n\nIf you are logged in, but don't have the correct permission, you see {{msg-mw|Userrights-notallowed}}.", - "userrights-notallowed": "Error displayed on [[Special:UserRights]] when you don't have the permission.", "userrights-changeable-col": "Used when editing user groups in [[Special:Userrights]].\n\nThe message is the head of a column of group assignments.\n\nParameters:\n* $1 - (Optional) for PLURAL use, the number of items in the column following the message. Avoid PLURAL, if your language can do without.", "userrights-unchangeable-col": "Used when editing user groups in [[Special:Userrights]]. The message is the head of a column of group assignments.\n\nParameters:\n* $1 - (Optional) for PLURAL use, the number of items in the column following the message. Avoid PLURAL, if your language allows that.", "userrights-irreversible-marker": "{{optional}}\nParameters:\n* $1 - group member", "userrights-conflict": "Shown on [[Special:UserRights]] if the target's rights have been changed since the form was loaded.", - "userrights-removed-self": "Shown on [[Special:UserRights]] in a green box after the user removed its own rights to access that page.", "group": "{{Identical|Group}}", "group-user": "{{doc-group|user}}\n{{Identical|User}}", "group-autoconfirmed": "{{doc-group|autoconfirmed}}\nOn Wikimedia sites autoconfirmed users are users which are older than 4 days. After those 4 days, they have more rights.", -- 2.20.1