}
public function getDescription() {
- $target = self::getTarget( $this->mTarget );
+ $target = self::getTarget( $this->mTarget, $this->getUser() );
if ( !$target instanceof User ) {
return $this->msg( 'emailuser-title-notarget' )->text();
}
throw new ErrorPageError( $title, $msg, $params );
}
// Got a valid target user name? Else ask for one.
- $ret = self::getTarget( $this->mTarget );
+ $ret = self::getTarget( $this->mTarget, $this->getUser() );
if ( !$ret instanceof User ) {
if ( $this->mTarget != '' ) {
// Messages used here: notargettext, noemailtext, nowikiemailtext
* Validate target User
*
* @param string $target Target user name
- * @return User User object on success or a string on error
+ * @param User|null $sender User sending the email
+ * @return User|string User object on success or a string on error
*/
- public static function getTarget( $target ) {
+ public static function getTarget( $target, User $sender = null ) {
+ if ( $sender === null ) {
+ wfDeprecated( __METHOD__ . ' without specifying the sending user', '1.30' );
+ }
+
if ( $target == '' ) {
wfDebug( "Target is empty.\n" );
}
$nu = User::newFromName( $target );
- if ( !$nu instanceof User || !$nu->getId() ) {
+ $error = self::validateTarget( $nu, $sender );
+
+ return $error ? $error : $nu;
+ }
+
+ /**
+ * Validate target User
+ *
+ * @param User $target Target user
+ * @param User|null $sender User sending the email
+ * @return string Error message or empty string if valid.
+ * @since 1.30
+ */
+ public static function validateTarget( $target, User $sender = null ) {
+ if ( $sender === null ) {
+ wfDeprecated( __METHOD__ . ' without specifying the sending user', '1.30' );
+ }
+
+ if ( !$target instanceof User || !$target->getId() ) {
wfDebug( "Target is invalid user.\n" );
return 'notarget';
- } elseif ( !$nu->isEmailConfirmed() ) {
+ }
+
+ if ( !$target->isEmailConfirmed() ) {
wfDebug( "User has no valid email.\n" );
return 'noemail';
- } elseif ( !$nu->canReceiveEmail() ) {
+ }
+
+ if ( !$target->canReceiveEmail() ) {
wfDebug( "User does not allow user emails.\n" );
return 'nowikiemail';
}
- return $nu;
+ if ( $target->getEditCount() === 0 &&
+ ( $sender === null || !$sender->isAllowed( 'sendemail-new-users' ) )
+ ) {
+ // Determine if target has any other logged actions.
+ $dbr = wfGetDB( DB_REPLICA );
+ $log_id = $dbr->selectField(
+ 'logging',
+ 'log_id',
+ [
+ 'log_user' => $target->getId(),
+ "NOT (log_type = 'newusers' AND log_action = 'autocreate')",
+ ],
+ __METHOD__,
+ [ 'LIMIT' => 1 ]
+ );
+
+ if ( !$log_id ) {
+ wfDebug( "User has no logged actions on this wiki.\n" );
+
+ return 'nowikiemail';
+ }
+ }
+
+ if ( $sender !== null && !$target->getOption( 'email-allow-new-users' ) &&
+ $sender->isNewbie()
+ ) {
+ wfDebug( "User does not allow user emails from new users.\n" );
+
+ return 'nowikiemail';
+ }
+
+ if ( $sender !== null ) {
+ $blacklist = $target->getOption( 'email-blacklist', [] );
+ if ( $blacklist ) {
+ $lookup = CentralIdLookup::factory();
+ $senderId = $lookup->centralIdFromLocalUser( $sender );
+ if ( $senderId !== 0 && in_array( $senderId, $blacklist ) ) {
+ wfDebug( "User does not allow user emails from this user.\n" );
+
+ return 'nowikiemail';
+ }
+ }
+ }
+
+ return '';
}
/**
return "blockedemailuser";
}
- if ( $user->pingLimiter( 'emailuser' ) ) {
+ // Check the ping limiter without incrementing it - we'll check it
+ // again later and increment it on a successful send
+ if ( $user->pingLimiter( 'emailuser', 0 ) ) {
wfDebug( "Ping limiter triggered.\n" );
return 'actionthrottledtext';
public static function submit( array $data, IContextSource $context ) {
$config = $context->getConfig();
- $target = self::getTarget( $data['Target'] );
+ $target = self::getTarget( $data['Target'], $context->getUser() );
if ( !$target instanceof User ) {
// Messages used here: notargettext, noemailtext, nowikiemailtext
return Status::newFatal( $target . 'text' );
$text .= $context->msg( 'emailuserfooter',
$from->name, $to->name )->inContentLanguage()->text();
+ // Check and increment the rate limits
+ if ( $context->getUser()->pingLimiter( 'emailuser' ) ) {
+ throw new ThrottledError();
+ }
+
$error = false;
if ( !Hooks::run( 'EmailUser', [ &$to, &$from, &$subject, &$text, &$error ] ) ) {
if ( $error instanceof Status ) {