r49458 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r49457‎ | r49458 | r49459 >
Date:09:45, 14 April 2009
Author:werdna
Status:deferred (Comments)
Tags:
Comment:
Basic implementation of global preferences. For now, a simple on/off toggle per-wiki.

Still need some way of letting users opt into global preferences without overwriting their existing global preferences (I suspect the best way to do this would be to just run the maintenance script for user preference migration.
Modified paths:
  • /branches/preferences-work/extensions/CentralAuth/CentralAuth.i18n.php (modified) (history)
  • /branches/preferences-work/extensions/CentralAuth/CentralAuth.php (modified) (history)
  • /branches/preferences-work/extensions/CentralAuth/CentralAuthHooks.php (modified) (history)
  • /branches/preferences-work/extensions/CentralAuth/CentralAuthUser.php (modified) (history)
  • /branches/preferences-work/extensions/CentralAuth/central-auth.sql (modified) (history)
  • /branches/preferences-work/extensions/CentralAuth/db_patches/patch-global_properties.sql (added) (history)
  • /branches/preferences-work/phase3/docs/hooks.txt (modified) (history)
  • /branches/preferences-work/phase3/includes/Preferences.php (modified) (history)
  • /branches/preferences-work/phase3/includes/User.php (modified) (history)

Diff [purge]

Index: branches/preferences-work/phase3/docs/hooks.txt
@@ -1397,6 +1397,9 @@
13981398 $ip: User's IP address
13991399 &$blocked: Whether the user is blocked, to be modified by the hook
14001400
 1401+'UserLoadAfterLoadFromSession': called to authenticate users on external/environmental means; occurs after session is loaded
 1402+$user: user object being loaded
 1403+
14011404 'UserLoadDefaults': called when loading a default user
14021405 $user: user object
14031406 $name: user name
@@ -1409,8 +1412,9 @@
14101413 $user: user object being loaded
14111414 &$result: set this to a boolean value to abort the normal authentification process
14121415
1413 -'UserLoadAfterLoadFromSession': called to authenticate users on external/environmental means; occurs after session is loaded
1414 -$user: user object being loaded
 1416+'UserLoadOptions': when user options/preferences are being loaded from the database.
 1417+$user: User object
 1418+&$options: Options, can be modified.
14151419
14161420 'UserLoginComplete': after a user has logged in
14171421 $user: the user object that was created on login
@@ -1450,6 +1454,10 @@
14511455 'UserSaveSettings': called when saving user settings
14521456 $user: User object
14531457
 1458+'UserSaveOptions': Called just before saving user preferences/options.
 1459+$user: User object
 1460+&$options: Options, modifiable
 1461+
14541462 'UserSetCookies': called when setting user cookies
14551463 $user: User object
14561464 &$session: session array, will be added to $_SESSION
Index: branches/preferences-work/phase3/includes/User.php
@@ -3391,6 +3391,8 @@
33923392 $this->load();
33933393 if ($this->mOptionsLoaded || !$this->getId() )
33943394 return;
 3395+
 3396+ $this->mOptions = self::getDefaultOptions();
33953397
33963398 // Load from database
33973399 $dbr = wfGetDB( DB_SLAVE );
@@ -3401,14 +3403,13 @@
34023404 __METHOD__
34033405 );
34043406
3405 - global $wgDefaultUserOptions;
3406 - $this->mOptions = self::getDefaultOptions();
3407 -
34083407 while( $row = $dbr->fetchObject( $res ) ) {
34093408 $this->mOptions[$row->up_property] = unserialize( $row->up_value );
34103409 }
34113410
34123411 $this->mOptionsLoaded = true;
 3412+
 3413+ wfRunHooks( 'UserLoadOptions', array( $this, &$this->mOptions ) );
34133414 }
34143415
34153416 protected function saveOptions() {
@@ -3417,7 +3418,14 @@
34183419
34193420 $insert_rows = array();
34203421
3421 - foreach( $this->mOptions as $key => $value ) {
 3422+ $saveOptions = $this->mOptions;
 3423+
 3424+ // Allow hooks to abort, for instance to save to a global profile.
 3425+ // Reset options to default state before saving.
 3426+ if (!wfRunHooks( 'UserSaveOptions', array($this, &$saveOptions) ) )
 3427+ return;
 3428+
 3429+ foreach( $saveOptions as $key => $value ) {
34223430 $ser = serialize($value);
34233431
34243432 if ( is_null(self::getDefaultOption($key)) ||
Index: branches/preferences-work/phase3/includes/Preferences.php
@@ -741,6 +741,8 @@
742742 'label-message' => 'tog-uselivepreview',
743743 );
744744
 745+ wfRunHooks( 'GetPreferences', array( $user, &$defaultPreferences ) );
 746+
745747 ## Prod in defaults from the user
746748 global $wgDefaultUserOptions;
747749 foreach( $defaultPreferences as $name => &$info ) {
@@ -761,8 +763,6 @@
762764 $info['default'] = $globalDefault;
763765 }
764766 }
765 -
766 - wfRunHooks( 'GetPreferences', array( $user, &$defaultPreferences ) );
767767
768768 self::$defaultPreferences = $defaultPreferences;
769769
@@ -997,9 +997,10 @@
998998 global $wgUser, $wgEmailAuthentication, $wgEnableEmail;
999999
10001000 // Filter input
1001 - foreach( $formData as $name => &$value ) {
 1001+ foreach( array_keys($formData) as $name ) {
10021002 if ( isset(self::$saveFilters[$name]) ) {
1003 - $value = call_user_func( self::$saveFilters[$name], $value, $formData );
 1003+ $formData[$name] =
 1004+ call_user_func( self::$saveFilters[$name], $formData[$name], $formData );
10041005 }
10051006 }
10061007
@@ -1046,8 +1047,7 @@
10471048
10481049 foreach( $saveBlacklist as $b )
10491050 unset( $formData[$b] );
1050 -
1051 - // Reset options to default state before saving.
 1051+
10521052 // Keeps old preferences from interfering due to back-compat
10531053 // code, etc.
10541054 $wgUser->resetOptions();
Index: branches/preferences-work/extensions/CentralAuth/central-auth.sql
@@ -164,3 +164,13 @@
165165 PRIMARY KEY (ggr_group),
166166 KEY (ggr_set)
167167 ) /*$wgDBTableOptions*/;
 168+
 169+-- Allow users to share preferences across wikis
 170+CREATE TABLE global_preferences (
 171+ gp_user int(11) NOT NULL,
 172+ gp_key varbinary(255) NOT NULL,
 173+ gp_value BLOB,
 174+
 175+ PRIMARY KEY (up_user,up_property),
 176+ KEY (up_property)
 177+) /*$wgDBTableOptions*/;
Index: branches/preferences-work/extensions/CentralAuth/db_patches/patch-global_properties.sql
@@ -0,0 +1,9 @@
 2+-- Allow users to share preferences across wikis
 3+CREATE TABLE global_user_properties (
 4+ gp_user int(11) NOT NULL,
 5+ gp_property varbinary(255) NOT NULL,
 6+ gp_value BLOB,
 7+
 8+ PRIMARY KEY (gp_user,gp_property),
 9+ KEY (gp_property)
 10+) /*$wgDBTableOptions*/;
Index: branches/preferences-work/extensions/CentralAuth/CentralAuthUser.php
@@ -18,7 +18,7 @@
1919 */
2020 /*private*/ var $mName;
2121 /*private*/ var $mStateDirty = false;
22 - /*private*/ var $mVersion = 2;
 22+ /*private*/ var $mVersion = 3;
2323 /*private*/ var $mDelayInvalidation = 0;
2424
2525 static $mCacheVars = array(
@@ -33,6 +33,7 @@
3434 'mAuthenticationTimestamp',
3535 'mGroups',
3636 'mRights',
 37+ 'mProperties',
3738
3839 # Store the string list instead of the array, to save memory, and
3940 # avoid unserialize() overhead
@@ -93,6 +94,7 @@
9495 unset( $this->mGroups );
9596 unset( $this->mAttachedArray );
9697 unset( $this->mAttachedList );
 98+ unset( $this->mProperties );
9799 }
98100
99101 /**
@@ -190,6 +192,87 @@
191193 $this->mRights = $rights;
192194 $this->mGroups = array_keys($groups);
193195 }
 196+
 197+ /**
 198+ * Load user properties from the database.
 199+ */
 200+ protected function loadProperties() {
 201+ if ( isset($this->mProperties) ) return;
 202+
 203+ wfDebugLog( 'CentralAuth', "Loading properties for global user {$this->mName}" );
 204+
 205+ $dbr = self::getCentralDB();
 206+
 207+ $res = $dbr->select(
 208+ 'global_user_properties', array( 'gp_property', 'gp_value' ),
 209+ array( 'gp_user' => $this->getId() ), __METHOD__ );
 210+
 211+ $properties = array();
 212+
 213+ while( $row = $dbr->fetchObject( $res ) ) {
 214+ $properties[$row->gp_property] = unserialize($row->gp_value);
 215+ }
 216+
 217+ $this->mProperties = $properties;
 218+ }
 219+
 220+ function saveProperties() {
 221+ $this->loadProperties();
 222+ $dbw = self::getCentralDB();
 223+
 224+ $insert_rows = array();
 225+
 226+ foreach( $this->mProperties as $key => $value ) {
 227+ if ( is_null(User::getDefaultOption($key)) ||
 228+ $value != User::getDefaultOption( $key ) ) {
 229+ $ser = serialize($value);
 230+ $insert_rows[] = array(
 231+ 'gp_user' => $this->getId(),
 232+ 'gp_property' => $key,
 233+ 'gp_value' => $ser,
 234+ );
 235+ }
 236+ }
 237+
 238+ $dbw->begin();
 239+
 240+ $dbw->delete( 'global_user_properties',
 241+ array( 'gp_user' => $this->getId() ),
 242+ __METHOD__ );
 243+ $dbw->insert( 'global_user_properties', $insert_rows, __METHOD__ );
 244+
 245+ $dbw->commit();
 246+
 247+ $this->invalidateCache();
 248+ }
 249+
 250+ function setProperty( $key, $value ) {
 251+ $this->loadProperties();
 252+ $this->mProperties[$key] = $value;
 253+ $this->mStateDirty = true;
 254+ }
 255+
 256+ function setProperties( $properties, $method = 'replace' ) {
 257+ $this->loadProperties();
 258+ if ($method == 'replace') {
 259+ $this->mProperties = $properties;
 260+ } elseif ($method == 'insert') {
 261+ $this->mProperties = array_merge( $this->mProperties, $properties );
 262+ }
 263+
 264+ $this->mStateDirty = true;
 265+ }
 266+
 267+ function getProperties() {
 268+ $this->loadProperties();
 269+ return $this->mProperties;
 270+ }
 271+
 272+ function getProperty( $name ) {
 273+ $properties = $this->getProperties();
 274+
 275+ return $properties[$name];
 276+ }
194277
195278 /**
196279 * Load user state from a joined globaluser/localuser row
@@ -266,6 +349,7 @@
267350 $this->loadState();
268351 $this->loadAttached();
269352 $this->loadGroups();
 353+ $this->loadProperties();
270354
271355 $obj = array();
272356 foreach( self::$mCacheVars as $var ) {
Index: branches/preferences-work/extensions/CentralAuth/CentralAuth.php
@@ -172,6 +172,8 @@
173173 $wgHooks['UserLoadDefaults'][] = 'CentralAuthHooks::onUserLoadDefaults';
174174 $wgHooks['getUserPermissionsErrorsExpensive'][] = 'CentralAuthHooks::onGetUserPermissionsErrorsExpensive';
175175 $wgHooks['MakeGlobalVariablesScript'][] = 'CentralAuthHooks::onMakeGlobalVariablesScript';
 176+$wgHooks['UserSaveOptions'][] = 'CentralAuthHooks::onSavePreferences';
 177+$wgHooks['UserLoadOptions'][] = 'CentralAuthHooks::onUserLoadOptions';
176178
177179 // For interaction with the Special:Renameuser extension
178180 $wgHooks['RenameUserWarning'][] = 'CentralAuthHooks::onRenameUserWarning';
@@ -219,6 +221,8 @@
220222 $wgLogActions['gblrights/groupprms3'] = 'centralauth-rightslog-entry-groupperms3';
221223 foreach( array( 'newset', 'setrename', 'setnewtype', 'setchange' ) as $type )
222224 $wgLogActionsHandlers["gblrights/{$type}"] = 'efHandleWikiSetLogEntry';
 225+
 226+$wgDefaultUserOptions['globalpreferences'] = true;
223227
224228 function efHandleWikiSetLogEntry( $type, $action, $title, $skin, $params, $filterWikilinks = false ) {
225229 wfLoadExtensionMessages('SpecialCentralAuth');
Index: branches/preferences-work/extensions/CentralAuth/CentralAuthHooks.php
@@ -83,6 +83,13 @@
8484 );
8585
8686 $preferences = array_insert_after( $preferences, $prefInsert, 'registrationdate' );
 87+
 88+ $preferences['globalpreferences'] =
 89+ array(
 90+ 'section' => 'personal',
 91+ 'label-message' => 'centralauth-prefs-global',
 92+ 'type' => 'toggle',
 93+ );
8794
8895 return true;
8996 }
@@ -555,4 +562,36 @@
556563 }
557564 return true;
558565 }
 566+
 567+ static function onSavePreferences( $user, &$preferences ) {
 568+ $centralUser = CentralAuthUser::getInstance( $user );
 569+
 570+ if ($centralUser->exists() && $centralUser->isAttached() &&
 571+ !empty($preferences['globalpreferences']) ) {
 572+ // Save preferences into the global account.
 573+
 574+ $centralUser->setProperties( $preferences, 'replace' );
 575+ $centralUser->saveProperties();
 576+
 577+ $preferences = array( 'globalpreferences' => true );
 578+
 579+ return true;
 580+ }
 581+
 582+ return true;
 583+ }
 584+
 585+ static function onUserLoadOptions( $user, &$preferences ) {
 586+ $centralUser = CentralAuthUser::getInstance( $user );
 587+
 588+ if ($centralUser->exists() && $centralUser->isAttached() &&
 589+ !empty($preferences['globalpreferences']) ) {
 590+ // Pull preferences from global account
 591+
 592+ $preferences = array_merge( $preferences, $centralUser->getProperties() );
 593+ $preferences['globalpreferences'] = true;
 594+ }
 595+
 596+ return true;
 597+ }
559598 }
Index: branches/preferences-work/extensions/CentralAuth/CentralAuth.i18n.php
@@ -195,6 +195,7 @@
196196 'centralauth-prefs-count-unattached' => 'Unconfirmed accounts with your name remain on $1 {{PLURAL:$1|project|projects}}.',
197197 'centralauth-prefs-detail-unattached' => 'This project site has not been confirmed as belonging to the global account.',
198198 'centralauth-prefs-manage' => 'Manage your global account',
 199+ 'centralauth-prefs-global' => 'Use these preferences on all projects',
199200
200201 // Interaction with Special:Renameuser
201202 'centralauth-renameuser-merged' => "User $1 has been migrated to the unified login system.

Comments

#Comment by Werdna (talk | contribs)   09:52, 14 April 2009

Hmm, also doesn't account for having different defaults across wikis.

#Comment by Werdna (talk | contribs)   05:44, 23 April 2009

Fixed up with a whitelist for saving later on r49491.

Status & tagging log