[Rt-commit] rt branch, 4.2/html-templates, created. rt-4.1.8-162-gb098507

Thomas Sibley trs at bestpractical.com
Wed May 1 21:22:34 EDT 2013


The branch, 4.2/html-templates has been created
        at  b098507a8e701318aa813e95c6e8ba001e1b50e2 (commit)

- Log -----------------------------------------------------------------
commit e869c7f707ed1c5f7cb4c731184b1782d731dea3
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Thu Mar 25 16:42:59 2010 -0400

    HTML versions of the stock templates

diff --git a/etc/initialdata b/etc/initialdata
old mode 100755
new mode 100644
index 76dc108..1603e08
--- a/etc/initialdata
+++ b/etc/initialdata
@@ -216,7 +216,7 @@
       Content     => '', },
     {  Queue       => '0',
        Name        => 'Autoreply',                                         # loc
-       Description => 'Default Autoresponse template',                     # loc
+       Description => 'Plain text Autoresponse template',                     # loc
        Content     => 'Subject: AutoReply: {$Ticket->Subject}
 
 
@@ -244,10 +244,35 @@ you may reply to this message.
 {$Transaction->Content()}
 '
     },
+    {  Queue       => '0',
+       Name        => 'Autoreply in HTML',                              # loc
+       Description => 'HTML Autoresponse template',                     # loc
+       Content     => q[Subject: AutoReply: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>This message has been automatically generated in response to the
+creation of a trouble ticket regarding <b>{$Ticket->Subject()}</b>,
+a summary of which appears below.</p>
+
+<p>There is no need to reply to this message right now.  Your ticket has been
+assigned an ID of <b>{$Ticket->SubjectTag}</b>.</p>
+
+<p>Please include the string <b>{$Ticket->SubjectTag}</b>
+in the subject line of all future correspondence about this issue. To do so,
+you may reply to this message.</p>
 
+<p>Thank you,<br/>
+{$Ticket->QueueObj->CorrespondAddress()}</p>
+
+<hr/>
+{$Transaction->Content(Type => 'text/html')}
+],
+    },
     {  Queue       => '0',
        Name        => 'Transaction',                     # loc
-       Description => 'Default transaction template',    # loc
+       Description => 'Plain text transaction template', # loc
        Content     => 'RT-Attach-Message: yes
 
 
@@ -264,12 +289,33 @@ you may reply to this message.
 {$Transaction->Content()}
 '
     },
-
+    {  Queue       => '0',
+       Name        => 'Transaction in HTML',          # loc
+       Description => 'HTML transaction template',    # loc
+       Content     => 'RT-Attach-Message: yes
+Content-Type: text/html
+
+<b>{$Transaction->CreatedAsString}: Request <a href="{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}">{$Ticket->id}</a> was acted upon by {$Transaction->CreatorObj->Name}.</b>
+<br>
+<table border="0">
+<tr><td align="right"><b>Transaction:</b></td><td>{$Transaction->Description}</td></tr>
+<tr><td align="right"><b>Queue:</b></td><td>{$Ticket->QueueObj->Name}</td></tr>
+<tr><td align="right"><b>Subject:</b></td><td>{$Transaction->Subject || $Ticket->Subject || "(No subject given)"} </td></tr>
+<tr><td align="right"><b>Owner:</b></td><td>{$Ticket->OwnerObj->Name}</td></tr>
+<tr><td align="right"><b>Requestors:</b></td><td>{$Ticket->RequestorAddresses}</td></tr>
+<tr><td align="right"><b>Status:</b></td><td>{$Ticket->Status}</td></tr>
+<tr><td align="right"><b>Ticket URL:</b></td><td><a href="{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}">{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}</a></td></tr>
+</table>
+<br/>
+<br/>
+{$Transaction->Content( Type => "text/html")}
+'
+    },
     {
 
       Queue       => '0',
       Name        => 'Admin Correspondence',                     # loc
-      Description => 'Default admin correspondence template',    # loc
+      Description => 'Plain text admin correspondence template',    # loc
       Content     => 'RT-Attach-Message: yes
 
 
@@ -278,19 +324,38 @@ you may reply to this message.
 {$Transaction->Content()}
 '
     },
+    {  Queue       => '0',
+       Name        => 'Admin Correspondence in HTML',                     # loc
+       Description => 'HTML admin correspondence template',    # loc
+       Content     => 'RT-Attach-Message: yes
+Content-Type: text/html
 
+Ticket URL: <a href="{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}">{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}</a>
+<br />
+<br />
+{$Transaction->Content(Type => "text/html");}
+'
+    },
     {  Queue       => '0',
        Name        => 'Correspondence',                          # loc
-       Description => 'Default correspondence template',         # loc
+       Description => 'Plain text correspondence template',         # loc
        Content     => 'RT-Attach-Message: yes
 
 {$Transaction->Content()}
 '
     },
+    {  Queue       => '0',
+       Name        => 'Correspondence in HTML',                 # loc
+       Description => 'HTML correspondence template',           # loc
+       Content     => 'RT-Attach-Message: yes
+Content-Type: text/html
 
+{$Transaction->Content( Type => "text/html")}
+'
+    },
     {  Queue       => '0',
        Name        => 'Admin Comment',                           # loc
-       Description => 'Default admin comment template',          # loc
+       Description => 'Plain text admin comment template',          # loc
        Content     =>
 'Subject: [Comment] {my $s=($Transaction->Subject||$Ticket->Subject||""); $s =~ s/\\[Comment\\]\\s*//g; $s =~ s/^Re:\\s*//i; $s;}
 RT-Attach-Message: yes
@@ -302,7 +367,19 @@ This is a comment.  It is not sent to the Requestor(s):
 {$Transaction->Content()}
 '
     },
+    {  Queue       => '0',
+       Name        => 'Admin Comment in HTML',                  # loc
+       Description => 'HTML admin comment template',            # loc
+       Content     => 
+'Subject: [Comment] {my $s=($Transaction->Subject||$Ticket->Subject||""); $s =~ s/\\[Comment\\]\\s*//g; $s =~ s/^Re:\\s*//i; $s;}
+RT-Attach-Message: yes
+Content-Type: text/html
+
+<p>This is a comment about <a href="{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}">ticket {$Ticket->id}</a>. It is not sent to the Requestor(s):</p>
 
+{$Transaction->Content(Type => "text/html")}
+'
+    },
     {  Queue       => '0',
        Name        => 'Status Change',                                     # loc
        Description => 'Ticket status changed',                             # loc
@@ -314,7 +391,18 @@ This is a comment.  It is not sent to the Requestor(s):
 {$Transaction->Content()}
 '
     },
+    {  Queue       => '0',
+       Name        => 'Status Change in HTML',              # loc
+       Description => 'HTML Ticket status changed',              # loc
+       Content     => 'Subject: Status Changed to: {$Transaction->NewValue}
+Content-Type: text/html
 
+<a href="{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}">{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}</a>
+<br/>
+<br/>
+{$Transaction->Content(Type => "text/html")}
+'
+    },
     {
 
       Queue       => '0',
@@ -326,6 +414,15 @@ According to our records, your request has been resolved. If you have any
 further questions or concerns, please respond to this message.
 '
     },
+    {  Queue       => '0',
+       Name        => 'Resolved in HTML',               # loc
+       Description => 'HTML Ticket Resolved',           # loc
+       Content     => 'Subject: Resolved: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>According to our records, your request has been resolved.  If you have any further questions or concerns, please respond to this message.</p>
+'
+    },
     {  Queue       => '___Approvals',
        Name        => "New Pending Approval",    # loc
        Description =>
@@ -346,6 +443,25 @@ batch-process all your pending approvals.
 '
     },
     {  Queue       => '___Approvals',
+       Name        => "New Pending Approval in HTML",                                   # loc
+       Description => "Notify Owners and AdminCcs of new items pending their approval", # loc
+       Content     => 'Subject: New Pending Approval: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>There is a new item pending your approval: <b>{$Ticket->Subject()}</b>,
+a summary of which appears below.</p>
+
+<p>Please <a href="{RT->Config->Get(\'WebURL\')}Approvals/Display.html?id={$Ticket->id}">approve
+or reject this ticket</a>, or visit the <a href="{RT->Config->Get(\'WebURL\')}Approvals/">approvals
+overview</a> to batch-process all your pending approvals.</p>
+
+<hr />
+{$Transaction->Content()}
+'
+    },
+    {  Queue       => '___Approvals',
        Name        => "Approval Passed",    # loc
        Description =>
          "Notify Requestor of their ticket has been approved by some approver", # loc
@@ -360,6 +476,22 @@ Approver\'s notes: { $Notes }
 '
     },
     {  Queue       => '___Approvals',
+       Name        => "Approval Passed in HTML",    # loc
+       Description =>
+         "Notify Requestor of their ticket has been approved by some approver", # loc
+       Content => 'Subject: Ticket Approved: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>Your ticket has been approved by <b>{ eval { $Approver->Name } }</b>.
+Other approvals may be pending.</p>
+
+<p>Approver\'s notes:</p>
+<blockquote>{ $Notes }</blockquote>
+'
+    },
+    {  Queue       => '___Approvals',
        Name        => "All Approvals Passed",    # loc
        Description =>
          "Notify Requestor of their ticket has been approved by all approvers", # loc
@@ -374,6 +506,22 @@ Approver\'s notes: { $Notes }
 '
     },
     {  Queue       => '___Approvals',
+       Name        => "All Approvals Passed in HTML",    # loc
+       Description =>
+         "Notify Requestor of their ticket has been approved by all approvers", # loc
+       Content => 'Subject: Ticket Approved: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>Your ticket has been approved by <b>{ eval { $Approver->Name } }</b>.
+Its Owner may now start to act on it.</p>
+
+<p>Approver\'s notes:</p>
+<blockquote>{ $Notes }</blockquote>
+'
+    },
+    {  Queue       => '___Approvals',
        Name        => "Approval Rejected",    # loc
        Description =>
          "Notify Owner of their rejected ticket", # loc
@@ -387,6 +535,21 @@ Approver\'s notes: { $Notes }
 '
     },
     {  Queue       => '___Approvals',
+       Name        => "Approval Rejected in HTML",    # loc
+       Description =>
+         "Notify Owner of their rejected ticket", # loc
+       Content => 'Subject: Ticket Rejected: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>Your ticket has been rejected by <b>{ eval { $Approver->Name } }</b>.</p>
+
+<p>Approver\'s notes:</p>
+<blockquote>{ $Notes }</blockquote>
+'
+    },
+    {  Queue       => '___Approvals',
        Name        => "Approval Ready for Owner",    # loc
        Description =>
          "Notify Owner of their ticket has been approved and is ready to be acted on", # loc
@@ -398,6 +561,19 @@ The ticket has been approved, you may now start to act on it.
 
 '
     },
+    {  Queue       => '___Approvals',
+       Name        => "Approval Ready for Owner in HTML",    # loc
+       Description =>
+         "Notify Owner of their ticket has been approved and is ready to be acted on", # loc
+       Content => 'Subject: Ticket Approved: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>The ticket has been approved, you may now start to act on it.</p>
+
+'
+    },
     {  Queue       => 0,
        Name        => "Forward",    # loc
        Description => "Heading of a forwarded message", # loc
diff --git a/etc/upgrade/4.1.11/content b/etc/upgrade/4.1.11/content
new file mode 100644
index 0000000..3c68b69
--- /dev/null
+++ b/etc/upgrade/4.1.11/content
@@ -0,0 +1,190 @@
+use strict;
+use warnings;
+
+# New HTML templates
+
+our @Templates = (
+    {  Queue       => '0',
+       Name        => 'Autoreply in HTML',                              # loc
+       Description => 'HTML Autoresponse template',                     # loc
+       Content     => q[Subject: AutoReply: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>This message has been automatically generated in response to the
+creation of a trouble ticket regarding <b>{$Ticket->Subject()}</b>,
+a summary of which appears below.</p>
+
+<p>There is no need to reply to this message right now.  Your ticket has been
+assigned an ID of <b>{$Ticket->SubjectTag}</b>.</p>
+
+<p>Please include the string <b>{$Ticket->SubjectTag}</b>
+in the subject line of all future correspondence about this issue. To do so,
+you may reply to this message.</p>
+
+<p>Thank you,<br/>
+{$Ticket->QueueObj->CorrespondAddress()}</p>
+
+<hr/>
+{$Transaction->Content(Type => 'text/html')}
+],
+    },
+    {  Queue       => '0',
+       Name        => 'Transaction in HTML',          # loc
+       Description => 'HTML transaction template',    # loc
+       Content     => 'RT-Attach-Message: yes
+Content-Type: text/html
+
+<b>{$Transaction->CreatedAsString}: Request <a href="{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}">{$Ticket->id}</a> was acted upon by {$Transaction->CreatorObj->Name}.</b>
+<br>
+<table border="0">
+<tr><td align="right"><b>Transaction:</b></td><td>{$Transaction->Description}</td></tr>
+<tr><td align="right"><b>Queue:</b></td><td>{$Ticket->QueueObj->Name}</td></tr>
+<tr><td align="right"><b>Subject:</b></td><td>{$Transaction->Subject || $Ticket->Subject || "(No subject given)"} </td></tr>
+<tr><td align="right"><b>Owner:</b></td><td>{$Ticket->OwnerObj->Name}</td></tr>
+<tr><td align="right"><b>Requestors:</b></td><td>{$Ticket->RequestorAddresses}</td></tr>
+<tr><td align="right"><b>Status:</b></td><td>{$Ticket->Status}</td></tr>
+<tr><td align="right"><b>Ticket URL:</b></td><td><a href="{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}">{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}</a></td></tr>
+</table>
+<br/>
+<br/>
+{$Transaction->Content( Type => "text/html")}
+'
+    },
+    {  Queue       => '0',
+       Name        => 'Admin Correspondence in HTML',                     # loc
+       Description => 'HTML admin correspondence template',    # loc
+       Content     => 'RT-Attach-Message: yes
+Content-Type: text/html
+
+Ticket URL: <a href="{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}">{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}</a>
+<br />
+<br />
+{$Transaction->Content(Type => "text/html");}
+'
+    },
+    {  Queue       => '0',
+       Name        => 'Correspondence in HTML',                 # loc
+       Description => 'HTML correspondence template',           # loc
+       Content     => 'RT-Attach-Message: yes
+Content-Type: text/html
+
+{$Transaction->Content( Type => "text/html")}
+'
+    },
+    {  Queue       => '0',
+       Name        => 'Admin Comment in HTML',                  # loc
+       Description => 'HTML admin comment template',            # loc
+       Content     => 
+'Subject: [Comment] {my $s=($Transaction->Subject||$Ticket->Subject); $s =~ s/\\[Comment\\]\\s*//g; $s =~ s/^Re:\\s*//i; $s;}
+RT-Attach-Message: yes
+Content-Type: text/html
+
+<p>This is a comment about <a href="{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}">ticket {$Ticket->id}</a>. It is not sent to the Requestor(s):</p>
+
+{$Transaction->Content(Type => "text/html")}
+'
+    },
+    {  Queue       => '0',
+       Name        => 'Status Change in HTML',              # loc
+       Description => 'HTML Ticket status changed',              # loc
+       Content     => 'Subject: Status Changed to: {$Transaction->NewValue}
+Content-Type: text/html
+
+<a href="{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}">{RT->Config->Get("WebURL")}Ticket/Display.html?id={$Ticket->id}</a>
+<br/>
+<br/>
+{$Transaction->Content(Type => "text/html")}
+'
+    },
+    {  Queue       => '0',
+       Name        => 'Resolved in HTML',               # loc
+       Description => 'HTML Ticket Resolved',           # loc
+       Content     => 'Subject: Resolved: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>According to our records, your request has been resolved.  If you have any further questions or concerns, please respond to this message.</p>
+'
+    },
+    {  Queue       => '___Approvals',
+       Name        => "New Pending Approval in HTML",                                   # loc
+       Description => "Notify Owners and AdminCcs of new items pending their approval", # loc
+       Content     => 'Subject: New Pending Approval: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>There is a new item pending your approval: <b>{$Ticket->Subject()}</b>,
+a summary of which appears below.</p>
+
+<p>Please <a href="{RT->Config->Get(\'WebURL\')}Approvals/Display.html?id={$Ticket->id}">approve
+or reject this ticket</a>, or visit the <a href="{RT->Config->Get(\'WebURL\')}Approvals/">approvals
+overview</a> to batch-process all your pending approvals.</p>
+
+<hr />
+{$Transaction->Content()}
+'
+    },
+    {  Queue       => '___Approvals',
+       Name        => "Approval Passed in HTML",    # loc
+       Description =>
+         "Notify Requestor of their ticket has been approved by some approver", # loc
+       Content => 'Subject: Ticket Approved: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>Your ticket has been approved by <b>{ eval { $Approver->Name } }</b>.
+Other approvals may be pending.</p>
+
+<p>Approver\'s notes:</p>
+<blockquote>{ $Notes }</blockquote>
+'
+    },
+    {  Queue       => '___Approvals',
+       Name        => "All Approvals Passed in HTML",    # loc
+       Description =>
+         "Notify Requestor of their ticket has been approved by all approvers", # loc
+       Content => 'Subject: Ticket Approved: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>Your ticket has been approved by <b>{ eval { $Approver->Name } }</b>.
+Its Owner may now start to act on it.</p>
+
+<p>Approver\'s notes:</p>
+<blockquote>{ $Notes }</blockquote>
+'
+    },
+    {  Queue       => '___Approvals',
+       Name        => "Approval Rejected in HTML",    # loc
+       Description =>
+         "Notify Owner of their rejected ticket", # loc
+       Content => 'Subject: Ticket Rejected: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>Your ticket has been rejected by <b>{ eval { $Approver->Name } }</b>.</p>
+
+<p>Approver\'s notes:</p>
+<blockquote>{ $Notes }</blockquote>
+'
+    },
+    {  Queue       => '___Approvals',
+       Name        => "Approval Ready for Owner in HTML",    # loc
+       Description =>
+         "Notify Owner of their ticket has been approved and is ready to be acted on", # loc
+       Content => 'Subject: Ticket Approved: {$Ticket->Subject}
+Content-Type: text/html
+
+<p>Greetings,</p>
+
+<p>The ticket has been approved, you may now start to act on it.</p>
+
+'
+    },
+);
+

commit efb310994cfe6998045b354266ab796c0ebf4b62
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Fri Apr 2 14:05:24 2010 -0400

    Factor out our HTML to text conversion routine
    
    Switches to HTML::FormatText::WithLinks::AndTables for better formatting
    of links and tables.

diff --git a/lib/RT/Interface/Email.pm b/lib/RT/Interface/Email.pm
index b6f10f9..eb76f79 100644
--- a/lib/RT/Interface/Email.pm
+++ b/lib/RT/Interface/Email.pm
@@ -1878,6 +1878,33 @@ sub _RecordSendEmailFailure {
     }
 }
 
+=head2 ConvertHTMLToText HTML
+
+Takes HTML and converts it to plain text.  Appropriate for generating a plain
+text part from an HTML part of an email.
+
+=cut
+
+sub ConvertHTMLToText {
+    my $html = shift;
+
+    require HTML::FormatText::WithLinks::AndTables;
+    return HTML::FormatText::WithLinks::AndTables->convert(
+        $html => {
+            leftmargin      => 0,
+            rightmargin     => 78,
+            no_rowspacing   => 1,
+            before_link     => '',
+            after_link      => ' (%l)',
+            footnote        => '',
+            skip_linked_urls => 1,
+            with_emphasis   => 1,
+            bold_marker     => '"',
+            italic_marker   => '"',
+        }
+    );
+}
+
 RT::Base->_ImportOverlays();
 
 1;
diff --git a/lib/RT/Template.pm b/lib/RT/Template.pm
index 47ad1e2..01c74d3 100644
--- a/lib/RT/Template.pm
+++ b/lib/RT/Template.pm
@@ -641,20 +641,11 @@ sub _DowngradeFromHTML {
     $orig_entity->head->mime_attr( "Content-Type.charset" => 'utf-8' );
     $orig_entity->make_multipart('alternative', Force => 1);
 
-    require HTML::FormatText;
-    require HTML::TreeBuilder;
     require Encode;
-    # need to decode_utf8, see the doc of MIMEObj method
-    my $tree = HTML::TreeBuilder->new_from_content(
-        Encode::decode_utf8($new_entity->bodyhandle->as_string)
-    );
     $new_entity->bodyhandle(MIME::Body::InCore->new(
-        \(scalar HTML::FormatText->new(
-            leftmargin  => 0,
-            rightmargin => 78,
-        )->format( $tree ))
+        # need to decode_utf8, see the doc of MIMEObj method
+        \(RT::Interface::Email::ConvertHTMLToText(Encode::decode_utf8($new_entity->bodyhandle->as_string)))
     ));
-    $tree->delete;
 
     $orig_entity->add_part($new_entity, 0); # plain comes before html
     $self->{MIMEObj} = $orig_entity;
diff --git a/lib/RT/Transaction.pm b/lib/RT/Transaction.pm
index 8c61777..af70088 100644
--- a/lib/RT/Transaction.pm
+++ b/lib/RT/Transaction.pm
@@ -82,8 +82,7 @@ use RT::Attachments;
 use RT::Scrips;
 use RT::Ruleset;
 
-use HTML::FormatText;
-use HTML::TreeBuilder;
+use HTML::FormatText::WithLinks::AndTables;
 use HTML::Scrubber;
 
 # For EscapeHTML() and decode_entities()
@@ -341,12 +340,7 @@ sub Content {
             $content =~ s/<p>--\s+<br \/>.*?$//s if $args{'Quote'};
 
             if ($args{Type} ne 'text/html') {
-                my $tree = HTML::TreeBuilder->new_from_content( $content );
-                $content = HTML::FormatText->new(
-                    leftmargin  => 0,
-                    rightmargin => 78,
-                )->format( $tree);
-                $tree->delete;
+                $content = RT::Interface::Email::ConvertHTMLToText($content);
             }
         }
         else {
diff --git a/sbin/rt-test-dependencies.in b/sbin/rt-test-dependencies.in
index e703355..481df7e 100644
--- a/sbin/rt-test-dependencies.in
+++ b/sbin/rt-test-dependencies.in
@@ -201,6 +201,8 @@ File::Spec 0.8
 File::Temp 0.19
 HTML::Entities
 HTML::FormatText
+HTML::FormatText::WithLinks 0.14
+HTML::FormatText::WithLinks::AndTables
 HTML::Mason 1.43
 HTML::Mason::PSGIHandler 0.52
 HTML::Quoted

commit 85a9f4188a79fbb18328195618791865c9a82a85
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Fri Nov 19 16:09:13 2010 -0500

    Add a script and a note for switching to HTML templates when upgrading

diff --git a/.gitignore b/.gitignore
index 9707931..8c0dfc0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@
 /etc/upgrade/generate-rtaddressregexp
 /etc/upgrade/upgrade-articles
 /etc/upgrade/vulnerable-passwords
+/etc/upgrade/switch-templates-to
 /lib/RT/Generated.pm
 /Makefile
 /t/data/gnupg/keyrings/random_seed
diff --git a/configure.ac b/configure.ac
index 113377d..4e8fa75 100755
--- a/configure.ac
+++ b/configure.ac
@@ -397,6 +397,7 @@ AC_CONFIG_FILES([
                  etc/upgrade/generate-rtaddressregexp
                  etc/upgrade/upgrade-articles
                  etc/upgrade/vulnerable-passwords
+                 etc/upgrade/switch-templates-to
                  sbin/rt-attributes-viewer
                  sbin/rt-preferences-viewer
                  sbin/rt-session-viewer
diff --git a/docs/UPGRADING-4.2 b/docs/UPGRADING-4.2
index 7d5c0cb..f8f771a 100644
--- a/docs/UPGRADING-4.2
+++ b/docs/UPGRADING-4.2
@@ -88,3 +88,16 @@ UPGRADING FROM RT 4.0.0 and greater
 
   This command deletes records from Transactions table. This script can only fix
   TimeWorked mismatch, but not TimeLeft or TimeEstimated.
+
+* There are now HTML versions of the standard plain text templates.  Running
+  make upgrade as described in the README will insert the new templates into
+  existing installs.  While new installs use the HTML templates by default,
+  upgrades from older versions don't automatically switch to the HTML versions.
+  To switch existing scrips, run:
+
+    /opt/rt4/etc/upgrade/switch-templates-to html
+
+  To switch from HTML back to text, run:
+
+    /opt/rtr/etc/upgrade/switch-templates-to text
+
diff --git a/etc/upgrade/switch-templates-to.in b/etc/upgrade/switch-templates-to.in
new file mode 100644
index 0000000..d5c75c5
--- /dev/null
+++ b/etc/upgrade/switch-templates-to.in
@@ -0,0 +1,148 @@
+#!@PERL@
+# BEGIN BPS TAGGED BLOCK {{{
+# 
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2008 Best Practical Solutions, LLC 
+#                                          <jesse at bestpractical.com>
+# 
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
+# 
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+# 
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+# 
+# 
+# CONTRIBUTION SUBMISSION POLICY:
+# 
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+# 
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+# 
+# END BPS TAGGED BLOCK }}}
+use strict;
+use warnings;
+
+use lib "@LOCAL_LIB_PATH@";
+use lib "@RT_LIB_PATH@";
+
+use RT;
+
+my $to = shift || '';
+my $from;
+
+if ($to =~ /html|text/i) {
+    $to   = $to =~ /html/i  ? 'html' : 'text';
+    $from = $to eq 'html'   ? 'text' : 'html';
+} else {
+    print "Usage: $0 [html|text]\n";
+    warn "Please specify if you'd like to switch to HTML or text templates.\n";
+    exit 1;
+}
+
+RT::LoadConfig();
+RT->Config->Set('LogToScreen' => 'info');
+RT::Init();
+
+$| = 1;
+
+my @templates = (
+    "Autoreply",
+    "Transaction",
+    "Admin Correspondence",
+    "Correspondence",
+    "Admin Comment",
+    "Status Change",
+    "Resolved",
+    "New Pending Approval",
+    "Approval Passed",
+    "All Approvals Passed",
+    "Approval Rejected",
+    "Approval Ready for Owner",
+);
+
+$RT::Handle->BeginTransaction();
+
+use RT::Scrips;
+my $scrips = RT::Scrips->new( RT->SystemUser );
+$scrips->UnLimit;
+
+for (@templates) {
+    $scrips->Limit(
+        FIELD => 'Template',
+        VALUE => ($to eq 'html' ? $_ : "$_ in HTML"),
+        ENTRYAGGREGATOR => 'OR'
+    );
+}
+
+my $switched = 0;
+while ( my $s = $scrips->Next ) {
+    my $new = $s->TemplateObj->Name;
+
+    if ($to eq 'html') {
+        $new .= ' in HTML';
+    } else {
+        $new =~ s/ in HTML$//;
+    }
+
+    print $s->id, ": ", $s->Description, "\n";
+    print "    ", $s->TemplateObj->Name, " -> $new\n\n";
+
+    my ($ok, $msg) = $s->SetTemplate($new);
+
+    if ($ok) {
+        $switched++;
+    } else {
+        warn "    Couldn't switch templates: $msg\n";
+    }
+}
+
+$RT::Handle->Commit;
+
+if ($switched) {
+    print <<"    EOT";
+Switched $switched scrips to $to templates.  You should now manually port any
+customizations from the old templates to the new templates.
+    EOT
+    exit 1 if $switched != $scrips->Count;
+}
+elsif ($scrips->Count) {
+    print <<"    EOT";
+@{[$scrips->Count]} scrips using $from templates were found, but none were
+successfully switched to $to.  See the errors above.
+    EOT
+    exit 1;
+}
+else {
+    print <<"    EOT";
+No scrips were found using the $from templates, so none were switched to
+$to templates.
+    EOT
+}
+

commit 321c559d00f08d373853ffac3085b74f7cfe3e68
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Wed Nov 24 18:48:21 2010 -0500

    Add a switch_templates_ok method to switch and test the exit code

diff --git a/lib/RT/Test.pm b/lib/RT/Test.pm
index 97ab94a..4e98e7f 100644
--- a/lib/RT/Test.pm
+++ b/lib/RT/Test.pm
@@ -996,6 +996,46 @@ sub add_rights {
     return 1;
 }
 
+=head2 switch_templates_to TYPE
+
+This runs etc/upgrade/switch-templates-to in order to change the templates from
+HTML to text or vice versa.  TYPE is the type to switch to, either C<html> or
+C<text>.
+
+=cut
+
+sub switch_templates_to {
+    my $self = shift;
+    my $type = shift;
+
+    return $self->run_and_capture(
+        command => "$RT::EtcPath/upgrade/switch-templates-to",
+        args    => $type,
+    );
+}
+
+=head2 switch_templates_ok TYPE
+
+Calls L<switch_template_to> and tests the return values.
+
+=cut
+
+sub switch_templates_ok {
+    my $self = shift;
+    my $type = shift;
+
+    my ($exit, $output) = $self->switch_templates_to($type);
+    
+    if ($exit >> 8) {
+        Test::More::fail("Switched templates to $type cleanly");
+        diag("**** etc/upgrade/switch-templates-to exited with ".($exit >> 8).":\n$output");
+    } else {
+        Test::More::pass("Switched templates to $type cleanly");
+    }
+
+    return ($exit, $output);
+}
+
 sub run_mailgate {
     my $self = shift;
 
@@ -1034,10 +1074,13 @@ sub run_and_capture {
 
     $cmd .= ' --debug' if delete $args{'debug'};
 
+    my $args = delete $args{'args'};
+
     while( my ($k,$v) = each %args ) {
         next unless $v;
         $cmd .= " --$k '$v'";
     }
+    $cmd .= " $args" if defined $args;
     $cmd .= ' 2>&1';
 
     DBIx::SearchBuilder::Record::Cachable->FlushCache;

commit 9ea3b147ecd63fa3c055c103acdd3fa32a17bed2
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Thu Dec 2 18:41:23 2010 -0500

    Add basic structure and content tests for outgoing HTML mail

diff --git a/t/mail/html-outgoing.t b/t/mail/html-outgoing.t
new file mode 100644
index 0000000..bffc1fd
--- /dev/null
+++ b/t/mail/html-outgoing.t
@@ -0,0 +1,165 @@
+use strict;
+use warnings;
+use RT::Test tests => undef;
+BEGIN {
+    plan skip_all => 'Email::Abstract and Test::Email required.'
+        unless eval { require Email::Abstract; require Test::Email; 1 };
+    plan tests => 19;
+}
+
+RT::Test->switch_templates_ok('html');
+
+use RT::Test::Email;
+
+my $root = RT::User->new(RT->SystemUser);
+$root->Load('root');
+
+# Set root as admincc
+my $q = RT::Queue->new(RT->SystemUser);
+$q->Load('General');
+my ($ok, $msg) = $q->AddWatcher( Type => 'AdminCc', PrincipalId => $root->Id );
+ok($ok, "Added root as a watcher on the General queue");
+
+# Create a couple users to test notifications
+my %users;
+for my $user_name (qw(enduser tech)) {
+    my $user = $users{$user_name} = RT::User->new(RT->SystemUser);
+    $user->Create( Name => ucfirst($user_name),
+                   Privileged => 1,
+                   EmailAddress => $user_name.'@example.com');
+    my ($val, $msg);
+    ($val, $msg) = $user->PrincipalObj->GrantRight(Object =>$q, Right => $_)
+        for qw(ModifyTicket OwnTicket ShowTicket);
+}
+
+my $t = RT::Ticket->new(RT->SystemUser);
+my ($tid, $ttrans, $tmsg);
+
+diag "Autoreply and AdminCc (Transaction)";
+mail_ok {
+    ($tid, $ttrans, $tmsg) = 
+        $t->Create(Subject => "The internet is broken",
+                   Owner => 'Tech', Requestor => 'Enduser',
+                   Queue => 'General');
+} { from    => qr/The default queue/,
+    to      => 'enduser at example.com',
+    subject => qr/\Q[example.com #1] AutoReply: The internet is broken\E/,
+    body    => parts_regex(
+        'trouble ticket regarding "The internet is broken"',
+        'trouble ticket regarding <b>The internet is broken</b>'
+    ),
+    'Content-Type' => qr{multipart},
+},{ from    => qr/RT System/,
+    bcc     => 'root at localhost',
+    subject => qr/\Q[example.com #1] The internet is broken\E/,
+    body    => parts_regex(
+        'Request 1 \(http://localhost:\d+/Ticket/Display\.html\?id=1\)\s+?was acted upon by RT_System',
+        'Request <a href="http://localhost:\d+/Ticket/Display\.html\?id=1">1</a> was acted upon by RT_System\.</b>'
+    ),
+    'Content-Type' => qr{multipart},
+};
+
+diag "Admin Correspondence and Correspondence";
+mail_ok {
+    ($ok, $tmsg) = $t->Correspond(
+        MIMEObj => HTML::Mason::Commands::MakeMIMEEntity(
+            Body => '<p>This is a test of <b>HTML</b> correspondence.</p>',
+            Type => 'text/html',
+        ),
+    );
+} { from    => qr/RT System/,
+    bcc     => 'root at localhost',
+    subject => qr/\Q[example.com #1] The internet is broken\E/,
+    body    => parts_regex(
+        'Ticket URL: http://localhost:\d+/Ticket/Display\.html\?id=1.+?'.
+        'This is a test of "HTML" correspondence\.',
+        'Ticket URL: <a href="(http://localhost:\d+/Ticket/Display\.html\?id=1)">\1</a>.+?'.
+        '<p>This is a test of <b>HTML</b> correspondence\.</p>'
+    ),
+    'Content-Type' => qr{multipart},
+},{ from    => qr/RT System/,
+    to      => 'enduser at example.com',
+    subject => qr/\Q[example.com #1] The internet is broken\E/,
+    body    => parts_regex(
+        'This is a test of "HTML" correspondence\.',
+        '<p>This is a test of <b>HTML</b> correspondence\.</p>'
+    ),
+    'Content-Type' => qr{multipart},
+};
+
+
+diag "Admin Comment in HTML";
+mail_ok {
+    ($ok, $tmsg) = $t->Comment(
+        MIMEObj => HTML::Mason::Commands::MakeMIMEEntity(
+            Body => '<p>Comment test, <em>please!</em></p>',
+            Type => 'text/html',
+        ),
+    );
+} { from    => qr/RT System/,
+    bcc     => 'root at localhost',
+    subject => qr/\Q[example.com #1] [Comment] The internet is broken\E/,
+    body    => parts_regex(
+        'This is a comment about ticket 1 \(http://localhost:\d+/Ticket/Display\.html\?id=1\)\..+?'.
+        'It is not sent to the Requestor\(s\):.+?'.
+        'Comment test, "please!"',
+
+        '<p>This is a comment about <a href="http://localhost:\d+/Ticket/Display\.html\?id=1">ticket 1</a>\. '.
+        'It is not sent to the Requestor\(s\):</p>.+?'.
+        '<p>Comment test, <em>please!</em></p>',
+    ),
+    'Content-Type' => qr{multipart},
+};
+
+
+diag "Resolved in HTML templates";
+mail_ok {
+    ($ok, $tmsg) = $t->SetStatus('resolved');
+} { from    => qr/RT System/,
+    to      => 'enduser at example.com',
+    subject => qr/\Q[example.com #1] Resolved: The internet is broken\E/,
+    body    => parts_regex(
+        'According to our records, your request has been resolved\.',
+        '<p>According to our records, your request has been resolved\.',
+    ),
+    'Content-Type' => qr{multipart},
+};
+
+
+diag "Status changes in HTML";
+my $scrip = RT::Scrip->new(RT->SystemUser);
+my ($sval, $smsg) =$scrip->Create(
+    ScripCondition => 'On Status Change',
+    ScripAction => 'Notify Requestors',
+    Template => 'Status Change in HTML',
+    Queue => $q->Id,
+    Description => 'Tell requestors about status changes'
+);
+ok ($sval, $smsg);
+ok ($scrip->Id, "Created the scrip");
+ok ($scrip->TemplateObj->Id, "Created the scrip template");
+ok ($scrip->ConditionObj->Id, "Created the scrip condition");
+ok ($scrip->ActionObj->Id, "Created the scrip action");
+
+mail_ok {
+    ($ok, $tmsg) = $t->SetStatus('stalled');
+} { from    => qr/RT System/,
+    to      => 'enduser at example.com',
+    subject => qr/\Q[example.com #1] Status Changed to: stalled\E/,
+    body    => parts_regex(
+        'http://localhost:\d+/Ticket/Display\.html\?id=1.+?',
+        '<a href="(http://localhost:\d+/Ticket/Display\.html\?id=1)">\1</a>'
+    ),
+    'Content-Type' => qr{multipart},
+};
+
+
+sub parts_regex {
+    my ($text, $html) = @_;
+
+    my $pattern = 'Content-Type: text/plain.+?' . $text . '.+?' .
+                  'Content-Type: text/html.+?'  . $html;
+
+    return qr/$pattern/s;
+}
+

commit 7a33b13f6979870ed055ba2b4cce522f1f5cf847
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Fri Nov 19 13:15:49 2010 -0500

    Switch the default scrip templates to HTML for new installs
    
    This also switches the default for testing.  As an escape hatch,
    RT::Test now sports a text_templates flag.
    
    Tests which failed non-obviously with HTML templates enabled were copied
    to a t/mail/*-plaintext.t filenames and flipped back to testing
    plaintext.  The original files were fixed to expect the New World Order
    of HTML.  This way both the new HTML templates and the old plaintext
    templates are tested.

diff --git a/etc/initialdata b/etc/initialdata
index 1603e08..da7e2f8 100644
--- a/etc/initialdata
+++ b/etc/initialdata
@@ -690,23 +690,23 @@ Hour:         { $SubscriptionObj->SubValue('Hour') }
     {  Description    => 'On Comment Notify AdminCcs as Comment',
        ScripCondition => 'On Comment',
        ScripAction    => 'Notify AdminCcs As Comment',
-       Template       => 'Admin Comment' },
+       Template       => 'Admin Comment in HTML' },
     {  Description    => 'On Comment Notify Other Recipients as Comment',
        ScripCondition => 'On Comment',
        ScripAction    => 'Notify Other Recipients As Comment',
-       Template       => 'Correspondence' },
+       Template       => 'Correspondence in HTML' },
     {  Description    => 'On Correspond Notify AdminCcs',
        ScripCondition => 'On Correspond',
        ScripAction    => 'Notify AdminCcs',
-       Template       => 'Admin Correspondence' },
+       Template       => 'Admin Correspondence in HTML' },
     {  Description    => 'On Correspond Notify Other Recipients',
        ScripCondition => 'On Correspond',
        ScripAction    => 'Notify Other Recipients',
-       Template       => 'Correspondence' },
+       Template       => 'Correspondence in HTML' },
     {  Description    => 'On Correspond Notify Requestors and Ccs',
        ScripCondition => 'On Correspond',
        ScripAction    => 'Notify Requestors And Ccs',
-       Template       => 'Correspondence' },
+       Template       => 'Correspondence in HTML' },
     {  Description    => 'On Correspond Open Tickets',
        ScripCondition => 'On Correspond',
        ScripAction    => 'Open Tickets',
@@ -714,19 +714,19 @@ Hour:         { $SubscriptionObj->SubValue('Hour') }
     {  Description    => 'On Create Autoreply To Requestors',
        ScripCondition => 'On Create',
        ScripAction    => 'AutoReply To Requestors',
-       Template       => 'AutoReply' },
+       Template       => 'AutoReply in HTML' },
     {  Description    => 'On Create Notify AdminCcs',
        ScripCondition => 'On Create',
        ScripAction    => 'Notify AdminCcs',
-       Template       => 'Transaction' },
+       Template       => 'Transaction in HTML' },
     {  Description    => 'On Owner Change Notify Owner',
        ScripCondition => 'On Owner Change',
        ScripAction    => 'Notify Owner',
-       Template       => 'Transaction' },
+       Template       => 'Transaction in HTML' },
     {  Description    => 'On Resolve Notify Requestors',
        ScripCondition => 'On Resolve',
        ScripAction    => 'Notify Requestors',
-       Template       => 'Resolved' },
+       Template       => 'Resolved in HTML' },
     {  Description    => "On transaction, add any tags in the transaction's subject to the ticket's subject",
        ScripCondition => 'On Transaction',
        ScripAction    => 'Extract Subject Tag',
diff --git a/lib/RT/Test.pm b/lib/RT/Test.pm
index 4e98e7f..fe64378 100644
--- a/lib/RT/Test.pm
+++ b/lib/RT/Test.pm
@@ -189,6 +189,12 @@ sub import {
         $level++;
     }
 
+    # By default we test HTML templates, but text templates are
+    # available on request
+    if ( $args{'text_templates'} ) {
+        $class->switch_templates_ok('text');
+    }
+
     Test::More->export_to_level($level);
     Test::NoWarnings->export_to_level($level);
 
diff --git a/t/api/txn_content.t b/t/api/txn_content.t
index 392b6a7..d44862d 100644
--- a/t/api/txn_content.t
+++ b/t/api/txn_content.t
@@ -1,7 +1,7 @@
 use warnings;
 use strict;
 
-use RT::Test tests => 3;
+use RT::Test tests => 4;
 use MIME::Entity;
 my $ticket = RT::Ticket->new(RT->SystemUser);
 my $mime   = MIME::Entity->build(
@@ -16,4 +16,8 @@ my $txns = $ticket->Transactions;
 $txns->Limit( FIELD => 'Type', VALUE => 'Create' );
 my $txn = $txns->First;
 ok( $txn, 'got Create txn' );
-is( $txn->Content, "this is body\n", "txn's content" );
+
+# ->Content converts from text/html to plain text if we don't explicitly ask
+# for html. Our html -> text converter seems to add an extra trailing newline
+is( $txn->Content, "this is body\n\n", "txn's html content converted to plain text" );
+is( $txn->Content(Type => 'text/html'), "this is body\n", "txn's html content" );
diff --git a/t/mail/charsets-outgoing.t b/t/mail/charsets-outgoing-plaintext.t
similarity index 99%
copy from t/mail/charsets-outgoing.t
copy to t/mail/charsets-outgoing-plaintext.t
index 2fc91f2..e9569fd 100644
--- a/t/mail/charsets-outgoing.t
+++ b/t/mail/charsets-outgoing-plaintext.t
@@ -2,7 +2,7 @@ use strict;
 use warnings;
 use Encode;
 
-use RT::Test tests => 78;
+use RT::Test tests => 79, text_templates => 1;
 
 my %string = (
     ru => {
diff --git a/t/mail/charsets-outgoing.t b/t/mail/charsets-outgoing.t
index 2fc91f2..11f257b 100644
--- a/t/mail/charsets-outgoing.t
+++ b/t/mail/charsets-outgoing.t
@@ -33,7 +33,7 @@ diag "make sure queue has no subject tag";
 diag "set intial simple autoreply template";
 {
     my $template = RT::Template->new( RT->SystemUser );
-    $template->Load('Autoreply');
+    $template->Load('Autoreply in HTML');
     ok $template->id, "loaded autoreply tempalte";
 
     my ($status, $msg) = $template->SetContent(
@@ -145,7 +145,7 @@ foreach my $prefix_set ( 'ru', 'latin1' ) {
 diag "add non-ascii subject prefix in the autoreply template";
 {
     my $template = RT::Template->new( RT->SystemUser );
-    $template->Load('Autoreply');
+    $template->Load('Autoreply in HTML');
     ok $template->id, "loaded autoreply tempalte";
 
     my ($status, $msg) = $template->SetContent(
@@ -249,7 +249,7 @@ diag "don't change subject via template";
 # we should test situation when subject is not changed from template
 {
     my $template = RT::Template->new( RT->SystemUser );
-    $template->Load('Autoreply');
+    $template->Load('Autoreply in HTML');
     ok $template->id, "loaded autoreply tempalte";
 
     my ($status, $msg) = $template->SetContent(
diff --git a/t/mail/gnupg-outgoing-encrypted-plaintext.t b/t/mail/gnupg-outgoing-encrypted-plaintext.t
new file mode 100644
index 0000000..35cfced
--- /dev/null
+++ b/t/mail/gnupg-outgoing-encrypted-plaintext.t
@@ -0,0 +1,27 @@
+use strict;
+use warnings;
+
+use RT::Test::GnuPG
+  tests          => 104,
+  text_templates => 1,
+  gnupg_options  => {
+    passphrase    => 'rt-test',
+    'trust-model' => 'always',
+  };
+
+RT::Test->import_gnupg_key('rt-recipient at example.com');
+RT::Test->import_gnupg_key( 'rt-test at example.com', 'public' );
+
+my $queue = RT::Test->load_or_create_queue(
+    Name              => 'Regression',
+    CorrespondAddress => 'rt-recipient at example.com',
+    CommentAddress    => 'rt-recipient at example.com',
+    Encrypt           => 1,
+);
+ok $queue && $queue->id, 'loaded or created queue';
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+create_and_test_outgoing_emails( $queue, $m );
+
diff --git a/t/mail/gnupg-outgoing-plain-plaintext.t b/t/mail/gnupg-outgoing-plain-plaintext.t
new file mode 100644
index 0000000..32e7d5d
--- /dev/null
+++ b/t/mail/gnupg-outgoing-plain-plaintext.t
@@ -0,0 +1,25 @@
+use strict;
+use warnings;
+
+use RT::Test::GnuPG
+  tests          => 104,
+  text_templates => 1,
+  gnupg_options  => {
+    passphrase    => 'rt-test',
+    'trust-model' => 'always',
+  };
+
+RT::Test->import_gnupg_key('rt-recipient at example.com');
+RT::Test->import_gnupg_key( 'rt-test at example.com', 'public' );
+
+my $queue = RT::Test->load_or_create_queue(
+    Name              => 'Regression',
+    CorrespondAddress => 'rt-recipient at example.com',
+    CommentAddress    => 'rt-recipient at example.com',
+);
+ok $queue && $queue->id, 'loaded or created queue';
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+create_and_test_outgoing_emails( $queue, $m );
diff --git a/t/mail/gnupg-outgoing-signed-plaintext.t b/t/mail/gnupg-outgoing-signed-plaintext.t
new file mode 100644
index 0000000..cf46edd
--- /dev/null
+++ b/t/mail/gnupg-outgoing-signed-plaintext.t
@@ -0,0 +1,27 @@
+use strict;
+use warnings;
+
+use RT::Test::GnuPG
+  tests          => 104,
+  text_templates => 1,
+  gnupg_options  => {
+    passphrase    => 'rt-test',
+    'trust-model' => 'always',
+  };
+
+RT::Test->import_gnupg_key('rt-recipient at example.com');
+RT::Test->import_gnupg_key( 'rt-test at example.com', 'public' );
+
+my $queue = RT::Test->load_or_create_queue(
+    Name              => 'Regression',
+    CorrespondAddress => 'rt-recipient at example.com',
+    CommentAddress    => 'rt-recipient at example.com',
+    Sign              => 1,
+);
+ok $queue && $queue->id, 'loaded or created queue';
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+create_and_test_outgoing_emails( $queue, $m );
+
diff --git a/t/mail/gnupg-outgoing-signed_encrypted-plaintext.t b/t/mail/gnupg-outgoing-signed_encrypted-plaintext.t
new file mode 100644
index 0000000..c2753d0
--- /dev/null
+++ b/t/mail/gnupg-outgoing-signed_encrypted-plaintext.t
@@ -0,0 +1,28 @@
+use strict;
+use warnings;
+
+use RT::Test::GnuPG
+  tests          => 104,
+  text_templates => 1,
+  gnupg_options  => {
+    passphrase    => 'rt-test',
+    'trust-model' => 'always',
+  };
+
+RT::Test->import_gnupg_key('rt-recipient at example.com');
+RT::Test->import_gnupg_key( 'rt-test at example.com', 'public' );
+
+my $queue = RT::Test->load_or_create_queue(
+    Name              => 'Regression',
+    CorrespondAddress => 'rt-recipient at example.com',
+    CommentAddress    => 'rt-recipient at example.com',
+    Sign              => 1,
+    Encrypt           => 1,
+);
+ok $queue && $queue->id, 'loaded or created queue';
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in';
+
+create_and_test_outgoing_emails( $queue, $m );
+
diff --git a/t/mail/html-outgoing.t b/t/mail/html-outgoing.t
index bffc1fd..d97c9bc 100644
--- a/t/mail/html-outgoing.t
+++ b/t/mail/html-outgoing.t
@@ -4,11 +4,9 @@ use RT::Test tests => undef;
 BEGIN {
     plan skip_all => 'Email::Abstract and Test::Email required.'
         unless eval { require Email::Abstract; require Test::Email; 1 };
-    plan tests => 19;
+    plan tests => 18;
 }
 
-RT::Test->switch_templates_ok('html');
-
 use RT::Test::Email;
 
 my $root = RT::User->new(RT->SystemUser);
diff --git a/t/mail/multipart.t b/t/mail/multipart.t
index 1c11064..d1c46f3 100644
--- a/t/mail/multipart.t
+++ b/t/mail/multipart.t
@@ -37,4 +37,4 @@ is(@msgs,2,"sent 2 emails");
 diag("We're skipping any testing of the autoreply");
 
 my $entity = parse_mail($msgs[1]);
-is($entity->parts, 0, "only one entity");
+is($entity->parts, 2, "only two parts");
diff --git a/t/mail/sendmail.t b/t/mail/sendmail-plaintext.t
similarity index 99%
copy from t/mail/sendmail.t
copy to t/mail/sendmail-plaintext.t
index 44903f3..6bb8bb7 100644
--- a/t/mail/sendmail.t
+++ b/t/mail/sendmail-plaintext.t
@@ -2,7 +2,7 @@ use strict;
 use warnings;
 use File::Spec ();
 
-use RT::Test tests => 141;
+use RT::Test tests => 142, text_templates => 1;
 
 use RT::EmailParser;
 use RT::Tickets;
diff --git a/t/mail/sendmail.t b/t/mail/sendmail.t
index 44903f3..327d2ad 100644
--- a/t/mail/sendmail.t
+++ b/t/mail/sendmail.t
@@ -2,7 +2,7 @@ use strict;
 use warnings;
 use File::Spec ();
 
-use RT::Test tests => 141;
+use RT::Test tests => 174;
 
 use RT::EmailParser;
 use RT::Tickets;
@@ -203,9 +203,13 @@ sub utf8_redef_sendmessage {
                   "hey, look. it's a mime entity" );
         main::is( ref( $MIME->head ) , 'MIME::Head',
                   "its mime header is a mime header. yay" );
-        main::like( $MIME->head->get('Content-Type') , qr/utf-8/,
-                  "Its content type is utf-8" );
-        my $message_as_string = $MIME->bodyhandle->as_string();
+        main::like( $MIME->head->get('Content-Type') , qr/multipart\/alternative/,
+                  "Its content type is multipart/alternative" );
+        main::like( $MIME->parts(0)->head->get('Content-Type') , qr/text\/plain.+?utf-8/,
+                  "first part's content type is text/plain utf-8" );
+        main::like( $MIME->parts(1)->head->get('Content-Type') , qr/text\/html.+?utf-8/,
+                  "second part's content type is text/html utf-8" );
+        my $message_as_string = $MIME->parts(0)->bodyhandle->as_string();
         use Encode;
         $message_as_string = Encode::decode_utf8($message_as_string);
         main::like(
@@ -229,9 +233,14 @@ sub iso8859_redef_sendmessage {
                   "hey, look. it's a mime entity" );
         main::is( ref( $MIME->head ) , 'MIME::Head',
                   "its mime header is a mime header. yay" );
-        main::like( $MIME->head->get('Content-Type') , qr/iso-8859-1/,
-                  "Its content type is iso-8859-1 - " . $MIME->head->get("Content-Type") );
-        my $message_as_string = $MIME->bodyhandle->as_string();
+
+        main::like( $MIME->head->get('Content-Type') , qr/multipart\/alternative/,
+                  "Its content type is multipart/alternative" );
+        main::like( $MIME->parts(0)->head->get('Content-Type') , qr/text\/plain.+?iso-8859-1/,
+                  "Its content type is iso-8859-1 - " . $MIME->parts(0)->head->get("Content-Type") );
+        main::like( $MIME->parts(1)->head->get('Content-Type') , qr/text\/html.+?iso-8859-1/,
+                  "Its content type is iso-8859-1 - " . $MIME->parts(1)->head->get("Content-Type") );
+        my $message_as_string = $MIME->parts(0)->bodyhandle->as_string();
         use Encode;
         $message_as_string = Encode::decode("iso-8859-1",$message_as_string);
         main::like(
@@ -296,9 +305,9 @@ sub text_html_redef_sendmessage {
         my $self = shift;
         my $MIME = shift;
         return (1) unless ($self->ScripObj->ScripActionObj->Name eq "Notify AdminCcs" );
-        is ($MIME->parts, 0, "generated correspondence mime entity
-                does not have parts");
-        is ($MIME->head->mime_type , "text/plain", "The mime type is a plain");
+        is ($MIME->parts, 2, "generated correspondence mime entity has parts");
+        is ($MIME->parts(0)->head->mime_type , "text/plain", "The first part mime type is a plain");
+        is ($MIME->parts(1)->head->mime_type , "text/html", "The second part mime type is a plain");
     };
 }
 
@@ -379,7 +388,10 @@ sub text_plain_russian_redef_sendmessage {
         my $self = shift; 
         my $MIME = shift; 
         return (1) unless ($self->ScripObj->ScripActionObj->Name eq "Notify AdminCcs" );
-        is ($MIME->head->mime_type , "text/plain", "The only part is text/plain ");
+        is ($MIME->head->mime_type , "multipart/alternative", "The top part is multipart/alternative");
+        is ($MIME->parts, 2, "generated correspondence mime entity has parts");
+        is ($MIME->parts(0)->head->mime_type , "text/plain", "The first part mime type is a plain");
+        is ($MIME->parts(1)->head->mime_type , "text/html", "The second part mime type is a plain");
             my $subject  = $MIME->head->get("subject");
         chomp($subject);
         #is( $subject ,      /^=\?KOI8-R\?B\?W2V4YW1wbGUuY39tICM3XSDUxdPUINTF09Q=\?=/ , "The $subject is encoded correctly");
diff --git a/t/web/attachment_encoding.t b/t/web/attachment_encoding.t
index 5af7fda..fd91b4a 100644
--- a/t/web/attachment_encoding.t
+++ b/t/web/attachment_encoding.t
@@ -85,7 +85,7 @@ diag 'test with attachemnts' if $ENV{TEST_VERBOSE};
         '-> /Ticket/Attachment/...' );
     $m->content_contains( '附件', 'has content 附件' );
 
-    ( $id ) = $m->uri =~ /(\d+)\D+$/;
+    ( $id ) = $m->uri =~ m{/(\d+)/[^/]+$};
     ok( $id, 'found attachment id' );
     $attachment = RT::Attachment->new( $RT::SystemUser );
     ok($attachment->Load($id), "load att $id");
diff --git a/t/web/html_template.t b/t/web/html_template.t
index 78b95a3..cd9a031 100644
--- a/t/web/html_template.t
+++ b/t/web/html_template.t
@@ -14,7 +14,7 @@ diag('make Autoreply template a html one and add utf8 chars')
 
 {
     $m->follow_link_ok( { id => 'tools-config-global-templates' },     '-> Templates' );
-    $m->follow_link_ok( { text => 'Autoreply' },     '-> Autoreply' );
+    $m->follow_link_ok( { text => 'Autoreply in HTML' },       '-> Autoreply in HTML' );
 
     $m->submit_form(
         form_name => 'ModifyTemplate',

commit 3f6383752ebce0b31e02305d42262ffb19b5c455
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Apr 30 14:57:24 2013 -0700

    Avoid hardcoding a full list of default global templates in tests

diff --git a/t/web/scrips.t b/t/web/scrips.t
index f1aef54..ff201fd 100644
--- a/t/web/scrips.t
+++ b/t/web/scrips.t
@@ -195,32 +195,19 @@ note "check templates in scrip's admin interface";
     my ($status, $msg) = $template->Create( Queue => $queue_g->id, Name => 'foo' );
     ok $status, 'created a template';
 
+    my $templates = RT::Templates->new( RT->SystemUser );
+    $templates->LimitToGlobal;
+
     my @default = (
           '',
-          'Admin Comment',
-          'Admin Correspondence',
-          'Autoreply',
-          'Blank',
-          'Correspondence',
-          'Email Digest',
-          'Error to RT owner: public key',
-          'Error: bad GnuPG data',
-          'Error: Missing dashboard',
-          'Error: no private key',
-          'Error: public key',
-          'Forward',
-          'Forward Ticket',
-          'PasswordChange',
-          'Resolved',
-          'Status Change',
-          'Transaction'
+          map $_->Name, @{$templates->ItemsArrayRef}
     );
 
     $m->follow_link_ok( { id => 'tools-config-global-scrips-create' } );
     ok $m->form_name('CreateScrip');
     my @templates = ($m->find_all_inputs( type => 'option', name => 'Template' ))[0]
         ->possible_values;
-    is_deeply(\@templates, \@default);
+    is_deeply([sort @templates], [sort @default]);
 
     $m->follow_link_ok( { id => 'tools-config-queues' } );
     $m->follow_link_ok( { text => 'General' } );

commit fea768629f006ce91a8ab440c2cd1326a281db9a
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Tue Apr 30 20:48:12 2013 -0700

    Stop stripping X-RT-Original-Encoding in GnuPG tests
    
    The function in question is used to take an _outgoing_ message RT sent,
    turn it around, clean it up, and reinject it back _into_ RT: the
    outgoing GnuPG support is tested with the incoming GnuPG support.
    
    The commit which introduced this code (3a83c99) is huge and offers no
    reasoning for stripping the various headers.  It's apparent that some of
    the headers need to be stripped from the top-level MIME part so that RT
    lets the mail enter RT again without detecting it as a loop.  The regex
    approach, however, also removes the listed headers from subparts.  In
    particular, X-RT-Original-Encoding is unlike the other headers since
    almost all subparts will have it set.  The other headers should only
    appear at the top-level.
    
    Modifying the subparts causes decryption/signature verification to fail
    since the content no longer matches what was encrypted/signed.  This bug
    in the testing infrastructure wasn't noticed with RT's standard plain
    text templates since they only have a single textual part.  With the
    switch to HTML templates, tests started failing verification.  This
    commit makes them pass again.

diff --git a/lib/RT/Test/GnuPG.pm b/lib/RT/Test/GnuPG.pm
index ec44672..8d840e3 100644
--- a/lib/RT/Test/GnuPG.pm
+++ b/lib/RT/Test/GnuPG.pm
@@ -231,7 +231,7 @@ sub cleanup_headers {
     # strip id from subject to create new ticket
     $mail =~ s/^(Subject:)\s*\[.*?\s+#\d+\]\s*/$1 /m;
     # strip several headers
-    foreach my $field ( qw(Message-ID X-RT-Original-Encoding RT-Originator RT-Ticket X-RT-Loop-Prevention) ) {
+    foreach my $field ( qw(Message-ID RT-Originator RT-Ticket X-RT-Loop-Prevention) ) {
         $mail =~ s/^$field:.*?\n(?! |\t)//gmsi;
     }
     return $mail;

commit 89f2ebf45c731a81406d4bcfe88959ed35398606
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Wed May 1 14:34:27 2013 -0700

    Convert HTML article content to plain text using the standard function
    
    Consistent handling of HTML conversion makes it easier to fix bugs in
    one place.  The now-standard function also produces better results than
    the plain HTML::FormatText solution.
    
    I removed the HTML::FormatText and HTML::TreeBuilder dependencies
    because they are no longer explicitly used.  They are still implicit
    dependencies via the other HTML::FormatText::* modules.

diff --git a/sbin/rt-test-dependencies.in b/sbin/rt-test-dependencies.in
index 481df7e..280f8f0 100644
--- a/sbin/rt-test-dependencies.in
+++ b/sbin/rt-test-dependencies.in
@@ -200,14 +200,12 @@ File::ShareDir
 File::Spec 0.8
 File::Temp 0.19
 HTML::Entities
-HTML::FormatText
 HTML::FormatText::WithLinks 0.14
 HTML::FormatText::WithLinks::AndTables
 HTML::Mason 1.43
 HTML::Mason::PSGIHandler 0.52
 HTML::Quoted
 HTML::Scrubber 0.08
-HTML::TreeBuilder
 HTTP::Message 6.0
 IPC::Run3
 JSON
diff --git a/share/html/Articles/Article/Elements/Preformatted b/share/html/Articles/Article/Elements/Preformatted
index d4ab9f9..f77564b 100644
--- a/share/html/Articles/Article/Elements/Preformatted
+++ b/share/html/Articles/Article/Elements/Preformatted
@@ -89,19 +89,6 @@ my $cfs = $class->ArticleCustomFields;
 $include{"CF-Title-".$_->Id} = $include{"CF-Value-".$_->Id} = 1 while $_ = $cfs->Next;
 $include{$_} = not $class->FirstAttribute("Skip-$_") for keys %include;
 
-my $de_htmlify = sub {
-    my $content = shift;
-    require HTML::TreeBuilder;
-    my $tree = HTML::TreeBuilder->new;
-    $tree->parse($content);
-    $tree->eof();
-
-    require HTML::FormatText;
-    my $formatter = HTML::FormatText->new(leftmargin => 0, rightmargin => 50);
-    $content = $formatter->format($tree);
-    return $content;
-};
-
 my $get_content = sub {
     my $value = shift;
     return '' unless $value;
@@ -116,7 +103,7 @@ my $get_content = sub {
     );
 
     if ( $content =~ /<.{1,5}>/ ) {
-        $content = $de_htmlify->( $content );
+        $content = RT::Interface::Email::ConvertHTMLToText( $content );
     }
     return $content;
 };

commit b098507a8e701318aa813e95c6e8ba001e1b50e2
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Wed May 1 15:38:58 2013 -0700

    Don't use bold/italic emphasis markers in the HTML → text conversion
    
    Quotes are not quite right and may litter the text with seemingly random
    quoted phrases.  The standard asterisks/underscores tend to look ugly
    and are much more distracting than the equivalent bold/italic text is in
    HTML.  Readability is improved by removing emphasis markers entirely.

diff --git a/lib/RT/Interface/Email.pm b/lib/RT/Interface/Email.pm
index eb76f79..2138e7d 100644
--- a/lib/RT/Interface/Email.pm
+++ b/lib/RT/Interface/Email.pm
@@ -1898,9 +1898,7 @@ sub ConvertHTMLToText {
             after_link      => ' (%l)',
             footnote        => '',
             skip_linked_urls => 1,
-            with_emphasis   => 1,
-            bold_marker     => '"',
-            italic_marker   => '"',
+            with_emphasis   => 0,
         }
     );
 }
diff --git a/t/mail/html-outgoing.t b/t/mail/html-outgoing.t
index d97c9bc..fc52292 100644
--- a/t/mail/html-outgoing.t
+++ b/t/mail/html-outgoing.t
@@ -43,7 +43,7 @@ mail_ok {
     to      => 'enduser at example.com',
     subject => qr/\Q[example.com #1] AutoReply: The internet is broken\E/,
     body    => parts_regex(
-        'trouble ticket regarding "The internet is broken"',
+        'trouble ticket regarding The internet is broken',
         'trouble ticket regarding <b>The internet is broken</b>'
     ),
     'Content-Type' => qr{multipart},
@@ -70,7 +70,7 @@ mail_ok {
     subject => qr/\Q[example.com #1] The internet is broken\E/,
     body    => parts_regex(
         'Ticket URL: http://localhost:\d+/Ticket/Display\.html\?id=1.+?'.
-        'This is a test of "HTML" correspondence\.',
+        'This is a test of HTML correspondence\.',
         'Ticket URL: <a href="(http://localhost:\d+/Ticket/Display\.html\?id=1)">\1</a>.+?'.
         '<p>This is a test of <b>HTML</b> correspondence\.</p>'
     ),
@@ -79,7 +79,7 @@ mail_ok {
     to      => 'enduser at example.com',
     subject => qr/\Q[example.com #1] The internet is broken\E/,
     body    => parts_regex(
-        'This is a test of "HTML" correspondence\.',
+        'This is a test of HTML correspondence\.',
         '<p>This is a test of <b>HTML</b> correspondence\.</p>'
     ),
     'Content-Type' => qr{multipart},

-----------------------------------------------------------------------


More information about the Rt-commit mailing list