Watcher: Support for inline attachments (elastic/elasticsearch#2601)

If an attachment is configured of disposition type INLINE, and is referred to
in HTML body parts, then some email clients can display images inside of an HTML
email and refer to those attachments.

Watcher already had support for inlined attachments, however this could not be configured
from a watch, but just via the Java API. Also it was not tested.

This commit changes the attachment to decide on creation if it should be inline or a regular
attachment and adds a test.

Relates elastic/elasticsearch#2381
Relates elastic/elasticsearch#2464
Closes elastic/elasticsearch#2557

Original commit: elastic/x-pack-elasticsearch@84935ffb18
This commit is contained in:
Alexander Reelsen 2016-06-27 10:45:10 +02:00 committed by GitHub
parent 88d0d4ddf5
commit 32c9f86124
15 changed files with 228 additions and 257 deletions

View File

@ -7,6 +7,7 @@ package org.elasticsearch.xpack.notification.email;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.inject.Provider;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
@ -16,19 +17,26 @@ import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.MessagingException;
import javax.mail.Part;
import javax.mail.internet.MimeBodyPart;
import javax.mail.util.ByteArrayDataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import static javax.mail.Part.ATTACHMENT;
import static javax.mail.Part.INLINE;
/**
*
*/
public abstract class Attachment extends BodyPartSource {
protected Attachment(String id, String name, String contentType) {
private final boolean inline;
protected Attachment(String id, String name, String contentType, boolean inline) {
super(id, name, contentType);
this.inline = inline;
}
@Override
@ -36,13 +44,17 @@ public abstract class Attachment extends BodyPartSource {
MimeBodyPart part = new MimeBodyPart();
part.setContentID(id);
part.setFileName(name);
part.setDisposition(Part.ATTACHMENT);
part.setDisposition(inline ? INLINE : ATTACHMENT);
writeTo(part);
return part;
}
public abstract String type();
public boolean isInline() {
return inline;
}
/**
* intentionally not emitting path as it may come as an information leak
*/
@ -65,22 +77,22 @@ public abstract class Attachment extends BodyPartSource {
private final Path path;
private final DataSource dataSource;
public File(String id, Path path) {
this(id, path.getFileName().toString(), path);
public File(String id, Path path, boolean inline) {
this(id, path.getFileName().toString(), path, inline);
}
public File(String id, Path path, String contentType) {
this(id, path.getFileName().toString(), path, contentType);
public File(String id, Path path, String contentType, boolean inline) {
this(id, path.getFileName().toString(), path, contentType, inline);
}
@SuppressForbidden(reason = "uses toFile")
public File(String id, String name, Path path) {
this(id, name, path, fileTypeMap.getContentType(path.toFile()));
public File(String id, String name, Path path, boolean inline) {
this(id, name, path, fileTypeMap.getContentType(path.toFile()), inline);
}
@SuppressForbidden(reason = "uses toFile")
public File(String id, String name, Path path, String contentType) {
super(id, name, contentType);
public File(String id, String name, Path path, String contentType, boolean inline) {
super(id, name, contentType, inline);
this.path = path;
this.dataSource = new FileDataSource(path.toFile());
}
@ -105,16 +117,16 @@ public abstract class Attachment extends BodyPartSource {
private final byte[] bytes;
public Bytes(String id, byte[] bytes, String contentType) {
this(id, id, bytes, contentType);
public Bytes(String id, byte[] bytes, String contentType, boolean inline) {
this(id, id, bytes, contentType, inline);
}
public Bytes(String id, String name, byte[] bytes) {
this(id, name, bytes, fileTypeMap.getContentType(name));
public Bytes(String id, String name, byte[] bytes, boolean inline) {
this(id, name, bytes, fileTypeMap.getContentType(name), inline);
}
public Bytes(String id, String name, byte[] bytes, String contentType) {
super(id, name, contentType);
public Bytes(String id, String name, byte[] bytes, String contentType, boolean inline) {
super(id, name, contentType, inline);
this.bytes = bytes;
}
@ -134,6 +146,68 @@ public abstract class Attachment extends BodyPartSource {
}
}
public static class Stream extends Attachment {
static final String TYPE = "stream";
private final Provider<InputStream> source;
public Stream(String id, String name, boolean inline, Provider<InputStream> source) {
this(id, name, fileTypeMap.getContentType(name), inline, source);
}
public Stream(String id, String name, String contentType, boolean inline, Provider<InputStream> source) {
super(id, name, contentType, inline);
this.source = source;
}
@Override
public String type() {
return TYPE;
}
@Override
protected void writeTo(MimeBodyPart part) throws MessagingException {
DataSource ds = new StreamDataSource(name, contentType, source);
DataHandler dh = new DataHandler(ds);
part.setDataHandler(dh);
}
static class StreamDataSource implements DataSource {
private final String name;
private final String contentType;
private final Provider<InputStream> source;
public StreamDataSource(String name, String contentType, Provider<InputStream> source) {
this.name = name;
this.contentType = contentType;
this.source = source;
}
@Override
public InputStream getInputStream() throws IOException {
return source.get();
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public String getContentType() {
return contentType;
}
@Override
public String getName() {
return name;
}
}
}
public static class XContent extends Bytes {
protected XContent(String id, ToXContent content, XContentType type) {
@ -141,7 +215,7 @@ public abstract class Attachment extends BodyPartSource {
}
protected XContent(String id, String name, ToXContent content, XContentType type) {
super(id, name, bytes(name, content, type), mimeType(type));
super(id, name, bytes(name, content, type), mimeType(type), false);
}
static String mimeType(XContentType type) {

View File

@ -49,11 +49,10 @@ public class Email implements ToXContent {
final String textBody;
final String htmlBody;
final Map<String, Attachment> attachments;
final Map<String, Inline> inlines;
public Email(String id, Address from, AddressList replyTo, Priority priority, DateTime sentDate,
AddressList to, AddressList cc, AddressList bcc, String subject, String textBody, String htmlBody,
Map<String, Attachment> attachments, Map<String, Inline> inlines) {
Map<String, Attachment> attachments) {
this.id = id;
this.from = from;
@ -67,7 +66,6 @@ public class Email implements ToXContent {
this.textBody = textBody;
this.htmlBody = htmlBody;
this.attachments = attachments;
this.inlines = inlines;
}
public String id() {
@ -118,10 +116,6 @@ public class Email implements ToXContent {
return attachments;
}
public Map<String, Inline> inlines() {
return inlines;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
@ -249,7 +243,6 @@ public class Email implements ToXContent {
private String textBody;
private String htmlBody;
private Map<String, Attachment> attachments = new HashMap<>();
private Map<String, Inline> inlines = new HashMap<>();
private Builder() {
}
@ -267,7 +260,6 @@ public class Email implements ToXContent {
textBody = email.textBody;
htmlBody = email.htmlBody;
attachments.putAll(email.attachments);
inlines.putAll(email.inlines);
return this;
}
@ -358,14 +350,6 @@ public class Email implements ToXContent {
return this;
}
public Builder inline(Inline inline) {
if (inlines == null) {
throw new IllegalStateException("Email has already been built!");
}
inlines.put(inline.id(), inline);
return this;
}
/**
* Build the email. Note that adding items to attachments or inlines
* after this is called is incorrect.
@ -373,9 +357,8 @@ public class Email implements ToXContent {
public Email build() {
assert id != null : "email id should not be null (should be set to the watch id";
Email email = new Email(id, from, replyTo, priority, sentDate, to, cc, bcc, subject, textBody, htmlBody,
unmodifiableMap(attachments), unmodifiableMap(inlines));
unmodifiableMap(attachments));
attachments = null;
inlines = null;
return email;
}

View File

@ -1,189 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.notification.email;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.inject.Provider;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.xpack.notification.email.support.BodyPartSource;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.MessagingException;
import javax.mail.Part;
import javax.mail.internet.MimeBodyPart;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
/**
*
*/
public abstract class Inline extends BodyPartSource {
protected Inline(String id, String name, String contentType) {
super(id, name, contentType);
}
public abstract String type();
@Override
public final MimeBodyPart bodyPart() throws MessagingException {
MimeBodyPart part = new MimeBodyPart();
part.setDisposition(Part.INLINE);
part.setContentID(id);
part.setFileName(name);
writeTo(part);
return part;
}
/**
* intentionally not emitting path as it may come as an information leak
*/
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject()
.field("type", type())
.field("id", id)
.field("name", name)
.field("content_type", contentType)
.endObject();
}
protected abstract void writeTo(MimeBodyPart part) throws MessagingException;
public static class File extends Inline {
static final String TYPE = "file";
private final Path path;
private DataSource dataSource;
public File(String id, Path path) {
this(id, path.getFileName().toString(), path);
}
@SuppressForbidden(reason = "uses toFile")
public File(String id, String name, Path path) {
this(id, name, path, fileTypeMap.getContentType(path.toFile()));
}
@SuppressForbidden(reason = "uses toFile")
public File(String id, String name, Path path, String contentType) {
super(id, name, contentType);
this.path = path;
this.dataSource = new FileDataSource(path.toFile());
}
public Path path() {
return path;
}
public String type() {
return TYPE;
}
@Override
public void writeTo(MimeBodyPart part) throws MessagingException {
part.setDataHandler(new DataHandler(dataSource, contentType));
}
}
public static class Stream extends Inline {
static final String TYPE = "stream";
private final Provider<InputStream> source;
public Stream(String id, String name, Provider<InputStream> source) {
this(id, name, fileTypeMap.getContentType(name), source);
}
public Stream(String id, String name, String contentType, Provider<InputStream> source) {
super(id, name, contentType);
this.source = source;
}
@Override
public String type() {
return TYPE;
}
@Override
protected void writeTo(MimeBodyPart part) throws MessagingException {
DataSource ds = new StreamDataSource(name, contentType, source);
DataHandler dh = new DataHandler(ds);
part.setDataHandler(dh);
}
static class StreamDataSource implements DataSource {
private final String name;
private final String contentType;
private final Provider<InputStream> source;
public StreamDataSource(String name, String contentType, Provider<InputStream> source) {
this.name = name;
this.contentType = contentType;
this.source = source;
}
@Override
public InputStream getInputStream() throws IOException {
return source.get();
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public String getContentType() {
return contentType;
}
@Override
public String getName() {
return name;
}
}
}
public static class Bytes extends Stream {
public Bytes(String id, String name, String contentType, byte[] bytes) {
super(id, name, contentType, new BytesStreamProvider(bytes));
}
public Bytes(String id, String name, String contentType, BytesReference bytes) {
super(id, name, contentType, new BytesStreamProvider(bytes));
}
static class BytesStreamProvider implements Provider<InputStream> {
private final BytesReference bytes;
public BytesStreamProvider(byte[] bytes) {
this(new BytesArray(bytes));
}
public BytesStreamProvider(BytesReference bytes) {
this.bytes = bytes;
}
@Override
public InputStream get() {
return new ByteArrayInputStream(bytes.array(), bytes.arrayOffset(), bytes.length());
}
}
}
}

View File

@ -92,17 +92,15 @@ public enum Profile implements ToXContent {
alternative.addBodyPart(html);
}
if (!email.inlines.isEmpty()) {
for (Inline inline : email.inlines.values()) {
related.addBodyPart(inline.bodyPart());
}
}
if (!email.attachments.isEmpty()) {
for (Attachment attachment : email.attachments.values()) {
if (attachment.isInline()) {
related.addBodyPart(attachment.bodyPart());
} else {
mixed.addBodyPart(attachment.bodyPart());
}
}
}
return message;
}

View File

@ -54,10 +54,16 @@ public class DataAttachment implements EmailAttachmentParser.EmailAttachment {
return Objects.hash(id, dataAttachment);
}
@Override
public String id() {
return id;
}
@Override
public boolean inline() {
return false;
}
public static Builder builder(String id) {
return new Builder(id);
}

View File

@ -30,6 +30,14 @@ public interface EmailAttachmentParser<T extends EmailAttachmentParser.EmailAtta
* @return The id of this attachment
*/
String id();
/**
* Allows the attachment to decide of it should be of disposition type attachment or inline, which is important
* for being able to display inside of desktop email clients
*
* @return a boolean flagging this attachment as being inline
*/
boolean inline();
}
/**

View File

@ -14,15 +14,15 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.Variables;
import org.elasticsearch.xpack.common.http.HttpClient;
import org.elasticsearch.xpack.common.http.HttpRequest;
import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
import org.elasticsearch.xpack.common.http.HttpResponse;
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.watch.Payload;
import org.elasticsearch.xpack.notification.email.Attachment;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.Variables;
import org.elasticsearch.xpack.watcher.watch.Payload;
import java.io.IOException;
import java.util.Map;
@ -30,6 +30,7 @@ import java.util.Map;
public class HttpEmailAttachementParser implements EmailAttachmentParser<HttpRequestAttachment> {
public interface Fields {
ParseField INLINE = new ParseField("inline");
ParseField REQUEST = new ParseField("request");
ParseField CONTENT_TYPE = new ParseField("content_type");
}
@ -56,6 +57,7 @@ public class HttpEmailAttachementParser implements EmailAttachmentParser<HttpReq
@Override
public HttpRequestAttachment parse(String id, XContentParser parser) throws IOException {
boolean inline = false;
String contentType = null;
HttpRequestTemplate requestTemplate = null;
@ -66,6 +68,8 @@ public class HttpEmailAttachementParser implements EmailAttachmentParser<HttpReq
currentFieldName = parser.currentName();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.CONTENT_TYPE)) {
contentType = parser.text();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.INLINE)) {
inline = parser.booleanValue();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.REQUEST)) {
requestTemplate = requestTemplateParser.parse(parser);
} else {
@ -75,7 +79,7 @@ public class HttpEmailAttachementParser implements EmailAttachmentParser<HttpReq
}
if (requestTemplate != null) {
return new HttpRequestAttachment(id, requestTemplate, contentType);
return new HttpRequestAttachment(id, requestTemplate, inline, contentType);
}
throw new ElasticsearchParseException("Could not parse http request attachment");
@ -94,7 +98,7 @@ public class HttpEmailAttachementParser implements EmailAttachmentParser<HttpReq
if (response.hasContent()) {
String contentType = attachment.getContentType();
String attachmentContentType = Strings.hasLength(contentType) ? contentType : response.contentType();
return new Attachment.Bytes(attachment.id(), response.body().toBytes(), attachmentContentType);
return new Attachment.Bytes(attachment.id(), response.body().toBytes(), attachmentContentType, attachment.inline());
} else {
logger.error("Empty response body: [host[{}], port[{}], method[{}], path[{}]: response status [{}]", httpRequest.host(),
httpRequest.port(), httpRequest.method(), httpRequest.path(), response.status());

View File

@ -16,12 +16,14 @@ import java.util.Objects;
public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachment {
private final HttpRequestTemplate requestTemplate;
private boolean inline;
private final String contentType;
private final String id;
public HttpRequestAttachment(String id, HttpRequestTemplate requestTemplate, @Nullable String contentType) {
public HttpRequestAttachment(String id, HttpRequestTemplate requestTemplate, boolean inline, @Nullable String contentType) {
this.id = id;
this.requestTemplate = requestTemplate;
this.inline = inline;
this.contentType = contentType;
}
@ -38,6 +40,11 @@ public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachm
return id;
}
@Override
public boolean inline() {
return inline;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(id)
@ -46,6 +53,9 @@ public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachm
if (Strings.hasLength(contentType)) {
builder.field(HttpEmailAttachementParser.Fields.CONTENT_TYPE.getPreferredName(), contentType);
}
if (inline) {
builder.field(HttpEmailAttachementParser.Fields.INLINE.getPreferredName(), inline);
}
return builder.endObject().endObject();
}
@ -65,12 +75,12 @@ public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachm
HttpRequestAttachment otherDataAttachment = (HttpRequestAttachment) o;
return Objects.equals(id, otherDataAttachment.id) && Objects.equals(requestTemplate, otherDataAttachment.requestTemplate)
&& Objects.equals(contentType, otherDataAttachment.contentType);
&& Objects.equals(contentType, otherDataAttachment.contentType) && Objects.equals(inline, otherDataAttachment.inline);
}
@Override
public int hashCode() {
return Objects.hash(id, requestTemplate, contentType);
return Objects.hash(id, requestTemplate, contentType, inline);
}
public static class Builder {
@ -78,6 +88,7 @@ public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachm
private String id;
private HttpRequestTemplate httpRequestTemplate;
private String contentType;
private boolean inline = false;
private Builder(String id) {
this.id = id;
@ -93,8 +104,13 @@ public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachm
return this;
}
public Builder inline(boolean inline) {
this.inline = inline;
return this;
}
public HttpRequestAttachment build() {
return new HttpRequestAttachment(id, httpRequestTemplate, contentType);
return new HttpRequestAttachment(id, httpRequestTemplate, inline, contentType);
}
}

View File

@ -41,9 +41,8 @@ public class EmailTests extends ESTestCase {
String textBody = randomFrom("Random Body", "", null);
String htmlBody = randomFrom("<hr /><b>BODY</b><hr />", "", null);
Map<String, Attachment> attachments = null;
Map<String, Inline> inlines = null;
Email email = new Email(id, from, replyTo, priority, sentDate, to, cc, bcc, subject, textBody, htmlBody, attachments, inlines);
Email email = new Email(id, from, replyTo, priority, sentDate, to, cc, bcc, subject, textBody, htmlBody, attachments);
XContentBuilder builder = XContentFactory.jsonBuilder();
email.toXContent(builder, ToXContent.EMPTY_PARAMS);

View File

@ -109,7 +109,8 @@ public class ManualPublicSmtpServersTester {
.textBody("_text_body")
.htmlBody("<b>html body</b><p/><p/><img src=\"cid:logo.png\"/>")
.attach(new Attachment.XContent.Yaml("test.yml", content))
.inline(new Inline.Stream("logo.png", "logo.png", () -> InternalEmailServiceTests.class.getResourceAsStream(path)))
.attach(new Attachment.Stream("logo.png", "logo.png", true,
() -> InternalEmailServiceTests.class.getResourceAsStream(path)))
.build();
EmailService.EmailSent sent = service.send(email, null, profile);

View File

@ -0,0 +1,62 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.notification.email;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.common.secret.SecretService;
import javax.mail.BodyPart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
public class ProfileTests extends ESTestCase {
public void testThatInlineAttachmentsAreCreated() throws Exception {
String path = "/org/elasticsearch/xpack/watcher/actions/email/service/logo.png";
Attachment attachment = new Attachment.Stream("inline.png", "inline.png", true,
() -> InternalEmailServiceTests.class.getResourceAsStream(path));
Email email = Email.builder()
.id("foo")
.from("foo@example.org")
.to("bar@example.org")
.subject(randomAsciiOfLength(10))
.attach(attachment)
.build();
Settings settings = Settings.builder()
.put("default_account", "foo")
.put("account.foo.smtp.host", "_host")
.build();
Accounts accounts = new Accounts(settings, SecretService.Insecure.INSTANCE, logger);
Session session = accounts.account("foo").getConfig().createSession();
MimeMessage mimeMessage = Profile.STANDARD.toMimeMessage(email, session);
Object content = ((MimeMultipart) mimeMessage.getContent()).getBodyPart(0).getContent();
assertThat(content, instanceOf(MimeMultipart.class));
MimeMultipart multipart = (MimeMultipart) content;
assertThat(multipart.getCount(), is(2));
boolean foundInlineAttachment = false;
BodyPart bodyPart = null;
for (int i = 0; i < multipart.getCount(); i++) {
bodyPart = multipart.getBodyPart(i);
if (Part.INLINE.equalsIgnoreCase(bodyPart.getDisposition())) {
foundInlineAttachment = true;
break;
}
}
assertThat("Expected to find an inline attachment in mime message, but didnt", foundInlineAttachment, is(true));
}
}

View File

@ -93,7 +93,8 @@ public class EmailAttachmentParsersTests extends ESTestCase {
attachments.add(new DataAttachment("my-name.json", org.elasticsearch.xpack.notification.email.DataAttachment.JSON));
HttpRequestTemplate requestTemplate = HttpRequestTemplate.builder("localhost", 80).scheme(Scheme.HTTP).path("/").build();
HttpRequestAttachment httpRequestAttachment = new HttpRequestAttachment("other-id", requestTemplate, null);
boolean inline = randomBoolean();
HttpRequestAttachment httpRequestAttachment = new HttpRequestAttachment("other-id", requestTemplate, inline, null);
attachments.add(httpRequestAttachment);
EmailAttachments emailAttachments = new EmailAttachments(attachments);
@ -105,6 +106,9 @@ public class EmailAttachmentParsersTests extends ESTestCase {
assertThat(builder.string(), containsString("other-id"));
assertThat(builder.string(), containsString("localhost"));
assertThat(builder.string(), containsString("/"));
if (inline) {
assertThat(builder.string(), containsString("inline"));
}
}
public void testThatTwoAttachmentsWithTheSameIdThrowError() throws Exception {
@ -161,7 +165,7 @@ public class EmailAttachmentParsersTests extends ESTestCase {
@Override
public Attachment toAttachment(WatchExecutionContext ctx, Payload payload, TestEmailAttachment attachment) {
return new Attachment.Bytes(attachment.id(), attachment.getValue().getBytes(Charsets.UTF_8), "personalContentType");
return new Attachment.Bytes(attachment.id(), attachment.getValue().getBytes(Charsets.UTF_8), "personalContentType", false);
}
}
@ -193,6 +197,11 @@ public class EmailAttachmentParsersTests extends ESTestCase {
return id;
}
@Override
public boolean inline() {
return false;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(id)

View File

@ -37,15 +37,13 @@ import static org.mockito.Mockito.when;
public class HttpEmailAttachementParserTests extends ESTestCase {
private SecretService.Insecure secretService;
private HttpAuthRegistry authRegistry;
private HttpRequestTemplate.Parser httpRequestTemplateParser;
private HttpClient httpClient;
@Before
public void init() throws Exception {
secretService = SecretService.Insecure.INSTANCE;
authRegistry = new HttpAuthRegistry(singletonMap(BasicAuth.TYPE, new BasicAuthFactory(secretService)));
SecretService.Insecure secretService = SecretService.Insecure.INSTANCE;
HttpAuthRegistry authRegistry = new HttpAuthRegistry(singletonMap(BasicAuth.TYPE, new BasicAuthFactory(secretService)));
httpRequestTemplateParser = new HttpRequestTemplate.Parser(authRegistry);
httpClient = mock(HttpClient.class);
@ -77,9 +75,12 @@ public class HttpEmailAttachementParserTests extends ESTestCase {
if (configureContentType) {
builder.field("content_type", "application/foo");
}
boolean isInline = randomBoolean();
if (isInline) {
builder.field("inline", true);
}
builder.endObject().endObject().endObject();
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
logger.info("JSON: {}", builder.string());
EmailAttachments emailAttachments = emailAttachmentsParser.parse(parser);
assertThat(emailAttachments.getAttachments(), hasSize(1));
@ -89,6 +90,7 @@ public class HttpEmailAttachementParserTests extends ESTestCase {
attachments.get(0).toXContent(toXcontentBuilder, ToXContent.EMPTY_PARAMS);
toXcontentBuilder.endObject();
assertThat(toXcontentBuilder.string(), is(builder.string()));
}
assertThat(attachments.get(0).inline(), is(isInline));
}
}

View File

@ -610,7 +610,8 @@ public class EmailActionTests extends ESTestCase {
when(httpClient.execute(any(HttpRequest.class))).thenReturn(mockResponse);
HttpRequestTemplate template = HttpRequestTemplate.builder("localhost", 1234).build();
attachments.add(new HttpRequestAttachment(randomAsciiOfLength(10), template, randomFrom("my/custom-type", null)));
attachments.add(new HttpRequestAttachment(randomAsciiOfLength(10), template,
randomBoolean(), randomFrom("my/custom-type", null)));
} else if ("data".equals(attachmentType)) {
attachments.add(new org.elasticsearch.xpack.notification.email.attachment.DataAttachment(randomAsciiOfLength(10),
randomFrom(DataAttachment.JSON, DataAttachment.YAML)));

View File

@ -207,7 +207,4 @@ public class EmailAttachmentTests extends AbstractWatcherIntegrationTestCase {
fail("waited too long for email to be received");
}
}
}