You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2020/11/11 04:42:55 UTC
[james-project] 03/07: JAMES-3439 Various refactorings regarding
Email/set create attachments (mixed)
This is an automated email from the ASF dual-hosted git repository.
rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 78ce27cd5d548768bfebddd25dfb0b2c38258248
Author: LanKhuat <dl...@linagora.com>
AuthorDate: Tue Nov 10 10:57:12 2020 +0700
JAMES-3439 Various refactorings regarding Email/set create attachments (mixed)
---
.../rfc8621/contract/EmailSetMethodContract.scala | 54 ++++------------
.../james/jmap/json/EmailGetSerializer.scala | 5 +-
.../james/jmap/json/EmailSetSerializer.scala | 8 ++-
.../org/apache/james/jmap/mail/EmailBodyPart.scala | 54 ++++++++++------
.../org/apache/james/jmap/mail/EmailSet.scala | 71 ++++++++++++----------
.../jmap/method/EmailSetCreatePerformer.scala | 5 +-
6 files changed, 97 insertions(+), 100 deletions(-)
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala
index 47b7a64..32322e7 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala
@@ -1932,14 +1932,12 @@ trait EmailSetMethodContract {
.inPath("methodResponses[0][1].created.aaaaaa")
.isEqualTo("{}".stripMargin)
- val blobIdToDownload = Json.parse(response)
+ val messageId = Json.parse(response)
.\("methodResponses")
.\(1).\(1)
.\("list")
.\(0)
- .\("attachments")
- .\(0)
- .\("blobId")
+ .\("id")
.get.asInstanceOf[JsString].value
assertThatJson(response)
@@ -1954,7 +1952,7 @@ trait EmailSetMethodContract {
| "attachments": [
| {
| "partId": "3",
- | "blobId": "$blobIdToDownload",
+ | "blobId": "${messageId}_3",
| "size": 11,
| "type": "text/plain",
| "charset": "UTF-8",
@@ -1964,7 +1962,7 @@ trait EmailSetMethodContract {
| "htmlBody": [
| {
| "partId": "2",
- | "blobId": "1_2",
+ | "blobId": "${messageId}_2",
| "size": 166,
| "type": "text/html",
| "charset": "UTF-8"
@@ -1978,21 +1976,6 @@ trait EmailSetMethodContract {
| }
| }
|}]""".stripMargin)
-
- val downloadResponse = `given`
- .basePath("")
- .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
- .when
- .get(s"/download/$accountId/$blobIdToDownload")
- .`then`
- .statusCode(SC_OK)
- .contentType("text/plain")
- .extract
- .body
- .asInputStream()
-
- assertThat(downloadResponse)
- .hasSameContentAs(new ByteArrayInputStream(payload))
}
@Test
@@ -2006,9 +1989,9 @@ trait EmailSetMethodContract {
.header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
.contentType("text/plain")
.body(payload)
- .when
+ .when
.post(s"/upload/$ACCOUNT_ID/")
- .`then`
+ .`then`
.statusCode(SC_CREATED)
.extract
.body
@@ -2057,7 +2040,7 @@ trait EmailSetMethodContract {
.header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
.body(request)
.when
- .post.prettyPeek()
+ .post
.`then`
.statusCode(SC_OK)
.contentType(JSON)
@@ -2103,21 +2086,6 @@ trait EmailSetMethodContract {
| }
| ]
|}]""".stripMargin)
-
- val downloadResponse = `given`
- .basePath("")
- .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
- .when
- .get(s"/download/$accountId/$blobIdToDownload")
- .`then`
- .statusCode(SC_OK)
- .contentType("text/plain")
- .extract
- .body
- .asInputStream()
-
- assertThat(downloadResponse)
- .hasSameContentAs(new ByteArrayInputStream(payload))
}
@Test
@@ -2167,7 +2135,8 @@ trait EmailSetMethodContract {
.inPath("methodResponses[0][1].notCreated.aaaaaa")
.isEqualTo(s"""{
| "type": "invalidArguments",
- | "description": "Attachment not found: 123"
+ | "description": "Attachment not found: 123",
+ | "properties": ["attachments"]
|}""".stripMargin)
}
@@ -2224,7 +2193,7 @@ trait EmailSetMethodContract {
.addHeader(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
.setBody(request)
.build, new ResponseSpecBuilder().build)
- .post
+ .post
.`then`
.statusCode(SC_OK)
.contentType(JSON)
@@ -2237,7 +2206,8 @@ trait EmailSetMethodContract {
.inPath("methodResponses[0][1].notCreated.aaaaaa")
.isEqualTo(s"""{
| "type": "invalidArguments",
- | "description": "Attachment not found: $blobId"
+ | "description": "Attachment not found: $blobId",
+ | "properties": ["attachments"]
|}""".stripMargin)
}
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
index fb89158..4d34d5b 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
@@ -21,7 +21,7 @@ package org.apache.james.jmap.json
import org.apache.james.jmap.api.model.Preview
import org.apache.james.jmap.core.Properties
-import org.apache.james.jmap.mail.{AddressesHeaderValue, BlobId, Charset, DateHeaderValue, Disposition, EmailAddress, EmailAddressGroup, EmailBody, EmailBodyMetadata, EmailBodyPart, EmailBodyValue, EmailFastView, EmailFullView, EmailGetRequest, EmailGetResponse, EmailHeader, EmailHeaderName, EmailHeaderValue, EmailHeaderView, EmailHeaders, EmailIds, EmailMetadata, EmailMetadataView, EmailNotFound, EmailView, EmailerName, FetchAllBodyValues, FetchHTMLBodyValues, FetchTextBodyValues, Group [...]
+import org.apache.james.jmap.mail._
import org.apache.james.mailbox.model.{Cid, MailboxId, MessageId}
import play.api.libs.functional.syntax._
import play.api.libs.json._
@@ -42,7 +42,8 @@ object EmailGetSerializer {
private implicit val typeWrites: Writes[Type] = Json.valueWrites[Type]
private implicit val charsetWrites: Writes[Charset] = Json.valueWrites[Charset]
private implicit val dispositionWrites: Writes[Disposition] = Json.valueWrites[Disposition]
- private implicit val languageWrites: Writes[Language] = Json.valueWrites[Language]
+ private implicit val languageWrites: Format[Language] = Json.valueFormat[Language]
+ private implicit val languagesFormat: Format[Languages] = Json.valueFormat[Languages]
private implicit val locationWrites: Writes[Location] = Json.valueWrites[Location]
private implicit val emailerNameWrites: Writes[EmailerName] = Json.valueWrites[EmailerName]
private implicit val emailAddressWrites: Writes[EmailAddress] = Json.writes[EmailAddress]
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala
index d7f467c..fa97676 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala
@@ -28,9 +28,9 @@ import org.apache.james.jmap.core.Id.IdConstraint
import org.apache.james.jmap.core.{Id, SetError, UTCDate}
import org.apache.james.jmap.mail.EmailSet.{EmailCreationId, UnparsedMessageId, UnparsedMessageIdConstraint}
import org.apache.james.jmap.mail.KeywordsFactory.STRICT_KEYWORDS_FACTORY
-import org.apache.james.jmap.mail.{AddressesHeaderValue, AsAddresses, AsDate, AsGroupedAddresses, AsMessageIds, AsRaw, AsText, AsURLs, Attachment, BlobId, Charset, ClientEmailBodyValue, ClientHtmlBody, ClientPartId, DateHeaderValue, DestroyIds, Disposition, EmailAddress, EmailAddressGroup, EmailCreationRequest, EmailCreationResponse, EmailHeader, EmailHeaderName, EmailHeaderValue, EmailSetRequest, EmailSetResponse, EmailSetUpdate, EmailerName, GroupName, GroupedAddressesHeaderValue, Head [...]
+import org.apache.james.jmap.mail.{AddressesHeaderValue, AsAddresses, AsDate, AsGroupedAddresses, AsMessageIds, AsRaw, AsText, AsURLs, Attachment, BlobId, Charset, ClientCid, ClientEmailBodyValue, ClientHtmlBody, ClientPartId, DateHeaderValue, DestroyIds, Disposition, EmailAddress, EmailAddressGroup, EmailCreationRequest, EmailCreationResponse, EmailHeader, EmailHeaderName, EmailHeaderValue, EmailSetRequest, EmailSetResponse, EmailSetUpdate, EmailerName, GroupName, GroupedAddressesHeader [...]
import org.apache.james.mailbox.model.{MailboxId, MessageId}
-import play.api.libs.json.{JsArray, JsBoolean, JsError, JsNull, JsObject, JsResult, JsString, JsSuccess, JsValue, Json, OWrites, Reads, Writes}
+import play.api.libs.json.{Format, JsArray, JsBoolean, JsError, JsNull, JsObject, JsResult, JsString, JsSuccess, JsValue, Json, OWrites, Reads, Writes}
import scala.util.Try
@@ -353,8 +353,10 @@ class EmailSetSerializer @Inject()(messageIdFactory: MessageId.Factory, mailboxI
private implicit val nameReads: Reads[Name] = Json.valueReads[Name]
private implicit val charsetReads: Reads[Charset] = Json.valueReads[Charset]
private implicit val dispositionReads: Reads[Disposition] = Json.valueReads[Disposition]
- private implicit val languageReads: Reads[Language] = Json.valueReads[Language]
+ private implicit val languageReads: Format[Language] = Json.valueFormat[Language]
+ private implicit val languagesWrites: Format[Languages] = Json.valueFormat[Languages]
private implicit val locationReads: Reads[Location] = Json.valueReads[Location]
+ private implicit val cidFormat: Format[ClientCid] = Json.valueFormat[ClientCid]
private implicit val attachmentReads: Reads[Attachment] = Json.reads[Attachment]
private implicit val emailCreationRequestWithoutHeadersReads: Reads[EmailCreationRequestWithoutHeaders] = Json.reads[EmailCreationRequestWithoutHeaders]
private implicit val emailCreationRequestReads: Reads[EmailCreationRequest] = {
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailBodyPart.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailBodyPart.scala
index 0c08138..348fe37 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailBodyPart.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailBodyPart.scala
@@ -30,16 +30,16 @@ import eu.timepit.refined.refineV
import org.apache.commons.io.IOUtils
import org.apache.james.jmap.core.Properties
import org.apache.james.jmap.mail.Email.Size
-import org.apache.james.jmap.mail.EmailBodyPart.{MULTIPART_ALTERNATIVE, TEXT_HTML, TEXT_PLAIN}
+import org.apache.james.jmap.mail.EmailBodyPart.{FILENAME_PREFIX, MULTIPART_ALTERNATIVE, TEXT_HTML, TEXT_PLAIN}
import org.apache.james.jmap.mail.PartId.PartIdValue
import org.apache.james.mailbox.model.{Cid, MessageId, MessageResult}
import org.apache.james.mime4j.codec.{DecodeMonitor, DecoderUtil}
+import org.apache.james.mime4j.dom.field.{ContentLanguageField, ContentTypeField, FieldName}
import org.apache.james.mime4j.dom.{Entity, Message, Multipart, TextBody => Mime4JTextBody}
import org.apache.james.mime4j.message.{DefaultMessageBuilder, DefaultMessageWriter}
-import org.apache.james.mime4j.stream.MimeConfig
+import org.apache.james.mime4j.stream.{Field, MimeConfig, RawField}
import scala.jdk.CollectionConverters._
-import scala.jdk.OptionConverters._
import scala.util.{Failure, Success, Try}
object PartId {
@@ -124,24 +124,12 @@ object EmailBodyPart {
blobId = blobId,
headers = entity.getHeader.getFields.asScala.toList.map(EmailHeader(_)),
size = size,
- name = Option(entity.getFilename).map(Name)
- .orElse({
- headerValue(entity, "Content-Type")
- .map(value => DecoderUtil.decodeEncodedWords(value, DecodeMonitor.SILENT))
- .filter(_.contains(FILENAME_PREFIX))
- .map(v => Name(v.substring(v.indexOf(FILENAME_PREFIX) + FILENAME_PREFIX.length + 1).replace("\"", "")))
- }),
+ name = Name.of(entity),
`type` = Type(entity.getMimeType),
charset = Option(entity.getCharset).map(Charset),
disposition = Option(entity.getDispositionType).map(Disposition(_)),
- cid = headerValue(entity, "Content-Id")
- .flatMap(Cid.parser()
- .relaxed()
- .unwrap()
- .parse(_)
- .toScala),
- language = headerValue(entity, "Content-Language")
- .map(_.split("; ").toList.map(Language)),
+ cid = ClientCid.of(entity),
+ language = Languages.of(entity),
location = headerValue(entity, "Content-Location")
.map(Location),
subParts = subParts,
@@ -169,6 +157,15 @@ object EmailBodyPart {
} yield (aValue, bValue)
}
+object Name {
+ def of(entity: Entity): Option[Name] = Option(entity.getHeader.getField(FieldName.CONTENT_TYPE))
+ .flatMap {
+ case contentTypeField: ContentTypeField => Option(contentTypeField.getParameter(FILENAME_PREFIX))
+ .map(DecoderUtil.decodeEncodedWords(_, DecodeMonitor.SILENT))
+ case _ => None
+ }.map(Name(_))
+}
+
case class Name(value: String)
case class Type(value: String)
case class Charset(value: String)
@@ -179,8 +176,25 @@ object Disposition {
}
case class Disposition(value: String)
+
+object Languages {
+ def of(entity: Entity): Option[Languages] =
+ Option(entity.getHeader.getField(FieldName.CONTENT_LANGUAGE))
+ .flatMap {
+ case contentLanguageField: ContentLanguageField => Some(Languages(contentLanguageField.getLanguages.asScala.toList.map(Language)))
+ case _ => None
+ }
+}
+
+case class Languages(value: List[Language]) {
+ def asField: Field = new RawField("Content-Language", value.map(_.value).mkString(", "))
+}
+
case class Language(value: String)
-case class Location(value: String)
+
+case class Location(value: String) {
+ def asField: Field = new RawField("Content-Location", value)
+}
case class EmailBodyPart(partId: PartId,
blobId: Option[BlobId],
@@ -191,7 +205,7 @@ case class EmailBodyPart(partId: PartId,
charset: Option[Charset],
disposition: Option[Disposition],
cid: Option[Cid],
- language: Option[List[Language]],
+ language: Option[Languages],
location: Option[Location],
subParts: Option[List[EmailBodyPart]],
entity: Entity) {
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala
index 585017e..eb06e54 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailSet.scala
@@ -1,4 +1,4 @@
-/****************************************************************
+/** **************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
- * *
- * http://www.apache.org/licenses/LICENSE-2.0 *
- * *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
- ****************************************************************/
+ * ***************************************************************/
package org.apache.james.jmap.mail
import java.io.IOException
@@ -32,18 +32,19 @@ import org.apache.james.jmap.core.{AccountId, SetError, UTCDate}
import org.apache.james.jmap.mail.EmailSet.{EmailCreationId, UnparsedMessageId}
import org.apache.james.jmap.method.WithAccountId
import org.apache.james.mailbox.exception.AttachmentNotFoundException
-import org.apache.james.mailbox.model.{AttachmentId, AttachmentMetadata, MessageId}
+import org.apache.james.mailbox.model.{AttachmentId, AttachmentMetadata, MessageId, Cid => MailboxCid}
import org.apache.james.mailbox.{AttachmentContentLoader, AttachmentManager, MailboxSession}
import org.apache.james.mime4j.codec.EncoderUtil
import org.apache.james.mime4j.codec.EncoderUtil.Usage
-import org.apache.james.mime4j.dom.Message
-import org.apache.james.mime4j.dom.field.{ContentTypeField, FieldName}
+import org.apache.james.mime4j.dom.field.{ContentIdField, ContentTypeField, FieldName}
+import org.apache.james.mime4j.dom.{Entity, Message}
import org.apache.james.mime4j.field.Fields
import org.apache.james.mime4j.message.{BodyPartBuilder, MultipartBuilder}
-import org.apache.james.mime4j.stream.RawField
+import org.apache.james.mime4j.stream.{Field, RawField}
import play.api.libs.json.JsObject
import scala.jdk.CollectionConverters._
+import scala.jdk.OptionConverters._
import scala.util.{Right, Try}
object EmailSet {
@@ -73,14 +74,27 @@ case class ClientEmailBodyValue(value: String,
isEncodingProblem: Option[IsEncodingProblem],
isTruncated: Option[IsTruncated])
+object ClientCid {
+ def of(entity: Entity): Option[MailboxCid] =
+ Option(entity.getHeader.getField(FieldName.CONTENT_ID))
+ .flatMap {
+ case contentIdField: ContentIdField => MailboxCid.parser().relaxed().unwrap().parse(contentIdField.getId).toScala
+ case _ => None
+ }
+}
+
+case class ClientCid(value: String) {
+ def asField: Field = new RawField("Content-ID", value)
+}
+
case class Attachment(blobId: BlobId,
`type`: Type,
name: Option[Name],
charset: Option[Charset],
disposition: Option[Disposition],
- language: Option[List[Language]],
+ language: Option[Languages],
location: Option[Location],
- cid: Option[String]) {
+ cid: Option[ClientCid]) {
def isInline: Boolean = disposition.contains("inline")
}
@@ -137,7 +151,6 @@ case class EmailCreationRequest(mailboxIds: MailboxIds,
attachmentContentLoader: AttachmentContentLoader,
mailboxSession: MailboxSession): Either[Exception, MultipartBuilder] = {
val multipartBuilder = MultipartBuilder.create(SubType.MIXED_SUBTYPE)
- val bodypartBuilder = BodyPartBuilder.create()
val maybeAttachments: Either[Exception, List[(Attachment, AttachmentMetadata, Array[Byte])]] =
attachments
@@ -147,26 +160,20 @@ case class EmailCreationRequest(mailboxIds: MailboxIds,
.flatMap(attachmentAndMetadata => loadAttachment(attachmentAndMetadata._1, attachmentAndMetadata._2, attachmentContentLoader, mailboxSession)))
.sequence
+ multipartBuilder.addBodyPart(BodyPartBuilder.create().setBody(maybeHtmlBody.getOrElse(""), SubType.HTML_SUBTYPE, StandardCharsets.UTF_8).build)
maybeAttachments.map(list => {
list.foldLeft(multipartBuilder) {
- case (builder, (attachment, attachmentMetadata, content)) =>
+ case (acc, (attachment, storedMetadata, content)) =>
+ val bodypartBuilder = BodyPartBuilder.create()
bodypartBuilder.setBody(content, attachment.`type`.value)
- .setField(contentTypeField(attachment, attachmentMetadata))
+ .setField(contentTypeField(attachment, storedMetadata))
.setContentDisposition(attachment.disposition.getOrElse(Disposition.ATTACHMENT).value)
+ attachment.cid.map(_.asField).foreach(bodypartBuilder.addField)
+ attachment.location.map(_.asField).foreach(bodypartBuilder.addField)
+ attachment.language.map(_.asField).foreach(bodypartBuilder.addField)
- if (attachment.cid.isDefined) {
- bodypartBuilder.setField(new RawField("Content-ID", attachment.cid.get))
- }
- if(attachment.location.isDefined) {
- bodypartBuilder.setField(new RawField("Content-Location", attachment.location.map(_.value).get))
- }
- if(attachment.language.isDefined) {
- bodypartBuilder.setField(new RawField("Content-Language", attachment.language.get.map(_.value).mkString("; ")))
- }
-
- builder.addBodyPart(BodyPartBuilder.create().setBody(maybeHtmlBody.getOrElse(""), SubType.HTML_SUBTYPE, StandardCharsets.UTF_8).build)
- builder.addBodyPart(bodypartBuilder)
- builder
+ acc.addBodyPart(bodypartBuilder)
+ acc
}
})
}
@@ -264,7 +271,7 @@ case class EmailSetUpdate(keywords: Option[Keywords],
Left(new IllegalArgumentException("Partial update and reset specified for mailboxIds"))
} else if (keywords.isDefined && (keywordsToAdd.isDefined || keywordsToRemove.isDefined)) {
Left(new IllegalArgumentException("Partial update and reset specified for keywords"))
- } else {
+ } else {
val mailboxIdsIdentity: Function[MailboxIds, MailboxIds] = ids => ids
val mailboxIdsAddition: Function[MailboxIds, MailboxIds] = mailboxIdsToAdd
.map(toBeAdded => (ids: MailboxIds) => ids ++ toBeAdded)
@@ -307,12 +314,14 @@ case class EmailSetUpdate(keywords: Option[Keywords],
mailboxIdsToAdd.isEmpty && mailboxIdsToRemove.isEmpty
}
-case class ValidatedEmailSetUpdate private (keywordsTransformation: Function[Keywords, Keywords],
- mailboxIdsTransformation: Function[MailboxIds, MailboxIds],
- update: EmailSetUpdate)
+case class ValidatedEmailSetUpdate private(keywordsTransformation: Function[Keywords, Keywords],
+ mailboxIdsTransformation: Function[MailboxIds, MailboxIds],
+ update: EmailSetUpdate)
class EmailUpdateValidationException() extends IllegalArgumentException
+
case class InvalidEmailPropertyException(property: String, cause: String) extends EmailUpdateValidationException
+
case class InvalidEmailUpdateException(property: String, cause: String) extends EmailUpdateValidationException
case class EmailCreationResponse(id: MessageId)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetCreatePerformer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetCreatePerformer.scala
index 3008d70..1fcac8c 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetCreatePerformer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetCreatePerformer.scala
@@ -22,10 +22,11 @@ package org.apache.james.jmap.method
import java.time.ZonedDateTime
import java.util.Date
+import eu.timepit.refined.auto._
import javax.inject.Inject
import javax.mail.Flags
import org.apache.james.jmap.core.SetError.SetErrorDescription
-import org.apache.james.jmap.core.{SetError, UTCDate}
+import org.apache.james.jmap.core.{Properties, SetError, UTCDate}
import org.apache.james.jmap.json.EmailSetSerializer
import org.apache.james.jmap.mail.EmailSet.EmailCreationId
import org.apache.james.jmap.mail.{EmailCreationRequest, EmailCreationResponse, EmailSetRequest}
@@ -60,7 +61,7 @@ object EmailSetCreatePerformer {
case class CreationFailure(clientId: EmailCreationId, e: Throwable) extends CreationResult {
def asMessageSetError: SetError = e match {
case e: MailboxNotFoundException => SetError.notFound(SetErrorDescription("Mailbox " + e.getMessage))
- case e: AttachmentNotFoundException => SetError.invalidArguments(SetErrorDescription(s"${e.getMessage}"))
+ case e: AttachmentNotFoundException => SetError.invalidArguments(SetErrorDescription(s"${e.getMessage}"), Some(Properties("attachments")))
case e: IllegalArgumentException => SetError.invalidArguments(SetErrorDescription(e.getMessage))
case _ => SetError.serverFail(SetErrorDescription(e.getMessage))
}
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org