Optimize email sending on password reset
[lhc/web/wiklou.git] / includes / user / PasswordReset.php
index 4ee256c..73e5cbc 100644 (file)
@@ -100,9 +100,10 @@ class PasswordReset implements LoggerAwareInterface {
                        } elseif ( !$user->isAllowed( 'editmyprivateinfo' ) ) {
                                // Maybe not all users have permission to change private data
                                $status = StatusValue::newFatal( 'badaccess' );
-                       } elseif ( $user->isBlocked() ) {
+                       } elseif ( $this->isBlocked( $user ) ) {
                                // Maybe the user is blocked (check this here rather than relying on the parent
-                               // method as we have a more specific error message to use here
+                               // method as we have a more specific error message to use here and we want to
+                               // ignore some types of blocks)
                                $status = StatusValue::newFatal( 'blocked-mailpassword' );
                        }
 
@@ -121,10 +122,9 @@ class PasswordReset implements LoggerAwareInterface {
         *
         * @since 1.29 Fourth argument for displayPassword removed.
         * @param User $performingUser The user that does the password reset
-        * @param string $username The user whose password is reset
-        * @param string $email Alternative way to specify the user
-        * @return StatusValue Will contain the passwords as a username => password array if the
-        *   $displayPassword flag was set
+        * @param string|null $username The user whose password is reset
+        * @param string|null $email Alternative way to specify the user
+        * @return StatusValue
         * @throws LogicException When the user is not allowed to perform the action
         * @throws MWException On unexpected DB errors
         */
@@ -226,7 +226,6 @@ class PasswordReset implements LoggerAwareInterface {
                        'requestingUser' => $performingUser->getName(),
                        'targetUsername' => $username,
                        'targetEmail' => $email,
-                       'actualUser' => $firstUser->getName(),
                ];
 
                if ( !$result->isGood() ) {
@@ -237,17 +236,43 @@ class PasswordReset implements LoggerAwareInterface {
                        return $result;
                }
 
-               $passwords = [];
-               foreach ( $reqs as $req ) {
-                       $this->authManager->changeAuthenticationData( $req );
-               }
-
-               $this->logger->info(
-                       "{requestingUser} did password reset of {actualUser}",
-                       $logContext
+               DeferredUpdates::addUpdate(
+                       new SendPasswordResetEmailUpdate( $this->authManager, $reqs, $logContext ),
+                       DeferredUpdates::POSTSEND
                );
 
-               return StatusValue::newGood( $passwords );
+               return StatusValue::newGood();
+       }
+
+       /**
+        * Check whether the user is blocked.
+        * Ignores certain types of system blocks that are only meant to force users to log in.
+        * @param User $user
+        * @return bool
+        * @since 1.30
+        */
+       protected function isBlocked( User $user ) {
+               $block = $user->getBlock() ?: $user->getGlobalBlock();
+               if ( !$block ) {
+                       return false;
+               }
+               $type = $block->getSystemBlockType();
+               if ( in_array( $type, [ null, 'global-block' ], true ) ) {
+                       // Normal block. Maybe it was meant for someone else and the user just needs to log in;
+                       // or maybe it was issued specifically to prevent some IP from messing with password
+                       // reset? Go out on a limb and use the registration allowed flag to decide.
+                       return $block->prevents( 'createaccount' );
+               } elseif ( $type === 'proxy' ) {
+                       // we disallow actions through proxy even if the user is logged in
+                       // so it makes sense to disallow password resets as well
+                       return true;
+               } elseif ( in_array( $type, [ 'dnsbl', 'wgSoftBlockRanges' ], true ) ) {
+                       // these are just meant to force login so let's not prevent that
+                       return false;
+               } else {
+                       // some extension - we'll have to guess
+                       return true;
+               }
        }
 
        /**
@@ -256,11 +281,14 @@ class PasswordReset implements LoggerAwareInterface {
         * @throws MWException On unexpected database errors
         */
        protected function getUsersByEmail( $email ) {
+               $userQuery = User::getQueryInfo();
                $res = wfGetDB( DB_REPLICA )->select(
-                       'user',
-                       User::selectFields(),
+                       $userQuery['tables'],
+                       $userQuery['fields'],
                        [ 'user_email' => $email ],
-                       __METHOD__
+                       __METHOD__,
+                       [],
+                       $userQuery['joins']
                );
 
                if ( !$res ) {