*/
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.
*
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
*
* 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( '&',
'mEmailTokenExpires',
'mRegistration',
'mEditCount',
- // user_group table
+ // user_groups table
'mGroups',
// user_properties table
'mOptionOverrides',
* Lazy-initialized variables, invalidated with clearInstanceCache
*/
var $mNewtalk, $mDatePreference, $mBlockedby, $mHash, $mRights,
- $mBlockreason, $mEffectiveGroups, $mBlockedGlobally,
+ $mBlockreason, $mEffectiveGroups, $mFormerGroups, $mBlockedGlobally,
$mLocked, $mHideName, $mOptions;
/**
}
}
+ /**
+ * 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
$this->mSkin = null;
$this->mRights = null;
$this->mEffectiveGroups = null;
- $this->mOptions = null;
+ $this->mOptions = null;
if ( $reloadFrom ) {
$this->mLoadedItems = array();
}
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
'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 ) );
// 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' ),
// 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' ),
--- /dev/null
+-- 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*/;
--- /dev/null
+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 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,
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