Merge "Check for global blocks"
[lhc/web/wiklou.git] / includes / user / User.php
index 831966e..601f9a5 100644 (file)
  */
 
 use MediaWiki\Session\SessionManager;
+use MediaWiki\Session\Token;
 
 /**
  * String Some punctuation to prevent editing from broken text-mangling proxies.
- * @deprecated since 1.27, use \\MediaWiki\\Session\\Token::SUFFIX
+ * @deprecated since 1.27, use \MediaWiki\Session\Token::SUFFIX
  * @ingroup Constants
  */
-define( 'EDIT_TOKEN_SUFFIX', MediaWiki\Session\Token::SUFFIX );
+define( 'EDIT_TOKEN_SUFFIX', Token::SUFFIX );
 
 /**
  * The User object encapsulates all of the user-specific settings (user_id,
@@ -53,7 +54,7 @@ class User implements IDBAccessObject {
        /**
         * Global constant made accessible as class constants so that autoloader
         * magic can be used.
-        * @deprecated since 1.27, use \\MediaWiki\\Session\\Token::SUFFIX
+        * @deprecated since 1.27, use \MediaWiki\Session\Token::SUFFIX
         */
        const EDIT_TOKEN_SUFFIX = EDIT_TOKEN_SUFFIX;
 
@@ -200,6 +201,7 @@ class User implements IDBAccessObject {
 
        /** Cache variables */
        // @{
+       /** @var int */
        public $mId;
        /** @var string */
        public $mName;
@@ -273,8 +275,8 @@ class User implements IDBAccessObject {
        protected $mImplicitGroups;
        /** @var array */
        protected $mFormerGroups;
-       /** @var bool */
-       protected $mBlockedGlobally;
+       /** @var Block */
+       protected $mGlobalBlock;
        /** @var bool */
        protected $mLocked;
        /** @var bool */
@@ -1068,9 +1070,9 @@ class User implements IDBAccessObject {
                // Clean up name according to title rules,
                // but only when validation is requested (bug 12654)
                $t = ( $validate !== false ) ?
-                       Title::newFromText( $name ) : Title::makeTitle( NS_USER, $name );
+                       Title::newFromText( $name, NS_USER ) : Title::makeTitle( NS_USER, $name );
                // Check for invalid titles
-               if ( is_null( $t ) ) {
+               if ( is_null( $t ) || $t->getNamespace() !== NS_USER || $t->isExternal() ) {
                        return false;
                }
 
@@ -1990,8 +1992,22 @@ class User implements IDBAccessObject {
         * @return bool True if blocked, false otherwise
         */
        public function isBlockedGlobally( $ip = '' ) {
-               if ( $this->mBlockedGlobally !== null ) {
-                       return $this->mBlockedGlobally;
+               return $this->getGlobalBlock( $ip ) instanceof Block;
+       }
+
+       /**
+        * Check if user is blocked on all wikis.
+        * Do not use for actual edit permission checks!
+        * This is intended for quick UI checks.
+        *
+        * @param string $ip IP address, uses current client if none given
+        * @return Block|null Block object if blocked, null otherwise
+        * @throws FatalError
+        * @throws MWException
+        */
+       public function getGlobalBlock( $ip = '' ) {
+               if ( $this->mGlobalBlock !== null ) {
+                       return $this->mGlobalBlock ?: null;
                }
                // User is already an IP?
                if ( IP::isIPAddress( $this->getName() ) ) {
@@ -2000,9 +2016,17 @@ class User implements IDBAccessObject {
                        $ip = $this->getRequest()->getIP();
                }
                $blocked = false;
-               Hooks::run( 'UserIsBlockedGlobally', [ &$this, $ip, &$blocked ] );
-               $this->mBlockedGlobally = (bool)$blocked;
-               return $this->mBlockedGlobally;
+               $block = null;
+               Hooks::run( 'UserIsBlockedGlobally', [ &$this, $ip, &$blocked, &$block ] );
+
+               if ( $blocked && $block === null ) {
+                       // back-compat: UserIsBlockedGlobally didn't have $block param first
+                       $block = new Block;
+                       $block->setTarget( $ip );
+               }
+
+               $this->mGlobalBlock = $blocked ? $block : false;
+               return $this->mGlobalBlock ?: null;
        }
 
        /**
@@ -2052,7 +2076,8 @@ class User implements IDBAccessObject {
                        // Don't load if this was initialized from an ID
                        $this->load();
                }
-               return $this->mId;
+
+               return (int)$this->mId;
        }
 
        /**
@@ -2162,7 +2187,7 @@ class User implements IDBAccessObject {
                // Get the "last viewed rev" timestamp from the oldest message notification
                $timestamp = $dbr->selectField( 'user_newtalk',
                        'MIN(user_last_timestamp)',
-                       $this->isAnon() ? [ 'user_ip' => $this->getName() ] : [ 'user_id' => $this->getID() ],
+                       $this->isAnon() ? [ 'user_ip' => $this->getName() ] : [ 'user_id' => $this->getId() ],
                        __METHOD__ );
                $rev = $timestamp ? Revision::loadFromTimestamp( $dbr, $utp, $timestamp ) : null;
                return [ [ 'wiki' => wfWikiID(), 'link' => $utp->getLocalURL(), 'rev' => $rev ] ];
@@ -2691,14 +2716,36 @@ class User implements IDBAccessObject {
                        return Status::newGood( true );
                }
 
+               $type = $oldaddr != '' ? 'changed' : 'set';
+               $notificationResult = null;
+
+               if ( $wgEmailAuthentication ) {
+                       // Send the user an email notifying the user of the change in registered
+                       // email address on their previous email address
+                       if ( $type == 'changed' ) {
+                               $change = $str != '' ? 'changed' : 'removed';
+                               $notificationResult = $this->sendMail(
+                                       wfMessage( 'notificationemail_subject_' . $change )->text(),
+                                       wfMessage( 'notificationemail_body_' . $change,
+                                               $this->getRequest()->getIP(),
+                                               $this->getName(),
+                                               $str )->text()
+                               );
+                       }
+               }
+
                $this->setEmail( $str );
 
                if ( $str !== '' && $wgEmailAuthentication ) {
                        // Send a confirmation request to the new address if needed
-                       $type = $oldaddr != '' ? 'changed' : 'set';
                        $result = $this->sendConfirmationMail( $type );
+
+                       if ( $notificationResult !== null ) {
+                               $result->merge( $notificationResult );
+                       }
+
                        if ( $result->isGood() ) {
-                               // Say to the caller that a confirmation mail has been sent
+                               // Say to the caller that a confirmation and notification mail has been sent
                                $result->value = 'eauth';
                        }
                } else {
@@ -3268,7 +3315,7 @@ class User implements IDBAccessObject {
                if ( $this->getId() ) {
                        $dbw->insert( 'user_groups',
                                [
-                                       'ug_user' => $this->getID(),
+                                       'ug_user' => $this->getId(),
                                        'ug_group' => $group,
                                ],
                                __METHOD__,
@@ -3306,14 +3353,14 @@ class User implements IDBAccessObject {
                $dbw = wfGetDB( DB_MASTER );
                $dbw->delete( 'user_groups',
                        [
-                               'ug_user' => $this->getID(),
+                               'ug_user' => $this->getId(),
                                'ug_group' => $group,
                        ], __METHOD__
                );
                // Remember that the user was in this group
                $dbw->insert( 'user_former_groups',
                        [
-                               'ufg_user' => $this->getID(),
+                               'ufg_user' => $this->getId(),
                                'ufg_group' => $group,
                        ],
                        __METHOD__,
@@ -3338,7 +3385,7 @@ class User implements IDBAccessObject {
         * @return bool
         */
        public function isLoggedIn() {
-               return $this->getID() != 0;
+               return $this->getId() != 0;
        }
 
        /**
@@ -3465,10 +3512,9 @@ class User implements IDBAccessObject {
         */
        public function addWatch( $title, $checkRights = self::CHECK_USER_RIGHTS ) {
                if ( !$checkRights || $this->isAllowed( 'editmywatchlist' ) ) {
-                       WatchedItemStore::getDefaultInstance()->addWatchBatch( [
-                               [ $this, $title->getSubjectPage() ],
-                               [ $this, $title->getTalkPage() ],
-                       ]
+                       WatchedItemStore::getDefaultInstance()->addWatchBatchForUser(
+                               $this,
+                               [ $title->getSubjectPage(), $title->getTalkPage() ]
                        );
                }
                $this->invalidateCache();
@@ -4198,7 +4244,7 @@ class User implements IDBAccessObject {
         * @since 1.27
         * @param string|array $salt Array of Strings Optional function-specific data for hashing
         * @param WebRequest|null $request WebRequest object to use or null to use $wgRequest
-        * @return MediaWiki\\Session\\Token The new edit token
+        * @return MediaWiki\Session\Token The new edit token
         */
        public function getEditTokenObject( $salt = '', $request = null ) {
                if ( $this->isAnon() ) {
@@ -4228,7 +4274,7 @@ class User implements IDBAccessObject {
 
        /**
         * Get the embedded timestamp from a token.
-        * @deprecated since 1.27, use \\MediaWiki\\Session\\Token::getTimestamp instead.
+        * @deprecated since 1.27, use \MediaWiki\Session\Token::getTimestamp instead.
         * @param string $val Input token
         * @return int|null
         */
@@ -4264,7 +4310,7 @@ class User implements IDBAccessObject {
         * @return bool Whether the token matches
         */
        public function matchEditTokenNoSuffix( $val, $salt = '', $request = null, $maxage = null ) {
-               $val = substr( $val, 0, strspn( $val, '0123456789abcdef' ) ) . self::EDIT_TOKEN_SUFFIX;
+               $val = substr( $val, 0, strspn( $val, '0123456789abcdef' ) ) . Token::SUFFIX;
                return $this->matchEditToken( $val, $salt, $request, $maxage );
        }