| Index: trunk/phase3/maintenance/parserTests.php |
| — | — | @@ -327,7 +327,7 @@ |
| 328 | 328 | 'recentchanges', |
| 329 | 329 | 'watchlist', 'math', 'searchindex', |
| 330 | 330 | 'interwiki', 'querycache', |
| 331 | | - 'objectcache', 'groups' |
| | 331 | + 'objectcache' |
| 332 | 332 | ); |
| 333 | 333 | } |
| 334 | 334 | |
| — | — | @@ -406,13 +406,6 @@ |
| 407 | 407 | 'iw_local' => 1 ), |
| 408 | 408 | ) ); |
| 409 | 409 | |
| 410 | | - # Hack: initialize a group |
| 411 | | - $db->insert( 'groups', array( |
| 412 | | - 'gr_id' => 1, |
| 413 | | - 'gr_name' => 'Anonymous', |
| 414 | | - 'gr_description' => 'Anonymous users', |
| 415 | | - 'gr_rights' => 'read' ) ); |
| 416 | | - |
| 417 | 410 | # Hack: Insert an image to work with |
| 418 | 411 | $db->insert( 'image', array( |
| 419 | 412 | 'img_name' => 'Foobar.jpg', |
| Index: trunk/phase3/maintenance/updaters.inc |
| — | — | @@ -12,7 +12,7 @@ |
| 13 | 13 | |
| 14 | 14 | $wgRenamedTables = array( |
| 15 | 15 | # from to patch file |
| 16 | | - array( 'group', 'groups', 'patch-rename-group.sql' ), |
| | 16 | +# array( 'group', 'groups', 'patch-rename-group.sql' ), |
| 17 | 17 | ); |
| 18 | 18 | |
| 19 | 19 | $wgNewTables = array( |
| — | — | @@ -22,8 +22,6 @@ |
| 23 | 23 | array( 'objectcache', 'patch-objectcache.sql' ), |
| 24 | 24 | array( 'categorylinks', 'patch-categorylinks.sql' ), |
| 25 | 25 | array( 'logging', 'patch-logging.sql' ), |
| 26 | | - array( 'user_rights', 'patch-user_rights.sql' ), |
| 27 | | - array( 'groups', 'patch-userlevels.sql' ), |
| 28 | 26 | array( 'validate', 'patch-validate.sql' ), |
| 29 | 27 | ); |
| 30 | 28 | |
| — | — | @@ -38,8 +36,6 @@ |
| 39 | 37 | array( 'user', 'user_real_name', 'patch-user-realname.sql' ), |
| 40 | 38 | array( 'user', 'user_token', 'patch-user_token.sql' ), |
| 41 | 39 | array( 'user', 'user_email_token', 'patch-user_email_token.sql' ), |
| 42 | | - array( 'user_rights', 'ur_user', 'patch-rename-user_groups-and_rights.sql' ), |
| 43 | | - array( 'groups', 'gr_rights', 'patch-userlevels-rights.sql' ), |
| 44 | 40 | array( 'logging', 'log_params', 'patch-log_params.sql' ), |
| 45 | 41 | array( 'archive', 'ar_rev_id', 'patch-archive-rev_id.sql' ), |
| 46 | 42 | array( 'archive', 'ar_text_id', 'patch-archive-text_id.sql' ), |
| — | — | @@ -238,20 +234,6 @@ |
| 239 | 235 | } |
| 240 | 236 | } |
| 241 | 237 | |
| 242 | | -# Assumes that the groups table has been added. |
| 243 | | -function do_group_update() { |
| 244 | | - global $wgDatabase; |
| 245 | | - $res = $wgDatabase->safeQuery( 'SELECT COUNT(*) AS c FROM !', |
| 246 | | - $wgDatabase->tableName( 'groups' ) ); |
| 247 | | - $row = $wgDatabase->fetchObject( $res ); |
| 248 | | - $wgDatabase->freeResult( $res ); |
| 249 | | - if( $row->c == 0 ) { |
| 250 | | - echo "Adding default group definitions... "; |
| 251 | | - dbsource( "maintenance/archives/patch-userlevels-defaultgroups.sql", $wgDatabase ); |
| 252 | | - echo "ok\n"; |
| 253 | | - } |
| 254 | | -} |
| 255 | | - |
| 256 | 238 | /** |
| 257 | 239 | * 1.4 betas were missing the 'binary' marker from logging.log_title, |
| 258 | 240 | * which causes a collation mismatch error on joins in MySQL 4.1. |
| — | — | @@ -572,6 +554,81 @@ |
| 573 | 555 | } |
| 574 | 556 | } |
| 575 | 557 | |
| | 558 | +function do_user_groups_update() { |
| | 559 | + $fname = 'do_user_groups_update'; |
| | 560 | + global $wgDatabase; |
| | 561 | + |
| | 562 | + if( $wgDatabase->tableExists( 'user_groups' ) ) { |
| | 563 | + echo "...user_groups table already exists.\n"; |
| | 564 | + return do_user_groups_reformat(); |
| | 565 | + } |
| | 566 | + |
| | 567 | + echo "Adding user_groups table... "; |
| | 568 | + dbsource( 'maintenance/archives/patch-user_groups.sql', $wgDatabase ); |
| | 569 | + echo "ok\n"; |
| | 570 | + |
| | 571 | + if( !$wgDatabase->tableExists( 'user_rights' ) ) { |
| | 572 | + if( $wgDatabase->fieldExists( 'user', 'user_rights' ) ) { |
| | 573 | + echo "Upgrading from a 1.3 or older database? Breaking out user_rights for conversion..."; |
| | 574 | + dbsource( 'maintenance/archives/patch-user_rights.sql', $wgDatabase ); |
| | 575 | + echo "ok\n"; |
| | 576 | + } else { |
| | 577 | + echo "*** WARNING: couldn't locate user_rights table or field for upgrade.\n"; |
| | 578 | + echo "*** You may need to manually configure some sysops by manipulating\n"; |
| | 579 | + echo "*** the user_groups table.\n"; |
| | 580 | + return; |
| | 581 | + } |
| | 582 | + } |
| | 583 | + |
| | 584 | + echo "Converting user_rights table to user_groups... "; |
| | 585 | + $result = $wgDatabase->select( 'user_rights', |
| | 586 | + array( 'ur_user', 'ur_rights' ), |
| | 587 | + array( "ur_rights != ''" ), |
| | 588 | + $fname ); |
| | 589 | + |
| | 590 | + while( $row = $wgDatabase->fetchObject( $result ) ) { |
| | 591 | + $groups = array_unique( |
| | 592 | + array_map( 'trim', |
| | 593 | + explode( ',', $row->ur_rights ) ) ); |
| | 594 | + |
| | 595 | + foreach( $groups as $group ) { |
| | 596 | + $wgDatabase->insert( 'user_groups', |
| | 597 | + array( |
| | 598 | + 'ug_user' => $row->ur_user, |
| | 599 | + 'ug_group' => $group ), |
| | 600 | + $fname ); |
| | 601 | + } |
| | 602 | + } |
| | 603 | + $wgDatabase->freeResult( $result ); |
| | 604 | + echo "ok\n"; |
| | 605 | +} |
| | 606 | + |
| | 607 | +function do_user_groups_reformat() { |
| | 608 | + # Check for bogus formats from previous 1.5 alpha code. |
| | 609 | + global $wgDatabase; |
| | 610 | + $info = $wgDatabase->fieldInfo( 'user_groups', 'ug_group' ); |
| | 611 | + |
| | 612 | + if( $info->type == 'int' ) { |
| | 613 | + $oldug = $wgDatabase->tableName( 'user_groups' ); |
| | 614 | + $newug = $wgDatabase->tableName( 'user_groups_bogus' ); |
| | 615 | + echo "user_groups is in bogus intermediate format. Renaming to $newug... "; |
| | 616 | + $wgDatabase->query( "ALTER TABLE $oldug RENAME TO $newug" ); |
| | 617 | + echo "ok\n"; |
| | 618 | + |
| | 619 | + echo "Re-adding fresh user_groups table... "; |
| | 620 | + dbsource( 'maintenance/archives/patch-user_groups.sql', $wgDatabase ); |
| | 621 | + echo "ok\n"; |
| | 622 | + |
| | 623 | + echo "***\n"; |
| | 624 | + echo "*** WARNING: You will need to manually fix up user permissions in the user_groups\n"; |
| | 625 | + echo "*** table. Old 1.5 alpha versions did some pretty funky stuff...\n"; |
| | 626 | + echo "***\n"; |
| | 627 | + } else { |
| | 628 | + echo "...user_groups is in current format.\n"; |
| | 629 | + } |
| | 630 | + |
| | 631 | +} |
| | 632 | + |
| 576 | 633 | function do_all_updates() { |
| 577 | 634 | global $wgNewTables, $wgNewFields, $wgRenamedTables; |
| 578 | 635 | |
| — | — | @@ -592,9 +649,6 @@ |
| 593 | 650 | flush(); |
| 594 | 651 | } |
| 595 | 652 | |
| 596 | | - # Add default group data |
| 597 | | - do_group_update(); flush(); |
| 598 | | - |
| 599 | 653 | # Do schema updates which require special handling |
| 600 | 654 | do_interwiki_update(); flush(); |
| 601 | 655 | do_index_update(); flush(); |
| — | — | @@ -615,6 +669,7 @@ |
| 616 | 670 | do_drop_img_type(); flush(); |
| 617 | 671 | |
| 618 | 672 | do_user_unique_update(); flush(); |
| | 673 | + do_user_groups_update(); flush(); |
| 619 | 674 | |
| 620 | 675 | initialiseMessages(); flush(); |
| 621 | 676 | } |
| Index: trunk/phase3/maintenance/archives/patch-user_groups.sql |
| — | — | @@ -0,0 +1,25 @@ |
| | 2 | +-- |
| | 3 | +-- User permissions have been broken out to a separate table; |
| | 4 | +-- this allows sites with a shared user table to have different |
| | 5 | +-- permissions assigned to a user in each project. |
| | 6 | +-- |
| | 7 | +-- This table replaces the old user_rights field which used a |
| | 8 | +-- comma-separated blob. |
| | 9 | +-- |
| | 10 | +CREATE TABLE /*$wgDBprefix*/user_groups ( |
| | 11 | + -- Key to user_id |
| | 12 | + ug_user int(5) unsigned NOT NULL default '0', |
| | 13 | + |
| | 14 | + -- Group names are short symbolic string keys. |
| | 15 | + -- The set of group names is open-ended, though in practice |
| | 16 | + -- only some predefined ones are likely to be used. |
| | 17 | + -- |
| | 18 | + -- At runtime $wgGroupPermissions will associate group keys |
| | 19 | + -- with particular permissions. A user will have the combined |
| | 20 | + -- permissions of any group they're explicitly in, plus |
| | 21 | + -- the implicit '*' and 'user' groups. |
| | 22 | + ug_group char(16) NOT NULL default '', |
| | 23 | + |
| | 24 | + PRIMARY KEY (ug_user,ug_group), |
| | 25 | + KEY (ug_group) |
| | 26 | +) TYPE=InnoDB; |
| Property changes on: trunk/phase3/maintenance/archives/patch-user_groups.sql |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| 1 | 27 | + native |
| Added: svn:keywords |
| 2 | 28 | + Author Date Id Revision |
| Index: trunk/phase3/maintenance/tables.sql |
| — | — | @@ -114,17 +114,25 @@ |
| 115 | 115 | -- this allows sites with a shared user table to have different |
| 116 | 116 | -- permissions assigned to a user in each project. |
| 117 | 117 | -- |
| | 118 | +-- This table replaces the old user_rights field which used a |
| | 119 | +-- comma-separated blob. |
| 118 | 120 | -- |
| 119 | | -CREATE TABLE /*$wgDBprefix*/user_rights ( |
| | 121 | +CREATE TABLE /*$wgDBprefix*/user_groups ( |
| 120 | 122 | -- Key to user_id |
| 121 | | - ur_user int(5) unsigned NOT NULL, |
| | 123 | + ug_user int(5) unsigned NOT NULL default '0', |
| 122 | 124 | |
| 123 | | - -- Comma-separated list of permission keys |
| 124 | | - ur_rights tinyblob NOT NULL default '', |
| | 125 | + -- Group names are short symbolic string keys. |
| | 126 | + -- The set of group names is open-ended, though in practice |
| | 127 | + -- only some predefined ones are likely to be used. |
| | 128 | + -- |
| | 129 | + -- At runtime $wgGroupPermissions will associate group keys |
| | 130 | + -- with particular permissions. A user will have the combined |
| | 131 | + -- permissions of any group they're explicitly in, plus |
| | 132 | + -- the implicit '*' and 'user' groups. |
| | 133 | + ug_group char(16) NOT NULL default '', |
| 125 | 134 | |
| 126 | | - UNIQUE KEY ur_user (ur_user) |
| 127 | | - |
| | 135 | + PRIMARY KEY (ug_user,ug_group), |
| | 136 | + KEY (ug_group) |
| 128 | 137 | ) TYPE=InnoDB; |
| 129 | 138 | |
| 130 | 139 | -- The following table is no longer needed with Enotif >= 2.00 |
| — | — | @@ -795,19 +803,11 @@ |
| 796 | 804 | |
| 797 | 805 | |
| 798 | 806 | -- Hold group name and description |
| 799 | | -CREATE TABLE /*$wgDBprefix*/groups ( |
| 800 | | - gr_id int(5) unsigned NOT NULL auto_increment, |
| 801 | | - gr_name varchar(50) NOT NULL default '', |
| 802 | | - gr_description varchar(255) NOT NULL default '', |
| 803 | | - gr_rights tinyblob, |
| 804 | | - PRIMARY KEY (gr_id) |
| 805 | | - |
| 806 | | -) TYPE=InnoDB; |
| 807 | | - |
| 808 | | -CREATE TABLE /*$wgDBprefix*/user_groups ( |
| 809 | | - ug_user int(5) unsigned NOT NULL default '0', |
| 810 | | - ug_group int(5) unsigned NOT NULL default '0', |
| 811 | | - PRIMARY KEY (ug_user,ug_group) |
| 812 | | - |
| 813 | | -) TYPE=InnoDB; |
| | 807 | +--CREATE TABLE /*$wgDBprefix*/groups ( |
| | 808 | +-- gr_id int(5) unsigned NOT NULL auto_increment, |
| | 809 | +-- gr_name varchar(50) NOT NULL default '', |
| | 810 | +-- gr_description varchar(255) NOT NULL default '', |
| | 811 | +-- gr_rights tinyblob, |
| | 812 | +-- PRIMARY KEY (gr_id) |
| | 813 | +-- |
| | 814 | +--) TYPE=InnoDB; |
| Index: trunk/phase3/config/index.php |
| — | — | @@ -565,7 +565,6 @@ |
| 566 | 566 | print "<li>Creating tables..."; |
| 567 | 567 | dbsource( "../maintenance/tables.sql", $wgDatabase ); |
| 568 | 568 | dbsource( "../maintenance/interwiki.sql", $wgDatabase ); |
| 569 | | - dbsource( "../maintenance/archives/patch-userlevels-defaultgroups.sql", $wgDatabase ); |
| 570 | 569 | print " done.</li>\n"; |
| 571 | 570 | |
| 572 | 571 | print "<li>Initializing data..."; |
| — | — | @@ -585,9 +584,10 @@ |
| 586 | 585 | if ( 0 == $u->idForName() ) { |
| 587 | 586 | $u->addToDatabase(); |
| 588 | 587 | $u->setPassword( $conf->getSysopPass() ); |
| 589 | | - $u->addRight( "sysop" ); |
| 590 | | - $u->addRight( "bureaucrat" ); |
| 591 | 588 | $u->saveSettings(); |
| | 589 | + |
| | 590 | + $u->addGroup( "sysop" ); |
| | 591 | + $u->addGroup( "bureaucrat" ); |
| 592 | 592 | |
| 593 | 593 | print "<li>Created sysop account <tt>" . |
| 594 | 594 | htmlspecialchars( $conf->SysopName ) . "</tt>.</li>\n"; |
| Index: trunk/phase3/includes/SpecialUserrights.php |
| — | — | @@ -10,7 +10,6 @@ |
| 11 | 11 | |
| 12 | 12 | /** */ |
| 13 | 13 | require_once('HTMLForm.php'); |
| 14 | | -require_once('Group.php'); |
| 15 | 14 | |
| 16 | 15 | /** Entry point */ |
| 17 | 16 | function wfSpecialUserrights() { |
| — | — | @@ -73,12 +72,12 @@ |
| 74 | 73 | $u = User::newFromName($username); |
| 75 | 74 | |
| 76 | 75 | if(is_null($u)) { |
| 77 | | - $wgOut->addHTML('<p>'.wfMsg('nosuchusershort',$username).'</p>'); |
| | 76 | + $wgOut->addWikiText( wfMsg( 'nosuchusershort', htmlspecialchars( $username ) ) ); |
| 78 | 77 | return; |
| 79 | 78 | } |
| 80 | 79 | |
| 81 | 80 | if($u->getID() == 0) { |
| 82 | | - $wgOut->addHTML('<p>'.wfMsg('nosuchusershort',$username).'</p>'); |
| | 81 | + $wgOut->addWikiText( wfMsg( 'nosuchusershort', htmlspecialchars( $username ) ) ); |
| 83 | 82 | return; |
| 84 | 83 | } |
| 85 | 84 | |
| — | — | @@ -93,10 +92,17 @@ |
| 94 | 93 | $newGroups = array_merge($newGroups, $addgroup); |
| 95 | 94 | } |
| 96 | 95 | $newGroups = array_unique( $newGroups ); |
| | 96 | + |
| | 97 | + wfDebug( 'oldGroups: ' . print_r( $oldGroups, true ) ); |
| | 98 | + wfDebug( 'newGroups: ' . print_r( $newGroups, true ) ); |
| 97 | 99 | |
| 98 | 100 | // save groups in user object and database |
| 99 | | - $u->setGroups($newGroups); |
| 100 | | - $u->saveSettings(); |
| | 101 | + foreach( $removegroup as $group ) { |
| | 102 | + $u->removeGroup( $group ); |
| | 103 | + } |
| | 104 | + foreach( $addgroup as $group ) { |
| | 105 | + $u->addGroup( $group ); |
| | 106 | + } |
| 101 | 107 | |
| 102 | 108 | $log = new LogPage( 'rights' ); |
| 103 | 109 | $log->addEntry( 'rights', Title::makeTitle( NS_USER, $u->getName() ), '', array( $this->makeGroupNameList( $oldGroups ), |
| — | — | @@ -104,15 +110,7 @@ |
| 105 | 111 | } |
| 106 | 112 | |
| 107 | 113 | function makeGroupNameList( $ids ) { |
| 108 | | - $s = ''; |
| 109 | | - foreach( $ids as $id ) { |
| 110 | | - if ( $s != '' ) { |
| 111 | | - $s .= ', '; |
| 112 | | - } |
| 113 | | - $groupObj = Group::newFromId( $id ); |
| 114 | | - $s .= $groupObj->getExpandedName(); |
| 115 | | - } |
| 116 | | - return $s; |
| | 114 | + return implode( ', ', $ids ); |
| 117 | 115 | } |
| 118 | 116 | |
| 119 | 117 | /** |
| — | — | @@ -126,7 +124,10 @@ |
| 127 | 125 | $wgOut->addHTML( "<form name=\"uluser\" action=\"$this->action\" method=\"post\">\n" ); |
| 128 | 126 | $wgOut->addHTML( $this->fieldset( 'lookup-user', |
| 129 | 127 | $this->textbox( 'user-editname' ) . |
| 130 | | - '<input type="submit" name="ssearchuser" value="'.wfMsg('editusergroup').'" />' |
| | 128 | + wfElement( 'input', array( |
| | 129 | + 'type' => 'submit', |
| | 130 | + 'name' => 'ssearchuser', |
| | 131 | + 'value' => wfMsg( 'editusergroup' ) ) ) |
| 131 | 132 | )); |
| 132 | 133 | $wgOut->addHTML( "</form>\n" ); |
| 133 | 134 | } |
| — | — | @@ -139,30 +140,30 @@ |
| 140 | 141 | global $wgOut; |
| 141 | 142 | |
| 142 | 143 | $user = User::newFromName($username); |
| 143 | | - $encUser = htmlspecialchars( $username ); |
| 144 | | - if(is_null($user)) { |
| 145 | | - $wgOut->addHTML('<p>'.wfMsg('nosuchusershort', $encUser).'</p>'); |
| | 144 | + if( is_null( $user ) || $user->getID() == 0 ) { |
| | 145 | + $wgOut->addWikiText( wfMsg( 'nosuchusershort', wfEscapeWikiText( $username ) ) ); |
| 146 | 146 | return; |
| 147 | 147 | } |
| 148 | | - |
| 149 | | - if($user->getID() == 0) { |
| 150 | | - $wgOut->addHTML('<p>'.wfMsg('nosuchusershort', $encUser).'</p>'); |
| 151 | | - return; |
| 152 | | - } |
| 153 | 148 | |
| 154 | 149 | $groups = $user->getGroups(); |
| 155 | 150 | |
| 156 | 151 | $wgOut->addHTML( "<form name=\"editGroup\" action=\"$this->action\" method=\"post\">\n". |
| 157 | | - '<input type="hidden" name="user-editname" value="'.$encUser.'" />'); |
| 158 | | - $wgOut->addHTML( $this->fieldset( 'editusergroup', |
| 159 | | - wfMsg('editing', $this->mRequest->getVal('user-editname')).".<br />\n" . |
| | 152 | + wfElement( 'input', array( |
| | 153 | + 'type' => 'hidden', |
| | 154 | + 'name' => 'user-editname', |
| | 155 | + 'value' => $username ) ) . |
| | 156 | + $this->fieldset( 'editusergroup', |
| | 157 | + $wgOut->parse( wfMsg('editing', $username ) ) . |
| 160 | 158 | '<table border="0" align="center"><tr><td>'. |
| 161 | 159 | HTMLSelectGroups('member', $this->mName.'-groupsmember', $groups,true,6). |
| 162 | 160 | '</td><td>'. |
| 163 | 161 | HTMLSelectGroups('available', $this->mName.'-groupsavailable', $groups,true,6,true). |
| 164 | 162 | '</td></tr></table>'."\n". |
| 165 | | - '<p>'.wfMsg('userrights-groupshelp').'</p>'."\n". |
| 166 | | - '<input type="submit" name="saveusergroups" value="'.wfMsg('saveusergroups').'" />' |
| | 163 | + $wgOut->parse( wfMsg('userrights-groupshelp') ) . |
| | 164 | + wfElement( 'input', array( |
| | 165 | + 'type' => 'submit', |
| | 166 | + 'name' => 'saveusergroups', |
| | 167 | + 'value' => wfMsg( 'saveusergroups' ) ) ) |
| 167 | 168 | )); |
| 168 | 169 | $wgOut->addHTML( "</form>\n" ); |
| 169 | 170 | } |
| Index: trunk/phase3/includes/HTMLForm.php |
| — | — | @@ -120,26 +120,34 @@ |
| 121 | 121 | * @param boolean $reverse If true, multiple select will hide selected elements (default false). |
| 122 | 122 | */ |
| 123 | 123 | function HTMLSelectGroups($selectname, $selectmsg, $selected=array(), $multiple=false, $size=6, $reverse=false) { |
| 124 | | - global $wgOut; |
| 125 | | - $groups =& Group::getAllGroups(); |
| | 124 | + $groups = User::getAllGroups(); |
| | 125 | + $out = htmlspecialchars( wfMsg( $selectmsg ) ); |
| 126 | 126 | |
| 127 | | - $out = wfMsg($selectmsg); |
| 128 | | - $out .= '<select name="'.$selectname; |
| 129 | | - if($multiple) { $out.='[]" multiple="multiple" size="'.$size; } |
| 130 | | - $out.= "\">\n"; |
| | 127 | + if( $multiple ) { |
| | 128 | + $attribs = array( |
| | 129 | + 'name' => $selectname . '[]', |
| | 130 | + 'multiple'=> 'multiple', |
| | 131 | + 'size' => $size ); |
| | 132 | + } else { |
| | 133 | + $attribs = array( 'name' => $selectname ); |
| | 134 | + } |
| | 135 | + $out .= wfElement( 'select', $attribs, null ); |
| 131 | 136 | |
| 132 | | - foreach ( $groups as $id => $g ) { |
| 133 | | - if($multiple) { |
| | 137 | + foreach( $groups as $group ) { |
| | 138 | + $attribs = array( 'value' => $group ); |
| | 139 | + if( $multiple ) { |
| 134 | 140 | // for multiple will only show the things we want |
| 135 | | - if(in_array($id, $selected) xor $reverse) { |
| 136 | | - $out .= '<option value="'.$id.'">'.$wgOut->parse( $g->getExpandedName() )."</option>\n"; |
| | 141 | + if( !in_array( $group, $selected ) xor $reverse ) { |
| | 142 | + continue; |
| 137 | 143 | } |
| 138 | 144 | } else { |
| 139 | | - $out .= '<option '; |
| 140 | | - if(in_array($id, $selected)) { $out .= 'selected="selected" '; } |
| 141 | | - $out .= 'value="'.$id.'">'.$wgOut->parse( $g->getExpandedName() )."</option>\n"; |
| | 145 | + if( in_array( $group, $selected ) ) { |
| | 146 | + $attribs['selected'] = 'selected'; |
| | 147 | + } |
| 142 | 148 | } |
| | 149 | + $out .= wfElement( 'option', $attribs, User::getGroupName( $group ) ) . "\n"; |
| 143 | 150 | } |
| | 151 | + |
| 144 | 152 | $out .= "</select>\n"; |
| 145 | 153 | return $out; |
| 146 | 154 | } |
| Index: trunk/phase3/includes/DefaultSettings.php |
| — | — | @@ -671,13 +671,26 @@ |
| 672 | 672 | $wgAutoblockExpiry = 86400; # Number of seconds before autoblock entries expire |
| 673 | 673 | |
| 674 | 674 | /** |
| 675 | | - * Static user groups serialized record |
| 676 | | - * To avoid database access, you can set this to a user groups record as returned |
| 677 | | - * by Special:Groups with the magic parameter showrecord=1. This will however mean |
| 678 | | - * that you won't be able to edit them at runtime. |
| | 675 | + * Permission keys given to users in each group. |
| | 676 | + * All users are implicitly in the '*' group including anonymous visitors; |
| | 677 | + * logged-in users are all implicitly in the 'user' group. These will be |
| | 678 | + * combined with the permissions of all groups that a given user is listed |
| | 679 | + * in in the user_groups table. |
| 679 | 680 | */ |
| 680 | | -$wgStaticGroups = false; |
| | 681 | +$wgGroupPermissions = array( |
| | 682 | + '*' => array( 'read', 'createaccount' ), |
| | 683 | + 'user' => array( 'read', 'move' ), |
| | 684 | + |
| | 685 | + 'bot' => array( 'bot' ), |
| | 686 | + 'sysop' => array( 'createaccount', 'patrol', 'protect', 'delete', |
| | 687 | + 'rollback', 'block', 'editinterface' ), |
| | 688 | + 'bureaucrat' => array( 'userrights' ), |
| | 689 | + 'steward' => array( 'makesysop' ), # technically this is for an extension... |
| | 690 | + 'developer' => array( 'siteadmin' ), |
| | 691 | +); |
| 681 | 692 | |
| | 693 | + |
| | 694 | + |
| 682 | 695 | # Proxy scanner settings |
| 683 | 696 | # |
| 684 | 697 | |
| — | — | @@ -1319,15 +1332,7 @@ |
| 1320 | 1333 | # $wgLocaltimezone = 'CET'; |
| 1321 | 1334 | $wgLocaltimezone = null; |
| 1322 | 1335 | |
| 1323 | | -/** |
| 1324 | | - * User level management |
| 1325 | | - * The number is the database id of a group you want users to be attached by |
| 1326 | | - * default. A better interface should be coded [av] |
| 1327 | | - */ |
| 1328 | | -$wgAnonGroupId = 1; |
| 1329 | | -$wgLoggedInGroupId = 2; |
| 1330 | 1336 | |
| 1331 | | - |
| 1332 | 1337 | /** |
| 1333 | 1338 | * When translating messages with wfMsg(), it is not always clear what should be |
| 1334 | 1339 | * considered UI messages and what shoud be content messages. |
| Index: trunk/phase3/includes/SpecialPage.php |
| — | — | @@ -72,7 +72,7 @@ |
| 73 | 73 | 'Lockdb' => new SpecialPage( 'Lockdb', 'siteadmin' ), |
| 74 | 74 | 'Unlockdb' => new SpecialPage( 'Unlockdb', 'siteadmin' ), |
| 75 | 75 | 'Userrights' => new SpecialPage( 'Userrights', 'userrights' ), |
| 76 | | - 'Groups' => new SpecialPage( 'Groups' ), |
| | 76 | + // 'Groups' => new SpecialPage( 'Groups' ), # currently borken |
| 77 | 77 | ); |
| 78 | 78 | |
| 79 | 79 | global $wgUseValidation ; |
| Index: trunk/phase3/includes/Title.php |
| — | — | @@ -958,7 +958,7 @@ |
| 959 | 959 | /** If anon users can create an account, |
| 960 | 960 | they need to reach the login page first! */ |
| 961 | 961 | if( $wgUser->isAllowed( 'createaccount' ) |
| 962 | | - && $this->mId == NS_SPECIAL |
| | 962 | + && $this->getNamespace() == NS_SPECIAL |
| 963 | 963 | && $this->getText() == 'Userlogin' ) { |
| 964 | 964 | return true; |
| 965 | 965 | } |
| Index: trunk/phase3/includes/SpecialStatistics.php |
| — | — | @@ -13,7 +13,7 @@ |
| 14 | 14 | $fname = 'wfSpecialStatistics'; |
| 15 | 15 | |
| 16 | 16 | $dbr =& wfGetDB( DB_SLAVE ); |
| 17 | | - extract( $dbr->tableNames( 'page', 'site_stats', 'user', 'user_rights' ) ); |
| | 17 | + extract( $dbr->tableNames( 'page', 'site_stats', 'user', 'user_groups' ) ); |
| 18 | 18 | |
| 19 | 19 | $sql = "SELECT COUNT(page_namespace) AS total FROM $page"; |
| 20 | 20 | $res = $dbr->query( $sql, $fname ); |
| — | — | @@ -44,7 +44,7 @@ |
| 45 | 45 | $row = $dbr->fetchObject( $res ); |
| 46 | 46 | $total = $row->total; |
| 47 | 47 | |
| 48 | | - $sql = "SELECT COUNT(ur_user) AS total FROM $user_rights WHERE ur_rights LIKE '%sysop%'"; |
| | 48 | + $sql = "SELECT COUNT(*) AS total FROM $user_groups WHERE ug_group='sysop'"; |
| 49 | 49 | $res = $dbr->query( $sql, $fname ); |
| 50 | 50 | $row = $dbr->fetchObject( $res ); |
| 51 | 51 | $admins = $row->total; |
| Index: trunk/phase3/includes/SpecialListusers.php |
| — | — | @@ -64,18 +64,22 @@ |
| 65 | 65 | // form header |
| 66 | 66 | $out = '<form method="get" action="'.$action.'">' . |
| 67 | 67 | '<input type="hidden" name="title" value="'.$special.'" />' . |
| 68 | | - wfMsg( 'grouplevels-editgroup-name' ) . '<select name="group">'; |
| | 68 | + wfMsg( 'groups-editgroup-name' ) . '<select name="group">'; |
| 69 | 69 | |
| 70 | 70 | // get all group names and IDs |
| 71 | | - $groups =& Group::getAllGroups(); |
| | 71 | + $groups = User::getAllGroups(); |
| 72 | 72 | |
| 73 | 73 | // we want a default empty group |
| 74 | 74 | $out.= '<option value=""></option>'; |
| 75 | 75 | |
| 76 | 76 | // build the dropdown list menu using datas from the database |
| 77 | 77 | foreach ( $groups as $group ) { |
| 78 | | - $selected = ($group->getId() == $this->requestedGroup) ? ' selected ' : '' ; |
| 79 | | - $out.= '<option value="'.$group->getId().'" '.$selected.'>'.$group->getExpandedName().'</option>'; |
| | 78 | + $selected = ($group == $this->requestedGroup); |
| | 79 | + $out .= wfElement( 'option', |
| | 80 | + array_merge( |
| | 81 | + array( 'value' => $group ), |
| | 82 | + $selected ? array( 'selected' => 'selected' ) : array() ), |
| | 83 | + User::getGroupName( $group ) ); |
| 80 | 84 | } |
| 81 | 85 | $out .= '</select> '; |
| 82 | 86 | |
| — | — | @@ -89,24 +93,16 @@ |
| 90 | 94 | |
| 91 | 95 | function getSQL() { |
| 92 | 96 | $dbr =& wfGetDB( DB_SLAVE ); |
| 93 | | - /* system showing possible actions for users |
| 94 | 97 | $user = $dbr->tableName( 'user' ); |
| 95 | | - $user_rights = $dbr->tableName( 'user_rights' ); |
| 96 | | - $userspace = Namespace::getUser(); |
| 97 | | - return "SELECT ur_rights as type, $userspace as namespace, user_name as title, " . |
| 98 | | - "user_name as value FROM $user LEFT JOIN $user_rights ON user_id = ur_user"; |
| 99 | | - */ |
| 100 | | - /** Show groups instead */ |
| 101 | | - $user = $dbr->tableName( 'user' ); |
| 102 | 98 | $user_groups = $dbr->tableName( 'user_groups' ); |
| 103 | 99 | |
| 104 | 100 | $userspace = NS_USER; |
| 105 | | - $sql = "SELECT CONCAT('Listusers ', ug_group) as type, $userspace AS namespace, user_name AS title, user_name as value " . |
| | 101 | + $sql = "SELECT 'Listusers' as type, $userspace AS namespace, user_name AS title, ug_group as value " . |
| 106 | 102 | "FROM $user ". |
| 107 | 103 | "LEFT JOIN $user_groups ON user_id =ug_user "; |
| 108 | 104 | |
| 109 | 105 | if($this->requestedGroup != '') { |
| 110 | | - $sql .= "WHERE ug_group = '" . IntVal( $this->requestedGroup ) . "' "; |
| | 106 | + $sql .= 'WHERE ug_group = ' . $dbr->addQuotes( $this->requestedGroup ) . ' '; |
| 111 | 107 | if($this->requestedUser != '') { |
| 112 | 108 | $sql .= "AND user_name = " . $dbr->addQuotes( $this->requestedUser ) . ' '; |
| 113 | 109 | } |
| — | — | @@ -138,10 +134,7 @@ |
| 139 | 135 | function clearGroups() { |
| 140 | 136 | $this->concatGroups = ''; |
| 141 | 137 | } |
| 142 | | -/* |
| 143 | | - var $previousResult = false; |
| 144 | | - var $concatGroups = ''; |
| 145 | | -*/ |
| | 138 | + |
| 146 | 139 | function formatResult( $skin, $result ) { |
| 147 | 140 | global $wgContLang; |
| 148 | 141 | $name = false; |
| — | — | @@ -155,9 +148,9 @@ |
| 156 | 149 | } |
| 157 | 150 | |
| 158 | 151 | if( is_object( $result ) && $result->type != '') { |
| 159 | | - $group = Group::newFromId( intval( strstr( $result->type, ' ' ) ) ); |
| | 152 | + $group = $result->value; |
| 160 | 153 | if ( $group ) { |
| 161 | | - $groupName = $group->getExpandedName(); |
| | 154 | + $groupName = User::getGroupName( $group ); |
| 162 | 155 | $this->appendGroups( $skin->makeLink( wfMsgForContent( 'administrators' ), $groupName ) ); |
| 163 | 156 | } |
| 164 | 157 | } |
| Index: trunk/phase3/includes/User.php |
| — | — | @@ -9,7 +9,6 @@ |
| 10 | 10 | * |
| 11 | 11 | */ |
| 12 | 12 | require_once( 'WatchedItem.php' ); |
| 13 | | -require_once( 'Group.php' ); |
| 14 | 13 | |
| 15 | 14 | # Number of characters in user_token field |
| 16 | 15 | define( 'USER_TOKEN_LENGTH', 32 ); |
| — | — | @@ -32,9 +31,7 @@ |
| 33 | 32 | var $mToken; |
| 34 | 33 | var $mRealName; |
| 35 | 34 | var $mHash; |
| 36 | | - /** Array of group id the user belong to */ |
| 37 | 35 | var $mGroups; |
| 38 | | - /**#@-*/ |
| 39 | 36 | |
| 40 | 37 | /** Construct using User:loadDefaults() */ |
| 41 | 38 | function User() { |
| — | — | @@ -563,7 +560,7 @@ |
| 564 | 561 | * Load a user from the database |
| 565 | 562 | */ |
| 566 | 563 | function loadFromDatabase() { |
| 567 | | - global $wgCommandLineMode, $wgAnonGroupId, $wgLoggedInGroupId; |
| | 564 | + global $wgCommandLineMode; |
| 568 | 565 | $fname = "User::loadFromDatabase"; |
| 569 | 566 | |
| 570 | 567 | # Counter-intuitive, breaks various things, use User::setLoaded() if you want to suppress |
| — | — | @@ -577,15 +574,9 @@ |
| 578 | 575 | $this->mId = IntVal( $this->mId ); |
| 579 | 576 | |
| 580 | 577 | /** Anonymous user */ |
| 581 | | - if(!$this->mId) { |
| | 578 | + if( !$this->mId ) { |
| 582 | 579 | /** Get rights */ |
| 583 | | - $anong = Group::newFromId($wgAnonGroupId); |
| 584 | | - if (!$anong) |
| 585 | | - wfDebugDieBacktrace("Please update your database schema " |
| 586 | | - ."and populate initial group data from " |
| 587 | | - ."maintenance/archives patches"); |
| 588 | | - $anong->loadFromDatabase(); |
| 589 | | - $this->mRights = explode(',', $anong->getRights()); |
| | 580 | + $this->mRights = $this->getGroupPermissions( array( '*' ) ); |
| 590 | 581 | $this->mDataLoaded = true; |
| 591 | 582 | return; |
| 592 | 583 | } # the following stuff is for non-anonymous users only |
| — | — | @@ -607,31 +598,16 @@ |
| 608 | 599 | $this->mTouched = wfTimestamp(TS_MW,$s->user_touched); |
| 609 | 600 | $this->mToken = $s->user_token; |
| 610 | 601 | |
| 611 | | - // Get groups id |
| 612 | | - $res = $dbr->select( 'user_groups', array( 'ug_group' ), array( 'ug_user' => $this->mId ) ); |
| 613 | | - |
| 614 | | - // add the default group for logged in user |
| 615 | | - $this->mGroups = array( $wgLoggedInGroupId ); |
| 616 | | - |
| 617 | | - while($group = $dbr->fetchRow($res)) { |
| 618 | | - if ( $group[0] != $wgLoggedInGroupId ) { |
| 619 | | - $this->mGroups[] = $group[0]; |
| 620 | | - } |
| | 602 | + $res = $dbr->select( 'user_groups', |
| | 603 | + array( 'ug_group' ), |
| | 604 | + array( 'ug_user' => $this->mId ), |
| | 605 | + $fname ); |
| | 606 | + $this->mGroups = array(); |
| | 607 | + while( $row = $dbr->fetchObject( $res ) ) { |
| | 608 | + $this->mGroups[] = $row->ug_group; |
| 621 | 609 | } |
| 622 | | - |
| 623 | | - |
| 624 | | - $this->mRights = array(); |
| 625 | | - // now we merge groups rights to get this user rights |
| 626 | | - foreach($this->mGroups as $aGroupId) { |
| 627 | | - $g = Group::newFromId($aGroupId); |
| 628 | | - $g->loadFromDatabase(); |
| 629 | | - $this->mRights = array_merge($this->mRights, explode(',', $g->getRights())); |
| 630 | | - } |
| 631 | | - |
| 632 | | - // array merge duplicate rights which are part of several groups |
| 633 | | - $this->mRights = array_unique($this->mRights); |
| 634 | | - |
| 635 | | - $dbr->freeResult($res); |
| | 610 | + $effectiveGroups = array_merge( array( '*', 'user' ), $this->mGroups ); |
| | 611 | + $this->mRights = $this->getGroupPermissions( $effectiveGroups ); |
| 636 | 612 | } |
| 637 | 613 | |
| 638 | 614 | $this->mDataLoaded = true; |
| — | — | @@ -830,24 +806,75 @@ |
| 831 | 807 | $this->loadFromDatabase(); |
| 832 | 808 | return $this->mRights; |
| 833 | 809 | } |
| 834 | | - |
| 835 | | - function addRight( $rname ) { |
| 836 | | - $this->loadFromDatabase(); |
| 837 | | - array_push( $this->mRights, $rname ); |
| 838 | | - $this->invalidateCache(); |
| 839 | | - } |
| 840 | 810 | |
| | 811 | + /** |
| | 812 | + * Get the list of explicit group memberships this user has. |
| | 813 | + * The implicit * and user groups are not included. |
| | 814 | + * @return array of strings |
| | 815 | + */ |
| 841 | 816 | function getGroups() { |
| 842 | 817 | $this->loadFromDatabase(); |
| 843 | 818 | return $this->mGroups; |
| 844 | 819 | } |
| 845 | 820 | |
| 846 | | - function setGroups($groups) { |
| 847 | | - $this->loadFromDatabase(); |
| 848 | | - $this->mGroups = $groups; |
| | 821 | + /** |
| | 822 | + * Get the list of implicit group memberships this user has. |
| | 823 | + * This includes all explicit groups, plus 'user' if logged in |
| | 824 | + * and '*' for all accounts. |
| | 825 | + * @return array of strings |
| | 826 | + */ |
| | 827 | + function getEffectiveGroups() { |
| | 828 | + $base = array( '*' ); |
| | 829 | + if( $this->isLoggedIn() ) { |
| | 830 | + $base[] = 'user'; |
| | 831 | + } |
| | 832 | + return array_merge( $base, $this->getGroups() ); |
| | 833 | + } |
| | 834 | + |
| | 835 | + /** |
| | 836 | + * Remove the user from the given group. |
| | 837 | + * This takes immediate effect. |
| | 838 | + * @string $group |
| | 839 | + */ |
| | 840 | + function addGroup( $group ) { |
| | 841 | + $dbw =& wfGetDB( DB_MASTER ); |
| | 842 | + $dbw->insert( 'user_groups', |
| | 843 | + array( |
| | 844 | + 'ug_user' => $this->getID(), |
| | 845 | + 'ug_group' => $group, |
| | 846 | + ), |
| | 847 | + 'User::addGroup', |
| | 848 | + array( 'IGNORE' ) ); |
| | 849 | + |
| | 850 | + $this->mGroups = array_merge( $this->mGroups, array( $group ) ); |
| | 851 | + $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups() ); |
| | 852 | + |
| 849 | 853 | $this->invalidateCache(); |
| | 854 | + $this->saveSettings(); |
| 850 | 855 | } |
| | 856 | + |
| | 857 | + /** |
| | 858 | + * Remove the user from the given group. |
| | 859 | + * This takes immediate effect. |
| | 860 | + * @string $group |
| | 861 | + */ |
| | 862 | + function removeGroup( $group ) { |
| | 863 | + $dbw =& wfGetDB( DB_MASTER ); |
| | 864 | + $dbw->delete( 'user_groups', |
| | 865 | + array( |
| | 866 | + 'ug_user' => $this->getID(), |
| | 867 | + 'ug_group' => $group, |
| | 868 | + ), |
| | 869 | + 'User::removeGroup' ); |
| | 870 | + |
| | 871 | + $this->mGroups = array_diff( $this->mGroups, array( $group ) ); |
| | 872 | + $this->mRights = User::getGroupPermissions( $this->getEffectiveGroups() ); |
| | 873 | + |
| | 874 | + $this->invalidateCache(); |
| | 875 | + $this->saveSettings(); |
| | 876 | + } |
| 851 | 877 | |
| | 878 | + |
| 852 | 879 | /** |
| 853 | 880 | * A more legible check for non-anonymousness. |
| 854 | 881 | * Returns true if the user is not an anonymous visitor. |
| — | — | @@ -1167,23 +1194,7 @@ |
| 1168 | 1195 | 'user_id' => $this->mId |
| 1169 | 1196 | ), $fname |
| 1170 | 1197 | ); |
| 1171 | | - $dbw->set( 'user_rights', 'ur_rights', implode( ',', $this->mRights ), |
| 1172 | | - 'ur_user='. $this->mId, $fname ); |
| 1173 | 1198 | $wgMemc->delete( "$wgDBname:user:id:$this->mId" ); |
| 1174 | | - |
| 1175 | | - // delete old groups |
| 1176 | | - $dbw->delete( 'user_groups', array( 'ug_user' => $this->mId), $fname); |
| 1177 | | - |
| 1178 | | - // save new ones |
| 1179 | | - foreach ($this->mGroups as $group) { |
| 1180 | | - $dbw->replace( 'user_groups', |
| 1181 | | - array(array('ug_user','ug_group')), |
| 1182 | | - array( |
| 1183 | | - 'ug_user' => $this->mId, |
| 1184 | | - 'ug_group' => $group |
| 1185 | | - ), $fname |
| 1186 | | - ); |
| 1187 | | - } |
| 1188 | 1199 | } |
| 1189 | 1200 | |
| 1190 | 1201 | |
| — | — | @@ -1226,21 +1237,6 @@ |
| 1227 | 1238 | ), $fname |
| 1228 | 1239 | ); |
| 1229 | 1240 | $this->mId = $dbw->insertId(); |
| 1230 | | - $dbw->insert( 'user_rights', |
| 1231 | | - array( |
| 1232 | | - 'ur_user' => $this->mId, |
| 1233 | | - 'ur_rights' => implode( ',', $this->mRights ) |
| 1234 | | - ), $fname |
| 1235 | | - ); |
| 1236 | | - |
| 1237 | | - foreach ($this->mGroups as $group) { |
| 1238 | | - $dbw->insert( 'user_groups', |
| 1239 | | - array( |
| 1240 | | - 'ug_user' => $this->mId, |
| 1241 | | - 'ug_group' => $group |
| 1242 | | - ), $fname |
| 1243 | | - ); |
| 1244 | | - } |
| 1245 | 1241 | } |
| 1246 | 1242 | |
| 1247 | 1243 | function spreadBlock() { |
| — | — | @@ -1591,6 +1587,51 @@ |
| 1592 | 1588 | return false; |
| 1593 | 1589 | return true; |
| 1594 | 1590 | } |
| | 1591 | + |
| | 1592 | + /** |
| | 1593 | + * @param array $groups list of groups |
| | 1594 | + * @return array list of permission key names for given groups combined |
| | 1595 | + * @static |
| | 1596 | + */ |
| | 1597 | + function getGroupPermissions( $groups ) { |
| | 1598 | + global $wgGroupPermissions; |
| | 1599 | + $rights = array(); |
| | 1600 | + foreach( $groups as $group ) { |
| | 1601 | + if( isset( $wgGroupPermissions[$group] ) ) { |
| | 1602 | + $rights = array_merge( $rights, $wgGroupPermissions[$group] ); |
| | 1603 | + } |
| | 1604 | + } |
| | 1605 | + return $rights; |
| | 1606 | + } |
| | 1607 | + |
| | 1608 | + /** |
| | 1609 | + * @param string $group key name |
| | 1610 | + * @return string localized descriptive name, if provided |
| | 1611 | + * @static |
| | 1612 | + */ |
| | 1613 | + function getGroupName( $group ) { |
| | 1614 | + $key = "group-$group-name"; |
| | 1615 | + $name = wfMsg( $key ); |
| | 1616 | + if( $name == '' || $name == "<$key>" ) { |
| | 1617 | + return $group; |
| | 1618 | + } else { |
| | 1619 | + return $name; |
| | 1620 | + } |
| | 1621 | + } |
| | 1622 | + |
| | 1623 | + /** |
| | 1624 | + * Return the set of defined explicit groups. |
| | 1625 | + * The * and 'user' groups are not included. |
| | 1626 | + * @return array |
| | 1627 | + * @static |
| | 1628 | + */ |
| | 1629 | + function getAllGroups() { |
| | 1630 | + global $wgGroupPermissions; |
| | 1631 | + return array_diff( |
| | 1632 | + array_keys( $wgGroupPermissions ), |
| | 1633 | + array( '*', 'user' ) ); |
| | 1634 | + } |
| | 1635 | + |
| 1595 | 1636 | } |
| 1596 | 1637 | |
| 1597 | 1638 | ?> |
| Index: trunk/phase3/RELEASE-NOTES |
| — | — | @@ -272,6 +272,7 @@ |
| 273 | 273 | * (bug 2309) Allow templates and template parameters in HTML attribute zone, |
| 274 | 274 | with proper validation checks. (regression from fix for 2304) |
| 275 | 275 | * Disallow close tags and enforce empty tags for <hr> and <br> |
| | 276 | +* Changed user_groups format quite a bit. |
| 276 | 277 | |
| 277 | 278 | |
| 278 | 279 | === Caveats === |