r9367 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r9366‎ | r9367 | r9368 >
Date:09:49, 9 June 2005
Author:vibber
Status:old
Tags:
Comment:
Rework the user_groups system, again, into something that seems to actually
more or less work for now.

* user_groups ur_group is now a short string key ('sysop' etc)
* groups table is gone
* user_rights table is gone
* Permissions for groups are for now set in $wgGroupPermissions.
An in-database management system could be re-added in the future
if it's really needed, but for now it's mostly just been screwing
things up.
* Group.php and Special:Groups are deprecated; will probably die.
* User group memberships are set explicitly through addGroup and
removeGroup methods instead of being re-saved on every change to
the user record.

Group keys are migrated from user_rights at upgrade time for older wikis.
The fields in prior 1.5alpha tables were too screwed up and will need to
manually have sysops re-assigned.

The Makesysop extension will need some minor tweaks.
Modified paths:
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/config/index.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/HTMLForm.php (modified) (history)
  • /trunk/phase3/includes/SpecialListusers.php (modified) (history)
  • /trunk/phase3/includes/SpecialPage.php (modified) (history)
  • /trunk/phase3/includes/SpecialStatistics.php (modified) (history)
  • /trunk/phase3/includes/SpecialUserrights.php (modified) (history)
  • /trunk/phase3/includes/Title.php (modified) (history)
  • /trunk/phase3/includes/User.php (modified) (history)
  • /trunk/phase3/maintenance/archives/patch-user_groups.sql (added) (history)
  • /trunk/phase3/maintenance/parserTests.php (modified) (history)
  • /trunk/phase3/maintenance/tables.sql (modified) (history)
  • /trunk/phase3/maintenance/updaters.inc (modified) (history)

Diff [purge]

Index: trunk/phase3/maintenance/parserTests.php
@@ -327,7 +327,7 @@
328328 'recentchanges',
329329 'watchlist', 'math', 'searchindex',
330330 'interwiki', 'querycache',
331 - 'objectcache', 'groups'
 331+ 'objectcache'
332332 );
333333 }
334334
@@ -406,13 +406,6 @@
407407 'iw_local' => 1 ),
408408 ) );
409409
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 -
417410 # Hack: Insert an image to work with
418411 $db->insert( 'image', array(
419412 'img_name' => 'Foobar.jpg',
Index: trunk/phase3/maintenance/updaters.inc
@@ -12,7 +12,7 @@
1313
1414 $wgRenamedTables = array(
1515 # from to patch file
16 - array( 'group', 'groups', 'patch-rename-group.sql' ),
 16+# array( 'group', 'groups', 'patch-rename-group.sql' ),
1717 );
1818
1919 $wgNewTables = array(
@@ -22,8 +22,6 @@
2323 array( 'objectcache', 'patch-objectcache.sql' ),
2424 array( 'categorylinks', 'patch-categorylinks.sql' ),
2525 array( 'logging', 'patch-logging.sql' ),
26 - array( 'user_rights', 'patch-user_rights.sql' ),
27 - array( 'groups', 'patch-userlevels.sql' ),
2826 array( 'validate', 'patch-validate.sql' ),
2927 );
3028
@@ -38,8 +36,6 @@
3937 array( 'user', 'user_real_name', 'patch-user-realname.sql' ),
4038 array( 'user', 'user_token', 'patch-user_token.sql' ),
4139 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' ),
4440 array( 'logging', 'log_params', 'patch-log_params.sql' ),
4541 array( 'archive', 'ar_rev_id', 'patch-archive-rev_id.sql' ),
4642 array( 'archive', 'ar_text_id', 'patch-archive-text_id.sql' ),
@@ -238,20 +234,6 @@
239235 }
240236 }
241237
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 -
256238 /**
257239 * 1.4 betas were missing the 'binary' marker from logging.log_title,
258240 * which causes a collation mismatch error on joins in MySQL 4.1.
@@ -572,6 +554,81 @@
573555 }
574556 }
575557
 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+
576633 function do_all_updates() {
577634 global $wgNewTables, $wgNewFields, $wgRenamedTables;
578635
@@ -592,9 +649,6 @@
593650 flush();
594651 }
595652
596 - # Add default group data
597 - do_group_update(); flush();
598 -
599653 # Do schema updates which require special handling
600654 do_interwiki_update(); flush();
601655 do_index_update(); flush();
@@ -615,6 +669,7 @@
616670 do_drop_img_type(); flush();
617671
618672 do_user_unique_update(); flush();
 673+ do_user_groups_update(); flush();
619674
620675 initialiseMessages(); flush();
621676 }
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
127 + native
Added: svn:keywords
228 + Author Date Id Revision
Index: trunk/phase3/maintenance/tables.sql
@@ -114,17 +114,25 @@
115115 -- this allows sites with a shared user table to have different
116116 -- permissions assigned to a user in each project.
117117 --
 118+-- This table replaces the old user_rights field which used a
 119+-- comma-separated blob.
118120 --
119 -CREATE TABLE /*$wgDBprefix*/user_rights (
 121+CREATE TABLE /*$wgDBprefix*/user_groups (
120122 -- Key to user_id
121 - ur_user int(5) unsigned NOT NULL,
 123+ ug_user int(5) unsigned NOT NULL default '0',
122124
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 '',
125134
126 - UNIQUE KEY ur_user (ur_user)
127 -
 135+ PRIMARY KEY (ug_user,ug_group),
 136+ KEY (ug_group)
128137 ) TYPE=InnoDB;
129138
130139 -- The following table is no longer needed with Enotif >= 2.00
@@ -795,19 +803,11 @@
796804
797805
798806 -- 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 @@
566566 print "<li>Creating tables...";
567567 dbsource( "../maintenance/tables.sql", $wgDatabase );
568568 dbsource( "../maintenance/interwiki.sql", $wgDatabase );
569 - dbsource( "../maintenance/archives/patch-userlevels-defaultgroups.sql", $wgDatabase );
570569 print " done.</li>\n";
571570
572571 print "<li>Initializing data...";
@@ -585,9 +584,10 @@
586585 if ( 0 == $u->idForName() ) {
587586 $u->addToDatabase();
588587 $u->setPassword( $conf->getSysopPass() );
589 - $u->addRight( "sysop" );
590 - $u->addRight( "bureaucrat" );
591588 $u->saveSettings();
 589+
 590+ $u->addGroup( "sysop" );
 591+ $u->addGroup( "bureaucrat" );
592592
593593 print "<li>Created sysop account <tt>" .
594594 htmlspecialchars( $conf->SysopName ) . "</tt>.</li>\n";
Index: trunk/phase3/includes/SpecialUserrights.php
@@ -10,7 +10,6 @@
1111
1212 /** */
1313 require_once('HTMLForm.php');
14 -require_once('Group.php');
1514
1615 /** Entry point */
1716 function wfSpecialUserrights() {
@@ -73,12 +72,12 @@
7473 $u = User::newFromName($username);
7574
7675 if(is_null($u)) {
77 - $wgOut->addHTML('<p>'.wfMsg('nosuchusershort',$username).'</p>');
 76+ $wgOut->addWikiText( wfMsg( 'nosuchusershort', htmlspecialchars( $username ) ) );
7877 return;
7978 }
8079
8180 if($u->getID() == 0) {
82 - $wgOut->addHTML('<p>'.wfMsg('nosuchusershort',$username).'</p>');
 81+ $wgOut->addWikiText( wfMsg( 'nosuchusershort', htmlspecialchars( $username ) ) );
8382 return;
8483 }
8584
@@ -93,10 +92,17 @@
9493 $newGroups = array_merge($newGroups, $addgroup);
9594 }
9695 $newGroups = array_unique( $newGroups );
 96+
 97+ wfDebug( 'oldGroups: ' . print_r( $oldGroups, true ) );
 98+ wfDebug( 'newGroups: ' . print_r( $newGroups, true ) );
9799
98100 // 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+ }
101107
102108 $log = new LogPage( 'rights' );
103109 $log->addEntry( 'rights', Title::makeTitle( NS_USER, $u->getName() ), '', array( $this->makeGroupNameList( $oldGroups ),
@@ -104,15 +110,7 @@
105111 }
106112
107113 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 );
117115 }
118116
119117 /**
@@ -126,7 +124,10 @@
127125 $wgOut->addHTML( "<form name=\"uluser\" action=\"$this->action\" method=\"post\">\n" );
128126 $wgOut->addHTML( $this->fieldset( 'lookup-user',
129127 $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' ) ) )
131132 ));
132133 $wgOut->addHTML( "</form>\n" );
133134 }
@@ -139,30 +140,30 @@
140141 global $wgOut;
141142
142143 $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 ) ) );
146146 return;
147147 }
148 -
149 - if($user->getID() == 0) {
150 - $wgOut->addHTML('<p>'.wfMsg('nosuchusershort', $encUser).'</p>');
151 - return;
152 - }
153148
154149 $groups = $user->getGroups();
155150
156151 $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 ) ) .
160158 '<table border="0" align="center"><tr><td>'.
161159 HTMLSelectGroups('member', $this->mName.'-groupsmember', $groups,true,6).
162160 '</td><td>'.
163161 HTMLSelectGroups('available', $this->mName.'-groupsavailable', $groups,true,6,true).
164162 '</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' ) ) )
167168 ));
168169 $wgOut->addHTML( "</form>\n" );
169170 }
Index: trunk/phase3/includes/HTMLForm.php
@@ -120,26 +120,34 @@
121121 * @param boolean $reverse If true, multiple select will hide selected elements (default false).
122122 */
123123 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 ) );
126126
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 );
131136
132 - foreach ( $groups as $id => $g ) {
133 - if($multiple) {
 137+ foreach( $groups as $group ) {
 138+ $attribs = array( 'value' => $group );
 139+ if( $multiple ) {
134140 // 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;
137143 }
138144 } 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+ }
142148 }
 149+ $out .= wfElement( 'option', $attribs, User::getGroupName( $group ) ) . "\n";
143150 }
 151+
144152 $out .= "</select>\n";
145153 return $out;
146154 }
Index: trunk/phase3/includes/DefaultSettings.php
@@ -671,13 +671,26 @@
672672 $wgAutoblockExpiry = 86400; # Number of seconds before autoblock entries expire
673673
674674 /**
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.
679680 */
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+);
681692
 693+
 694+
682695 # Proxy scanner settings
683696 #
684697
@@ -1319,15 +1332,7 @@
13201333 # $wgLocaltimezone = 'CET';
13211334 $wgLocaltimezone = null;
13221335
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;
13301336
1331 -
13321337 /**
13331338 * When translating messages with wfMsg(), it is not always clear what should be
13341339 * considered UI messages and what shoud be content messages.
Index: trunk/phase3/includes/SpecialPage.php
@@ -72,7 +72,7 @@
7373 'Lockdb' => new SpecialPage( 'Lockdb', 'siteadmin' ),
7474 'Unlockdb' => new SpecialPage( 'Unlockdb', 'siteadmin' ),
7575 'Userrights' => new SpecialPage( 'Userrights', 'userrights' ),
76 - 'Groups' => new SpecialPage( 'Groups' ),
 76+ // 'Groups' => new SpecialPage( 'Groups' ), # currently borken
7777 );
7878
7979 global $wgUseValidation ;
Index: trunk/phase3/includes/Title.php
@@ -958,7 +958,7 @@
959959 /** If anon users can create an account,
960960 they need to reach the login page first! */
961961 if( $wgUser->isAllowed( 'createaccount' )
962 - && $this->mId == NS_SPECIAL
 962+ && $this->getNamespace() == NS_SPECIAL
963963 && $this->getText() == 'Userlogin' ) {
964964 return true;
965965 }
Index: trunk/phase3/includes/SpecialStatistics.php
@@ -13,7 +13,7 @@
1414 $fname = 'wfSpecialStatistics';
1515
1616 $dbr =& wfGetDB( DB_SLAVE );
17 - extract( $dbr->tableNames( 'page', 'site_stats', 'user', 'user_rights' ) );
 17+ extract( $dbr->tableNames( 'page', 'site_stats', 'user', 'user_groups' ) );
1818
1919 $sql = "SELECT COUNT(page_namespace) AS total FROM $page";
2020 $res = $dbr->query( $sql, $fname );
@@ -44,7 +44,7 @@
4545 $row = $dbr->fetchObject( $res );
4646 $total = $row->total;
4747
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'";
4949 $res = $dbr->query( $sql, $fname );
5050 $row = $dbr->fetchObject( $res );
5151 $admins = $row->total;
Index: trunk/phase3/includes/SpecialListusers.php
@@ -64,18 +64,22 @@
6565 // form header
6666 $out = '<form method="get" action="'.$action.'">' .
6767 '<input type="hidden" name="title" value="'.$special.'" />' .
68 - wfMsg( 'grouplevels-editgroup-name' ) . '<select name="group">';
 68+ wfMsg( 'groups-editgroup-name' ) . '<select name="group">';
6969
7070 // get all group names and IDs
71 - $groups =& Group::getAllGroups();
 71+ $groups = User::getAllGroups();
7272
7373 // we want a default empty group
7474 $out.= '<option value=""></option>';
7575
7676 // build the dropdown list menu using datas from the database
7777 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 ) );
8084 }
8185 $out .= '</select> ';
8286
@@ -89,24 +93,16 @@
9094
9195 function getSQL() {
9296 $dbr =& wfGetDB( DB_SLAVE );
93 - /* system showing possible actions for users
9497 $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' );
10298 $user_groups = $dbr->tableName( 'user_groups' );
10399
104100 $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 " .
106102 "FROM $user ".
107103 "LEFT JOIN $user_groups ON user_id =ug_user ";
108104
109105 if($this->requestedGroup != '') {
110 - $sql .= "WHERE ug_group = '" . IntVal( $this->requestedGroup ) . "' ";
 106+ $sql .= 'WHERE ug_group = ' . $dbr->addQuotes( $this->requestedGroup ) . ' ';
111107 if($this->requestedUser != '') {
112108 $sql .= "AND user_name = " . $dbr->addQuotes( $this->requestedUser ) . ' ';
113109 }
@@ -138,10 +134,7 @@
139135 function clearGroups() {
140136 $this->concatGroups = '';
141137 }
142 -/*
143 - var $previousResult = false;
144 - var $concatGroups = '';
145 -*/
 138+
146139 function formatResult( $skin, $result ) {
147140 global $wgContLang;
148141 $name = false;
@@ -155,9 +148,9 @@
156149 }
157150
158151 if( is_object( $result ) && $result->type != '') {
159 - $group = Group::newFromId( intval( strstr( $result->type, ' ' ) ) );
 152+ $group = $result->value;
160153 if ( $group ) {
161 - $groupName = $group->getExpandedName();
 154+ $groupName = User::getGroupName( $group );
162155 $this->appendGroups( $skin->makeLink( wfMsgForContent( 'administrators' ), $groupName ) );
163156 }
164157 }
Index: trunk/phase3/includes/User.php
@@ -9,7 +9,6 @@
1010 *
1111 */
1212 require_once( 'WatchedItem.php' );
13 -require_once( 'Group.php' );
1413
1514 # Number of characters in user_token field
1615 define( 'USER_TOKEN_LENGTH', 32 );
@@ -32,9 +31,7 @@
3332 var $mToken;
3433 var $mRealName;
3534 var $mHash;
36 - /** Array of group id the user belong to */
3735 var $mGroups;
38 - /**#@-*/
3936
4037 /** Construct using User:loadDefaults() */
4138 function User() {
@@ -563,7 +560,7 @@
564561 * Load a user from the database
565562 */
566563 function loadFromDatabase() {
567 - global $wgCommandLineMode, $wgAnonGroupId, $wgLoggedInGroupId;
 564+ global $wgCommandLineMode;
568565 $fname = "User::loadFromDatabase";
569566
570567 # Counter-intuitive, breaks various things, use User::setLoaded() if you want to suppress
@@ -577,15 +574,9 @@
578575 $this->mId = IntVal( $this->mId );
579576
580577 /** Anonymous user */
581 - if(!$this->mId) {
 578+ if( !$this->mId ) {
582579 /** 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( '*' ) );
590581 $this->mDataLoaded = true;
591582 return;
592583 } # the following stuff is for non-anonymous users only
@@ -607,31 +598,16 @@
608599 $this->mTouched = wfTimestamp(TS_MW,$s->user_touched);
609600 $this->mToken = $s->user_token;
610601
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;
621609 }
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 );
636612 }
637613
638614 $this->mDataLoaded = true;
@@ -830,24 +806,75 @@
831807 $this->loadFromDatabase();
832808 return $this->mRights;
833809 }
834 -
835 - function addRight( $rname ) {
836 - $this->loadFromDatabase();
837 - array_push( $this->mRights, $rname );
838 - $this->invalidateCache();
839 - }
840810
 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+ */
841816 function getGroups() {
842817 $this->loadFromDatabase();
843818 return $this->mGroups;
844819 }
845820
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+
849853 $this->invalidateCache();
 854+ $this->saveSettings();
850855 }
 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+ }
851877
 878+
852879 /**
853880 * A more legible check for non-anonymousness.
854881 * Returns true if the user is not an anonymous visitor.
@@ -1167,23 +1194,7 @@
11681195 'user_id' => $this->mId
11691196 ), $fname
11701197 );
1171 - $dbw->set( 'user_rights', 'ur_rights', implode( ',', $this->mRights ),
1172 - 'ur_user='. $this->mId, $fname );
11731198 $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 - }
11881199 }
11891200
11901201
@@ -1226,21 +1237,6 @@
12271238 ), $fname
12281239 );
12291240 $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 - }
12451241 }
12461242
12471243 function spreadBlock() {
@@ -1591,6 +1587,51 @@
15921588 return false;
15931589 return true;
15941590 }
 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 == "&lt;$key&gt;" ) {
 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+
15951636 }
15961637
15971638 ?>
Index: trunk/phase3/RELEASE-NOTES
@@ -272,6 +272,7 @@
273273 * (bug 2309) Allow templates and template parameters in HTML attribute zone,
274274 with proper validation checks. (regression from fix for 2304)
275275 * Disallow close tags and enforce empty tags for <hr> and <br>
 276+* Changed user_groups format quite a bit.
276277
277278
278279 === Caveats ===

Status & tagging log