From: Guy Pyrzak Date: Sun, 3 Oct 2010 20:44:42 +0000 (-0700) Subject: Bug 65477: Send HTML bugmail X-Git-Tag: bugzilla-4.1.1~240 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=71320dae661a8ca351128d917c894b0f8318eaf3;p=thirdparty%2Fbugzilla.git Bug 65477: Send HTML bugmail r=mkanat, a=mkanat --- diff --git a/Bugzilla/BugMail.pm b/Bugzilla/BugMail.pm index 2ac5752938..dfd7584ea6 100644 --- a/Bugzilla/BugMail.pm +++ b/Bugzilla/BugMail.pm @@ -29,6 +29,7 @@ # Byron Jones # Reed Loden # Frédéric Buclin +# Guy Pyrzak use strict; @@ -83,10 +84,9 @@ sub Send { # can 'have' a role, if the person in that role has changed, or people are # watching. my @assignees = ($bug->assigned_to); - my @qa_contacts = ($bug->qa_contact); + my @qa_contacts = $bug->qa_contact || (); my @ccs = @{ $bug->cc_users }; - # Include the people passed in as being in particular roles. # This can include people who used to hold those roles. # At this point, we don't care if there are duplicates in these arrays. @@ -104,6 +104,7 @@ sub Send { push(@ccs, Bugzilla::User->check($cc)); } } + my %user_cache = map { $_->id => $_ } (@assignees, @qa_contacts, @ccs); my @diffs; if (!$start) { @@ -123,7 +124,7 @@ sub Send { blocker => $params->{blocker} }); } else { - push(@diffs, _get_diffs($bug, $end)); + push(@diffs, _get_diffs($bug, $end, \%user_cache)); } my $comments = $bug->comments({ after => $start, to => $end }); @@ -220,7 +221,8 @@ sub Send { foreach my $user_id (keys %recipients) { my %rels_which_want; my $sent_mail = 0; - my $user = new Bugzilla::User($user_id); + $user_cache{$user_id} ||= new Bugzilla::User($user_id); + my $user = $user_cache{$user_id}; # Deleted users must be excluded. next unless $user; @@ -353,19 +355,47 @@ sub sendMail { new_comments => \@send_comments, threadingmarker => build_thread_marker($bug->id, $user->id, !$bug->lastdiffed), }; - - my $msg; - my $template = Bugzilla->template_inner($user->settings->{'lang'}->{'value'}); - $template->process("email/newchangedmail.txt.tmpl", $vars, \$msg) - || ThrowTemplateError($template->error()); - + my $msg = _generate_bugmail($user, $vars); MessageToMTA($msg); return 1; } +sub _generate_bugmail { + my ($user, $vars) = @_; + my $template = Bugzilla->template_inner($user->settings->{'lang'}->{'value'}); + my ($msg_text, $msg_html, $msg_header); + + $template->process("email/bugmail-header.txt.tmpl", $vars, \$msg_header) + || ThrowTemplateError($template->error()); + $template->process("email/bugmail.txt.tmpl", $vars, \$msg_text) + || ThrowTemplateError($template->error()); + $template->process("email/bugmail.html.tmpl", $vars, \$msg_html) + || ThrowTemplateError($template->error()); + + my @parts = ( + Email::MIME->create( + attributes => { + content_type => "text/plain", + }, + body => $msg_text, + ), + Email::MIME->create( + attributes => { + content_type => "text/html", + }, + body => $msg_html, + ), + ); + + my $email = new Email::MIME($msg_header); + $email->parts_set(\@parts); + $email->content_type_set('multipart/alternative'); + return $email; +} + sub _get_diffs { - my ($bug, $end) = @_; + my ($bug, $end, $user_cache) = @_; my $dbh = Bugzilla->dbh; my @args = ($bug->id); @@ -377,20 +407,20 @@ sub _get_diffs { } my $diffs = $dbh->selectall_arrayref( - "SELECT profiles.login_name, profiles.realname, fielddefs.name AS field_name, + "SELECT fielddefs.name AS field_name, bugs_activity.bug_when, bugs_activity.removed AS old, bugs_activity.added AS new, bugs_activity.attach_id, - bugs_activity.comment_id + bugs_activity.comment_id, bugs_activity.who FROM bugs_activity INNER JOIN fielddefs ON fielddefs.id = bugs_activity.fieldid - INNER JOIN profiles - ON profiles.userid = bugs_activity.who WHERE bugs_activity.bug_id = ? $when_restriction ORDER BY bugs_activity.bug_when", {Slice=>{}}, @args); foreach my $diff (@$diffs) { + $user_cache->{$diff->{who}} ||= new Bugzilla::User($diff->{who}); + $diff->{who} = $user_cache->{$diff->{who}}; if ($diff->{attach_id}) { $diff->{isprivate} = $dbh->selectrow_array( 'SELECT isprivate FROM attachments WHERE attach_id = ?', diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm index 5ff5482b28..ee4d6cba25 100644 --- a/Bugzilla/Template.pm +++ b/Bugzilla/Template.pm @@ -348,8 +348,12 @@ sub get_bug_link { } # Prevent code injection in the title. $title = html_quote(clean_text($title)); - my $linkval = "show_bug.cgi?id=" . $bug->id; + + if ($options->{full_url}) { + $linkval = correct_urlbase() . $linkval; + } + if (defined $options->{comment_num}) { $linkval .= "#c" . $options->{comment_num}; } diff --git a/template/en/default/email/bugmail-common.txt.html b/template/en/default/email/bugmail-common.txt.html new file mode 100644 index 0000000000..b6cadaf110 --- /dev/null +++ b/template/en/default/email/bugmail-common.txt.html @@ -0,0 +1,38 @@ +[%# The contents of this file are subject to the Mozilla Public + # License Version 1.1 (the "License"); you may not use this file + # except in compliance with the License. You may obtain a copy of + # the License at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS + # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + # implied. See the License for the specific language governing + # rights and limitations under the License. + # + # The Original Code is the Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Guy Pyrzak + # Portions created by the Initial Developer are Copyright (C) 2010 the + # Initial Developer. All Rights Reserved. + # + # Contributor(s): Guy Pyrzak + #%] + +[% PROCESS "global/field-descs.none.tmpl" %] + +[% field_label = field_descs.${change.field_name} %] +[% old_value = display_value(change.field_name, change.old) %] +[% new_value = display_value(change.field_name, change.new) %] + +[% IF change.field_name == "estimated_time" || change.field_name == "remaining_time" %] + [% old_value = old_value FILTER format('%.2f') %] + [% new_value = new_value FILTER format('%.2f') %] +[% END %] + +[% IF change.attach_id %] + [% field_label = field_label.replace('^(Attachment )?', "Attachment #${change.attach_id} ") %] +[% END %] + +[% IF change.field_name == 'longdescs.isprivate' %] + [% field_label = field_label.replace('^(Comment )?', "Comment #${change.num} ") %] +[% END %] + \ No newline at end of file diff --git a/template/en/default/email/bugmail-header.txt.tmpl b/template/en/default/email/bugmail-header.txt.tmpl new file mode 100644 index 0000000000..c2b4ea4f59 --- /dev/null +++ b/template/en/default/email/bugmail-header.txt.tmpl @@ -0,0 +1,47 @@ +[%# The contents of this file are subject to the Mozilla Public + # License Version 1.1 (the "License"); you may not use this file + # except in compliance with the License. You may obtain a copy of + # the License at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS + # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + # implied. See the License for the specific language governing + # rights and limitations under the License. + # + # The Original Code is the Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): André Batosti + # Frédéric Buclin + # Guy Pyrzak + #%] + +[% PROCESS "global/field-descs.none.tmpl" %] +[% PROCESS "global/reason-descs.none.tmpl" %] +[% isnew = bug.lastdiffed ? 0 : 1 %] + +From: [% Param('mailfrom') %] +To: [% to_user.email %] +Subject: [[% terms.Bug %] [%+ bug.id %]] [% 'New: ' IF isnew %][%+ bug.short_desc %] +Date: [% delta_ts || bug.delta_ts FILTER time("%a, %d %b %Y %T %z", to_user.timezone) %] +X-Bugzilla-Reason: [% reasonsheader %] +X-Bugzilla-Type: [% isnew ? 'new' : 'changed' %] +X-Bugzilla-Watch-Reason: [% reasonswatchheader %] +[% IF Param('useclassification') %] +X-Bugzilla-Classification: [% bug.classification %] +[% END %] +X-Bugzilla-Product: [% bug.product %] +X-Bugzilla-Component: [% bug.component %] +X-Bugzilla-Keywords: [% bug.keywords %] +X-Bugzilla-Severity: [% bug.bug_severity %] +X-Bugzilla-Who: [% changer.login %] +X-Bugzilla-Status: [% bug.bug_status %] +X-Bugzilla-Priority: [% bug.priority %] +X-Bugzilla-Assigned-To: [% bug.assigned_to.login %] +X-Bugzilla-Target-Milestone: [% bug.target_milestone %] +X-Bugzilla-Changed-Fields: [% changedfields.join(" ") %] +[%+ threadingmarker %] diff --git a/template/en/default/email/bugmail.html.tmpl b/template/en/default/email/bugmail.html.tmpl new file mode 100644 index 0000000000..888d47bc4d --- /dev/null +++ b/template/en/default/email/bugmail.html.tmpl @@ -0,0 +1,126 @@ +[%# The contents of this file are subject to the Mozilla Public + # License Version 1.1 (the "License"); you may not use this file + # except in compliance with the License. You may obtain a copy of + # the License at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS + # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + # implied. See the License for the specific language governing + # rights and limitations under the License. + # + # The Original Code is the Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Guy Pyrzak + # Portions created by the Initial Developer are Copyright (C) 2010 the + # Initial Developer. All Rights Reserved. + # + # Contributor(s): Guy Pyrzak + #%] + +[% PROCESS "global/field-descs.none.tmpl" %] +[% PROCESS "global/reason-descs.none.tmpl" %] + +[% isnew = bug.lastdiffed ? 0 : 1 %] + + + + + + [% PROCESS generate_diffs %] +

+ [% FOREACH comment = new_comments.reverse %] +

+ [% IF comment.count %] + [% "Comment # ${comment.count}" FILTER bug_link( bug, + {comment_num => comment.count, full_url => 1}) FILTER none %] + from [% INCLUDE global/user.html.tmpl who = comment.author %] + [% END %] +
[% comment.body_full({ wrap => 1 }) FILTER html %]
+
+ [% END %] +

+

+ + Configure [% terms.bug %]mail + +

+ + You are receiving this mail because: + +
    + [% FOREACH reason = reasons %] + [% IF reason_descs.$reason %] +
  • [% reason_descs.$reason FILTER html %]
  • + [% END %] + [% END %] + [% FOREACH reason = reasons_watch %] + [% IF watch_reason_descs.$reason %] +
  • [% watch_reason_descs.$reason FILTER html %]
  • + [% END %] + [% END %] +
+ + + +[% BLOCK generate_diffs %] + + [% "${terms.Bug} ${bug.id}" FILTER bug_link(bug, full_url => 1) FILTER none %] + + [% last_changer = "" %] + + [% FOREACH change = diffs %] + [% IF !isnew && change.who.login != last_changer %] + [% last_changer = change.who.login %] + [% IF change.blocker %] + + + + [% ELSE %] + + + + [% END %] + + + + + + [% END %] + + [% PROCESS "email/bugmail-common.txt.html" %] + + [% IF isnew %] + + + + + [% ELSE %] + + + + + + [% END %] + [% END %] +
+ [% "${terms.Bug} ${bug.id}" FILTER bug_link(bug, full_url => 1) FILTER none %] depends + on [% "${terms.bug} ${change.blocker.id}" + FILTER bug_link(change.blocker, full_url => 1) FILTER none %], + which changed state. +
+ [% INCLUDE global/user.html.tmpl who = change.who %] + changed: +
WhatRemovedAdded
[% field_label FILTER html %][% new_value FILTER html %]
[% field_label FILTER html %] + [% IF old_value %] + [% old_value FILTER html %] + [% ELSE %] +   + [% END%] + + [% IF new_value %] + [% new_value FILTER html %] + [% ELSE %] +   + [% END%] +
+[% END %] \ No newline at end of file diff --git a/template/en/default/email/newchangedmail.txt.tmpl b/template/en/default/email/bugmail.txt.tmpl similarity index 58% rename from template/en/default/email/newchangedmail.txt.tmpl rename to template/en/default/email/bugmail.txt.tmpl index de4a248e3e..31efaba334 100644 --- a/template/en/default/email/newchangedmail.txt.tmpl +++ b/template/en/default/email/bugmail.txt.tmpl @@ -17,6 +17,7 @@ # # Contributor(s): André Batosti # Frédéric Buclin + # Guy Pyrzak #%] [% PROCESS "global/field-descs.none.tmpl" %] @@ -24,28 +25,6 @@ [% isnew = bug.lastdiffed ? 0 : 1 %] -From: [% Param('mailfrom') %] -To: [% to_user.email %] -Subject: [[% terms.Bug %] [%+ bug.id %]] [% 'New: ' IF isnew %][%+ bug.short_desc %] -Date: [% delta_ts || bug.delta_ts FILTER time("%a, %d %b %Y %T %z", to_user.timezone) %] -X-Bugzilla-Reason: [% reasonsheader %] -X-Bugzilla-Type: [% isnew ? 'new' : 'changed' %] -X-Bugzilla-Watch-Reason: [% reasonswatchheader %] -[% IF Param('useclassification') %] -X-Bugzilla-Classification: [% bug.classification %] -[% END %] -X-Bugzilla-Product: [% bug.product %] -X-Bugzilla-Component: [% bug.component %] -X-Bugzilla-Keywords: [% bug.keywords %] -X-Bugzilla-Severity: [% bug.bug_severity %] -X-Bugzilla-Who: [% changer.login %] -X-Bugzilla-Status: [% bug.bug_status %] -X-Bugzilla-Priority: [% bug.priority %] -X-Bugzilla-Assigned-To: [% bug.assigned_to.login %] -X-Bugzilla-Target-Milestone: [% bug.target_milestone %] -X-Bugzilla-Changed-Fields: [% changedfields.join(" ") %] -[%+ threadingmarker %] - [%+ PROCESS generate_diffs -%] [% FOREACH comment = new_comments %] @@ -74,42 +53,25 @@ Configure [% terms.bug %]mail: [% urlbase %]userprefs.cgi?tab=email [%+ last_changer = "" %] [% FOREACH change = diffs %] - [% IF !isnew && change.login_name != last_changer %] - [% last_changer = change.login_name %] + [% IF !isnew && change.who.login != last_changer %] + [% last_changer = change.who.login %] [% IF change.blocker %] [% terms.Bug %] [%+ bug.id %] depends on [% terms.bug %] [%+ change.blocker.id %], which changed state. [%+ terms.Bug %] [%+ change.blocker.id %] Summary: [% change.blocker.short_desc %] [%+ urlbase %]show_bug.cgi?id=[% change.blocker.id %] [% ELSE %] - [%~ IF change.realname %] - [% change.realname _ " <" _ change.login_name _ ">" %] + [%~ IF change.who.name %] + [% change.who.name _ " <" _ change.who.login _ ">" %] [% ELSE %] - [% change.login_name %] + [% change.who.login %] [% END %] changed: [% END %] What |Removed |Added ---------------------------------------------------------------------------- [%+ END %][%# End of IF. This indentation is intentional! ~%] - - [% field_label = field_descs.${change.field_name} %] - [% old_value = display_value(change.field_name, change.old) %] - [% new_value = display_value(change.field_name, change.new) %] - - [%~ IF change.field_name == "estimated_time" || change.field_name == "remaining_time" %] - [% old_value = old_value FILTER format('%.2f') %] - [% new_value = new_value FILTER format('%.2f') %] - [% END %] - - [%~ IF change.attach_id %] - [% field_label = field_label.replace('^(Attachment )?', "Attachment #${change.attach_id} ") %] - [% END %] - - [%~ IF change.field_name == 'longdescs.isprivate' %] - [% field_label = field_label.replace('^(Comment )?', "Comment #${change.num} ") %] - [% END %] - + [% PROCESS "email/bugmail-common.txt.html"%] [%~ IF isnew %] [% format_columns(2, field_label _ ":", new_value) -%] [% ELSE %]