Skip to content

Commit

Permalink
Fix JENKINS-23126
Browse files Browse the repository at this point in the history
Added option to send in both HTML and plain text. The plain text version
is a stripped version of the HTML using the Jericho library.
  • Loading branch information
slide committed Feb 21, 2015
1 parent 72fcd04 commit 7ab3d59
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 38 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Expand Up @@ -129,6 +129,11 @@
<artifactId>jsoup</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>net.htmlparser.jericho</groupId>
<artifactId>jericho-html</artifactId>
<version>3.3</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
Expand Down
32 changes: 26 additions & 6 deletions src/main/java/hudson/plugins/emailext/ExtendedEmailPublisher.java
Expand Up @@ -564,8 +564,7 @@ private MimeMessage createMail(ExtendedEmailPublisherContext context) throws Mes
msg.setSentDate(new Date());
setSubject(context, msg, charset);

Multipart multipart = new MimeMultipart();
multipart.addBodyPart(getContent(context, charset));
Multipart multipart = addContent(context, charset);

AttachmentUtils attachments = new AttachmentUtils(attachmentsPattern);
attachments.attach(multipart, context);
Expand Down Expand Up @@ -684,9 +683,11 @@ public boolean isExecuteOnMatrixNodes() {
|| MatrixTriggerMode.ONLY_CONFIGURATIONS == mtm;
}

private MimeBodyPart getContent(ExtendedEmailPublisherContext context, String charset)
private Multipart addContent(ExtendedEmailPublisherContext context, String charset)
throws MessagingException {
final String text = ContentBuilder.transformText(context.getTrigger().getEmail().getBody(), context, getRuntimeMacros(context));
final Multipart multipart;
boolean doBoth = false;

String messageContentType = context.getTrigger().getEmail().getContentType().equals("project") ? contentType : context.getTrigger().getEmail().getContentType();
// contentType is null if the project was not reconfigured after upgrading.
Expand All @@ -698,6 +699,15 @@ private MimeBodyPart getContent(ExtendedEmailPublisherContext context, String ch
messageContentType = "text/plain";
}
}

if("both".equals(messageContentType)) {
doBoth = true;
multipart = new MimeMultipart("alternative");
messageContentType = "text/html";
} else {
multipart = new MimeMultipart();
}

messageContentType += "; charset=" + charset;

try {
Expand All @@ -723,12 +733,22 @@ private MimeBodyPart getContent(ExtendedEmailPublisherContext context, String ch
MimeBodyPart msgPart = new MimeBodyPart();
debug(context.getListener().getLogger(), "messageContentType = %s", messageContentType);
if (messageContentType.startsWith("text/html")) {
String inlinedCssHtml = new CssInliner().process(text);
msgPart.setContent(inlinedCssHtml, messageContentType);
CssInliner inliner = new CssInliner();
if(doBoth) {
MimeBodyPart plainTextPart = new MimeBodyPart();
plainTextPart.setContent(inliner.stripHtml(text), "text/plain; charset=" + charset);
multipart.addBodyPart(plainTextPart);
}
String inlinedCssHtml = inliner.process(text);
msgPart.setContent(inlinedCssHtml, messageContentType);
} else {
msgPart.setContent(text, messageContentType);
}
return msgPart;

multipart.addBodyPart(msgPart);

return multipart;

}

@Override
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/hudson/plugins/emailext/plugins/CssInliner.java
Expand Up @@ -12,6 +12,7 @@
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.StringTokenizer;
import net.htmlparser.jericho.Source;
import org.apache.commons.lang.StringEscapeUtils;

/**
Expand Down Expand Up @@ -67,6 +68,10 @@ private String fetchStyles(Document doc) {
}
return styles.toString();
}

public String stripHtml(String input) {
return new Source(input).getRenderer().toString();
}

/**
* Takes an input string representing an html document and processes it with
Expand Down
Expand Up @@ -25,6 +25,7 @@ f.entry(title: _("Content Type"), help: "/plugin/email-ext/help/projectConfig/co
f.option(selected: 'default'==instance?.contentType, value: "default", _("Default Content Type"))
f.option(selected: 'text/plain'==instance?.contentType, value: "text/plain", _("projectContentType.plainText"))
f.option(selected: 'text/html'==instance?.contentType, value: "text/html", _("projectContentType.html"))
f.option(selected: 'both'==instance?.contentType, value: "both", _("projectContentType.both"))
}
}
f.entry(title: _("Default Subject"), help: "/plugin/email-ext/help/projectConfig/defaultSubject.html") {
Expand Down
@@ -1,5 +1,6 @@
projectContentType.plainText=Plain Text (text/plain)
projectContentType.html=HTML (text/html)
projectContentType.both=Both HTML and Plain Text
description=Can use wildcards like ''module/dist/**/*.zip''. \
See the <a href="{0}">@includes of Ant fileset</a> for the exact format. \
The base directory is <a href="ws/">the workspace</a>.
Expand Down
Expand Up @@ -26,6 +26,7 @@ f.advanced() {
f.option(selected: 'project'== (instance != null ? instance.email.contentType : ""), value: "project", _("Project Content Type"))
f.option(selected: 'text/plain'==(instance != null ? instance.email.contentType : ""), value: "text/plain", _("projectContentType.plainText"))
f.option(selected: 'text/html'==(instance != null ? instance.email.contentType : ""), value: "text/html", _("projectContentType.html"))
f.option(selected: 'both'==(instance != null ? instance.email.contentType : ""), value: "both", _("projectContentType.both"))
}
}
f.entry(title: _("Subject"), help: "/plugin/email-ext/help/projectConfig/mailType/subject.html") {
Expand Down
Expand Up @@ -2,4 +2,5 @@ description=Can use wildcards like ''module/dist/**/*.zip''. \
See the <a href="{0}">@includes of Ant fileset</a> for the exact format. \
The base directory is <a href="ws/">the workspace</a>.
projectContentType.plainText=Plain Text (text/plain)
projectContentType.html=HTML (text/html)
projectContentType.html=HTML (text/html)
projectContentType.both=Both HTML and Plain Text
8 changes: 4 additions & 4 deletions src/test/java/hudson/plugins/emailext/EmailTypeTest.java
Expand Up @@ -8,11 +8,11 @@
import java.net.URL;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.junit.Test;

import static org.junit.Assert.*;
import org.junit.Rule;
import org.jvnet.hudson.test.Bug;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;

public class EmailTypeTest {
Expand Down Expand Up @@ -91,8 +91,8 @@ public void testUpgadeToRecipientProvider() throws IOException {
assertEquals(3, pub.configuredTriggers.get(0).getEmail().getRecipientProviders().size());
}

@Test
@Bug(24506)
@Test
@Issue("JENKINS-24506")
public void testUpgradeTriggerWithNoRecipients() throws IOException {
URL url = this.getClass().getResource("/recipient-provider-upgrade2.xml");
File jobConfig = new File(url.getFile());
Expand Down
Expand Up @@ -2,7 +2,6 @@

import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
import com.gargoylesoftware.htmlunit.html.HtmlDivision;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSelect;
import com.gargoylesoftware.htmlunit.html.HtmlTextArea;
Expand All @@ -14,7 +13,7 @@

import static org.junit.Assert.*;

import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.Issue;

public class ExtendedEmailPublisherDescriptorTest {

Expand Down Expand Up @@ -100,7 +99,7 @@ public void testGlobalConfigDefaultState() throws Exception {
}

@Test
@Bug(20030)
@Issue("JENKINS-20030")
public void testGlobalConfigSimpleRoundTrip() throws Exception {
ExtendedEmailPublisherDescriptor descriptor = j.jenkins.getDescriptorByType(ExtendedEmailPublisherDescriptor.class);
HtmlPage page = j.createWebClient().goTo("configure");
Expand All @@ -112,7 +111,7 @@ public void testGlobalConfigSimpleRoundTrip() throws Exception {
}

@Test
@Bug(20133)
@Issue("JENKINS-20133")
public void testPrecedenceBulkSettingRoundTrip() throws Exception {
ExtendedEmailPublisherDescriptor descriptor = j.jenkins.getDescriptorByType(ExtendedEmailPublisherDescriptor.class);
HtmlPage page = j.createWebClient().goTo("configure");
Expand All @@ -124,7 +123,7 @@ public void testPrecedenceBulkSettingRoundTrip() throws Exception {
}

@Test
@Bug(20133)
@Issue("JENKINS-20133")
public void testListIDRoundTrip() throws Exception {
ExtendedEmailPublisherDescriptor descriptor = j.jenkins.getDescriptorByType(ExtendedEmailPublisherDescriptor.class);
HtmlPage page = j.createWebClient().goTo("configure");
Expand Down
@@ -1,5 +1,7 @@
package hudson.plugins.emailext;

import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlTextInput;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
Expand All @@ -26,7 +28,9 @@
import hudson.plugins.emailext.plugins.trigger.SuccessTrigger;
import hudson.tasks.Builder;
import hudson.tasks.Mailer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -40,6 +44,7 @@
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import static org.hamcrest.CoreMatchers.not;

import static org.junit.Assert.*;
Expand All @@ -49,11 +54,13 @@
import static org.junit.matchers.JUnitMatchers.containsString;
import static org.junit.matchers.JUnitMatchers.hasItem;
import static org.junit.matchers.JUnitMatchers.hasItems;
import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.FailureBuilder;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsRule.WebClient;
import org.jvnet.hudson.test.MockBuilder;
import org.jvnet.hudson.test.SleepBuilder;
import org.jvnet.hudson.test.recipes.WithPlugin;
import org.jvnet.mock_javamail.Mailbox;
import org.kohsuke.stapler.Stapler;

Expand Down Expand Up @@ -530,7 +537,7 @@ public void testCancelFromPresendScriptCausesNoEmail() throws Exception {
}

@Test
@Bug(22777)
@Issue("JENKINS-22777")
public void testEmergencyRerouteOverridesPresendScript() throws Exception {
publisher.getDescriptor().setEmergencyReroute("emergency@foo.com");
publisher.presendScript = "import javax.mail.Message.RecipientType\n"
Expand Down Expand Up @@ -868,7 +875,7 @@ public Void call() throws Exception {
});
}

@Bug(20524)
@Issue("JENKINS-20524")
@Test
public void testMultipleTriggersOfSameType()
throws Exception {
Expand All @@ -891,7 +898,7 @@ public void testMultipleTriggersOfSameType()
assertEquals(2, Mailbox.get("mickey@disney.com").size());
}

@Bug(22154)
@Issue("JENKINS-22154")
@Test
public void testProjectDisable() throws Exception {
FreeStyleProject prj = j.createFreeStyleProject("JENKINS-22154");
Expand All @@ -914,24 +921,63 @@ public void testProjectDisable() throws Exception {
hasItem("Extended Email Publisher is currently disabled in project settings"));
}

/* Need to find out why this gets a 404 on the fileprovider.js file
@Test
@Bug(15442)
public void testConfiguredStateNoTriggers()
throws Exception {
FreeStyleProject prj = j.createFreeStyleProject("JENKINS-15442");
prj.getPublishersList().add(publisher);

// @Test
// @Issue("JENKINS-15442")
// @WithPlugin("config-file-provider")
// public void testConfiguredStateNoTriggers()
// throws Exception {
// FreeStyleProject prj = j.createFreeStyleProject("JENKINS-15442");
// prj.getPublishersList().add(publisher);
//
// publisher.recipientList = "mickey@disney.com";
// publisher.configuredTriggers.clear();
//
// final WebClient client = j.createWebClient();
// final HtmlPage page = client.goTo("job/JENKINS-15442/configure");
// final HtmlTextInput recipientList = page.getElementByName("project_recipient_list");
// assertEquals(recipientList.getText(), "mickey@disney.com");
// }

@Test
@Issue("JENKINS-23126")
public void testPlainTextAndHtml() throws Exception {
FreeStyleProject prj = j.createFreeStyleProject("JENKINS-23126");
prj.getPublishersList().add(publisher);

publisher.recipientList = "mickey@disney.com";
publisher.configuredTriggers.clear();
final String content = "<html><head><title>Foo</title></head><body><b>This is a test</b><br/>Hello world</body></html>";
publisher.contentType = "both";
publisher.recipientList = "mickey@disney.com";
publisher.configuredTriggers.add(new SuccessTrigger(recProviders, "$DEFAULT_RECIPIENTS",
"$DEFAULT_REPLYTO", "$DEFAULT_SUBJECT", content, "", 0, "project"));

for (EmailTrigger trigger : publisher.configuredTriggers) {
trigger.getEmail().addRecipientProvider(new ListRecipientProvider());
}

FreeStyleBuild build = prj.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(build);

assertEquals(1, Mailbox.get("mickey@disney.com").size());

final WebClient client = j.createWebClient();
final HtmlPage page = client.goTo("job/JENKINS-15442/configure");
final HtmlTextInput recipientList = page.getElementByName("project_recipient_list");
assertEquals(recipientList.getText(), "mickey@disney.com");
}
*/
@Bug(16376)
Message msg = Mailbox.get("mickey@disney.com").get(0);
assertTrue("Message should be multipart", msg instanceof MimeMessage);
assertTrue("Content should be a MimeMultipart", msg.getContent() instanceof MimeMultipart);

MimeMultipart part = (MimeMultipart)msg.getContent();
assertEquals("Should have two body items (html + plaintext)", 2, part.getCount());

BodyPart plainText = part.getBodyPart(0);
String plainTextString = IOUtils.toString(plainText.getInputStream(), publisher.getDescriptor().getCharset()).replace("\r", "");
assertEquals("Should have the same plain text body", "This is a test\nHello world", plainTextString);

BodyPart html = part.getBodyPart(1);
String htmlString = IOUtils.toString(html.getInputStream(), publisher.getDescriptor().getCharset());

assertEquals("Should have the same HTML body", content, htmlString);
}

@Issue("JENKINS-16376")
@Test
public void testConcurrentBuilds()
throws Exception {
Expand Down
Expand Up @@ -2,7 +2,7 @@

import static org.junit.Assert.*;
import org.junit.Test;
import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.Issue;

/**
* Tests for CssInliner
Expand All @@ -24,7 +24,7 @@ public void testEmailWithoutCss() {
}

@Test
@Bug(25719)
@Issue("JENKINS-25719")
public void testEntities() {
String input = "<html>"
+ " <head>"
Expand Down
Binary file not shown.

0 comments on commit 7ab3d59

Please sign in to comment.