Wikia code/includes/User.php
From MediaWiki.org
< Wikia code | includes
Some removals of un-used Wikia core-hacks: http://dev.wikia.com/wiki/Special:Code/Wikia_Trunk/44954
Another simple removal: http://dev.wikia.com/wiki/Special:Code/Wikia_Trunk/44955
--- D:\Programming\SVN\mediawiki\branches\REL1_16\phase3\includes\User.php 2011-07-18 22:31:27.990234400 +0100 +++ D:\Programming\SVN\wikia\trunk\includes\User.php 2011-08-17 15:28:46.352539100 +0100 @@ -90,6 +90,8 @@ 'ccmeonemails', 'diffonly', 'showhiddencats', + 'searchsuggest', # Wikia + 'htmlemails', # Wikia 'noconvertlink', 'norollbackdiff', ); @@ -212,6 +214,7 @@ /** @name Lazy-initialized variables, invalidated with clearInstanceCache */ //@{ + var $mTheme; # Wikia - Skin chooser related var $mNewtalk, $mDatePreference, $mBlockedby, $mHash, $mSkin, $mRights, $mBlockreason, $mBlock, $mEffectiveGroups, $mBlockedGlobally, $mLocked, $mHideName, $mOptions; @@ -277,7 +280,7 @@ * @private */ function loadFromId() { - global $wgMemc; + global $wgMemc, $wgSharedDB; # Wikia if ( $this->mId == 0 ) { $this->loadDefaults(); return false; @@ -291,7 +294,26 @@ $data = false; } - if ( !$data ) { + $isExpired = false; + if( !empty( $wgSharedDB ) ) { + # Wikia + /* + * This code is responsible for re-invalidate user object data from database + * instead of memcache if user preferences had been changed on another wiki + */ + $isExpired = true; + if(!empty($data)) { + $_key = wfSharedMemcKey( "user_touched", $this->mId ); + $_touched = $wgMemc->get( $_key ); + if($_touched == null){ + $wgMemc->set( $_key, $data['mTouched'] ); + } else if( $_touched <= $data['mTouched'] ) { + $isExpired = false; + } + } + } + + if ( !$data || $isExpired ) { # Wikia wfDebug( "Cache miss for user {$this->mId}\n" ); # Load from DB if ( !$this->loadFromDatabase() ) { @@ -303,9 +325,11 @@ wfDebug( "Got user {$this->mId} from cache\n" ); # Restore from cache foreach ( self::$mCacheVars as $name ) { + if( isset( $data[$name] ) ) { $this->$name = $data[$name]; } } + } return true; } @@ -470,6 +494,22 @@ $s = $dbr->selectRow( 'user', array( 'user_id' ), array( 'user_name' => $nt->getText() ), __METHOD__ ); if ( $s === false ) { + $user_name = $nt->getText(); + wfRunHooks( 'UserNameLoadFromId', array( $user_name, &$s ) ); + } + + /* wikia change */ + if ( $s === false ) { + global $wgExternalAuthType; + if ( $wgExternalAuthType ) { + $mExtUser = ExternalUser::newFromName( $nt->getText() ); + if ( is_object( $mExtUser ) && ( 0 != $mExtUser->getId() ) ) { + $mExtUser->linkToLocal( $mExtUser->getId() ); + } + } + } + + if ( $s === false ) { $result = null; } else { $result = $s->user_id; @@ -610,10 +650,41 @@ static function isCreatableName( $name ) { global $wgInvalidUsernameCharacters; return - self::isUsableName( $name ) && + self::isUsableName( $name ) && self::isInvalidUsernameCharacters( $name ) && self::isNotMaxNameChars( $name ); + } + - // Registration-time character blacklisting... - !preg_match( '/[' . preg_quote( $wgInvalidUsernameCharacters, '/' ) . ']/', $name ); + /** + * Check for Invalid Characters inside user name + * * @param $name \string String to match + * @return \bool True or false + */ + + static function isInvalidUsernameCharacters($name) { + global $wgInvalidUsernameCharacters; + if ( !empty( $wgInvalidUsernameCharacters ) ) { + return !preg_match( '/[' . preg_quote( $wgInvalidUsernameCharacters, '/' ) . ']/', $name ); + } else { + return true; + } + } + + /** + * Check for max name length + * * @param $name \string String to match + * @return \bool True or false + */ + + static function isNotMaxNameChars($name) { + global $wgWikiaMaxNameChars; + + if( empty($wgWikiaMaxNameChars) ) { + //emergency fallback + global $wgMaxNameChars; + $wgWikiaMaxNameChars = $wgMaxNameChars; + } + + return !( mb_strlen($name) > $wgWikiaMaxNameChars ); } /** @@ -677,8 +748,8 @@ if( !wfRunHooks( 'isValidEmailAddr', array( $addr, &$result ) ) ) { return $result; } - - return strpos( $addr, '@' ) !== false; + //switch again to regular expression - it can however reject rarely used TLDs like .museum - Marooned at Wikia.com + return preg_match('/^[a-z0-9._%+-]+@(?:[a-z0-9\-]+\.)+[a-z]{2,4}$/i', $addr) !== 0; } /** @@ -829,6 +900,8 @@ $this->mEmailTokenExpires = null; $this->mRegistration = wfTimestamp( TS_MW ); $this->mGroups = array(); + $this->mMonacoData = null; + $this->mMonacoSidebar = null; wfRunHooks( 'UserLoadDefaults', array( $this, $name ) ); @@ -857,14 +930,6 @@ return $result; } - if ( $wgExternalAuthType && $wgAutocreatePolicy == 'view' ) { - $extUser = ExternalUser::newFromCookie(); - if ( $extUser ) { - # TODO: Automatically create the user here (or probably a bit - # lower down, in fact) - } - } - if ( isset( $_COOKIE["{$wgCookiePrefix}UserID"] ) ) { $sId = intval( $_COOKIE["{$wgCookiePrefix}UserID"] ); if( isset( $_SESSION['wsUserID'] ) && $sId != $_SESSION['wsUserID'] ) { @@ -896,6 +961,14 @@ return false; } + // move it lower down + if ( $wgExternalAuthType && $wgAutocreatePolicy == 'view' ) { + $extUser = ExternalUser::newFromCookie(); + if ( $extUser ) { + $extUser->linkToLocal( $sId ); + } + } + $passwordCorrect = FALSE; $proposedUser = User::newFromId( $sId ); if ( !$proposedUser->isLoggedIn() ) { @@ -927,6 +1000,7 @@ $this->loadFromUserObject( $proposedUser ); $_SESSION['wsToken'] = $this->mToken; wfDebug( "Logged in from $from\n" ); + wfRunHooks( 'UserLoadFromSessionInfo', array( $this, $from ) ); return true; } else { # Invalid credentials @@ -966,6 +1040,11 @@ } $dbr = wfGetDB( DB_MASTER ); + if ( !is_object( $dbr ) ) { + $this->loadDefaults(); + return false; + } + $s = $dbr->selectRow( 'user', '*', array( 'user_id' => $this->mId ), __METHOD__ ); wfRunHooks( 'UserLoadFromDatabase', array( $this, &$s ) ); @@ -975,6 +1054,8 @@ $this->loadFromRow( $s ); $this->mGroups = null; // deferred $this->getEditCount(); // revalidation for nulls + $this->mMonacoData = null; + $this->mMonacoSidebar = null; return true; } else { # Invalid user_id @@ -1027,6 +1108,7 @@ $this->mGroups[] = $row->ug_group; } } + wfRunHooks( 'UserLoadGroups', array( $this ) ); } /** @@ -1041,6 +1123,7 @@ $this->mBlockedby = -1; # Unset $this->mHash = false; $this->mSkin = null; + $this->mTheme = null; # Wikia - Skin chooser related $this->mRights = null; $this->mEffectiveGroups = null; $this->mOptions = null; @@ -1101,6 +1184,9 @@ static function getToggles() { global $wgContLang, $wgUseRCPatrol; $extraToggles = array(); + /* Wikia change begin - @author: ADi */ + $extraToggles[] = 'marketingallowed'; + /* Wikia change end */ wfRunHooks( 'UserToggles', array( &$extraToggles ) ); if( $wgUseRCPatrol ) { $extraToggles[] = 'hidepatrolled'; @@ -1201,6 +1287,11 @@ # Extensions wfRunHooks( 'GetBlockedStatus', array( &$this ) ); + if ( !empty($this->mBlockedby) ) { + $this->mBlock->mBy = $this->mBlockedby; + $this->mBlock->mReason = $this->mBlockreason; + } + wfProfileOut( __METHOD__ ); } @@ -1588,6 +1679,14 @@ # Check memcached separately for anons, who have no # entire User object stored in there. if( !$this->mId ) { + # hack: don't check it for our varnish ip addresses + global $wgSquidServers, $wgSquidServersNoPurge; + if( in_array( $this->getName(), $wgSquidServers ) || + in_array( $this->getName(), $wgSquidServersNoPurge ) + ) { + return $this->mNewtalk; + } + global $wgMemc; $key = wfMemcKey( 'newtalk', 'ip', $this->getName() ); $newtalk = $wgMemc->get( $key ); @@ -1613,14 +1712,21 @@ */ function getNewMessageLinks() { $talks = array(); - if( !wfRunHooks( 'UserRetrieveNewTalks', array( &$this, &$talks ) ) ) - return $talks; + wfRunHooks( 'UserRetrieveNewTalks', array( &$this, &$talks) ); - if( !$this->getNewtalk() ) - return array(); + /* Wikia change begin - @author: XXX */ + if( $this->getNewtalk() ) { + global $wgCityId, $wgSitename; $up = $this->getUserPage(); $utp = $up->getTalkPage(); - return array( array( 'wiki' => wfWikiID(), 'link' => $utp->getLocalURL() ) ); + unset( $talks[$wgCityId] ); + $talks[0] = array( "wiki" => $wgSitename, "link" => $utp->getFullURL() ); + return $talks; + } + else { + return array_values($talks); + } + /* Wikia change end */ } /** @@ -1730,7 +1836,7 @@ * user_touched field when we update things. * @return \string Timestamp in TS_MW format */ - private static function newTouchedTimestamp() { + public static function newTouchedTimestamp() { global $wgClockSkewFudge; return wfTimestamp( TS_MW, time() + $wgClockSkewFudge ); } @@ -1745,8 +1851,10 @@ private function clearSharedCache() { $this->load(); if( $this->mId ) { - global $wgMemc; + global $wgMemc, $wgSharedDB; # Wikia $wgMemc->delete( wfMemcKey( 'user', 'id', $this->mId ) ); + # not uncyclo + if( !empty( $wgSharedDB ) ) $wgMemc->delete( wfSharedMemcKey( "user_touched", $this->mId ) ); # Wikia } } @@ -1760,6 +1868,7 @@ return; } $this->load(); + if ( wfReadOnly() ) { return; } if( $this->mId ) { $this->mTouched = self::newTouchedTimestamp(); @@ -1842,7 +1951,9 @@ // Save an invalid hash... $this->mPassword = ''; } else { - $this->mPassword = self::crypt( $str ); + // Wikia uses the old hashing until we migrate all wikis to MW 1.13 + //$this->mPassword = self::crypt( $str ); + $this->mPassword = self::oldCrypt( $str, $this->mId ); } $this->mNewpassword = ''; $this->mNewpassTime = null; @@ -1900,7 +2011,9 @@ */ function setNewpassword( $str, $throttle = true ) { $this->load(); - $this->mNewpassword = self::crypt( $str ); + // Wikia uses the old hashing until we migrate all wikis to MW 1.13 + //$this->mNewpassword = self::crypt( $str ); + $this->mNewpassword = self::oldCrypt( $str, $this->mId ); if ( $throttle ) { $this->mNewpassTime = wfTimestampNow(); } @@ -1948,6 +2061,14 @@ function setEmail( $str ) { $this->load(); $this->mEmail = $str; + + /* Wikia change begin - @author: Macbre */ + /* invalidate empty email - RT #44046 */ + if ($str == '') { + $this->invalidateEmail(); + } + /* Wikia change end */ + wfRunHooks( 'UserSetEmail', array( $this, &$this->mEmail ) ); } @@ -1989,7 +2110,26 @@ } if ( array_key_exists( $oname, $this->mOptions ) ) { - return $this->mOptions[$oname]; + # Wikia - Skin chooser related + if($oname == 'skin') { + if(strlen(trim($this->mOptions[$oname])) > 7 && substr(trim($this->mOptions[$oname]), 0, 6) == 'quartz') { + $this->mOptions[$oname] = 'quartz'; + $this->setOption('theme', substr(trim($this->mOptions[$oname]), 6)); + } else if(trim($this->mOptions[$oname]) == 'slate' || trim($this->mOptions[$oname]) == 'smoke') { + $this->mOptions[$oname] = 'quartz'; + $this->setOption('theme', trim($this->mOptions[$oname])); + } + } + + /* Wikia change begin - @author: Macbre */ + /* allow extensions to modify value returned by User::getOption() */ + /* make local copy of option value, so hook won't modify value read from DB and store in object */ + $value = $this->mOptions[$oname]; + + wfRunHooks( 'UserGetOption', array( $this->mOptions, $oname, &$value ) ); + + return $value; + /* Wikia change end */ } else { return $defaultOverride; } @@ -2047,7 +2187,18 @@ # Clear cached skin, so the new one displays immediately in Special:Preferences unset( $this->mSkin ); } - + # Wikia - Skin chooser related + if($oname == 'theme'){ + # Clear cached skin, so the new one displays immediately in Special:Preferences + unset($this->mTheme); + } + // Filter out any newlines that may have passed through input validation. + // Newlines are used to separate items in the options blob. + if( $val ) { + $val = str_replace( "\r\n", "\n", $val ); + $val = str_replace( "\r", "\n", $val ); + $val = str_replace( "\n", " ", $val ); + } // Explicitly NULL values should refer to defaults global $wgDefaultUserOptions; if( is_null( $val ) && isset( $wgDefaultUserOptions[$oname] ) ) { @@ -2270,6 +2421,7 @@ if ( !isset( $this->mSkin ) ) { wfProfileIn( __METHOD__ ); + /* global $wgHiddenPrefs; if( !in_array( 'skin', $wgHiddenPrefs ) ) { # get the user skin @@ -2283,6 +2435,12 @@ } $this->mSkin =& Skin::newFromKey( $userSkin ); + */ + + // Wikia change begin + wfRunHooks('AlternateGetSkin', array (&$this)); + // Wikia change end + wfProfileOut( __METHOD__ ); } if( $t || !$this->mSkin->getTitle() ) { @@ -2372,16 +2530,8 @@ // If the page is watched by the user (or may be watched), update the timestamp on any // any matching rows if ( $watched ) { - $dbw = wfGetDB( DB_MASTER ); - $dbw->update( 'watchlist', - array( /* SET */ - 'wl_notificationtimestamp' => null - ), array( /* WHERE */ - 'wl_title' => $title->getDBkey(), - 'wl_namespace' => $title->getNamespace(), - 'wl_user' => $this->getID() - ), __METHOD__ - ); + $wl = WatchedItem::fromUserTitle( $this, $title ); + $wl->clearWatch(); } } @@ -2407,11 +2557,33 @@ 'wl_user' => $currentUser ), __METHOD__ ); + + wfRunHooks( 'User::resetWatch', array ( $currentUser ) ); # We also need to clear here the "you have new message" notification for the own user_talk page # This is cleared one page view later in Article::viewUpdates(); } } + /** Wikia Change - begin - bringing this function back (don't see any harm in it and it's used in a few places) **/ + /** + * Encode this user's options as a string + * @return \string Encoded options + * @private + */ + function encodeOptions() { + $this->load(); + if ( is_null( $this->mOptions ) ) { + $this->mOptions = User::getDefaultOptions(); + } + $a = array(); + foreach ( $this->mOptions as $oname => $oval ) { + array_push( $a, $oname.'='.$oval ); + } + $s = implode( "\n", $a ); + return $s; + } + /** Wikia Change - end - bringing this function back (don't see any harm in it and it's used in a few places) **/ + /** * Set this user's options from an encoded string * @param $str \string Encoded options to import @@ -2528,6 +2700,29 @@ $this->mTouched = self::newTouchedTimestamp(); + /** + * @author Krzysztof Krzy┼╝aniak (eloy) + * trap for BugId: 4013 + */ + // wikia change begin + if( $this->mEmail == "devbox@wikia-inc.com" || $this->mEmail == "devbox+test@wikia-inc.com" ) { + // gather everything we know about request + global $wgCommandLineMode; + $log = "MOLI TRAP@devbox: "; + if( $wgCommandLineMode ) { + $log .= $argv[ 0 ]; + openlog( "trap", LOG_PID | LOG_PERROR, LOG_LOCAL6 ); + syslog( LOG_WARNING, "$log"); + closelog(); + } + else { + global $wgTitle; + $log .= $wgTitle->getFullUrl(); + error_log( $log ); + } + } + // wikia change end + $dbw = wfGetDB( DB_MASTER ); $dbw->update( 'user', array( /* SET */ @@ -2552,17 +2747,26 @@ wfRunHooks( 'UserSaveSettings', array( $this ) ); $this->clearSharedCache(); + + # Wikia - bad style fix for #1531 - needs review if it is still needed + global $wgRequest; + $action = $wgRequest->getVal( 'action'); + $commit = ( isset($action) && $action == 'ajax' ); + if ( $commit === true ) { + $dbw->commit(); + } + $this->getUserPage()->invalidateCache(); } /** * If only this user's username is known, and it exists, return the user ID. */ - function idForName() { + function idForName( $fromMaster = false ) { $s = trim( $this->getName() ); if ( $s === '' ) return 0; - $dbr = wfGetDB( DB_SLAVE ); + $dbr = ( $fromMaster ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); $id = $dbr->selectField( 'user', 'user_id', array( 'user_name' => $s ), __METHOD__ ); if ( $id === false ) { $id = 0; @@ -2615,6 +2819,12 @@ $dbw->insert( 'user', $fields, __METHOD__, array( 'IGNORE' ) ); if ( $dbw->affectedRows() ) { $newUser = User::newFromId( $dbw->insertId() ); + /** + * wikia, increase number of registered users for wfIniStats + */ + global $wgMemc; + $wgMemc->incr( wfSharedMemcKey( "registered-users-number" ) ); + } else { $newUser = null; } @@ -2709,7 +2920,7 @@ // Give a chance for extensions to modify the hash, if they have // extra options or other effects on the parser cache. - wfRunHooks( 'PageRenderingHash', array( &$confstr ) ); + wfRunHooks( 'PageRenderingHash', array( &$confstr/*Wikia change start*/, &$this/*Wikia change end*/ ) ); // Make it a valid memcached key fragment $confstr = str_replace( ' ', '_', $confstr ); @@ -2831,6 +3042,30 @@ return true; } } return false; } @@ -2924,7 +3159,7 @@ * * @return \types{\bool,\type{WikiError}} True on success, a WikiError object on failure. */ - function sendConfirmationMail() { + function sendConfirmationMail($mailtype = "ConfirmationMail", $mailmsg = 'confirmemail', $ip_arg = true) { global $wgLang; $expiration = null; // gets passed-by-ref and defined in next line. $token = $this->confirmationToken( $expiration ); @@ -2932,6 +3167,22 @@ $invalidateURL = $this->invalidationTokenUrl( $token ); $this->saveSettings(); + $manualURL = SpecialPage::getTitleFor( 'ConfirmEmail/manual' )->getFullURL(); + + $IP = wfGetIP(); + $name = $this->getName(); + $expDate = $wgLang->timeanddate( $expiration, false ); + + if(!$ip_arg) { + $args = array($name, $url, $expDate, $invalidateURL, $manualURL, $token); + } else { + $args = array($IP, $name, $url, $expDate, $invalidateURL, $manualURL, $token); + } + + /* Wikia change begin - @author: Marooned */ + /* HTML e-mails functionality */ + global $wgEnableRichEmails; + if (empty($wgEnableRichEmails)) { return $this->sendMail( wfMsg( 'confirmemail_subject' ), wfMsg( 'confirmemail_body', wfGetIP(), @@ -2940,7 +3191,40 @@ $wgLang->timeanddate( $expiration, false ), $invalidateURL, $wgLang->date( $expiration, false ), - $wgLang->time( $expiration, false ) ) ); + $wgLang->time( $expiration, false ) ), null, null, $mailtype ); + } else { + $wantHTML = $this->isAnon() || $this->getOption('htmlemails'); + + list($body, $bodyHTML) = wfMsgHTMLwithLanguage( $mailmsg.'_body', $this->getOption('language'), array(), $args, $wantHTML); + + return $this->sendMail( wfMsg( $mailmsg.'_subject' ), $body, null, null, $mailtype, $bodyHTML ); + } + /* Wikia change end */ + } + + /** + * Confirmation after change the emial + * + * @return \types{\bool,\type{WikiError}} True on success, a WikiError object on failure. + */ + function sendReConfirmationMail() { + $this->setOption("mail_edited","1"); + $this->saveSettings(); + return $this->sendConfirmationMail( 'ReConfirmationMail', 'reconfirmemail' ); + } + + /** + * Confirmation reminder after 7 day + * + * @return \types{\bool,\type{WikiError}} True on success, a WikiError object on failure. + */ + function sendConfirmationReminderMail() { + if( ($this->getOption("cr_mailed", 0) == 1) || ($this->getOption("mail_edited", 0) == 1) ) { + return false; + } + $this->setOption("cr_mailed","1"); + $this->saveSettings(); + return $this->sendConfirmationMail( 'ConfirmationReminder', 'confirmemailreminder', false ); } /** @@ -2951,9 +3235,11 @@ * @param $body \string Message body * @param $from \string Optional From address; if unspecified, default $wgPasswordSender will be used * @param $replyto \string Reply-To address + * @param $category \string type of e-mail used for statistics (added by Marooned @ Wikia) + * @param $bodyHTML \string rich version of $body (added by Marooned @ Wikia) * @return \types{\bool,\type{WikiError}} True on success, a WikiError object on failure */ - function sendMail( $subject, $body, $from = null, $replyto = null ) { + function sendMail( $subject, $body, $from = null, $replyto = null, $category = 'unknown', $bodyHTML = null, $priority = 0 ) { if( is_null( $from ) ) { global $wgPasswordSender; $from = $wgPasswordSender; @@ -2961,7 +3247,17 @@ $to = new MailAddress( $this ); $sender = new MailAddress( $from ); - return UserMailer::send( $to, $sender, $subject, $body, $replyto ); + + /* Wikia change begin - @author: Marooned */ + /* HTML e-mails functionality */ + global $wgEnableRichEmails; + $richMail = !empty($wgEnableRichEmails) && ($this->isAnon() || $this->getOption('htmlemails')) && !empty($bodyHTML); + if ($richMail) { + return UserMailer::sendHTML( $to, $sender, $subject, $body, $bodyHTML, $replyto, $category, $priority ); + } else { + return UserMailer::send( $to, $sender, $subject, $body, $replyto, null, $category, $priority ); + } + /* Wikia change end */ } /** @@ -3559,7 +3886,6 @@ * @return \bool */ static function comparePasswords( $hash, $password, $userId = false ) { - $m = false; $type = substr( $hash, 0, 3 ); $result = false; @@ -3639,10 +3965,19 @@ } else { wfDebug( "Loading options for user " . $this->getId() . " from database.\n" ); // Load from database + // wikia change, load always from first cluster when we use + // shared users database + // @author Krzysztof Krzy┼╝aniak (eloy) + global $wgExternalSharedDB, $wgSharedDB; + if( isset( $wgSharedDB ) ) { + $dbr = wfGetDB( DB_SLAVE, array(), $wgExternalSharedDB ); + } + else { $dbr = wfGetDB( DB_SLAVE ); + } $res = $dbr->select( 'user_properties', '*', array( 'up_user' => $this->getId() ), __METHOD__ @@ -3665,7 +4000,14 @@ $extuser = ExternalUser::newFromUser( $this ); $this->loadOptions(); + // wikia change + global $wgExternalSharedDB, $wgSharedDB, $wgGlobalUserProperties; + if( isset( $wgSharedDB ) ) { + $dbw = wfGetDB( DB_MASTER, array(), $wgExternalSharedDB ); + } + else { $dbw = wfGetDB( DB_MASTER ); + } $insert_rows = array(); @@ -3678,6 +4020,12 @@ foreach( $saveOptions as $key => $value ) { # Don't bother storing default values + # <Wikia> + if ( is_array( $wgGlobalUserProperties ) && in_array( $key, $wgGlobalUserProperties ) ) { + $insert_rows[] = array( 'up_user' => $this->getId(), 'up_property' => $key, 'up_value' => $value ); + } + # </Wikia> + else { if ( ( is_null( self::getDefaultOption( $key ) ) && !( $value === false || is_null($value) ) ) || $value != self::getDefaultOption( $key ) ) { @@ -3687,6 +4035,7 @@ 'up_value' => $value, ); } + } if ( $extuser && isset( $wgAllowPrefChange[$key] ) ) { switch ( $wgAllowPrefChange[$key] ) { case 'local': @@ -3700,9 +4049,13 @@ } $dbw->begin(); $dbw->delete( 'user_properties', array( 'up_user' => $this->getId() ), __METHOD__ ); $dbw->insert( 'user_properties', $insert_rows, __METHOD__ ); $dbw->commit(); + + if ( $extuser ) { + $extuser->updateUser(); + } } /**