Userrights work. Changes:
authorAndrew Garrett <werdna@users.mediawiki.org>
Wed, 19 Dec 2007 02:05:48 +0000 (02:05 +0000)
committerAndrew Garrett <werdna@users.mediawiki.org>
Wed, 19 Dec 2007 02:05:48 +0000 (02:05 +0000)
* Behaviour of $wgAddGroups and $wgRemoveGroups changed. New behaviour:
* * Granting the userrights privilege allows arbitrary changing of rights.
* * Without the userrights privilege, a user will be able to add and/or remove the groups specified in $wgAddGroups and $wgRemoveGroups for any groups they are in.
* Merge interwiki code from the MakeSysop extension into core.
* New permission userrights-interwiki for changing user rights on foreign wikis.

includes/SpecialPage.php
includes/SpecialUserrights.php
languages/messages/MessagesEn.php

index 7cffa12..9193e1c 100644 (file)
@@ -135,7 +135,7 @@ class SpecialPage
                'Import'                    => array( 'SpecialPage', 'Import', 'import' ),
                'Lockdb'                    => array( 'SpecialPage', 'Lockdb', 'siteadmin' ),
                'Unlockdb'                  => array( 'SpecialPage', 'Unlockdb', 'siteadmin' ),
-               'Userrights'                => array( 'SpecialPage', 'Userrights', 'userrights' ),
+               'Userrights'                => array( 'SpecialPage', 'Userrights' ),
                'MIMEsearch'                => array( 'SpecialPage', 'MIMEsearch' ),
                'Unwatchedpages'            => array( 'SpecialPage', 'Unwatchedpages', 'unwatchedpages' ),
                'Listredirects'             => array( 'SpecialPage', 'Listredirects' ),
index a2a877b..2f1cf02 100644 (file)
@@ -31,6 +31,7 @@ class UserrightsForm extends HTMLForm {
                $this->mPosted = $request->wasPosted();
                $this->mRequest =& $request;
                $this->mName = 'userrights';
+               $this->mReason = $request->getText( 'user-reason' );
 
                $titleObj = SpecialPage::getTitleFor( 'Userrights' );
                $this->action = $titleObj->escapeLocalURL();
@@ -64,66 +65,204 @@ class UserrightsForm extends HTMLForm {
                }
        }
 
-       /** Back-end for saveUserGroups()
-        * @param User $u
-        * @param array $removegroup
-        * @param array $addgroup
-        * @param string $reason
+
+       /**
+        * Save user groups changes in the database.
+        * Data comes from the editUserGroupsForm() form function
+        *
+        * @param string $username Username to apply changes to.
+        * @param array $removegroup id of groups to be removed.
+        * @param array $addgroup id of groups to be added.
+        * @param string $reason Reason for group change
+        *
         */
+       function saveUserGroups( $username, $removegroup, $addgroup, $reason = '') {
+               $split = $this->splitUsername( $username );
+               if( WikiError::isError( $split ) ) {
+                       $wgOut->addWikiText( wfMsg( 'userrights-nodatabase', $split->getMessage() ) );
+                       return;
+               }
 
-       function doSaveUserGroups($u, $removegroup, $addgroup, $reason)
-       {
-               $oldGroups = $u->getGroups();
+               list( $database, $name ) = $split;
+               $this->db =& $this->getDB( $database );
+               $userid = $this->getUserId( $database, $name );
+
+               if( $userid == 0) {
+                       $wgOut->addWikiText( wfMsg( 'nosuchusershort', wfEscapeWikiText( $username ) ) );
+                       return;
+               }
+
+               global $wgUser;
+               if ($database != '' && !$wgUser->isAllowed('userrights-interwiki')) {
+                       $wgOut->addWikiText( wfMsg( 'userrights-no-interwiki' ) );
+                       return;
+               }
+
+               $oldGroups = $this->getUserGroups( $database, $userid );
                $newGroups = $oldGroups;
-               // remove then add groups
+               // remove then add groups               
                if(isset($removegroup)) {
                        $newGroups = array_diff($newGroups, $removegroup);
                        foreach( $removegroup as $group ) {
-                               if ( $this->canRemove( $group ) ) {
-                                       $u->removeGroup( $group );
-                               }
+                               $this->removeUserGroup( $database, $userid, $group );
                        }
                }
                if(isset($addgroup)) {
                        $newGroups = array_merge($newGroups, $addgroup);
                        foreach( $addgroup as $group ) {
-                               if ( $this->canAdd( $group ) ) {
-                                       $u->addGroup( $group );
-                               }
+                               $this->addUserGroup( $database, $userid, $group );
                        }
                }
                $newGroups = array_unique( $newGroups );
 
+               // Ensure that caches are cleared
+               $this->touchUser( $database, $userid );
+
                wfDebug( 'oldGroups: ' . print_r( $oldGroups, true ) );
                wfDebug( 'newGroups: ' . print_r( $newGroups, true ) );
+               wfRunHooks( 'UserRights', array( &$u, $addgroup, $removegroup ) );
 
-               wfRunHooks( 'UserRights', array( &$u, $addgroup, $removegroup ) );      
                $log = new LogPage( 'rights' );
-               $log->addEntry( 'rights', Title::makeTitle( NS_USER, $u->getName() ), $reason, array( $this->makeGroupNameList( $oldGroups ),
+               $log->addEntry( 'rights', Title::makeTitle( NS_USER, $username ), $this->mReason, array( $this->makeGroupNameList( $oldGroups ),
                        $this->makeGroupNameList( $newGroups ) ) );
        }
 
        /**
-        * Save user groups changes in the database.
-        * Data comes from the editUserGroupsForm() form function
-        *
-        * @param string $username Username to apply changes to.
-        * @param array $removegroup id of groups to be removed.
-        * @param array $addgroup id of groups to be added.
-        * @param string $reason Reason for group change
-        *
+        * Edit user groups membership
+        * @param string $username Name of the user.
         */
-       function saveUserGroups( $username, $removegroup, $addgroup, $reason = '' ) {
-               global $wgOut;
-               $u = User::newFromName($username);
-               if(is_null($u)) {
-                       $wgOut->addWikiText( wfMsg( 'nosuchusershort', htmlspecialchars( $username ) ) );
+       function editUserGroupsForm($username) {
+               global $wgOut, $wgUser;
+               
+               $split = $this->splitUsername( $username );
+               if( WikiError::isError( $split ) ) {
+                       $wgOut->addWikiText( wfMsg( 'userrights-nodatabase', $split->getMessage() ) );
+                       return;
+               }
+
+               list( $database, $name ) = $split;
+               $this->db =& $this->getDB( $database );
+               $userid = $this->getUserId( $database, $name );
+
+               if( $name == '' ) {
+                       $wgOut->addWikiText( wfMsg( 'nouserspecified' ) );
+                       return;
+               } elseif( $userid == 0) {
+                       $wgOut->addWikiText( wfMsg( 'nosuchusershort', wfEscapeWikiText( $username ) ) );
+                       return;
                }
-               if($u->getID() == 0) {
-                       $wgOut->addWikiText( wfMsg( 'nosuchusershort', htmlspecialchars( $username ) ) );
+
+               global $wgUser;
+               if ($database != '' && !$wgUser->isAllowed('userrights-interwiki')) {
+                       $wgOut->addWikiText( wfMsg( 'userrights-no-interwiki' ) );
+                       return;
                }
 
-               $this->doSaveUserGroups($u, $removegroup, $addgroup, $reason);
+               $groups = $this->getUserGroups( $database, $userid );
+               
+               $this->showEditUserGroupsForm( $username, $groups );
+
+               if ($database == '') {
+                       $this->showLogFragment( User::newFromName($username), $wgOut );
+               }
+       }
+
+       function splitUsername( $username ) {
+               $parts = explode( '@', $username );
+               if( count( $parts ) < 2 ) {
+                       return array( '', $username );
+               }
+               list( $name, $database ) = $parts;
+
+               global $wgLocalDatabases;
+               return array_search( $database, $wgLocalDatabases ) !== false
+                       ? array( $database, $name )
+                       : new WikiError( 'Bogus database suffix "' . wfEscapeWikiText( $database ) . '"' );
+       }
+
+       /**
+        * Open a database connection to work on for the requested user.
+        * This may be a new connection to another database for remote users.
+        * @param string $database
+        * @return Database
+        */
+       function &getDB( $database ) {
+               if( $database == '' ) {
+                       $db =& wfGetDB( DB_MASTER );
+               } else {
+                       global $wgDBuser, $wgDBpassword;
+                       $server = $this->getMaster( $database );
+                       $db = new Database( $server, $wgDBuser, $wgDBpassword, $database );
+               }
+               return $db;
+       }
+       
+       /**
+        * Return the master server to connect to for the requested database.
+        */
+       function getMaster( $database ) {
+               global $wgDBserver, $wgAlternateMaster;
+               if( isset( $wgAlternateMaster[$database] ) ) {
+                       return $wgAlternateMaster[$database];
+               }
+               return $wgDBserver;
+       }
+
+       function getUserId( $database, $name ) {
+               if( $name === '' )
+                       return 0;
+               return ( $name{0} == "#" )
+                       ? IntVal( substr( $name, 1 ) )
+                       : IntVal( $this->db->selectField( 'user',
+                               'user_id',
+                               array( 'user_name' => $name ),
+                               'MakesysopStewardForm::getUserId' ) );
+       }
+
+       function getUserGroups( $database, $userid ) {
+               $res = $this->db->select( 'user_groups',
+                       array( 'ug_group' ),
+                       array( 'ug_user' => $userid ),
+                       'MakesysopStewardForm::getUserGroups' );
+               $groups = array();
+               while( $row = $this->db->fetchObject( $res ) ) {
+                       $groups[] = $row->ug_group;
+               }
+               return $groups;
+       }
+
+       function addUserGroup( $database, $userid, $group ) {
+               $this->db->insert( 'user_groups',
+                       array(
+                               'ug_user' => $userid,
+                               'ug_group' => $group,
+                       ),
+                       'MakesysopStewardForm::addUserGroup',
+                       array( 'IGNORE' ) );
+       }
+
+       function removeUserGroup( $database, $userid, $group ) {
+               $this->db->delete( 'user_groups',
+                       array(
+                               'ug_user' => $userid,
+                               'ug_group' => $group,
+                       ),
+                       'MakesysopStewardForm::addUserGroup' );
+       }
+
+       function touchUser( $database, $userid ) {
+               $this->db->update( 'user',
+                       array( 'user_touched' => $this->db->timestamp() ),
+                       array( 'user_id' => $userid ),
+                       'MakesysopStewardForm::touchUser' );
+               
+               global $wgMemc;
+               if ( function_exists( 'wfForeignMemcKey' ) ) {
+                       $key = wfForeignMemcKey( $database, false, 'user', 'id', $userid );
+               } else {
+                       $key = "$database:user:id:$userid";
+               }
+               $wgMemc->delete( $key );
        }
 
        function makeGroupNameList( $ids ) {
@@ -144,26 +283,6 @@ class UserrightsForm extends HTMLForm {
                $form .= '</form>';
                $wgOut->addHTML( $form );
        }
-
-       /**
-        * Edit user groups membership
-        * @param string $username Name of the user.
-        */
-       function editUserGroupsForm($username) {
-               global $wgOut;
-       
-               $user = User::newFromName($username);
-               if( is_null( $user ) ) {
-                       $wgOut->addWikiText( wfMsg( 'nouserspecified' ) );
-                       return;
-               } elseif( $user->getID() == 0 ) {
-                       $wgOut->addWikiText( wfMsg( 'nosuchusershort', wfEscapeWikiText( $username ) ) );
-                       return;
-               }
-
-               $this->showEditUserGroupsForm( $username, $user->getGroups() );
-               $this->showLogFragment( $user, $wgOut );
-       }
        
        /**
         * Go through used and available groups and return the ones that this
@@ -351,11 +470,7 @@ class UserrightsForm extends HTMLForm {
        private function changeableByGroup( $group ) {
                global $wgGroupPermissions, $wgAddGroups, $wgRemoveGroups;
        
-               if( empty($wgGroupPermissions[$group]['userrights']) ) {
-                       // This group doesn't give the right to modify anything
-                       return array( 'add' => array(), 'remove' => array() );
-               }
-               if( empty($wgAddGroups[$group]) and empty($wgRemoveGroups[$group]) ) {
+               if( $wgGroupPermissions[$group]['userrights'] == true ) {
                        // This group gives the right to modify everything (reverse-
                        // compatibility with old "userrights lets you change
                        // everything")
@@ -407,4 +522,4 @@ class UserrightsForm extends HTMLForm {
                $viewer->showList( $output );
        }
        
-}
+}
\ No newline at end of file
index ca587f6..13f8e0a 100644 (file)
@@ -1338,6 +1338,7 @@ Unselected groups will not be changed. You can deselect a group with CTRL + Left
 'userrights-available-none'   => 'You may not alter group membership.',
 'userrights-available-add'    => 'You can add users to $1.',
 'userrights-available-remove' => 'You can remove users from $1.',
+'userrights-no-interwiki'     => 'You do not have permission to edit user rights on other wikis.',
 
 # Groups
 'group'               => 'Group:',