Merge "Correct documentation of ChangeTags::buildTagFilterSelector"
[lhc/web/wiklou.git] / includes / User.php
index 63c0d37..4c044bd 100644 (file)
@@ -183,50 +183,50 @@ class User implements IDBAccessObject {
         */
        protected static $mAllRights = false;
 
-       /** @name Cache variables */
+       /** Cache variables */
        //@{
        public $mId;
-
+       /** @var string */
        public $mName;
-
+       /** @var string */
        public $mRealName;
-
        /**
         * @todo Make this actually private
         * @private
+        * @var Password
         */
        public $mPassword;
-
        /**
         * @todo Make this actually private
         * @private
+        * @var Password
         */
        public $mNewpassword;
-
+       /** @var string */
        public $mNewpassTime;
-
+       /** @var string */
        public $mEmail;
        /** @var string TS_MW timestamp from the DB */
        public $mTouched;
        /** @var string TS_MW timestamp from cache */
        protected $mQuickTouched;
-
+       /** @var string */
        protected $mToken;
-
+       /** @var string */
        public $mEmailAuthenticated;
-
+       /** @var string */
        protected $mEmailToken;
-
+       /** @var string */
        protected $mEmailTokenExpires;
-
+       /** @var string */
        protected $mRegistration;
-
+       /** @var int */
        protected $mEditCount;
-
+       /** @var array */
        public $mGroups;
-
+       /** @var array */
        protected $mOptionOverrides;
-
+       /** @var string */
        protected $mPasswordExpires;
        //@}
 
@@ -257,29 +257,29 @@ class User implements IDBAccessObject {
         * Lazy-initialized variables, invalidated with clearInstanceCache
         */
        protected $mNewtalk;
-
+       /** @var string */
        protected $mDatePreference;
-
+       /** @var string */
        public $mBlockedby;
-
+       /** @var string */
        protected $mHash;
-
+       /** @var array */
        public $mRights;
-
+       /** @var string */
        protected $mBlockreason;
-
+       /** @var array */
        protected $mEffectiveGroups;
-
+       /** @var array */
        protected $mImplicitGroups;
-
+       /** @var array */
        protected $mFormerGroups;
-
+       /** @var bool */
        protected $mBlockedGlobally;
-
+       /** @var bool */
        protected $mLocked;
-
+       /** @var bool */
        public $mHideName;
-
+       /** @var array */
        public $mOptions;
 
        /**
@@ -387,7 +387,8 @@ class User implements IDBAccessObject {
 
                // Try cache (unless this needs to lock the DB).
                // NOTE: if this thread called saveSettings(), the cache was cleared.
-               if ( ( $flags & self::READ_LOCKING ) || !$this->loadFromCache() ) {
+               $locking = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING );
+               if ( $locking || !$this->loadFromCache() ) {
                        wfDebug( "User: cache miss for user {$this->mId}\n" );
                        // Load from DB (make sure this thread sees its own changes)
                        if ( wfGetLB()->hasOrMadeRecentMasterChanges() ) {
@@ -837,10 +838,11 @@ class User implements IDBAccessObject {
         * able to set their password to this.
         *
         * @param string $password Desired password
+        * @param string $purpose one of 'login', 'create', 'reset'
         * @return Status
         * @since 1.23
         */
-       public function checkPasswordValidity( $password ) {
+       public function checkPasswordValidity( $password, $purpose = 'login' ) {
                global $wgPasswordPolicy;
 
                $upp = new UserPasswordPolicy(
@@ -857,7 +859,7 @@ class User implements IDBAccessObject {
                }
 
                if ( $result === false ) {
-                       $status->merge( $upp->checkUserPassword( $this, $password ) );
+                       $status->merge( $upp->checkUserPassword( $this, $password, $purpose ) );
                        return $status;
                } elseif ( $result === true ) {
                        return $status;
@@ -2151,6 +2153,7 @@ class User implements IDBAccessObject {
                                && $newMessageLinks[0]['wiki'] === wfWikiID()
                                && $newMessageLinks[0]['rev']
                        ) {
+                               /** @var Revision $newMessageRevision */
                                $newMessageRevision = $newMessageLinks[0]['rev'];
                                $newMessageRevisionId = $newMessageRevision->getId();
                        }
@@ -3382,19 +3385,24 @@ class User implements IDBAccessObject {
                                return;
                        }
 
-                       $nextid = $oldid ? $title->getNextRevisionID( $oldid ) : null;
+                       $that = $this;
+                       // Try to update the DB post-send and only if needed...
+                       DeferredUpdates::addCallableUpdate( function() use ( $that, $title, $oldid ) {
+                               if ( !$that->getNewtalk() ) {
+                                       return; // no notifications to clear
+                               }
 
-                       if ( !$oldid || !$nextid ) {
-                               // If we're looking at the latest revision, we should definitely clear it
-                               $this->setNewtalk( false );
-                       } else {
-                               // Otherwise we should update its revision, if it's present
-                               if ( $this->getNewtalk() ) {
-                                       // Naturally the other one won't clear by itself
-                                       $this->setNewtalk( false );
-                                       $this->setNewtalk( true, Revision::newFromId( $nextid ) );
+                               // Delete the last notifications (they stack up)
+                               $that->setNewtalk( false );
+
+                               // If there is a new, unseen, revision, use its timestamp
+                               $nextid = $oldid
+                                       ? $title->getNextRevisionID( $oldid, Title::GAID_FOR_UPDATE )
+                                       : null;
+                               if ( $nextid ) {
+                                       $that->setNewtalk( true, Revision::newFromId( $nextid ) );
                                }
-                       }
+                       } );
                }
 
                if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
@@ -3679,12 +3687,10 @@ class User implements IDBAccessObject {
                        $this->clearSharedCache();
                        // User was changed in the meantime or loaded with stale data
                        $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ? 'master' : 'slave';
-                       MWExceptionHandler::logException( new MWException(
+                       throw new MWException(
                                "CAS update failed on user_touched for user ID '{$this->mId}' (read from $from);" .
                                "the version of the user to be saved is older than the current version."
-                       ) );
-
-                       return;
+                       );
                }
 
                $this->mTouched = $newTouched;
@@ -3705,20 +3711,28 @@ class User implements IDBAccessObject {
 
        /**
         * If only this user's username is known, and it exists, return the user ID.
+        *
+        * @param int $flags Bitfield of User:READ_* constants; useful for existence checks
         * @return int
         */
-       public function idForName() {
+       public function idForName( $flags = 0 ) {
                $s = trim( $this->getName() );
                if ( $s === '' ) {
                        return 0;
                }
 
-               $dbr = wfGetDB( DB_SLAVE );
-               $id = $dbr->selectField( 'user', 'user_id', array( 'user_name' => $s ), __METHOD__ );
-               if ( $id === false ) {
-                       $id = 0;
-               }
-               return $id;
+               $db = ( ( $flags & self::READ_LATEST ) == self::READ_LATEST )
+                       ? wfGetDB( DB_MASTER )
+                       : wfGetDB( DB_SLAVE );
+
+               $options = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
+                       ? array( 'LOCK IN SHARE MODE' )
+                       : array();
+
+               $id = $db->selectField( 'user',
+                       'user_id', array( 'user_name' => $s ), __METHOD__, $options );
+
+               return (int)$id;
        }
 
        /**
@@ -4222,22 +4236,25 @@ class User implements IDBAccessObject {
         *
         * @param string $subject Message subject
         * @param string $body Message body
-        * @param string $from Optional From address; if unspecified, default
+        * @param User|null $from Optional sending user; if unspecified, default
         *   $wgPasswordSender will be used.
         * @param string $replyto Reply-To address
         * @return Status
         */
        public function sendMail( $subject, $body, $from = null, $replyto = null ) {
-               if ( is_null( $from ) ) {
-                       global $wgPasswordSender;
+               global $wgPasswordSender;
+
+               if ( $from instanceof User ) {
+                       $sender = MailAddress::newFromUser( $from );
+               } else {
                        $sender = new MailAddress( $wgPasswordSender,
                                wfMessage( 'emailsender' )->inContentLanguage()->text() );
-               } else {
-                       $sender = MailAddress::newFromUser( $from );
                }
-
                $to = MailAddress::newFromUser( $this );
-               return UserMailer::send( $to, $sender, $subject, $body, $replyto );
+
+               return UserMailer::send( $to, $sender, $subject, $body, array(
+                       'replyTo' => $replyto,
+               ) );
        }
 
        /**