Added one-time promote support via Autopromote::autopromoteOnceHook function. This...
authorAaron Schulz <aaron@users.mediawiki.org>
Sat, 25 Jun 2011 02:52:30 +0000 (02:52 +0000)
committerAaron Schulz <aaron@users.mediawiki.org>
Sat, 25 Jun 2011 02:52:30 +0000 (02:52 +0000)
includes/Autopromote.php
includes/DefaultSettings.php
includes/User.php
includes/installer/MysqlUpdater.php
includes/installer/SqliteUpdater.php
maintenance/archives/patch-user_former_groups.sql [new file with mode: 0644]
maintenance/postgres/archives/patch-user_former_groups.sql [new file with mode: 0644]
maintenance/postgres/tables.sql
maintenance/tables.sql

index e630db9..d9c1f5f 100644 (file)
@@ -5,6 +5,41 @@
  */
 
 class Autopromote {
+       /**
+        * A function which may be assigned to a hook in order to check 
+        *   autopromotion of the current user (\ref $wgUser) to the specified 
+        *   group.
+        *    
+        * Contrary to autopromotion by \ref $wgAutopromote, the group will be 
+        *   possible to remove manually via Special:UserRights. In such case it
+        *   will not be re-added autmoatically. The user will also not lose the
+        *   group if they no longer meet the criteria.
+        *   
+        * Example configuration: 
+        * \code $wgHooks['ArticleSaveComplete'][] = array (
+        *     'Autopromote::autopromoteOnceHook', 
+        *     array( 'somegroup' => array(APCOND_EDITCOUNT, 200) )
+        * ); \endcode
+        * 
+        * The second array should be of the same format as \ref $wgAutopromote.
+        * 
+        * This funciton simply runs User::autopromoteOnce() on $wgUser. You may
+        *   run this method from your custom function if you wish.  
+        * 
+        * @param $criteria array Groups and conditions which must be met in order to
+        *   aquire these groups. Array of the same format as \ref $wgAutopromote.
+        *               
+        * @return Always true.
+        * 
+        * @see User::autopromoteOnce()
+        * @see $wgAutopromote
+        */
+       public static function autopromoteOnceHook($criteria) {
+               global $wgUser; 
+               $wgUser->autopromoteOnce($criteria); 
+               return true; 
+       }
+       
        /**
         * Get the groups for the given user based on $wgAutopromote.
         *
@@ -26,6 +61,41 @@ class Autopromote {
 
                return $promote;
        }
+       
+       /**
+        * Get the groups for the given user based on the given criteria.
+        * 
+        * Does not return groups the user already belongs to or has once belonged.
+        * 
+        * @param $user The user to get the groups for
+        * @param $criteria array Groups and conditions the user must meet in order
+        *   to be promoted to these groups. Array of the same format as 
+        *   \ref $wgAutopromote. 
+        *               
+        * @return array Groups the user should be promoted to.
+        */
+       public static function getAutopromoteOnceGroups( User $user, $criteria ) {
+               $promote = array();
+               
+               //get the current groups 
+               $currentGroups = $user->getGroups();
+               
+               foreach( $criteria as $group => $cond ) {
+                       //do not check if the user's already a member
+                       if ( in_array($group, $currentGroups))
+                               continue;
+               
+                       //do not autopromote if the user has belonged to the group
+                       $formerGroups = $user->getFormerGroups();
+                       if ( in_array($group, $formerGroups) )
+                               continue;
+                               
+                       //finally - check the conditions 
+                       if ( self::recCheckCondition($cond, $user) )
+                               $promote[] = $group; 
+               }
+               return $promote;
+       }
 
        /**
         * Recursively check a condition.  Conditions are in the form
index a4c7cb2..ad7013b 100644 (file)
@@ -3513,6 +3513,12 @@ $wgAutoConfirmCount = 0;
  *
  * If $wgEmailAuthentication is off, APCOND_EMAILCONFIRMED will be true for any
  * user who has provided an e-mail address.
+ * 
+ * If the groups should be removable, consider using 
+ *   Autopromote::autopromoteOnceHook() instead.
+ * 
+ * @see Autopromote::autopromoteOnceHook()
+ * @see User::autopromoteOnce()
  */
 $wgAutopromote = array(
        'autoconfirmed' => array( '&',
index 23938d6..c2742a2 100644 (file)
@@ -71,7 +71,7 @@ class User {
                'mEmailTokenExpires',
                'mRegistration',
                'mEditCount',
-               // user_group table
+               // user_groups table
                'mGroups',
                // user_properties table
                'mOptionOverrides',
@@ -182,7 +182,7 @@ class User {
         * Lazy-initialized variables, invalidated with clearInstanceCache
         */
        var $mNewtalk, $mDatePreference, $mBlockedby, $mHash, $mRights,
-               $mBlockreason, $mEffectiveGroups, $mBlockedGlobally,
+               $mBlockreason, $mEffectiveGroups, $mFormerGroups, $mBlockedGlobally,
                $mLocked, $mHideName, $mOptions;
 
        /**
@@ -1102,6 +1102,33 @@ class User {
                }
        }
 
+       /**
+        * Add the user to the group if he/she meets given criteria.
+        * 
+        * Contrary to autopromotion by \ref $wgAutopromote, the group will be 
+        *   possible to remove manually via Special:UserRights. In such case it
+        *   will not be re-added autmoatically. The user will also not lose the
+        *   group if they no longer meet the criteria.
+        *   
+        * @param $criteria array Groups and conditions the user must meet in order
+        *   to be promoted to these groups. Array of the same format as 
+        *   \ref $wgAutopromote. 
+        *   
+        * @return array Array of groups the user has been promoted to.  
+        * 
+        * @see $wgAutopromote
+        * @see Autopromote::autopromoteOnceHook()
+        */
+       public function autopromoteOnce( $criteria ) {          
+               if ($this->getId())     {
+                       $toPromote = Autopromote::getAutopromoteOnceGroups($this, $criteria);
+                       foreach($toPromote as $group)
+                               $this->addGroup($group);
+                       return $toPromote;
+               }
+               return array(); 
+       }
+       
        /**
         * Clear various cached data stored in this object.
         * @param $reloadFrom String Reload user and user_groups table data from a
@@ -1116,7 +1143,7 @@ class User {
                $this->mSkin = null;
                $this->mRights = null;
                $this->mEffectiveGroups = null;
-               $this->mOptions = null;
+               $this->mOptions = null; 
 
                if ( $reloadFrom ) {
                        $this->mLoadedItems = array();
@@ -2240,7 +2267,31 @@ class User {
                }
                return $this->mEffectiveGroups;
        }
-
+       
+       /**
+        * Returns the groups the user has belonged to. 
+        * 
+        * The user may still belong to the returned groups. Compare with getGroups().
+        * 
+        * The function will not return groups the user had belonged to before MW 1.17
+        *  
+        * @return array Names of the groups the user has belonged to. 
+        */
+       function getFormerGroups() {
+               if(is_null($this->mFormerGroups)) {
+                       $dbr = wfGetDB( DB_MASTER );
+                       $res = $dbr->select( 'user_former_groups',
+                               array( 'ufg_group' ),
+                               array( 'ufg_user' => $this->mId ),
+                               __METHOD__ );
+                       $this->mFormerGroups = array();
+                       while( $row = $dbr->fetchObject( $res ) ) {
+                               $this->mFormerGroups[] = $row->ufg_group;
+                       }
+               }       
+               return $this->mFormerGroups;
+       }
+       
        /**
         * Get the user's edit count.
         * @return Int
@@ -2297,6 +2348,14 @@ class User {
                                        'ug_user'  => $this->getID(),
                                        'ug_group' => $group,
                                ), __METHOD__ );
+                       //remember that the user has had this group
+                       $dbw->insert( 'user_former_groups',
+                               array(
+                                       'ufg_user'  => $this->getID(),
+                                       'ufg_group' => $group,
+                               ),
+                               __METHOD__,
+                               array( 'IGNORE' ) );
                }
                $this->loadGroups();
                $this->mGroups = array_diff( $this->mGroups, array( $group ) );
index b4e9ac5..eb8a73d 100644 (file)
@@ -162,6 +162,7 @@ class MysqlUpdater extends DatabaseUpdater {
 
                        // 1.17
                        array( 'addTable', 'iwlinks',                           'patch-iwlinks.sql' ),
+                       array( 'addTable', 'user_former_groups',             'patch-user_former_groups.sql'),
                        array( 'addIndex', 'iwlinks', 'iwl_prefix_title_from',  'patch-rename-iwl_prefix.sql' ),
                        array( 'addField', 'updatelog',     'ul_value',         'patch-ul_value.sql' ),
                        array( 'addField', 'interwiki',     'iw_api',           'patch-iw_api_and_wikiid.sql' ),
index cd7f717..b3a8a21 100644 (file)
@@ -43,6 +43,7 @@ class SqliteUpdater extends DatabaseUpdater {
 
                        // 1.17
                        array( 'addTable', 'iwlinks',                            'patch-iwlinks.sql' ),
+                       array( 'addTable', 'user_former_groups',             'patch-user_former_groups.sql'),
                        array( 'addIndex', 'iwlinks',   'iwl_prefix_title_from', 'patch-rename-iwl_prefix.sql' ),
                        array( 'addField', 'updatelog', 'ul_value',              'patch-ul_value.sql' ),
                        array( 'addField', 'interwiki',     'iw_api',           'patch-iw_api_and_wikiid.sql' ),
diff --git a/maintenance/archives/patch-user_former_groups.sql b/maintenance/archives/patch-user_former_groups.sql
new file mode 100644 (file)
index 0000000..fdaaf8f
--- /dev/null
@@ -0,0 +1,10 @@
+-- Stores the groups the user has once belonged to. 
+-- The user may still belong these groups. Check user_groups.
+CREATE TABLE /*_*/user_former_groups (
+  -- Key to user_id
+  ufg_user int unsigned NOT NULL default 0,
+  ufg_group varbinary(16) NOT NULL default '',
+  
+  PRIMARY KEY (ufg_user,ufg_group),
+  KEY (ufg_group)
+) /*$wgDBTableOptions*/;
diff --git a/maintenance/postgres/archives/patch-user_former_groups.sql b/maintenance/postgres/archives/patch-user_former_groups.sql
new file mode 100644 (file)
index 0000000..9317a20
--- /dev/null
@@ -0,0 +1,5 @@
+CREATE TABLE user_former_groups (
+  ufg_user   INTEGER      NULL  REFERENCES mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+  ufg_group  TEXT     NOT NULL
+);
+CREATE UNIQUE INDEX user_former_groups_unique ON user_former_groups (ufg_user, ufg_group);
index 3482039..c942855 100644 (file)
@@ -54,6 +54,12 @@ CREATE TABLE user_groups (
 );
 CREATE UNIQUE INDEX user_groups_unique ON user_groups (ug_user, ug_group);
 
+CREATE TABLE user_former_groups (
+  ufg_user   INTEGER      NULL  REFERENCES mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+  ufg_group  TEXT     NOT NULL
+);
+CREATE UNIQUE INDEX user_former_groups_unique ON user_former_groups (ufg_user, ufg_group);
+
 CREATE TABLE user_newtalk (
   user_id              INTEGER      NOT NULL  REFERENCES mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
   user_ip              TEXT             NULL,
index cee01d5..4bfa703 100644 (file)
@@ -164,6 +164,16 @@ CREATE TABLE /*_*/user_groups (
 CREATE UNIQUE INDEX /*i*/ug_user_group ON /*_*/user_groups (ug_user,ug_group);
 CREATE INDEX /*i*/ug_group ON /*_*/user_groups (ug_group);
 
+-- Stores the groups the user has once belonged to. 
+-- The user may still belong these groups. Check user_groups.
+CREATE TABLE /*_*/user_former_groups (
+  -- Key to user_id
+  ufg_user int unsigned NOT NULL default 0,
+  ufg_group varbinary(16) NOT NULL default ''
+) /*$wgDBTableOptions*/;
+
+CREATE UNIQUE INDEX /*i*/ufg_user_group ON /*_*/user_former_groups (ufg_user,ufg_group);
+CREATE INDEX /*i*/ufg_group ON /*_*/user_former_groups (ufg_group);
 
 --
 -- Stores notifications of user talk page changes, for the display