Add isCurrentWikiId()/isCurrentWikiDomain()/getCurrentWikiDomain() to WikiMap
[lhc/web/wiklou.git] / includes / user / User.php
index d6d4db2..8cbedb9 100644 (file)
@@ -27,6 +27,7 @@ use MediaWiki\Auth\AuthManager;
 use MediaWiki\Auth\AuthenticationResponse;
 use MediaWiki\Auth\AuthenticationRequest;
 use MediaWiki\User\UserIdentity;
+use MediaWiki\Logger\LoggerFactory;
 use Wikimedia\IPSet;
 use Wikimedia\ScopedCallback;
 use Wikimedia\Rdbms\Database;
@@ -491,7 +492,7 @@ class User implements IDBAccessObject, UserIdentity {
         * @param int $userId
         */
        public static function purge( $wikiId, $userId ) {
-               $cache = ObjectCache::getMainWANInstance();
+               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
                $key = $cache->makeGlobalKey( 'user', 'id', $wikiId, $userId );
                $cache->delete( $key );
        }
@@ -502,7 +503,10 @@ class User implements IDBAccessObject, UserIdentity {
         * @return string
         */
        protected function getCacheKey( WANObjectCache $cache ) {
-               return $cache->makeGlobalKey( 'user', 'id', wfWikiID(), $this->mId );
+               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
+               $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+
+               return $cache->makeGlobalKey( 'user', 'id', $lbFactory->getLocalDomainID(), $this->mId );
        }
 
        /**
@@ -626,9 +630,12 @@ class User implements IDBAccessObject, UserIdentity {
        public static function newFromActorId( $id ) {
                global $wgActorTableSchemaMigrationStage;
 
-               if ( $wgActorTableSchemaMigrationStage <= MIGRATION_OLD ) {
+               // Technically we shouldn't allow this without SCHEMA_COMPAT_READ_NEW,
+               // but it does little harm and might be needed for write callers loading a User.
+               if ( !( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_NEW ) ) {
                        throw new BadMethodCallException(
-                               'Cannot use ' . __METHOD__ . ' when $wgActorTableSchemaMigrationStage is MIGRATION_OLD'
+                               'Cannot use ' . __METHOD__
+                                       . ' when $wgActorTableSchemaMigrationStage lacks SCHEMA_COMPAT_NEW'
                        );
                }
 
@@ -678,7 +685,9 @@ class User implements IDBAccessObject, UserIdentity {
                $user = new User;
                $user->mFrom = 'defaults';
 
-               if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD && $actorId !== null ) {
+               // Technically we shouldn't allow this without SCHEMA_COMPAT_READ_NEW,
+               // but it does little harm and might be needed for write callers loading a User.
+               if ( ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_NEW ) && $actorId !== null ) {
                        $user->mActorId = (int)$actorId;
                        if ( $user->mActorId !== 0 ) {
                                $user->mFrom = 'actor';
@@ -1050,7 +1059,7 @@ class User implements IDBAccessObject, UserIdentity {
                // Certain names may be reserved for batch processes.
                foreach ( $reservedUsernames as $reserved ) {
                        if ( substr( $reserved, 0, 4 ) == 'msg:' ) {
-                               $reserved = wfMessage( substr( $reserved, 4 ) )->inContentLanguage()->text();
+                               $reserved = wfMessage( substr( $reserved, 4 ) )->inContentLanguage()->plain();
                        }
                        if ( $reserved == $name ) {
                                return false;
@@ -1487,7 +1496,9 @@ class User implements IDBAccessObject, UserIdentity {
 
                $this->mGroupMemberships = null; // deferred
 
-               if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+               // Technically we shouldn't allow this without SCHEMA_COMPAT_READ_NEW,
+               // but it does little harm and might be needed for write callers loading a User.
+               if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_NEW ) {
                        if ( isset( $row->actor_id ) ) {
                                $this->mActorId = (int)$row->actor_id;
                                if ( $this->mActorId !== 0 ) {
@@ -2165,10 +2176,6 @@ class User implements IDBAccessObject, UserIdentity {
                        if ( isset( $limits['user'] ) ) {
                                $userLimit = $limits['user'];
                        }
-                       // limits for newbie logged-in users
-                       if ( $isNewbie && isset( $limits['newbie'] ) ) {
-                               $keys[$cache->makeKey( 'limiter', $action, 'user', $id )] = $limits['newbie'];
-                       }
                }
 
                // limits for anons and for newbie logged-in users
@@ -2200,6 +2207,11 @@ class User implements IDBAccessObject, UserIdentity {
                        }
                }
 
+               // limits for newbie logged-in users (override all the normal user limits)
+               if ( $id !== 0 && $isNewbie && isset( $limits['newbie'] ) ) {
+                       $userLimit = $limits['newbie'];
+               }
+
                // Set the user limit key
                if ( $userLimit !== false ) {
                        list( $max, $period ) = $userLimit;
@@ -2489,7 +2501,9 @@ class User implements IDBAccessObject, UserIdentity {
        public function getActorId( IDatabase $dbw = null ) {
                global $wgActorTableSchemaMigrationStage;
 
-               if ( $wgActorTableSchemaMigrationStage <= MIGRATION_OLD ) {
+               // Technically we should always return 0 without SCHEMA_COMPAT_READ_NEW,
+               // but it does little harm and might be needed for write callers loading a User.
+               if ( !( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) ) {
                        return 0;
                }
 
@@ -2499,7 +2513,7 @@ class User implements IDBAccessObject, UserIdentity {
 
                // Currently $this->mActorId might be null if $this was loaded from a
                // cache entry that was written when $wgActorTableSchemaMigrationStage
-               // was MIGRATION_OLD. Once that is no longer a possibility (i.e. when
+               // was SCHEMA_COMPAT_OLD. Once that is no longer a possibility (i.e. when
                // User::VERSION is incremented after $wgActorTableSchemaMigrationStage
                // has been removed), that condition may be removed.
                if ( $this->mActorId === null || !$this->mActorId && $dbw ) {
@@ -2624,7 +2638,7 @@ class User implements IDBAccessObject, UserIdentity {
                        // and it is always for the same wiki, but we double-check here in
                        // case that changes some time in the future.
                        if ( count( $newMessageLinks ) === 1
-                               && $newMessageLinks[0]['wiki'] === wfWikiID()
+                               && WikiMap::isCurrentWikiId( $newMessageLinks[0]['wiki'] )
                                && $newMessageLinks[0]['rev']
                        ) {
                                /** @var Revision $newMessageRevision */
@@ -2874,6 +2888,7 @@ class User implements IDBAccessObject, UserIdentity {
         * @return bool
         */
        public function setPassword( $str ) {
+               wfDeprecated( __METHOD__, '1.27' );
                return $this->setPasswordInternal( $str );
        }
 
@@ -2886,6 +2901,7 @@ class User implements IDBAccessObject, UserIdentity {
         *  through the web interface.
         */
        public function setInternalPassword( $str ) {
+               wfDeprecated( __METHOD__, '1.27' );
                $this->setPasswordInternal( $str );
        }
 
@@ -3538,6 +3554,7 @@ class User implements IDBAccessObject, UserIdentity {
                                }
                        }
 
+                       Hooks::run( 'UserGetRightsRemove', [ $this, &$this->mRights ] );
                        // Force reindexation of rights when a hook has unset one of them
                        $this->mRights = array_values( array_unique( $this->mRights ) );
 
@@ -4208,13 +4225,16 @@ class User implements IDBAccessObject, UserIdentity {
                                $this->clearSharedCache( 'refresh' );
                                // User was changed in the meantime or loaded with stale data
                                $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ? 'master' : 'replica';
-                               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."
+                               LoggerFactory::getInstance( 'preferences' )->warning(
+                                       "CAS update failed on user_touched for user ID '{user_id}' ({db_flag} read)",
+                                       [ 'user_id' => $this->mId, 'db_flag' => $from ]
+                               );
+                               throw new MWException( "CAS update failed on user_touched. " .
+                                       "The version of the user to be saved is older than the current version."
                                );
                        }
 
-                       if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+                       if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
                                $dbw->update(
                                        'actor',
                                        [ 'actor_name' => $this->mName ],
@@ -4312,9 +4332,10 @@ class User implements IDBAccessObject, UserIdentity {
                        $dbw->insert( 'user', $fields, $fname, [ 'IGNORE' ] );
                        if ( $dbw->affectedRows() ) {
                                $newUser = self::newFromId( $dbw->insertId() );
+                               $newUser->mName = $fields['user_name'];
+                               $newUser->updateActorId( $dbw );
                                // Load the user from master to avoid replica lag
                                $newUser->load( self::READ_LATEST );
-                               $newUser->updateActorId( $dbw );
                        } else {
                                $newUser = null;
                        }
@@ -4384,7 +4405,7 @@ class User implements IDBAccessObject, UserIdentity {
                                        'user',
                                        'user_id',
                                        [ 'user_name' => $this->mName ],
-                                       __METHOD__,
+                                       $fname,
                                        [ 'LOCK IN SHARE MODE' ]
                                );
                                $loaded = false;
@@ -4394,7 +4415,7 @@ class User implements IDBAccessObject, UserIdentity {
                                        }
                                }
                                if ( !$loaded ) {
-                                       throw new MWException( __METHOD__ . ": hit a key conflict attempting " .
+                                       throw new MWException( $fname . ": hit a key conflict attempting " .
                                                "to insert user '{$this->mName}' row, but it was not present in select!" );
                                }
                                return Status::newFatal( 'userexists' );
@@ -4423,7 +4444,7 @@ class User implements IDBAccessObject, UserIdentity {
        private function updateActorId( IDatabase $dbw ) {
                global $wgActorTableSchemaMigrationStage;
 
-               if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+               if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) {
                        $dbw->insert(
                                'actor',
                                [ 'actor_user' => $this->mId, 'actor_name' => $this->mName ],
@@ -4540,6 +4561,8 @@ class User implements IDBAccessObject, UserIdentity {
         * @return bool True if the given password is correct, otherwise False
         */
        public function checkPassword( $password ) {
+               wfDeprecated( __METHOD__, '1.27' );
+
                $manager = AuthManager::singleton();
                $reqs = AuthenticationRequest::loadRequestsFromSubmission(
                        $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN ),
@@ -4573,6 +4596,7 @@ class User implements IDBAccessObject, UserIdentity {
         * @return bool True if matches, false otherwise
         */
        public function checkTemporaryPassword( $plaintext ) {
+               wfDeprecated( __METHOD__, '1.27' );
                // Can't check the temporary password individually.
                return $this->checkPassword( $plaintext );
        }
@@ -5102,16 +5126,13 @@ class User implements IDBAccessObject, UserIdentity {
 
        /**
         * Get a list of implicit groups
+        * TODO: Should we deprecate this? It's trivial, but we don't want to encourage use of globals.
+        *
         * @return array Array of Strings Array of internal group names
         */
        public static function getImplicitGroups() {
                global $wgImplicitGroups;
-
-               $groups = $wgImplicitGroups;
-               # Deprecated, use $wgImplicitGroups instead
-               Hooks::run( 'UserGetImplicitGroups', [ &$groups ], '1.25' );
-
-               return $groups;
+               return $wgImplicitGroups;
        }
 
        /**
@@ -5645,14 +5666,18 @@ class User implements IDBAccessObject, UserIdentity {
                        ],
                        'joins' => [],
                ];
-               if ( $wgActorTableSchemaMigrationStage > MIGRATION_OLD ) {
+
+               // Technically we shouldn't allow this without SCHEMA_COMPAT_READ_NEW,
+               // but it does little harm and might be needed for write callers loading a User.
+               if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_NEW ) {
                        $ret['tables']['user_actor'] = 'actor';
                        $ret['fields'][] = 'user_actor.actor_id';
                        $ret['joins']['user_actor'] = [
-                               $wgActorTableSchemaMigrationStage === MIGRATION_NEW ? 'JOIN' : 'LEFT JOIN',
+                               ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) ? 'JOIN' : 'LEFT JOIN',
                                [ 'user_actor.actor_user = user_id' ]
                        ];
                }
+
                return $ret;
        }