*/
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;
//@}
* 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;
/**
Hooks::run( 'UserLoadAfterLoadFromSession', array( $this ) );
break;
default:
- throw new MWException( "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
+ throw new UnexpectedValueException(
+ "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
}
}
// 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() ) {
* 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(
}
if ( $result === false ) {
- $status->merge( $upp->checkUserPassword( $this, $password ) );
+ $status->merge( $upp->checkUserPassword( $this, $password, $purpose ) );
return $status;
} elseif ( $result === true ) {
return $status;
* - 'usable' Valid for batch processes and login
* - 'creatable' Valid for batch processes, login and account creation
*
- * @throws MWException
+ * @throws InvalidArgumentException
* @return bool|string
*/
public static function getCanonicalName( $name, $validate = 'valid' ) {
}
break;
default:
- throw new MWException( 'Invalid parameter value for $validate in ' . __METHOD__ );
+ throw new InvalidArgumentException(
+ 'Invalid parameter value for $validate in ' . __METHOD__ );
}
return $name;
}
&& $newMessageLinks[0]['wiki'] === wfWikiID()
&& $newMessageLinks[0]['rev']
) {
+ /** @var Revision $newMessageRevision */
$newMessageRevision = $newMessageLinks[0]['rev'];
$newMessageRevisionId = $newMessageRevision->getId();
}
/**
* Get the user touched timestamp
+ *
+ * Use this value only to validate caches via inequalities
+ * such as in the case of HTTP If-Modified-Since response logic
+ *
* @return string TS_MW Timestamp
*/
public function getTouched() {
if ( $this->mId ) {
if ( $this->mQuickTouched === null ) {
$key = wfMemcKey( 'user-quicktouched', 'id', $this->mId );
+ $cache = ObjectCache::getMainWANInstance();
- $timestamp = ObjectCache::getMainWANInstance()->getCheckKeyTime( $key );
- if ( $timestamp ) {
- $this->mQuickTouched = wfTimestamp( TS_MW, (int)$timestamp );
- } else {
- # Set the timestamp to get HTTP 304 cache hits
- $this->touch();
- }
+ $this->mQuickTouched = wfTimestamp( TS_MW, $cache->getCheckKeyTime( $key ) );
}
return max( $this->mTouched, $this->mQuickTouched );
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
+ }
+
+ // Delete the last notifications (they stack up)
+ $that->setNewtalk( false );
- 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 ) );
+ // 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 ) {
$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;
/**
* 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;
}
/**
*
* @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 );
}