From 43b7dc314234e476a80d9acbd07292d7286cca5a Mon Sep 17 00:00:00 2001 From: "lpsolit%gmail.com" <> Date: Wed, 2 Apr 2008 22:42:25 +0000 Subject: Bug 405946: Some emails are not sent in the language chosen by the addressee - Patch by Frédéric Buclin r=wurblzap a=LpSolit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Bugzilla/Bug.pm | 24 ++++------------ Bugzilla/Flag.pm | 58 +++++++++++++++++++------------------- Bugzilla/Token.pm | 83 ++++++++++++++++++++++++++++--------------------------- 3 files changed, 75 insertions(+), 90 deletions(-) (limited to 'Bugzilla') diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index 3d4c4b869..e523db6ae 100755 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -3024,7 +3024,6 @@ sub RemoveVotes { if (scalar(@list)) { foreach my $ref (@list) { my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = (@$ref); - my $s; $maxvotesperbug = min($votesperuser, $maxvotesperbug); @@ -3038,23 +3037,13 @@ sub RemoveVotes { my $removedvotes = $oldvotes - $newvotes; - $s = ($oldvotes == 1) ? "" : "s"; - my $oldvotestext = "You had $oldvotes vote$s on this bug."; - - $s = ($removedvotes == 1) ? "" : "s"; - my $removedvotestext = "You had $removedvotes vote$s removed from this bug."; - - my $newvotestext; if ($newvotes) { $dbh->do("UPDATE votes SET vote_count = ? " . "WHERE bug_id = ? AND who = ?", undef, ($newvotes, $id, $userid)); - $s = $newvotes == 1 ? "" : "s"; - $newvotestext = "You still have $newvotes vote$s on this bug." } else { $dbh->do("DELETE FROM votes WHERE bug_id = ? AND who = ?", undef, ($id, $userid)); - $newvotestext = "You have no more votes remaining on this bug."; } # Notice that we did not make sure that the user fit within the $votesperuser @@ -3065,7 +3054,6 @@ sub RemoveVotes { # Now lets send the e-mail to alert the user to the fact that their votes have # been reduced or removed. my $vars = { - 'to' => $name . Bugzilla->params->{'emailsuffix'}, 'bugid' => $id, 'reason' => $reason, @@ -3073,19 +3061,17 @@ sub RemoveVotes { 'votesremoved' => $removedvotes, 'votesold' => $oldvotes, 'votesnew' => $newvotes, - - 'votesremovedtext' => $removedvotestext, - 'votesoldtext' => $oldvotestext, - 'votesnewtext' => $newvotestext, - - 'count' => $removedvotes . "\n " . $newvotestext }; + my $voter = new Bugzilla::User($userid); + my $template = Bugzilla->template_inner($voter->settings->{'lang'}->{'value'}); + my $msg; - my $template = Bugzilla->template; $template->process("email/votes-removed.txt.tmpl", $vars, \$msg); push(@messages, $msg); } + Bugzilla->template_inner(""); + my $votes = $dbh->selectrow_array("SELECT SUM(vote_count) " . "FROM votes WHERE bug_id = ?", undef, $id) || 0; diff --git a/Bugzilla/Flag.pm b/Bugzilla/Flag.pm index f8c43b508..a65a8268b 100644 --- a/Bugzilla/Flag.pm +++ b/Bugzilla/Flag.pm @@ -1063,56 +1063,54 @@ or deleted. sub notify { my ($flag, $bug, $attachment) = @_; - my $template = Bugzilla->template; - # There is nobody to notify. return unless ($flag->{'addressee'} || $flag->type->cc_list); - my $attachment_is_private = $attachment ? $attachment->isprivate : undef; - # If the target bug is restricted to one or more groups, then we need # to make sure we don't send email about it to unauthorized users # on the request type's CC: list, so we have to trawl the list for users # not in those groups or email addresses that don't have an account. my @bug_in_groups = grep {$_->{'ison'} || $_->{'mandatory'}} @{$bug->groups}; + my $attachment_is_private = $attachment ? $attachment->isprivate : undef; - if (scalar(@bug_in_groups) || $attachment_is_private) { - my @new_cc_list; - foreach my $cc (split(/[, ]+/, $flag->type->cc_list)) { - my $ccuser = new Bugzilla::User({ name => $cc }) || next; - - next if (scalar(@bug_in_groups) && !$ccuser->can_see_bug($bug->bug_id)); - next if $attachment_is_private - && Bugzilla->params->{"insidergroup"} - && !$ccuser->in_group(Bugzilla->params->{"insidergroup"}); - push(@new_cc_list, $cc); - } - $flag->type->{'cc_list'} = join(", ", @new_cc_list); + my %recipients; + foreach my $cc (split(/[, ]+/, $flag->type->cc_list)) { + my $ccuser = new Bugzilla::User({ name => $cc }); + next if (scalar(@bug_in_groups) && (!$ccuser || !$ccuser->can_see_bug($bug->bug_id))); + next if $attachment_is_private && (!$ccuser || !$ccuser->is_insider); + # Prevent duplicated entries due to case sensitivity. + $cc = $ccuser ? $ccuser->email : $cc; + $recipients{$cc} = $ccuser; } - # If there is nobody left to notify, return. - return unless ($flag->{'addressee'} || $flag->type->cc_list); - - my @recipients = split(/[, ]+/, $flag->type->cc_list); # Only notify if the addressee is allowed to receive the email. if ($flag->{'addressee'} && $flag->{'addressee'}->email_enabled) { - push @recipients, $flag->{'addressee'}->email; + $recipients{$flag->{'addressee'}->email} = $flag->{'addressee'}; } - # Process and send notification for each recipient - foreach my $to (@recipients) - { - next unless $to; + # Process and send notification for each recipient. + # If there are users in the CC list who don't have an account, + # use the default language for email notifications. + my $default_lang; + if (grep { !$_ } values %recipients) { + my $default_user = new Bugzilla::User(); + $default_lang = $default_user->settings->{'lang'}->{'value'}; + } + + foreach my $to (keys %recipients) { my $vars = { 'flag' => $flag, 'to' => $to, 'bug' => $bug, 'attachment' => $attachment}; + + my $lang = $recipients{$to} ? + $recipients{$to}->settings->{'lang'}->{'value'} : $default_lang; + + my $template = Bugzilla->template_inner($lang); my $message; - my $rv = $template->process("request/email.txt.tmpl", $vars, \$message); - if (!$rv) { - Bugzilla->cgi->header(); - ThrowTemplateError($template->error()); - } + $template->process("request/email.txt.tmpl", $vars, \$message) + || ThrowTemplateError($template->error()); + Bugzilla->template_inner(""); MessageToMTA($message); } } diff --git a/Bugzilla/Token.pm b/Bugzilla/Token.pm index 2f911fca1..157cc0622 100644 --- a/Bugzilla/Token.pm +++ b/Bugzilla/Token.pm @@ -34,6 +34,7 @@ use Bugzilla::Constants; use Bugzilla::Error; use Bugzilla::Mailer; use Bugzilla::Util; +use Bugzilla::User; use Date::Format; use Date::Parse; @@ -80,20 +81,24 @@ sub issue_new_user_account_token { $template->process('account/email/request-new.txt.tmpl', $vars, \$message) || ThrowTemplateError($template->error()); + # In 99% of cases, the user getting the confirmation email is the same one + # who made the request, and so it is reasonable to send the email in the same + # language used to view the "Create a New Account" page (we cannot use his + # user prefs as the user has no account yet!). MessageToMTA($message); } sub IssueEmailChangeToken { - my ($userid, $old_email, $new_email) = @_; + my ($user, $old_email, $new_email) = @_; my $email_suffix = Bugzilla->params->{'emailsuffix'}; - my ($token, $token_ts) = _create_token($userid, 'emailold', $old_email . ":" . $new_email); + my ($token, $token_ts) = _create_token($user->id, 'emailold', $old_email . ":" . $new_email); - my $newtoken = _create_token($userid, 'emailnew', $old_email . ":" . $new_email); + my $newtoken = _create_token($user->id, 'emailnew', $old_email . ":" . $new_email); # Mail the user the token along with instructions for using it. - my $template = Bugzilla->template; + my $template = Bugzilla->template_inner($user->settings->{'lang'}->{'value'}); my $vars = {}; $vars->{'oldemailaddress'} = $old_email . $email_suffix; @@ -118,38 +123,34 @@ sub IssueEmailChangeToken { $template->process("account/email/change-new.txt.tmpl", $vars, \$message) || ThrowTemplateError($template->error()); + Bugzilla->template_inner(""); MessageToMTA($message); } # Generates a random token, adds it to the tokens table, and sends it # to the user with instructions for using it to change their password. sub IssuePasswordToken { - my $loginname = shift; + my $user = shift; my $dbh = Bugzilla->dbh; - my $template = Bugzilla->template; - my $vars = {}; - # Retrieve the user's ID from the database. - trick_taint($loginname); - my ($userid, $too_soon) = - $dbh->selectrow_array('SELECT profiles.userid, tokens.issuedate - FROM profiles - LEFT JOIN tokens - ON tokens.userid = profiles.userid - AND tokens.tokentype = ? - AND tokens.issuedate > NOW() - ' . - $dbh->sql_interval(10, 'MINUTE') . ' - WHERE ' . $dbh->sql_istrcmp('login_name', '?'), - undef, ('password', $loginname)); + my $too_soon = + $dbh->selectrow_array('SELECT 1 FROM tokens + WHERE userid = ? + AND tokentype = ? + AND issuedate > NOW() - ' . + $dbh->sql_interval(10, 'MINUTE'), + undef, ($user->id, 'password')); ThrowUserError('too_soon_for_new_token', {'type' => 'password'}) if $too_soon; - my ($token, $token_ts) = _create_token($userid, 'password', $::ENV{'REMOTE_ADDR'}); + my ($token, $token_ts) = _create_token($user->id, 'password', $::ENV{'REMOTE_ADDR'}); # Mail the user the token along with instructions for using it. - $vars->{'token'} = $token; - $vars->{'emailaddress'} = $loginname . Bugzilla->params->{'emailsuffix'}; + my $template = Bugzilla->template_inner($user->settings->{'lang'}->{'value'}); + my $vars = {}; + $vars->{'token'} = $token; + $vars->{'emailaddress'} = $user->email; $vars->{'max_token_age'} = MAX_TOKEN_AGE; $vars->{'token_ts'} = $token_ts; @@ -158,6 +159,7 @@ sub IssuePasswordToken { $vars, \$message) || ThrowTemplateError($template->error()); + Bugzilla->template_inner(""); MessageToMTA($message); } @@ -205,31 +207,28 @@ sub GenerateUniqueToken { return $token; } -# Cancels a previously issued token and notifies the system administrator. +# Cancels a previously issued token and notifies the user. # This should only happen when the user accidentally makes a token request # or when a malicious hacker makes a token request on behalf of a user. sub Cancel { my ($token, $cancelaction, $vars) = @_; my $dbh = Bugzilla->dbh; - my $template = Bugzilla->template; $vars ||= {}; # Get information about the token being canceled. trick_taint($token); - my ($issuedate, $tokentype, $eventdata, $loginname) = + my ($issuedate, $tokentype, $eventdata, $userid) = $dbh->selectrow_array('SELECT ' . $dbh->sql_date_format('issuedate') . ', - tokentype, eventdata, login_name + tokentype, eventdata, userid FROM tokens - LEFT JOIN profiles - ON tokens.userid = profiles.userid WHERE token = ?', undef, $token); - # If we are cancelling the creation of a new user account, then there + # If we are canceling the creation of a new user account, then there # is no entry in the 'profiles' table. - $loginname ||= $eventdata; - $vars->{'emailaddress'} = $loginname . Bugzilla->params->{'emailsuffix'}; - $vars->{'maintainer'} = Bugzilla->params->{'maintainer'}; + my $user = new Bugzilla::User($userid); + + $vars->{'emailaddress'} = $userid ? $user->email : $eventdata; $vars->{'remoteaddress'} = $::ENV{'REMOTE_ADDR'}; $vars->{'token'} = $token; $vars->{'tokentype'} = $tokentype; @@ -238,11 +237,13 @@ sub Cancel { $vars->{'cancelaction'} = $cancelaction; # Notify the user via email about the cancellation. + my $template = Bugzilla->template_inner($user->settings->{'lang'}->{'value'}); my $message; $template->process("account/cancel-token.txt.tmpl", $vars, \$message) || ThrowTemplateError($template->error()); + Bugzilla->template_inner(""); MessageToMTA($message); # Delete the token from the database. @@ -391,8 +392,8 @@ Bugzilla::Token - Provides different routines to manage tokens. use Bugzilla::Token; Bugzilla::Token::issue_new_user_account_token($login_name); - Bugzilla::Token::IssueEmailChangeToken($user_id, $old_email, $new_email); - Bugzilla::Token::IssuePasswordToken($login_name); + Bugzilla::Token::IssueEmailChangeToken($user, $old_email, $new_email); + Bugzilla::Token::IssuePasswordToken($user); Bugzilla::Token::DeletePasswordTokens($user_id, $reason); Bugzilla::Token::Cancel($token, $cancelaction, $vars); @@ -422,26 +423,26 @@ Bugzilla::Token - Provides different routines to manage tokens. Returns: Nothing. It throws an error if the same user made the same request in the last few minutes. -=item C +=item C Description: Sends two distinct tokens per email to the old and new email addresses to confirm the email address change for the given - user ID. These tokens remain valid for the next MAX_TOKEN_AGE days. + user. These tokens remain valid for the next MAX_TOKEN_AGE days. - Params: $user_id - The user ID of the user account requesting a new - email address. + Params: $user - User object of the user requesting a new + email address. $old_email - The current (old) email address of the user. $new_email - The new email address of the user. Returns: Nothing. -=item C +=item C - Description: Sends a token per email to the given login name. This token + Description: Sends a token per email to the given user. This token can be used to change the password (e.g. in case the user cannot remember his password and wishes to enter a new one). - Params: $login_name - The login name of the user requesting a new password. + Params: $user - User object of the user requesting a new password. Returns: Nothing. It throws an error if the same user made the same request in the last few minutes. -- cgit v1.2.3-24-g4f1b