This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit ff5a09a25880ca7482d679c4104ecb529eddbecb Author: Rene Cordier <[email protected]> AuthorDate: Wed Sep 23 14:49:03 2020 +0700 JAMES-3384 text, from, to, cc, bcc, subject, header, body parameters are not yet supported for filtering on Email/query --- .../contract/EmailQueryMethodContract.scala | 49 +++++++++++++++++- .../james/jmap/json/EmailQuerySerializer.scala | 10 +++- .../org/apache/james/jmap/mail/EmailQuery.scala | 18 ++++++- .../james/jmap/utils/search/MailboxFilter.scala | 59 +++++++++++++++++++++- 4 files changed, 132 insertions(+), 4 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/EmailQueryMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala index 0040ae2..e521a7f 100644 --- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala +++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailQueryMethodContract.scala @@ -920,7 +920,14 @@ trait EmailQueryMethodContract { @ValueSource(strings = Array( "allInThreadHaveKeyword", "someInThreadHaveKeyword", - "noneInThreadHaveKeyword" + "noneInThreadHaveKeyword", + "text", + "from", + "to", + "cc", + "bcc", + "subject", + "body" )) def listMailsShouldReturnUnsupportedFilterWhenValidButUnsupported(unsupportedFilter: String): Unit = { val request = @@ -961,6 +968,46 @@ trait EmailQueryMethodContract { """) } + @Test + def listMailsShouldReturnUnsupportedFilterWhenHeaderFilter(): Unit = { + val request = + s"""{ + | "using": [ + | "urn:ietf:params:jmap:core", + | "urn:ietf:params:jmap:mail"], + | "methodCalls": [[ + | "Email/query", + | { + | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6", + | "filter" : { + | "header": ["header1", "header2"] + | } + | }, + | "c1"]] + |}""".stripMargin + + val response = `given` + .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER) + .body(request) + .when + .post + .`then` + .statusCode(SC_OK) + .contentType(JSON) + .extract + .body + .asString + + assertThatJson(response) + .inPath("$.methodResponses[0][1]") + .isEqualTo(s""" + { + "type": "unsupportedFilter", + "description": "The filter header is syntactically valid, but the server cannot process it. If the filter was the result of a user’s search input, the client SHOULD suggest that the user simplify their search." + } + """) + } + @ParameterizedTest @ValueSource(strings = Array( "true", diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailQuerySerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailQuerySerializer.scala index 9d86b2b..e2dce1b 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailQuerySerializer.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailQuerySerializer.scala @@ -20,7 +20,7 @@ package org.apache.james.jmap.json import javax.inject.Inject -import org.apache.james.jmap.mail.{AllInThreadHaveKeywordSortProperty, Anchor, AnchorOffset, CollapseThreads, Collation, Comparator, EmailQueryRequest, EmailQueryResponse, FilterCondition, FromSortProperty, HasAttachment, HasKeywordSortProperty, IsAscending, ReceivedAtSortProperty, SizeSortProperty, SomeInThreadHaveKeywordSortProperty, SortProperty, SubjectSortProperty, ToSortProperty} +import org.apache.james.jmap.mail.{AllInThreadHaveKeywordSortProperty, Anchor, AnchorOffset, Bcc, Body, Cc, CollapseThreads, Collation, Comparator, EmailQueryRequest, EmailQueryResponse, FilterCondition, From, FromSortProperty, HasAttachment, HasKeywordSortProperty, Header, IsAscending, ReceivedAtSortProperty, SizeSortProperty, SomeInThreadHaveKeywordSortProperty, SortProperty, Subject, SubjectSortProperty, Text, To, ToSortProperty} import org.apache.james.jmap.model.{AccountId, CanCalculateChanges, Keyword, LimitUnparsed, PositionUnparsed, QueryState} import org.apache.james.mailbox.model.{MailboxId, MessageId} import play.api.libs.json._ @@ -49,6 +49,14 @@ class EmailQuerySerializer @Inject()(mailboxIdFactory: MailboxId.Factory) { case _ => JsError("Expecting keywords to be represented by a JsString") } private implicit val hasAttachmentReads: Reads[HasAttachment] = Json.valueReads[HasAttachment] + private implicit val textReads: Reads[Text] = Json.valueReads[Text] + private implicit val fromReads: Reads[From] = Json.valueReads[From] + private implicit val toReads: Reads[To] = Json.valueReads[To] + private implicit val ccReads: Reads[Cc] = Json.valueReads[Cc] + private implicit val bccReads: Reads[Bcc] = Json.valueReads[Bcc] + private implicit val subjectReads: Reads[Subject] = Json.valueReads[Subject] + private implicit val headerReads: Reads[Header] = Json.valueReads[Header] + private implicit val bodyReads: Reads[Body] = Json.valueReads[Body] private implicit val filterConditionReads: Reads[FilterCondition] = Json.reads[FilterCondition] private implicit val limitUnparsedReads: Reads[LimitUnparsed] = Json.valueReads[LimitUnparsed] private implicit val CanCalculateChangesFormat: Format[CanCalculateChanges] = Json.valueFormat[CanCalculateChanges] diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailQuery.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailQuery.scala index 4856bbc..6e5c308 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailQuery.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailQuery.scala @@ -31,6 +31,14 @@ case class UnsupportedSortException(unsupportedSort: String) extends Unsupported case class UnsupportedFilterException(unsupportedFilter: String) extends UnsupportedOperationException case class UnsupportedRequestParameterException(unsupportedParam: String) extends UnsupportedOperationException +case class Text(value: String) extends AnyVal +case class From(value: String) extends AnyVal +case class To(value: String) extends AnyVal +case class Cc(value: String) extends AnyVal +case class Bcc(value: String) extends AnyVal +case class Body(value: String) extends AnyVal +case class Header(value: String) extends AnyVal + case class FilterCondition(inMailbox: Option[MailboxId], inMailboxOtherThan: Option[Seq[MailboxId]], before: Option[UTCDate], @@ -42,7 +50,15 @@ case class FilterCondition(inMailbox: Option[MailboxId], hasAttachment: Option[HasAttachment], allInThreadHaveKeyword: Option[Keyword], someInThreadHaveKeyword: Option[Keyword], - noneInThreadHaveKeyword: Option[Keyword]) + noneInThreadHaveKeyword: Option[Keyword], + text: Option[Text], + from: Option[From], + to: Option[To], + cc: Option[Cc], + bcc: Option[Bcc], + subject: Option[Subject], + header: Option[Set[Header]], + body: Option[Body]) case class EmailQueryRequest(accountId: AccountId, position: Option[PositionUnparsed], diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/search/MailboxFilter.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/search/MailboxFilter.scala index 73fe224..3ef1239 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/search/MailboxFilter.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/search/MailboxFilter.scala @@ -61,7 +61,8 @@ object MailboxFilter { object QueryFilter { def buildQuery(request: EmailQueryRequest): Either[UnsupportedFilterException, SearchQuery.Builder] = { List(ReceivedBefore, ReceivedAfter, HasAttachment, HasKeyWord, NotKeyWord, MinSize, MaxSize, - AllInThreadHaveKeyword, NoneInThreadHaveKeyword, SomeInThreadHaveKeyword) + AllInThreadHaveKeyword, NoneInThreadHaveKeyword, SomeInThreadHaveKeyword, Text, From, + To, Cc, Bcc, Subject, Header, Body) .foldLeftM(new SearchQuery.Builder())((builder, filter) => filter.toQuery(builder, request)) } } @@ -163,4 +164,60 @@ object MailboxFilter { case None => Right(builder) } } + case object Text extends QueryFilter { + override def toQuery(builder: SearchQuery.Builder, request: EmailQueryRequest): Either[UnsupportedFilterException, SearchQuery.Builder] = + request.filter.flatMap(_.text) match { + case Some(_) => Left(UnsupportedFilterException("text")) + case None => Right(builder) + } + } + case object From extends QueryFilter { + override def toQuery(builder: SearchQuery.Builder, request: EmailQueryRequest): Either[UnsupportedFilterException, SearchQuery.Builder] = + request.filter.flatMap(_.from) match { + case Some(_) => Left(UnsupportedFilterException("from")) + case None => Right(builder) + } + } + case object To extends QueryFilter { + override def toQuery(builder: SearchQuery.Builder, request: EmailQueryRequest): Either[UnsupportedFilterException, SearchQuery.Builder] = + request.filter.flatMap(_.to) match { + case Some(_) => Left(UnsupportedFilterException("to")) + case None => Right(builder) + } + } + case object Cc extends QueryFilter { + override def toQuery(builder: SearchQuery.Builder, request: EmailQueryRequest): Either[UnsupportedFilterException, SearchQuery.Builder] = + request.filter.flatMap(_.cc) match { + case Some(_) => Left(UnsupportedFilterException("cc")) + case None => Right(builder) + } + } + case object Bcc extends QueryFilter { + override def toQuery(builder: SearchQuery.Builder, request: EmailQueryRequest): Either[UnsupportedFilterException, SearchQuery.Builder] = + request.filter.flatMap(_.bcc) match { + case Some(_) => Left(UnsupportedFilterException("bcc")) + case None => Right(builder) + } + } + case object Subject extends QueryFilter { + override def toQuery(builder: SearchQuery.Builder, request: EmailQueryRequest): Either[UnsupportedFilterException, SearchQuery.Builder] = + request.filter.flatMap(_.subject) match { + case Some(_) => Left(UnsupportedFilterException("subject")) + case None => Right(builder) + } + } + case object Header extends QueryFilter { + override def toQuery(builder: SearchQuery.Builder, request: EmailQueryRequest): Either[UnsupportedFilterException, SearchQuery.Builder] = + request.filter.flatMap(_.header) match { + case Some(_) => Left(UnsupportedFilterException("header")) + case None => Right(builder) + } + } + case object Body extends QueryFilter { + override def toQuery(builder: SearchQuery.Builder, request: EmailQueryRequest): Either[UnsupportedFilterException, SearchQuery.Builder] = + request.filter.flatMap(_.body) match { + case Some(_) => Left(UnsupportedFilterException("body")) + case None => Right(builder) + } + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
