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 === |