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/09/28 03:10:06 UTC
[james-project] branch master updated (08c46e3 -> d124e2b)
This is an automated email from the ASF dual-hosted git repository.
rcordier pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git.
from 08c46e3 James-3385: update Email/Query documentation
new 264f73d JAMES-3387 require accountId to be one of the accounts of the authenticated user
new 5e0d014 JAMES-3387 validate accountId for email/get
new 4b789e3 JAMES-3387 validate accountId for email/query
new a667ad5 JAMES-3387 refactor extract InvocationWithContext
new 60732e1 JAMES-3387 validate accountId for mailbox/get
new 5065639 JAMES-3387 validate accountId form mailbox/query
new c532fad JAMES-3387 validate accountId for vacationResponse/get
new d124e2b JAMES-3387 validate accountId for vacationResponse/set
The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../rfc8621/contract/EmailGetMethodContract.scala | 39 ++++
.../contract/EmailQueryMethodContract.scala | 243 +++++++--------------
.../contract/MailboxGetMethodContract.scala | 41 ++++
.../contract/MailboxQueryMethodContract.scala | 40 ++++
.../contract/MailboxSetMethodContract.scala | 47 ++++
.../VacationResponseGetMethodContract.scala | 41 ++++
.../VacationResponseSetMethodContract.scala | 50 +++++
.../org/apache/james/jmap/mail/EmailGet.scala | 3 +-
.../org/apache/james/jmap/mail/EmailQuery.scala | 3 +-
.../org/apache/james/jmap/mail/MailboxGet.scala | 3 +-
.../org/apache/james/jmap/mail/MailboxQuery.scala | 3 +-
.../org/apache/james/jmap/mail/MailboxSet.scala | 4 +-
.../james/jmap/mail/VacationResponseGet.scala | 3 +-
.../apache/james/jmap/method/CoreEchoMethod.scala | 5 +-
.../apache/james/jmap/method/EmailGetMethod.scala | 23 +-
.../james/jmap/method/EmailQueryMethod.scala | 44 ++--
.../james/jmap/method/MailboxGetMethod.scala | 46 ++--
.../james/jmap/method/MailboxQueryMethod.scala | 33 +--
.../james/jmap/method/MailboxSetMethod.scala | 22 +-
.../org/apache/james/jmap/method/Method.scala | 59 ++++-
.../jmap/method/VacationResponseGetMethod.scala | 59 +++--
.../jmap/method/VacationResponseSetMethod.scala | 25 +--
.../apache/james/jmap/routes/JMAPApiRoutes.scala | 50 ++---
.../james/jmap/vacation/VacationResponseSet.scala | 3 +-
.../james/jmap/method/CoreEchoMethodTest.scala | 8 +-
.../james/jmap/routes/JMAPApiRoutesTest.scala | 12 +-
26 files changed, 560 insertions(+), 349 deletions(-)
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 02/08: JAMES-3387 validate accountId for email/get
Posted by rc...@apache.org.
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 5e0d014f137fd67d353cc210920ea032d253acb2
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Wed Sep 23 15:59:40 2020 +0200
JAMES-3387 validate accountId for email/get
---
.../rfc8621/contract/EmailGetMethodContract.scala | 39 ++++++++++++++++++++++
.../org/apache/james/jmap/mail/EmailGet.scala | 3 +-
.../apache/james/jmap/method/EmailGetMethod.scala | 22 ++++++------
3 files changed, 51 insertions(+), 13 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/EmailGetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
index 61fb12f..0821e63 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailGetMethodContract.scala
@@ -73,6 +73,45 @@ trait EmailGetMethodContract {
def randomMessageId: MessageId
@Test
+ def emailGetShouldFailWhenWrongAccountId(): Unit = {
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(
+ s"""{
+ | "using": [
+ | "urn:ietf:params:jmap:core",
+ | "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [[
+ | "Email/get",
+ | {
+ | "accountId": "unknownAccountId",
+ | "ids": []
+ | },
+ | "c1"]]
+ |}""".stripMargin)
+ .when
+ .post
+ .`then`
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response).isEqualTo(
+ s"""{
+ | "sessionState": "75128aab4b1b",
+ | "methodResponses": [[
+ | "error",
+ | {
+ | "type": "accountNotFound"
+ | },
+ | "c1"
+ | ]]
+ |}""".stripMargin)
+ }
+
+ @Test
def idsShouldBeMandatory(): Unit = {
val response = `given`
.header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailGet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailGet.scala
index cd4ae81..96f3ea7 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailGet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/EmailGet.scala
@@ -28,6 +28,7 @@ import eu.timepit.refined.types.string.NonEmptyString
import org.apache.james.jmap.mail.Email.UnparsedEmailId
import org.apache.james.jmap.mail.EmailGetRequest.MaxBodyValueBytes
import org.apache.james.jmap.mail.EmailHeaders.SPECIFIC_HEADER_PREFIX
+import org.apache.james.jmap.method.WithAccountId
import org.apache.james.jmap.model.State.State
import org.apache.james.jmap.model.{AccountId, Properties}
import org.apache.james.mime4j.dom.Message
@@ -74,7 +75,7 @@ case class EmailGetRequest(accountId: AccountId,
fetchHTMLBodyValues: Option[FetchHTMLBodyValues],
maxBodyValueBytes: Option[MaxBodyValueBytes],
properties: Option[Properties],
- bodyProperties: Option[Properties])
+ bodyProperties: Option[Properties]) extends WithAccountId
case class EmailNotFound(value: Set[UnparsedEmailId]) {
def merge(other: EmailNotFound): EmailNotFound = EmailNotFound(this.value ++ other.value)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala
index ecc4663..0dbae7e 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala
@@ -37,7 +37,6 @@ import org.apache.james.jmap.routes.ProcessingContext
import org.apache.james.mailbox.MailboxSession
import org.apache.james.mailbox.model.MessageId
import org.apache.james.metrics.api.MetricFactory
-import org.reactivestreams.Publisher
import org.slf4j.{Logger, LoggerFactory}
import play.api.libs.json.{JsError, JsObject, JsSuccess}
import reactor.core.scala.publisher.{SFlux, SMono}
@@ -83,20 +82,19 @@ class EmailGetMethod @Inject() (readerFactory: EmailViewReaderFactory,
messageIdFactory: MessageId.Factory,
zoneIdProvider: ZoneIdProvider,
previewFactory: Preview.Factory,
- metricFactory: MetricFactory,
- sessionSupplier: SessionSupplier) extends Method {
+ val metricFactory: MetricFactory,
+ val sessionSupplier: SessionSupplier) extends MethodRequiringAccountId[EmailGetRequest] {
override val methodName = MethodName("Email/get")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
- override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, sessionSupplier: SessionSupplier): Publisher[(Invocation, ProcessingContext)] =
- metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
- asEmailGetRequest(invocation.arguments)
- .flatMap(computeResponseInvocation(_, invocation, mailboxSession))
- .onErrorResume({
- case e: IllegalArgumentException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId))
- case e: Throwable => SMono.raiseError(e)
- })
- .map(invocationResult => (invocationResult, processingContext)))
+ override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: EmailGetRequest): SMono[(Invocation, ProcessingContext)] = {
+ computeResponseInvocation(request, invocation, mailboxSession).onErrorResume({
+ case e: IllegalArgumentException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId))
+ case e: Throwable => SMono.raiseError(e)
+ }).map(invocationResult => (invocationResult, processingContext))
+ }
+
+ override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[EmailGetRequest] = asEmailGetRequest(invocation.arguments)
private def computeResponseInvocation(request: EmailGetRequest, invocation: Invocation, mailboxSession: MailboxSession): SMono[Invocation] =
validateProperties(request)
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 01/08: JAMES-3387 require accountId to be one of
the accounts of the authenticated user
Posted by rc...@apache.org.
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 264f73da547e952c7eba942494acbbb0dcd50dbf
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Wed Sep 23 15:52:34 2020 +0200
JAMES-3387 require accountId to be one of the accounts of the authenticated user
and validate it for mailbox/set
---
.../contract/MailboxSetMethodContract.scala | 47 ++++++++++++++++++++++
.../org/apache/james/jmap/mail/MailboxSet.scala | 4 +-
.../apache/james/jmap/method/CoreEchoMethod.scala | 1 +
.../apache/james/jmap/method/EmailGetMethod.scala | 6 ++-
.../james/jmap/method/EmailQueryMethod.scala | 4 +-
.../james/jmap/method/MailboxGetMethod.scala | 4 +-
.../james/jmap/method/MailboxQueryMethod.scala | 4 +-
.../james/jmap/method/MailboxSetMethod.scala | 22 +++++-----
.../org/apache/james/jmap/method/Method.scala | 40 +++++++++++++++++-
.../jmap/method/VacationResponseGetMethod.scala | 1 +
.../jmap/method/VacationResponseSetMethod.scala | 1 +
.../apache/james/jmap/routes/JMAPApiRoutes.scala | 10 +++--
.../james/jmap/method/CoreEchoMethodTest.scala | 3 +-
.../james/jmap/routes/JMAPApiRoutesTest.scala | 10 ++---
14 files changed, 127 insertions(+), 30 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/MailboxSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
index 4434d3f..106194c 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
@@ -62,6 +62,53 @@ trait MailboxSetMethodContract {
def errorInvalidMailboxIdMessage(value: String): String
@Test
+ def mailboxSetShouldFailWhenWrongAccountId(server: GuiceJamesServer): Unit = {
+ val request =
+ """
+ |{
+ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ],
+ | "methodCalls": [
+ | [
+ | "Mailbox/set",
+ | {
+ | "accountId": "unknownAccountId",
+ | "create": {
+ | "C42": {
+ | "name": "myMailbox"
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}
+ |""".stripMargin
+
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response).isEqualTo(
+ """{
+ | "sessionState": "75128aab4b1b",
+ | "methodResponses": [
+ | ["error", {
+ | "type": "accountNotFound"
+ | }, "c1"]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
def updateShouldFailWhenModifyingRole(server: GuiceJamesServer): Unit = {
val mailboxId: MailboxId = server.getProbe(classOf[MailboxProbeImpl])
.createMailbox(MailboxPath.forUser(BOB, "INBOX"))
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala
index 7cf5355..cbd034e 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxSet.scala
@@ -30,7 +30,7 @@ import org.apache.james.jmap.json.MailboxSerializer
import org.apache.james.jmap.mail.MailboxName.MailboxName
import org.apache.james.jmap.mail.MailboxPatchObject.MailboxPatchObjectKey
import org.apache.james.jmap.mail.MailboxSetRequest.{MailboxCreationId, UnparsedMailboxId, UnparsedMailboxIdConstraint}
-import org.apache.james.jmap.method.MailboxCreationParseException
+import org.apache.james.jmap.method.{MailboxCreationParseException, WithAccountId}
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.SetError.{SetErrorDescription, SetErrorType}
import org.apache.james.jmap.model.State.State
@@ -45,7 +45,7 @@ case class MailboxSetRequest(accountId: AccountId,
create: Option[Map[MailboxCreationId, JsObject]],
update: Option[Map[UnparsedMailboxId, MailboxPatchObject]],
destroy: Option[Seq[UnparsedMailboxId]],
- onDestroyRemoveEmails: Option[RemoveEmailsOnDestroy])
+ onDestroyRemoveEmails: Option[RemoveEmailsOnDestroy]) extends WithAccountId
object MailboxSetRequest {
type UnparsedMailboxIdConstraint = NonEmpty
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
index a7fd705..c956a81 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
@@ -20,6 +20,7 @@ package org.apache.james.jmap.method
import eu.timepit.refined.auto._
+import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.DefaultCapabilities.CORE_CAPABILITY
import org.apache.james.jmap.model.Invocation.MethodName
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala
index 361a49f..ecc4663 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala
@@ -24,6 +24,7 @@ import eu.timepit.refined.auto._
import eu.timepit.refined.types.string.NonEmptyString
import javax.inject.Inject
import org.apache.james.jmap.api.model.Preview
+import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.json.{EmailGetSerializer, ResponseSerializer}
import org.apache.james.jmap.mail.Email.UnparsedEmailId
import org.apache.james.jmap.mail.{Email, EmailBodyPart, EmailGetRequest, EmailGetResponse, EmailIds, EmailNotFound, EmailView, EmailViewReaderFactory, SpecificHeaderRequest}
@@ -82,11 +83,12 @@ class EmailGetMethod @Inject() (readerFactory: EmailViewReaderFactory,
messageIdFactory: MessageId.Factory,
zoneIdProvider: ZoneIdProvider,
previewFactory: Preview.Factory,
- metricFactory: MetricFactory) extends Method {
+ metricFactory: MetricFactory,
+ sessionSupplier: SessionSupplier) extends Method {
override val methodName = MethodName("Email/get")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
- override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] =
+ override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, sessionSupplier: SessionSupplier): Publisher[(Invocation, ProcessingContext)] =
metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
asEmailGetRequest(invocation.arguments)
.flatMap(computeResponseInvocation(_, invocation, mailboxSession))
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
index 4feb97e..0cf6810 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
@@ -21,6 +21,7 @@ package org.apache.james.jmap.method
import cats.implicits._
import eu.timepit.refined.auto._
import javax.inject.Inject
+import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.json.{EmailQuerySerializer, ResponseSerializer}
import org.apache.james.jmap.mail.{Comparator, EmailQueryRequest, EmailQueryResponse, UnsupportedFilterException, UnsupportedRequestParameterException, UnsupportedSortException}
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
@@ -44,7 +45,8 @@ import scala.jdk.CollectionConverters._
class EmailQueryMethod @Inject() (serializer: EmailQuerySerializer,
mailboxManager: MailboxManager,
- metricFactory: MetricFactory) extends Method {
+ metricFactory: MetricFactory,
+ sessionSupplier: SessionSupplier) extends Method {
override val methodName: MethodName = MethodName("Email/query")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
index e1a6a57..6e660c8 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
@@ -21,6 +21,7 @@ package org.apache.james.jmap.method
import eu.timepit.refined.auto._
import javax.inject.Inject
+import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.json.{MailboxSerializer, ResponseSerializer}
import org.apache.james.jmap.mail.MailboxSetRequest.UnparsedMailboxId
import org.apache.james.jmap.mail._
@@ -49,7 +50,8 @@ class MailboxGetMethod @Inject() (serializer: MailboxSerializer,
quotaFactory : QuotaLoaderWithPreloadedDefaultFactory,
mailboxIdFactory: MailboxId.Factory,
mailboxFactory: MailboxFactory,
- metricFactory: MetricFactory) extends Method {
+ metricFactory: MetricFactory,
+ val sessionSupplier: SessionSupplier) extends Method {
override val methodName: MethodName = MethodName("Mailbox/get")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala
index 46e9417..268dc1d 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala
@@ -20,6 +20,7 @@ package org.apache.james.jmap.method
import eu.timepit.refined.auto._
import javax.inject.Inject
+import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.json.{MailboxQuerySerializer, ResponseSerializer}
import org.apache.james.jmap.mail.{MailboxQueryRequest, MailboxQueryResponse}
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
@@ -35,7 +36,8 @@ import reactor.core.scala.publisher.{SFlux, SMono}
import reactor.core.scheduler.Schedulers
class MailboxQueryMethod @Inject()(systemMailboxesProvider: SystemMailboxesProvider,
- metricFactory: MetricFactory) extends Method {
+ metricFactory: MetricFactory,
+ val sessionSupplier: SessionSupplier) extends Method {
override val methodName = MethodName("Mailbox/query")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
index 465b22c..dc772c5 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
@@ -21,6 +21,7 @@ package org.apache.james.jmap.method
import eu.timepit.refined.auto._
import javax.inject.Inject
+import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.json.{MailboxSerializer, ResponseSerializer}
import org.apache.james.jmap.mail.MailboxSetRequest.{MailboxCreationId, UnparsedMailboxId}
import org.apache.james.jmap.mail.{InvalidPatchException, InvalidPropertyException, InvalidUpdateException, IsSubscribed, MailboxCreationRequest, MailboxCreationResponse, MailboxPatchObject, MailboxRights, MailboxSetError, MailboxSetRequest, MailboxSetResponse, MailboxUpdateResponse, NameUpdate, ParentIdUpdate, RemoveEmailsOnDestroy, ServerSetPropertyException, SortOrder, TotalEmails, TotalThreads, UnreadEmails, UnreadThreads, UnsupportedPropertyUpdatedException, ValidatedMailboxPatchObject}
@@ -147,21 +148,18 @@ class MailboxSetMethod @Inject()(serializer: MailboxSerializer,
subscriptionManager: SubscriptionManager,
mailboxIdFactory: MailboxId.Factory,
quotaFactory : QuotaLoaderWithPreloadedDefaultFactory,
- metricFactory: MetricFactory) extends Method {
+ val metricFactory: MetricFactory,
+ val sessionSupplier: SessionSupplier) extends MethodRequiringAccountId[MailboxSetRequest] {
override val methodName: MethodName = MethodName("Mailbox/set")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
- override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = {
- metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
- asMailboxSetRequest(invocation.arguments)
- .flatMap(mailboxSetRequest => {
- for {
- creationResultsWithUpdatedProcessingContext <- createMailboxes(mailboxSession, mailboxSetRequest, processingContext)
- deletionResults <- deleteMailboxes(mailboxSession, mailboxSetRequest, processingContext)
- updateResults <- updateMailboxes(mailboxSession, mailboxSetRequest, processingContext, capabilities)
- } yield (createResponse(capabilities, invocation, mailboxSetRequest, creationResultsWithUpdatedProcessingContext._1, deletionResults, updateResults), creationResultsWithUpdatedProcessingContext._2)
- }))
- }
+ override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: MailboxSetRequest): SMono[(Invocation, ProcessingContext)] = for {
+ creationResultsWithUpdatedProcessingContext <- createMailboxes(mailboxSession, request, processingContext)
+ deletionResults <- deleteMailboxes(mailboxSession, request, processingContext)
+ updateResults <- updateMailboxes(mailboxSession, request, processingContext, capabilities)
+ } yield (createResponse(capabilities, invocation, request, creationResultsWithUpdatedProcessingContext._1, deletionResults, updateResults), creationResultsWithUpdatedProcessingContext._2)
+
+ override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[MailboxSetRequest] = asMailboxSetRequest(invocation.arguments)
private def updateMailboxes(mailboxSession: MailboxSession,
mailboxSetRequest: MailboxSetRequest,
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
index e6dde8c..f4a40a5 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
@@ -19,12 +19,16 @@
package org.apache.james.jmap.method
+import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.Invocation.MethodName
-import org.apache.james.jmap.model.{Capabilities, Invocation}
+import org.apache.james.jmap.model.{AccountId, Capabilities, ErrorCode, Invocation, Session}
import org.apache.james.jmap.routes.ProcessingContext
import org.apache.james.mailbox.MailboxSession
+import org.apache.james.mailbox.exception.MailboxNotFoundException
+import org.apache.james.metrics.api.MetricFactory
import org.reactivestreams.Publisher
+import reactor.core.scala.publisher.SMono
trait Method {
val JMAP_RFC8621_PREFIX: String = "JMAP-RFC8621-"
@@ -36,3 +40,37 @@ trait Method {
def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)]
}
+trait WithAccountId {
+ def accountId: AccountId
+}
+trait MethodRequiringAccountId[REQUEST <: WithAccountId] extends Method {
+ def metricFactory: MetricFactory
+ def sessionSupplier: SessionSupplier
+
+ override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = {
+ val result = (for {
+ request <- getRequest(mailboxSession, invocation)
+ response <- validateAccountId(request.accountId, mailboxSession, sessionSupplier, invocation).flatMap{
+ case Right(_) => doProcess(capabilities, invocation, mailboxSession, processingContext, request)
+ case Left(invocation) => SMono.just((invocation, processingContext))
+ }
+ } yield response)
+ .onErrorResume {
+ case e: IllegalArgumentException => SMono.just((Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId), processingContext))
+ case e: Throwable => SMono.raiseError(e)
+ }
+
+ metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value, result)
+ }
+
+ private def validateAccountId(accountId: AccountId, mailboxSession: MailboxSession, sessionSupplier: SessionSupplier, invocation: Invocation): SMono[Either[Invocation, Session]] = {
+ sessionSupplier.generate(mailboxSession.getUser)
+ .filter(session => session.accounts.map(_.accountId).contains(accountId))
+ .map(session => Right[Invocation, Session](session).asInstanceOf[Either[Invocation, Session]])
+ .switchIfEmpty(SMono.just(Left[Invocation, Session](Invocation.error(ErrorCode.AccountNotFound, invocation.methodCallId))))
+ }
+
+ def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: REQUEST): SMono[(Invocation, ProcessingContext)]
+
+ def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[REQUEST]
+}
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala
index 4652add..a3c3e8b 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala
@@ -22,6 +22,7 @@ package org.apache.james.jmap.method
import eu.timepit.refined.auto._
import javax.inject.Inject
import org.apache.james.jmap.api.vacation.{VacationRepository, AccountId => JavaAccountId}
+import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.json.{ResponseSerializer, VacationSerializer}
import org.apache.james.jmap.mail.VacationResponse.UnparsedVacationResponseId
import org.apache.james.jmap.mail.{VacationResponse, VacationResponseGetRequest, VacationResponseGetResponse, VacationResponseNotFound}
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala
index bd34d88..4b24625 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala
@@ -22,6 +22,7 @@ package org.apache.james.jmap.method
import eu.timepit.refined.auto._
import javax.inject.Inject
import org.apache.james.jmap.api.vacation.{AccountId, VacationPatch, VacationRepository}
+import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.json.{ResponseSerializer, VacationSerializer}
import org.apache.james.jmap.method.VacationResponseSetMethod.VACATION_RESPONSE_PATCH_OBJECT_KEY
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
index 6833db8..ab870e1 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
@@ -33,7 +33,7 @@ import org.apache.james.jmap.HttpConstants.JSON_CONTENT_TYPE
import org.apache.james.jmap.JMAPUrls.JMAP
import org.apache.james.jmap.exceptions.UnauthorizedException
import org.apache.james.jmap.http.rfc8621.InjectionKeys
-import org.apache.james.jmap.http.{Authenticator, MailboxesProvisioner, UserProvisioning}
+import org.apache.james.jmap.http.{Authenticator, MailboxesProvisioner, SessionSupplier, UserProvisioning}
import org.apache.james.jmap.json.ResponseSerializer
import org.apache.james.jmap.method.Method
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
@@ -58,7 +58,8 @@ object JMAPApiRoutes {
class JMAPApiRoutes (val authenticator: Authenticator,
userProvisioner: UserProvisioning,
mailboxesProvisioner: MailboxesProvisioner,
- methods: Set[Method]) extends JMAPRoutes {
+ methods: Set[Method],
+ sessionSupplier: SessionSupplier) extends JMAPRoutes {
private val methodsByName: Map[MethodName, Method] = methods.map(method => method.methodName -> method).toMap
@@ -66,8 +67,9 @@ class JMAPApiRoutes (val authenticator: Authenticator,
def this(@Named(InjectionKeys.RFC_8621) authenticator: Authenticator,
userProvisioner: UserProvisioning,
mailboxesProvisioner: MailboxesProvisioner,
- javaMethods: java.util.Set[Method]) {
- this(authenticator, userProvisioner, mailboxesProvisioner, javaMethods.asScala.toSet)
+ javaMethods: java.util.Set[Method],
+ sessionSupplier: SessionSupplier) {
+ this(authenticator, userProvisioner, mailboxesProvisioner, javaMethods.asScala.toSet, sessionSupplier)
}
override def routes(): stream.Stream[JMAPRoute] = Stream.of(
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
index ff24174..77da9e6 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
@@ -18,9 +18,10 @@
* ***************************************************************/
package org.apache.james.jmap.method
+import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.json.Fixture.{invocation1, invocation2}
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
-import org.apache.james.jmap.model.{CapabilityIdentifier, Invocation}
+import org.apache.james.jmap.model.{CapabilityIdentifier, Invocation, JmapRfc8621Configuration}
import org.apache.james.jmap.routes.ProcessingContext
import org.apache.james.mailbox.MailboxSession
import org.mockito.Mockito.mock
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
index 069c3d6..7e5298f 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
@@ -36,12 +36,12 @@ import org.apache.james.dnsservice.api.DNSService
import org.apache.james.domainlist.memory.MemoryDomainList
import org.apache.james.jmap.JMAPUrls.JMAP
import org.apache.james.jmap._
-import org.apache.james.jmap.http.{Authenticator, BasicAuthenticationStrategy, MailboxesProvisioner, UserProvisioning}
+import org.apache.james.jmap.http.{Authenticator, BasicAuthenticationStrategy, MailboxesProvisioner, SessionSupplier, UserProvisioning}
import org.apache.james.jmap.method.{CoreEchoMethod, Method}
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.DefaultCapabilities.CORE_CAPABILITY
import org.apache.james.jmap.model.Invocation.MethodName
-import org.apache.james.jmap.model.{Capabilities, RequestLevelErrorType}
+import org.apache.james.jmap.model.{Capabilities, JmapRfc8621Configuration, RequestLevelErrorType}
import org.apache.james.jmap.routes.JMAPApiRoutesTest._
import org.apache.james.mailbox.extension.PreDeletionHook
import org.apache.james.mailbox.inmemory.{InMemoryMailboxManager, MemoryMailboxManagerProvider}
@@ -76,10 +76,10 @@ object JMAPApiRoutesTest {
private val userProvisionner: UserProvisioning = new UserProvisioning(usersRepository, new RecordingMetricFactory)
private val subscriptionManager: StoreSubscriptionManager = new StoreSubscriptionManager(mailboxManager.getMapperFactory)
private val mailboxesProvisioner: MailboxesProvisioner = new MailboxesProvisioner(mailboxManager, subscriptionManager, new RecordingMetricFactory)
-
+ private val sessionSupplier: SessionSupplier = new SessionSupplier(JmapRfc8621Configuration(JmapRfc8621Configuration.LOCALHOST_URL_PREFIX))
private val JMAP_METHODS: Set[Method] = Set(new CoreEchoMethod)
- private val JMAP_API_ROUTE: JMAPApiRoutes = new JMAPApiRoutes(AUTHENTICATOR, userProvisionner, mailboxesProvisioner, JMAP_METHODS)
+ private val JMAP_API_ROUTE: JMAPApiRoutes = new JMAPApiRoutes(AUTHENTICATOR, userProvisionner, mailboxesProvisioner, JMAP_METHODS, sessionSupplier)
private val ROUTES_HANDLER: ImmutableSet[JMAPRoutesHandler] = ImmutableSet.of(new JMAPRoutesHandler(Version.RFC8621, JMAP_API_ROUTE))
private val userBase64String: String = Base64.getEncoder.encodeToString("user1:password".getBytes(StandardCharsets.UTF_8))
@@ -443,7 +443,7 @@ class JMAPApiRoutesTest extends AnyFlatSpec with BeforeAndAfter with Matchers {
when(mockCoreEchoMethod.requiredCapabilities).thenReturn(Capabilities(CORE_CAPABILITY))
val methods: Set[Method] = Set(mockCoreEchoMethod)
- val apiRoute: JMAPApiRoutes = new JMAPApiRoutes(AUTHENTICATOR, userProvisionner, mailboxesProvisioner, methods)
+ val apiRoute: JMAPApiRoutes = new JMAPApiRoutes(AUTHENTICATOR, userProvisionner, mailboxesProvisioner, methods, sessionSupplier)
val routesHandler: ImmutableSet[JMAPRoutesHandler] = ImmutableSet.of(new JMAPRoutesHandler(Version.RFC8621, apiRoute))
val versionParser: VersionParser = new VersionParser(SUPPORTED_VERSIONS)
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 03/08: JAMES-3387 validate accountId for email/query
Posted by rc...@apache.org.
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 4b789e36a777b8c9c10ea004a7ae8666a2368eef
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Wed Sep 23 16:35:14 2020 +0200
JAMES-3387 validate accountId for email/query
---
.../contract/EmailQueryMethodContract.scala | 243 +++++++--------------
.../org/apache/james/jmap/mail/EmailQuery.scala | 3 +-
.../james/jmap/method/EmailQueryMethod.scala | 56 ++---
3 files changed, 114 insertions(+), 188 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 dcd7a7e..4cfac72 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
@@ -66,7 +66,6 @@ object EmailQueryMethodContract {
}
}
-
trait EmailQueryMethodContract {
private lazy val slowPacedPollInterval = ONE_HUNDRED_MILLISECONDS
@@ -92,17 +91,63 @@ trait EmailQueryMethodContract {
}
@Test
+ def emailQueryShouldFailWhenWrongAccountId(server: GuiceJamesServer): Unit = {
+ val request =
+ s"""{
+ | "using": [
+ | "urn:ietf:params:jmap:core",
+ | "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [[
+ | "Email/query",
+ | {
+ | "accountId": "unknownAccountId"
+ | },
+ | "c1"]]
+ |}""".stripMargin
+
+ awaitAtMostTenSeconds.untilAsserted { () =>
+ 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).isEqualTo(
+ s"""{
+ | "sessionState": "75128aab4b1b",
+ | "methodResponses": [[
+ | "error",
+ | {
+ | "type": "accountNotFound"
+ | },
+ | "c1"
+ | ]]
+ |}""".stripMargin)
+ }
+ }
+
+ private def buildTestMessage = {
+ Message.Builder
+ .of
+ .setSubject("test")
+ .setBody("testmail", StandardCharsets.UTF_8)
+ .build
+ }
+
+ @Test
def hasAttachmentShouldKeepMessageWithAttachmentWhenTrue(server: GuiceJamesServer): Unit = {
val mailboxProbe = server.getProbe(classOf[MailboxProbeImpl])
mailboxProbe.createMailbox(MailboxPath.inbox(BOB))
val messageId1: MessageId = mailboxProbe
.appendMessage(BOB.asString, MailboxPath.inbox(BOB),
AppendCommand.from(
- Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build))
+ buildTestMessage))
.getMessageId
val messageId2: MessageId = mailboxProbe
@@ -552,11 +597,7 @@ trait EmailQueryMethodContract {
val messageId1: MessageId = mailboxProbe
.appendMessage(BOB.asString, MailboxPath.inbox(BOB),
AppendCommand.from(
- Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build))
+ buildTestMessage))
.getMessageId
val messageId2: MessageId = mailboxProbe
@@ -621,11 +662,7 @@ trait EmailQueryMethodContract {
.appendMessage(BOB.asString, MailboxPath.inbox(BOB),
AppendCommand.builder()
.withInternalDate(beforeRequestDate)
- .build(Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build))
+ .build(buildTestMessage))
.getMessageId
val messageId2: MessageId = mailboxProbe
@@ -638,11 +675,7 @@ trait EmailQueryMethodContract {
.appendMessage(BOB.asString, MailboxPath.inbox(BOB),
AppendCommand.builder()
.withInternalDate(afterRequestDate)
- .build(Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build))
+ .build(buildTestMessage))
.getMessageId
val messageId4: MessageId = mailboxProbe
@@ -702,11 +735,7 @@ trait EmailQueryMethodContract {
@Test
def shouldListMailsInAllUserMailboxes(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(otherMailboxPath)
@@ -764,11 +793,7 @@ trait EmailQueryMethodContract {
@Test
def shouldNotListMailsFromOtherUserMailboxes(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(ANDRE, "other")
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(otherMailboxPath)
@@ -826,11 +851,7 @@ trait EmailQueryMethodContract {
@Test
def listMailsShouldBeSortedByDescendingOrderOfArrivalByDefault(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(otherMailboxPath)
@@ -1165,11 +1186,7 @@ trait EmailQueryMethodContract {
@Test
def listMailsShouldBeIdempotent(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(otherMailboxPath)
@@ -1224,11 +1241,7 @@ trait EmailQueryMethodContract {
@Test
def listMailsShouldBeSortedInAscendingOrderByDefault(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(otherMailboxPath)
@@ -1282,11 +1295,7 @@ trait EmailQueryMethodContract {
@Test
def listMailsShouldBeSortedInAscendingOrder(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
val now: Instant = Instant.now()
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
@@ -1341,11 +1350,7 @@ trait EmailQueryMethodContract {
@Test
def listMailsShouldBeSortedInDescendingOrder(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
val now: Instant = Instant.now()
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
@@ -1448,11 +1453,7 @@ trait EmailQueryMethodContract {
@Test
def shouldListMailsInASpecificUserMailboxes(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
val otherMailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(otherMailboxPath)
@@ -1823,11 +1824,7 @@ trait EmailQueryMethodContract {
@Test
def shouldReturnIllegalArgumentErrorForAnUnknownSpecificUserMailboxes(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
val otherMailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(otherMailboxPath)
@@ -2114,11 +2111,7 @@ trait EmailQueryMethodContract {
@Test
def shouldListMailsNotInASpecificUserMailboxes(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
val otherMailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(otherMailboxPath)
@@ -2166,11 +2159,7 @@ trait EmailQueryMethodContract {
@Test
def shouldListMailsNotInZeroMailboxes(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(otherMailboxPath)
@@ -2217,11 +2206,7 @@ trait EmailQueryMethodContract {
@Test
def listMailsInAFirstMailboxAndNotSomeOtherMailboxShouldReturnMailsInFirstMailbox(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
val inbox = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
val otherMailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(otherMailboxPath)
@@ -2270,11 +2255,7 @@ trait EmailQueryMethodContract {
@Test
def listMailsInAFirstMailboxAndNotInTheSameMailboxShouldReturnEmptyResult(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
val inbox = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(otherMailboxPath)
@@ -2323,11 +2304,7 @@ trait EmailQueryMethodContract {
@Test
def shouldListMailsReceivedBeforeADate(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(inbox(BOB))
val requestDate = ZonedDateTime.now().minusDays(1)
val messageId1 = sendMessageToBobInbox(server, message, Date.from(requestDate.toInstant))
@@ -2375,11 +2352,7 @@ trait EmailQueryMethodContract {
}
@Test
def shouldListMailsReceivedBeforeADateInclusively(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(inbox(BOB))
val requestDate = ZonedDateTime.now().minusDays(1)
val messageId1 = sendMessageToBobInbox(server, message, Date.from(requestDate.toInstant))
@@ -2427,11 +2400,7 @@ trait EmailQueryMethodContract {
@Test
def shouldListMailsReceivedAfterADate(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(inbox(BOB))
val receivedDateMessage1 = ZonedDateTime.now().minusDays(1)
sendMessageToBobInbox(server, message, Date.from(receivedDateMessage1.toInstant))
@@ -2480,11 +2449,7 @@ trait EmailQueryMethodContract {
@Test
def listMailsReceivedAfterADateShouldBeExclusive(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val receivedDateMessage1 = ZonedDateTime.now().minusDays(1)
sendMessageToBobInbox(server, message, Date.from(receivedDateMessage1.toInstant))
@@ -2532,11 +2497,7 @@ trait EmailQueryMethodContract {
@Test
def shouldLimitResultByTheLimitProvidedByTheClient(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
val requestDate = Date.from(ZonedDateTime.now().minusDays(1).toInstant)
@@ -2640,11 +2601,7 @@ trait EmailQueryMethodContract {
@Test
def theLimitshouldBeEnforcedByTheServerIfNoLimitProvidedByTheClient(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val allMessages = (0 to 300).toList.foldLeft(List[MessageId](), ZonedDateTime.now().minusYears(1))((acc, _) => {
@@ -2694,11 +2651,7 @@ trait EmailQueryMethodContract {
@Test
def theLimitshouldBeEnforcedByTheServerIfAGreaterLimitProvidedByTheClient(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val allMessages = (0 to 300).toList.foldLeft(List[MessageId](), ZonedDateTime.now().minusYears(1))((acc, _) => {
@@ -2749,11 +2702,7 @@ trait EmailQueryMethodContract {
@Test
def resultsShouldStartAtThePositionProvidedByTheClient(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val messageId1: MessageId = server.getProbe(classOf[MailboxProbeImpl])
.appendMessage(BOB.asString, MailboxPath.inbox(BOB), AppendCommand.builder()
@@ -2814,11 +2763,7 @@ trait EmailQueryMethodContract {
@Test
def zeroPositionQueryShouldReturnItemsFromTheStart(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val messageId1: MessageId = server.getProbe(classOf[MailboxProbeImpl])
.appendMessage(BOB.asString, MailboxPath.inbox(BOB), AppendCommand.builder()
@@ -2879,11 +2824,7 @@ trait EmailQueryMethodContract {
@Test
def resultsShouldBeEmptyWithoutErrorWhenThePositionProvidedByTheClientIsGreaterThanTheNumberOfResults(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val otherMailboxPath = MailboxPath.forUser(BOB, "other")
val requestDate = Date.from(ZonedDateTime.now().minusDays(1).toInstant)
@@ -2942,11 +2883,7 @@ trait EmailQueryMethodContract {
@Test
def shouldReturnAnIllegalArgumentExceptionIfThePositionIsNegative(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val requestDate = Date.from(ZonedDateTime.now().minusDays(1).toInstant)
sendMessageToBobInbox(server, message, Date.from(requestDate.toInstant))
@@ -3005,11 +2942,7 @@ trait EmailQueryMethodContract {
@ParameterizedTest
@MethodSource(value = Array("jmapSystemKeywords"))
def listMailsBySystemKeywordShouldReturnOnlyMailsWithThisSystemKeyword(keywordFlag: Flags, keywordName: String, server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val messageId = server.getProbe(classOf[MailboxProbeImpl])
.appendMessage(BOB.asString, MailboxPath.inbox(BOB), AppendCommand.builder().withFlags(keywordFlag).build(message))
@@ -3289,11 +3222,7 @@ trait EmailQueryMethodContract {
@Test
def listMailsByCustomKeywordShouldReturnOnlyMailsWithThisCustomKeyword(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
val messageId = server.getProbe(classOf[MailboxProbeImpl])
.appendMessage(BOB.asString, MailboxPath.inbox(BOB), AppendCommand.builder().withFlags(new Flags("custom")).build(message))
@@ -3340,11 +3269,7 @@ trait EmailQueryMethodContract {
@ParameterizedTest
@MethodSource(value = Array("jmapSystemKeywords"))
def listMailsNotBySystemKeywordShouldReturnOnlyMailsWithoutThisSystemKeyword(keywordFlag: Flags, keywordName: String, server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
server.getProbe(classOf[MailboxProbeImpl])
.appendMessage(BOB.asString, MailboxPath.inbox(BOB), AppendCommand.builder().withFlags(keywordFlag).build(message))
@@ -3390,11 +3315,7 @@ trait EmailQueryMethodContract {
@Test
def listMailsNotByCustomKeywordShouldReturnOnlyMailsWithoutThisCustomKeyword(server: GuiceJamesServer): Unit = {
- val message: Message = Message.Builder
- .of
- .setSubject("test")
- .setBody("testmail", StandardCharsets.UTF_8)
- .build
+ val message: Message = buildTestMessage
server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB))
server.getProbe(classOf[MailboxProbeImpl])
.appendMessage(BOB.asString, MailboxPath.inbox(BOB), AppendCommand.builder().withFlags(new Flags("custom")).build(message))
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 e91530b..8ca075a 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
@@ -20,6 +20,7 @@
package org.apache.james.jmap.mail
import org.apache.james.jmap.mail.Email.Size
import org.apache.james.jmap.mail.IsAscending.{ASCENDING, DESCENDING}
+import org.apache.james.jmap.method.WithAccountId
import org.apache.james.jmap.model.Limit.Limit
import org.apache.james.jmap.model.Position.Position
import org.apache.james.jmap.model.{AccountId, CanCalculateChanges, Keyword, LimitUnparsed, PositionUnparsed, QueryState, UTCDate}
@@ -67,7 +68,7 @@ case class EmailQueryRequest(accountId: AccountId,
comparator: Option[Set[Comparator]],
collapseThreads: Option[CollapseThreads],
anchor: Option[Anchor],
- anchorOffset: Option[AnchorOffset])
+ anchorOffset: Option[AnchorOffset]) extends WithAccountId
sealed trait SortProperty {
def toSortClause: Either[UnsupportedSortException, SortClause]
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
index 0cf6810..4787cb3 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
@@ -37,7 +37,6 @@ import org.apache.james.mailbox.exception.MailboxNotFoundException
import org.apache.james.mailbox.model.MultimailboxesSearchQuery
import org.apache.james.mailbox.{MailboxManager, MailboxSession}
import org.apache.james.metrics.api.MetricFactory
-import org.reactivestreams.Publisher
import play.api.libs.json.{JsError, JsSuccess}
import reactor.core.scala.publisher.{SFlux, SMono}
@@ -45,35 +44,38 @@ import scala.jdk.CollectionConverters._
class EmailQueryMethod @Inject() (serializer: EmailQuerySerializer,
mailboxManager: MailboxManager,
- metricFactory: MetricFactory,
- sessionSupplier: SessionSupplier) extends Method {
+ val metricFactory: MetricFactory,
+ val sessionSupplier: SessionSupplier) extends MethodRequiringAccountId[EmailQueryRequest] {
override val methodName: MethodName = MethodName("Email/query")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
- override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] =
- metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
- asEmailQueryRequest(invocation.arguments)
- .flatMap(processRequest(mailboxSession, invocation, _, capabilities))
- .onErrorResume {
- case e: UnsupportedRequestParameterException => SMono.just(Invocation.error(
- ErrorCode.InvalidArguments,
- s"The following parameter ${e.unsupportedParam} is syntactically valid, but is not supported by the server.",
- invocation.methodCallId))
- case e: UnsupportedSortException => SMono.just(Invocation.error(
- ErrorCode.UnsupportedSort,
- s"The sort ${e.unsupportedSort} is syntactically valid, but it includes a property the server does not support sorting on or a collation method it does not recognise.",
- invocation.methodCallId))
- case e: UnsupportedFilterException => SMono.just(Invocation.error(
- ErrorCode.UnsupportedFilter,
- s"The filter ${e.unsupportedFilter} 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.",
- invocation.methodCallId))
- case e: IllegalArgumentException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId))
- case e: MailboxNotFoundException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId))
- case e: Throwable => SMono.raiseError(e)
- }
- .map(invocationResult => (invocationResult, processingContext)))
+ override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: EmailQueryRequest): SMono[(Invocation, ProcessingContext)] = {
+ processRequest(mailboxSession, invocation, request, capabilities)
+ .onErrorResume {
+ case e: UnsupportedRequestParameterException => SMono.just(Invocation.error(
+ ErrorCode.InvalidArguments,
+ s"The following parameter ${e.unsupportedParam} is syntactically valid, but is not supported by the server.",
+ invocation.methodCallId))
+ case e: UnsupportedSortException => SMono.just(Invocation.error(
+ ErrorCode.UnsupportedSort,
+ s"The sort ${e.unsupportedSort} is syntactically valid, but it includes a property the server does not support sorting on or a collation method it does not recognise.",
+ invocation.methodCallId))
+ case e: UnsupportedFilterException => SMono.just(Invocation.error(
+ ErrorCode.UnsupportedFilter,
+ s"The filter ${e.unsupportedFilter} 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.",
+ invocation.methodCallId))
+ case e: IllegalArgumentException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId))
+ case e: MailboxNotFoundException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId))
+ case e: Throwable => SMono.raiseError(e)
+ }
+ .map(invocationResult => (invocationResult, processingContext))
+ }
+
- private def processRequest(mailboxSession: MailboxSession, invocation: Invocation, request: EmailQueryRequest, capabilities: Set[CapabilityIdentifier]): SMono[Invocation] = {
+ private def processRequest(mailboxSession: MailboxSession,
+ invocation: Invocation,
+ request: EmailQueryRequest,
+ capabilities: Set[CapabilityIdentifier]): SMono[Invocation] = {
searchQueryFromRequest(request, capabilities, mailboxSession) match {
case Left(error) => SMono.raiseError(error)
case Right(searchQuery) => for {
@@ -84,6 +86,8 @@ class EmailQueryMethod @Inject() (serializer: EmailQuerySerializer,
}
}
+ override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[EmailQueryRequest] = asEmailQueryRequest(invocation.arguments)
+
private def executeQuery(mailboxSession: MailboxSession, request: EmailQueryRequest, searchQuery: MultimailboxesSearchQuery, position: Position, limitToUse: Limit): SMono[EmailQueryResponse] = {
SFlux.fromPublisher(mailboxManager.search(searchQuery, mailboxSession, limitToUse))
.drop(position.value)
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 08/08: JAMES-3387 validate accountId for
vacationResponse/set
Posted by rc...@apache.org.
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 d124e2b21f76860a13686834ba5ce6864554c65d
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Thu Sep 24 15:14:14 2020 +0200
JAMES-3387 validate accountId for vacationResponse/set
---
.../VacationResponseSetMethodContract.scala | 50 ++++++++++++++++++++++
.../jmap/method/VacationResponseSetMethod.scala | 23 ++++------
.../james/jmap/vacation/VacationResponseSet.scala | 3 +-
3 files changed, 61 insertions(+), 15 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/VacationResponseSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseSetMethodContract.scala
index d2fc11e..a2a8c21 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseSetMethodContract.scala
@@ -45,6 +45,56 @@ trait VacationResponseSetMethodContract {
}
@Test
+ def vacationResponseSetShouldFailWhenWrongAccountId(server: GuiceJamesServer): Unit = {
+ val request =
+ s"""
+ |{
+ | "using": [ "urn:ietf:params:jmap:core",
+ | "urn:ietf:params:jmap:mail",
+ | "urn:ietf:params:jmap:vacationresponse" ],
+ | "methodCalls": [
+ | ["VacationResponse/set", {
+ | "accountId": "unknownAccountId",
+ | "update": {
+ | "singleton": {
+ | "isEnabled": true,
+ | "fromDate": "2014-10-30T14:12:00Z",
+ | "toDate": "2014-11-30T14:12:00Z",
+ | "subject": "I am in vacation",
+ | "textBody": "I'm currently enjoying life. Please disturb me later",
+ | "htmlBody": "I'm currently enjoying <b>life</b>. <br/>Please disturb me later"
+ | }
+ | }
+ | }, "c1"]
+ | ]
+ |}
+ |""".stripMargin
+
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response).isEqualTo(
+ """{
+ | "sessionState": "75128aab4b1b",
+ | "methodResponses": [
+ | ["error", {
+ | "type": "accountNotFound"
+ | }, "c1"]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
@Tag(CategoryTags.BASIC_FEATURE)
def updateShouldSucceed(): Unit = {
val request =
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala
index c3febb9..66e52e0 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala
@@ -30,12 +30,9 @@ import org.apache.james.jmap.model.DefaultCapabilities.{CORE_CAPABILITY, MAIL_CA
import org.apache.james.jmap.model.Invocation.{Arguments, MethodName}
import org.apache.james.jmap.model.SetError.SetErrorDescription
import org.apache.james.jmap.model.{Capabilities, Invocation, State}
-import org.apache.james.jmap.routes.ProcessingContext
import org.apache.james.jmap.vacation.{VacationResponseSetError, VacationResponseSetRequest, VacationResponseSetResponse, VacationResponseUpdateResponse}
import org.apache.james.mailbox.MailboxSession
import org.apache.james.metrics.api.MetricFactory
-import org.apache.james.util.date.ZonedDateTimeProvider
-import org.reactivestreams.Publisher
import play.api.libs.json.{JsError, JsObject, JsSuccess}
import reactor.core.scala.publisher.{SFlux, SMono}
@@ -73,22 +70,20 @@ object VacationResponseSetMethod {
val VACATION_RESPONSE_PATCH_OBJECT_KEY = "singleton"
}
-class VacationResponseSetMethod @Inject() (vacationRepository: VacationRepository,
- zonedDateTimeProvider: ZonedDateTimeProvider,
- metricFactory: MetricFactory) extends Method {
+class VacationResponseSetMethod @Inject()(vacationRepository: VacationRepository,
+ val metricFactory: MetricFactory,
+ val sessionSupplier: SessionSupplier) extends MethodRequiringAccountId[VacationResponseSetRequest] {
override val methodName: MethodName = MethodName("VacationResponse/set")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY, VACATION_RESPONSE_CAPABILITY)
- override def process(capabilities: Set[CapabilityIdentifier],
- invocation: InvocationWithContext,
- mailboxSession: MailboxSession): Publisher[InvocationWithContext] = {
- metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
- asVacationResponseSetRequest(invocation.invocation.arguments)
- .flatMap(vacationResponseSetRequest => update(mailboxSession, vacationResponseSetRequest)
- .map(updateResult => createResponse(invocation.invocation, vacationResponseSetRequest, updateResult)))
- .map(InvocationWithContext(_, invocation.processingContext)))
+ override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: VacationResponseSetRequest): SMono[InvocationWithContext] = {
+ update(mailboxSession, request)
+ .map(updateResult => createResponse(invocation.invocation, request, updateResult))
+ .map(InvocationWithContext(_, invocation.processingContext))
}
+ override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[VacationResponseSetRequest] = asVacationResponseSetRequest(invocation.arguments)
+
private def update(mailboxSession: MailboxSession, vacationResponseSetRequest: VacationResponseSetRequest): SMono[VacationResponseUpdateResults] = {
SFlux.fromIterable(vacationResponseSetRequest.parsePatch()
.map[SMono[VacationResponseUpdateResult]]({
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseSet.scala
index b7b00ca..6a68a53 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseSet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/vacation/VacationResponseSet.scala
@@ -24,6 +24,7 @@ import java.time.format.DateTimeFormatter
import org.apache.james.jmap.api.vacation.Vacation.ID
import org.apache.james.jmap.api.vacation.VacationPatch
+import org.apache.james.jmap.method.WithAccountId
import org.apache.james.jmap.model.AccountId
import org.apache.james.jmap.model.SetError.{SetErrorDescription, SetErrorType, invalidArgumentValue, serverFailValue}
import org.apache.james.jmap.model.State.State
@@ -35,7 +36,7 @@ import scala.util.{Failure, Success, Try}
case class VacationResponseSetRequest(accountId: AccountId,
update: Option[Map[String, VacationResponsePatchObject]],
create: Option[Map[String, JsObject]],
- destroy: Option[Seq[String]]) {
+ destroy: Option[Seq[String]]) extends WithAccountId{
def parsePatch(): Map[String, Either[IllegalArgumentException, VacationResponsePatchObject]] =
update.getOrElse(Map())
.map({
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 05/08: JAMES-3387 validate accountId for mailbox/get
Posted by rc...@apache.org.
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 60732e18edfb709509681ca8fcc376fd340bf425
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Thu Sep 24 14:46:20 2020 +0200
JAMES-3387 validate accountId for mailbox/get
---
.../contract/MailboxGetMethodContract.scala | 41 ++++++++++++++++++++
.../org/apache/james/jmap/mail/MailboxGet.scala | 3 +-
.../james/jmap/method/MailboxGetMethod.scala | 45 ++++++++++------------
3 files changed, 63 insertions(+), 26 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/MailboxGetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
index 3da44bd..843460f 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
@@ -74,6 +74,47 @@ trait MailboxGetMethodContract {
}
@Test
+ def mailboxGetShouldFailWhenWrongAccountId(): Unit = {
+ val request =
+ s"""{
+ | "using": [
+ | "urn:ietf:params:jmap:core",
+ | "urn:ietf:params:jmap:mail",
+ | "urn:ietf:params:jmap:vacationresponse"],
+ | "methodCalls": [[
+ | "Mailbox/get",
+ | {
+ | "accountId": "unknownAccountId",
+ | "ids": null
+ | },
+ | "c1"]]
+ |}""".stripMargin
+
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response).isEqualTo(
+ """{
+ | "sessionState": "75128aab4b1b",
+ | "methodResponses": [
+ | ["error", {
+ | "type": "accountNotFound"
+ | }, "c1"]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
def getMailboxesShouldIncludeRightsAndNamespaceIfSharesCapabilityIsUsed(server: GuiceJamesServer): Unit = {
val mailboxId: String = server.getProbe(classOf[MailboxProbeImpl])
.createMailbox(MailboxPath.forUser(BOB, "custom"))
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
index d36a430..b230a77 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
@@ -20,6 +20,7 @@
package org.apache.james.jmap.mail
import org.apache.james.jmap.mail.MailboxSetRequest.UnparsedMailboxId
+import org.apache.james.jmap.method.WithAccountId
import org.apache.james.jmap.model.State.State
import org.apache.james.jmap.model.{AccountId, Properties}
@@ -27,7 +28,7 @@ case class Ids(value: List[UnparsedMailboxId])
case class MailboxGetRequest(accountId: AccountId,
ids: Option[Ids],
- properties: Option[Properties])
+ properties: Option[Properties]) extends WithAccountId
case class NotFound(value: Set[UnparsedMailboxId]) {
def merge(other: NotFound): NotFound = NotFound(this.value ++ other.value)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
index d747717..15c01c9 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
@@ -37,7 +37,6 @@ import org.apache.james.mailbox.model.search.MailboxQuery
import org.apache.james.mailbox.model.{MailboxId, MailboxMetaData}
import org.apache.james.mailbox.{MailboxManager, MailboxSession, SubscriptionManager}
import org.apache.james.metrics.api.MetricFactory
-import org.reactivestreams.Publisher
import play.api.libs.json.{JsError, JsObject, JsSuccess}
import reactor.core.scala.publisher.{SFlux, SMono}
import reactor.core.scheduler.Schedulers
@@ -50,8 +49,8 @@ class MailboxGetMethod @Inject() (serializer: MailboxSerializer,
quotaFactory : QuotaLoaderWithPreloadedDefaultFactory,
mailboxIdFactory: MailboxId.Factory,
mailboxFactory: MailboxFactory,
- metricFactory: MetricFactory,
- val sessionSupplier: SessionSupplier) extends Method {
+ val metricFactory: MetricFactory,
+ val sessionSupplier: SessionSupplier) extends MethodRequiringAccountId[MailboxGetRequest] {
override val methodName: MethodName = MethodName("Mailbox/get")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
@@ -73,30 +72,26 @@ class MailboxGetMethod @Inject() (serializer: MailboxSerializer,
notFound = notFound)
}
- override def process(capabilities: Set[CapabilityIdentifier],
- invocation: InvocationWithContext,
- mailboxSession: MailboxSession): Publisher[InvocationWithContext] = {
- metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
- asMailboxGetRequest(invocation.invocation.arguments)
- .flatMap(mailboxGetRequest => {
- val requestedProperties: Properties = mailboxGetRequest.properties.getOrElse(Mailbox.allProperties)
- requestedProperties -- Mailbox.allProperties match {
- case invalidProperties if invalidProperties.isEmpty() => getMailboxes(capabilities, mailboxGetRequest, invocation.processingContext, mailboxSession)
- .reduce(MailboxGetResults.empty(), MailboxGetResults.merge)
- .map(mailboxes => mailboxes.asResponse(mailboxGetRequest.accountId))
- .map(mailboxGetResponse => Invocation(
- methodName = methodName,
- arguments = Arguments(serializer.serialize(mailboxGetResponse, requestedProperties, capabilities).as[JsObject]),
- methodCallId = invocation.invocation.methodCallId))
- case invalidProperties: Properties =>
- SMono.just(Invocation.error(errorCode = ErrorCode.InvalidArguments,
- description = s"The following properties [${invalidProperties.format()}] do not exist.",
- methodCallId = invocation.invocation.methodCallId))
- }
- })
- .map(InvocationWithContext(_, invocation.processingContext)))
+ override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: MailboxGetRequest): SMono[InvocationWithContext] = {
+ val requestedProperties: Properties = request.properties.getOrElse(Mailbox.allProperties)
+ (requestedProperties -- Mailbox.allProperties match {
+ case invalidProperties if invalidProperties.isEmpty() => getMailboxes(capabilities, request, invocation.processingContext, mailboxSession)
+ .reduce(MailboxGetResults.empty(), MailboxGetResults.merge)
+ .map(mailboxes => mailboxes.asResponse(request.accountId))
+ .map(mailboxGetResponse => Invocation(
+ methodName = methodName,
+ arguments = Arguments(serializer.serialize(mailboxGetResponse, requestedProperties, capabilities).as[JsObject]),
+ methodCallId = invocation.invocation.methodCallId))
+ case invalidProperties: Properties =>
+ SMono.just(Invocation.error(errorCode = ErrorCode.InvalidArguments,
+ description = s"The following properties [${invalidProperties.format()}] do not exist.",
+ methodCallId = invocation.invocation.methodCallId))
+ }).map(InvocationWithContext(_, invocation.processingContext))
+
}
+ override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[MailboxGetRequest] = asMailboxGetRequest(invocation.arguments)
+
private def asMailboxGetRequest(arguments: Arguments): SMono[MailboxGetRequest] = {
serializer.deserializeMailboxGetRequest(arguments.value) match {
case JsSuccess(mailboxGetRequest, _) => SMono.just(mailboxGetRequest)
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 04/08: JAMES-3387 refactor extract
InvocationWithContext
Posted by rc...@apache.org.
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 a667ad5f4db98e1c9fbe9c33d6c63667b6bddcec
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Thu Sep 24 13:58:47 2020 +0200
JAMES-3387 refactor extract InvocationWithContext
---
.../apache/james/jmap/method/CoreEchoMethod.scala | 6 ++--
.../apache/james/jmap/method/EmailGetMethod.scala | 9 +++--
.../james/jmap/method/EmailQueryMethod.scala | 30 +++-------------
.../james/jmap/method/MailboxGetMethod.scala | 15 ++++----
.../james/jmap/method/MailboxQueryMethod.scala | 10 +++---
.../james/jmap/method/MailboxSetMethod.scala | 10 +++---
.../org/apache/james/jmap/method/Method.scala | 37 ++++++++++++++------
.../jmap/method/VacationResponseGetMethod.scala | 17 +++++----
.../jmap/method/VacationResponseSetMethod.scala | 11 +++---
.../apache/james/jmap/routes/JMAPApiRoutes.scala | 40 ++++++++++------------
.../james/jmap/method/CoreEchoMethodTest.scala | 11 +++---
.../james/jmap/routes/JMAPApiRoutesTest.scala | 2 +-
12 files changed, 93 insertions(+), 105 deletions(-)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
index c956a81..dfe2aa5 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
@@ -20,12 +20,10 @@ package org.apache.james.jmap.method
import eu.timepit.refined.auto._
-import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.DefaultCapabilities.CORE_CAPABILITY
import org.apache.james.jmap.model.Invocation.MethodName
-import org.apache.james.jmap.model.{Capabilities, Invocation}
-import org.apache.james.jmap.routes.ProcessingContext
+import org.apache.james.jmap.model.{Capabilities}
import org.apache.james.mailbox.MailboxSession
import org.reactivestreams.Publisher
import reactor.core.scala.publisher.SMono
@@ -33,7 +31,7 @@ import reactor.core.scala.publisher.SMono
class CoreEchoMethod extends Method {
override val methodName = MethodName("Core/echo")
- override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = SMono.just((invocation, processingContext))
+ override def process(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession): Publisher[InvocationWithContext] = SMono.just(invocation)
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY)
}
\ No newline at end of file
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala
index 0dbae7e..36d4e93 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala
@@ -33,7 +33,6 @@ import org.apache.james.jmap.model.DefaultCapabilities.{CORE_CAPABILITY, MAIL_CA
import org.apache.james.jmap.model.Invocation.{Arguments, MethodName}
import org.apache.james.jmap.model.State.INSTANCE
import org.apache.james.jmap.model.{AccountId, Capabilities, ErrorCode, Invocation, Properties}
-import org.apache.james.jmap.routes.ProcessingContext
import org.apache.james.mailbox.MailboxSession
import org.apache.james.mailbox.model.MessageId
import org.apache.james.metrics.api.MetricFactory
@@ -87,11 +86,11 @@ class EmailGetMethod @Inject() (readerFactory: EmailViewReaderFactory,
override val methodName = MethodName("Email/get")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
- override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: EmailGetRequest): SMono[(Invocation, ProcessingContext)] = {
- computeResponseInvocation(request, invocation, mailboxSession).onErrorResume({
- case e: IllegalArgumentException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId))
+ override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: EmailGetRequest): SMono[InvocationWithContext] = {
+ computeResponseInvocation(request, invocation.invocation, mailboxSession).onErrorResume({
+ case e: IllegalArgumentException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.invocation.methodCallId))
case e: Throwable => SMono.raiseError(e)
- }).map(invocationResult => (invocationResult, processingContext))
+ }).map(invocationResult => InvocationWithContext(invocationResult, invocation.processingContext))
}
override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[EmailGetRequest] = asEmailGetRequest(invocation.arguments)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
index 4787cb3..5099c18 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
@@ -23,17 +23,15 @@ import eu.timepit.refined.auto._
import javax.inject.Inject
import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.json.{EmailQuerySerializer, ResponseSerializer}
-import org.apache.james.jmap.mail.{Comparator, EmailQueryRequest, EmailQueryResponse, UnsupportedFilterException, UnsupportedRequestParameterException, UnsupportedSortException}
+import org.apache.james.jmap.mail.{Comparator, EmailQueryRequest, EmailQueryResponse, UnsupportedRequestParameterException}
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.DefaultCapabilities.{CORE_CAPABILITY, MAIL_CAPABILITY}
import org.apache.james.jmap.model.Invocation.{Arguments, MethodName}
import org.apache.james.jmap.model.Limit.Limit
import org.apache.james.jmap.model.Position.Position
-import org.apache.james.jmap.model.{CanCalculateChanges, Capabilities, ErrorCode, Invocation, Limit, Position, QueryState}
-import org.apache.james.jmap.routes.ProcessingContext
+import org.apache.james.jmap.model.{CanCalculateChanges, Capabilities, Invocation, Limit, Position, QueryState}
import org.apache.james.jmap.utils.search.MailboxFilter
import org.apache.james.jmap.utils.search.MailboxFilter.QueryFilter
-import org.apache.james.mailbox.exception.MailboxNotFoundException
import org.apache.james.mailbox.model.MultimailboxesSearchQuery
import org.apache.james.mailbox.{MailboxManager, MailboxSession}
import org.apache.james.metrics.api.MetricFactory
@@ -49,29 +47,11 @@ class EmailQueryMethod @Inject() (serializer: EmailQuerySerializer,
override val methodName: MethodName = MethodName("Email/query")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
- override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: EmailQueryRequest): SMono[(Invocation, ProcessingContext)] = {
- processRequest(mailboxSession, invocation, request, capabilities)
- .onErrorResume {
- case e: UnsupportedRequestParameterException => SMono.just(Invocation.error(
- ErrorCode.InvalidArguments,
- s"The following parameter ${e.unsupportedParam} is syntactically valid, but is not supported by the server.",
- invocation.methodCallId))
- case e: UnsupportedSortException => SMono.just(Invocation.error(
- ErrorCode.UnsupportedSort,
- s"The sort ${e.unsupportedSort} is syntactically valid, but it includes a property the server does not support sorting on or a collation method it does not recognise.",
- invocation.methodCallId))
- case e: UnsupportedFilterException => SMono.just(Invocation.error(
- ErrorCode.UnsupportedFilter,
- s"The filter ${e.unsupportedFilter} 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.",
- invocation.methodCallId))
- case e: IllegalArgumentException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId))
- case e: MailboxNotFoundException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId))
- case e: Throwable => SMono.raiseError(e)
- }
- .map(invocationResult => (invocationResult, processingContext))
+ override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: EmailQueryRequest): SMono[InvocationWithContext] = {
+ processRequest(mailboxSession, invocation.invocation, request, capabilities)
+ .map(invocationResult => InvocationWithContext(invocationResult, invocation.processingContext))
}
-
private def processRequest(mailboxSession: MailboxSession,
invocation: Invocation,
request: EmailQueryRequest,
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
index 6e660c8..d747717 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
@@ -74,28 +74,27 @@ class MailboxGetMethod @Inject() (serializer: MailboxSerializer,
}
override def process(capabilities: Set[CapabilityIdentifier],
- invocation: Invocation,
- mailboxSession: MailboxSession,
- processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = {
+ invocation: InvocationWithContext,
+ mailboxSession: MailboxSession): Publisher[InvocationWithContext] = {
metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
- asMailboxGetRequest(invocation.arguments)
+ asMailboxGetRequest(invocation.invocation.arguments)
.flatMap(mailboxGetRequest => {
val requestedProperties: Properties = mailboxGetRequest.properties.getOrElse(Mailbox.allProperties)
requestedProperties -- Mailbox.allProperties match {
- case invalidProperties if invalidProperties.isEmpty() => getMailboxes(capabilities, mailboxGetRequest, processingContext, mailboxSession)
+ case invalidProperties if invalidProperties.isEmpty() => getMailboxes(capabilities, mailboxGetRequest, invocation.processingContext, mailboxSession)
.reduce(MailboxGetResults.empty(), MailboxGetResults.merge)
.map(mailboxes => mailboxes.asResponse(mailboxGetRequest.accountId))
.map(mailboxGetResponse => Invocation(
methodName = methodName,
arguments = Arguments(serializer.serialize(mailboxGetResponse, requestedProperties, capabilities).as[JsObject]),
- methodCallId = invocation.methodCallId))
+ methodCallId = invocation.invocation.methodCallId))
case invalidProperties: Properties =>
SMono.just(Invocation.error(errorCode = ErrorCode.InvalidArguments,
description = s"The following properties [${invalidProperties.format()}] do not exist.",
- methodCallId = invocation.methodCallId))
+ methodCallId = invocation.invocation.methodCallId))
}
})
- .map((_, processingContext)))
+ .map(InvocationWithContext(_, invocation.processingContext)))
}
private def asMailboxGetRequest(arguments: Arguments): SMono[MailboxGetRequest] = {
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala
index 268dc1d..ea0200b 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala
@@ -41,19 +41,19 @@ class MailboxQueryMethod @Inject()(systemMailboxesProvider: SystemMailboxesProvi
override val methodName = MethodName("Mailbox/query")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
- override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] =
+ override def process(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession): Publisher[InvocationWithContext] =
metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
- asMailboxQueryRequest(invocation.arguments)
- .flatMap(processRequest(mailboxSession, invocation, _))
+ asMailboxQueryRequest(invocation.invocation.arguments)
+ .flatMap(processRequest(mailboxSession, invocation.invocation, _))
.onErrorResume {
case e: IllegalArgumentException => SMono.just(
Invocation.error(
errorCode = ErrorCode.InvalidArguments,
description = e.getMessage,
- methodCallId = invocation.methodCallId))
+ methodCallId = invocation.invocation.methodCallId))
case e: Throwable => SMono.raiseError(e)
}
- .map(invocationResult => (invocationResult, processingContext)))
+ .map(invocationResult => InvocationWithContext(invocationResult, invocation.processingContext)))
private def processRequest(mailboxSession: MailboxSession, invocation: Invocation, request: MailboxQueryRequest): SMono[Invocation] = {
SFlux.fromPublisher(systemMailboxesProvider.getMailboxByRole(request.filter.role, mailboxSession.getUser))
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
index dc772c5..df6b77c 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
@@ -153,11 +153,11 @@ class MailboxSetMethod @Inject()(serializer: MailboxSerializer,
override val methodName: MethodName = MethodName("Mailbox/set")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
- override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: MailboxSetRequest): SMono[(Invocation, ProcessingContext)] = for {
- creationResultsWithUpdatedProcessingContext <- createMailboxes(mailboxSession, request, processingContext)
- deletionResults <- deleteMailboxes(mailboxSession, request, processingContext)
- updateResults <- updateMailboxes(mailboxSession, request, processingContext, capabilities)
- } yield (createResponse(capabilities, invocation, request, creationResultsWithUpdatedProcessingContext._1, deletionResults, updateResults), creationResultsWithUpdatedProcessingContext._2)
+ override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: MailboxSetRequest): SMono[InvocationWithContext] = for {
+ creationResultsWithUpdatedProcessingContext <- createMailboxes(mailboxSession, request, invocation.processingContext)
+ deletionResults <- deleteMailboxes(mailboxSession, request, invocation.processingContext)
+ updateResults <- updateMailboxes(mailboxSession, request, invocation.processingContext, capabilities)
+ } yield InvocationWithContext(createResponse(capabilities, invocation.invocation, request, creationResultsWithUpdatedProcessingContext._1, deletionResults, updateResults), creationResultsWithUpdatedProcessingContext._2)
override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[MailboxSetRequest] = asMailboxSetRequest(invocation.arguments)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
index f4a40a5..5ee14cb 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
@@ -20,6 +20,7 @@ package org.apache.james.jmap.method
import org.apache.james.jmap.http.SessionSupplier
+import org.apache.james.jmap.mail.{UnsupportedFilterException, UnsupportedRequestParameterException, UnsupportedSortException}
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.Invocation.MethodName
import org.apache.james.jmap.model.{AccountId, Capabilities, ErrorCode, Invocation, Session}
@@ -30,6 +31,8 @@ import org.apache.james.metrics.api.MetricFactory
import org.reactivestreams.Publisher
import reactor.core.scala.publisher.SMono
+case class InvocationWithContext(invocation: Invocation, processingContext: ProcessingContext)
+
trait Method {
val JMAP_RFC8621_PREFIX: String = "JMAP-RFC8621-"
@@ -37,7 +40,7 @@ trait Method {
val requiredCapabilities: Capabilities
- def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)]
+ def process(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession): Publisher[InvocationWithContext]
}
trait WithAccountId {
@@ -47,18 +50,32 @@ trait MethodRequiringAccountId[REQUEST <: WithAccountId] extends Method {
def metricFactory: MetricFactory
def sessionSupplier: SessionSupplier
- override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = {
+ override def process(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession): Publisher[InvocationWithContext] = {
val result = (for {
- request <- getRequest(mailboxSession, invocation)
- response <- validateAccountId(request.accountId, mailboxSession, sessionSupplier, invocation).flatMap{
- case Right(_) => doProcess(capabilities, invocation, mailboxSession, processingContext, request)
- case Left(invocation) => SMono.just((invocation, processingContext))
+ request <- getRequest(mailboxSession, invocation.invocation)
+ response <- validateAccountId(request.accountId, mailboxSession, sessionSupplier, invocation.invocation).flatMap{
+ case Right(_) => doProcess(capabilities, invocation, mailboxSession, request)
+ case Left(errorInvocation) => SMono.just(InvocationWithContext(errorInvocation, invocation.processingContext))
}
} yield response)
.onErrorResume {
- case e: IllegalArgumentException => SMono.just((Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId), processingContext))
- case e: Throwable => SMono.raiseError(e)
- }
+ case e: UnsupportedRequestParameterException => SMono.just(InvocationWithContext(Invocation.error(
+ ErrorCode.InvalidArguments,
+ s"The following parameter ${e.unsupportedParam} is syntactically valid, but is not supported by the server.",
+ invocation.invocation.methodCallId), invocation.processingContext))
+ case e: UnsupportedSortException => SMono.just(InvocationWithContext(Invocation.error(
+ ErrorCode.UnsupportedSort,
+ s"The sort ${e.unsupportedSort} is syntactically valid, but it includes a property the server does not support sorting on or a collation method it does not recognise.",
+ invocation.invocation.methodCallId), invocation.processingContext))
+ case e: UnsupportedFilterException => SMono.just(InvocationWithContext(Invocation.error(
+ ErrorCode.UnsupportedFilter,
+ s"The filter ${e.unsupportedFilter} 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.",
+ invocation.invocation.methodCallId), invocation.processingContext))
+ case e: IllegalArgumentException => SMono.just(InvocationWithContext(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.invocation.methodCallId), invocation.processingContext))
+ case e: MailboxNotFoundException => SMono.just(InvocationWithContext(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.invocation.methodCallId), invocation.processingContext))
+ case e: Throwable => SMono.raiseError(e)
+ }
+
metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value, result)
}
@@ -70,7 +87,7 @@ trait MethodRequiringAccountId[REQUEST <: WithAccountId] extends Method {
.switchIfEmpty(SMono.just(Left[Invocation, Session](Invocation.error(ErrorCode.AccountNotFound, invocation.methodCallId))))
}
- def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: REQUEST): SMono[(Invocation, ProcessingContext)]
+ def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: REQUEST): SMono[InvocationWithContext]
def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[REQUEST]
}
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala
index a3c3e8b..a9a3a7f 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala
@@ -64,29 +64,28 @@ class VacationResponseGetMethod @Inject() (vacationRepository: VacationRepositor
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY, VACATION_RESPONSE_CAPABILITY)
override def process(capabilities: Set[CapabilityIdentifier],
- invocation: Invocation,
- mailboxSession: MailboxSession,
- processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = {
+ invocation: InvocationWithContext,
+ mailboxSession: MailboxSession): Publisher[InvocationWithContext] = {
metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
- asVacationResponseGetRequest(invocation.arguments)
- .fold(e => handleRequestValidationErrors(e, invocation.methodCallId),
+ asVacationResponseGetRequest(invocation.invocation.arguments)
+ .fold(e => handleRequestValidationErrors(e, invocation.invocation.methodCallId),
vacationResponseGetRequest => {
val requestedProperties: Properties = vacationResponseGetRequest.properties.getOrElse(VacationResponse.allProperties)
requestedProperties -- VacationResponse.allProperties match {
- case invalidProperties if invalidProperties.isEmpty() => getVacationResponse(vacationResponseGetRequest, processingContext, mailboxSession)
+ case invalidProperties if invalidProperties.isEmpty() => getVacationResponse(vacationResponseGetRequest, invocation.processingContext, mailboxSession)
.reduce(VacationResponseGetResult.empty, VacationResponseGetResult.merge)
.map(vacationResult => vacationResult.asResponse(vacationResponseGetRequest.accountId))
.map(vacationResponseGetResponse => Invocation(
methodName = methodName,
arguments = Arguments(VacationSerializer.serialize(vacationResponseGetResponse, requestedProperties).as[JsObject]),
- methodCallId = invocation.methodCallId))
+ methodCallId = invocation.invocation.methodCallId))
case invalidProperties: Properties =>
SMono.just(Invocation.error(errorCode = ErrorCode.InvalidArguments,
description = s"The following properties [${invalidProperties.format}] do not exist.",
- methodCallId = invocation.methodCallId))
+ methodCallId = invocation.invocation.methodCallId))
}
})
- .map((_, processingContext)))
+ .map(InvocationWithContext(_, invocation.processingContext)))
}
private def asVacationResponseGetRequest(arguments: Arguments): Either[IllegalArgumentException, VacationResponseGetRequest] =
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala
index 4b24625..c3febb9 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala
@@ -80,14 +80,13 @@ class VacationResponseSetMethod @Inject() (vacationRepository: VacationRepositor
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY, VACATION_RESPONSE_CAPABILITY)
override def process(capabilities: Set[CapabilityIdentifier],
- invocation: Invocation,
- mailboxSession: MailboxSession,
- processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = {
+ invocation: InvocationWithContext,
+ mailboxSession: MailboxSession): Publisher[InvocationWithContext] = {
metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
- asVacationResponseSetRequest(invocation.arguments)
+ asVacationResponseSetRequest(invocation.invocation.arguments)
.flatMap(vacationResponseSetRequest => update(mailboxSession, vacationResponseSetRequest)
- .map(updateResult => createResponse(invocation, vacationResponseSetRequest, updateResult)))
- .map((_, processingContext)))
+ .map(updateResult => createResponse(invocation.invocation, vacationResponseSetRequest, updateResult)))
+ .map(InvocationWithContext(_, invocation.processingContext)))
}
private def update(mailboxSession: MailboxSession, vacationResponseSetRequest: VacationResponseSetRequest): SMono[VacationResponseUpdateResults] = {
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
index ab870e1..3ddf463 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
@@ -35,7 +35,7 @@ import org.apache.james.jmap.exceptions.UnauthorizedException
import org.apache.james.jmap.http.rfc8621.InjectionKeys
import org.apache.james.jmap.http.{Authenticator, MailboxesProvisioner, SessionSupplier, UserProvisioning}
import org.apache.james.jmap.json.ResponseSerializer
-import org.apache.james.jmap.method.Method
+import org.apache.james.jmap.method.{InvocationWithContext, Method}
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.Invocation.MethodName
import org.apache.james.jmap.model.ProblemDetails.{notJSONProblem, notRequestProblem, unknownCapabilityProblem}
@@ -120,25 +120,25 @@ class JMAPApiRoutes (val authenticator: Authenticator,
SMono.raiseError(UnsupportedCapabilitiesException(unsupportedCapabilities))
} else {
processSequentiallyAndUpdateContext(requestObject, mailboxSession, processingContext, capabilities)
- .flatMap((invocations : Seq[(Invocation, ProcessingContext)]) =>
+ .flatMap((invocations : Seq[InvocationWithContext]) =>
SMono.fromPublisher(httpServerResponse.status(OK)
.header(CONTENT_TYPE, JSON_CONTENT_TYPE)
.sendString(
SMono.fromCallable(() =>
- ResponseSerializer.serialize(ResponseObject(ResponseObject.SESSION_STATE, invocations.map(_._1))).toString),
+ ResponseSerializer.serialize(ResponseObject(ResponseObject.SESSION_STATE, invocations.map(_.invocation))).toString),
StandardCharsets.UTF_8)
.`then`())
)
}
}
- private def processSequentiallyAndUpdateContext(requestObject: RequestObject, mailboxSession: MailboxSession, processingContext: ProcessingContext, capabilities: Set[CapabilityIdentifier]): SMono[Seq[(Invocation, ProcessingContext)]] = {
+ private def processSequentiallyAndUpdateContext(requestObject: RequestObject, mailboxSession: MailboxSession, processingContext: ProcessingContext, capabilities: Set[CapabilityIdentifier]): SMono[Seq[(InvocationWithContext)]] = {
SFlux.fromIterable(requestObject.methodCalls)
- .foldLeft(List[SMono[(Invocation, ProcessingContext)]]())((acc, elem) => {
+ .foldLeft(List[SMono[InvocationWithContext]]())((acc, elem) => {
val lastProcessingContext: SMono[ProcessingContext] = acc.headOption
- .map(last => last.map(_._2))
+ .map(last => last.map(_.processingContext))
.getOrElse(SMono.just(processingContext))
- val invocation: SMono[(Invocation, ProcessingContext)] = lastProcessingContext.flatMap(context => process(capabilities, mailboxSession, context, elem))
+ val invocation: SMono[InvocationWithContext] = lastProcessingContext.flatMap(context => process(capabilities, mailboxSession, InvocationWithContext(elem, context)))
invocation.cache() :: acc
})
.map(_.reverse)
@@ -147,29 +147,27 @@ class JMAPApiRoutes (val authenticator: Authenticator,
.collectSeq())
}
- private def process(capabilities: Set[CapabilityIdentifier], mailboxSession: MailboxSession, processingContext: ProcessingContext, invocation: Invocation) : SMono[(Invocation, ProcessingContext)] = {
+ private def process(capabilities: Set[CapabilityIdentifier], mailboxSession: MailboxSession, invocation: InvocationWithContext) : SMono[InvocationWithContext] = {
SMono.defer(() => {
- processingContext.resolveBackReferences(invocation) match {
- case Left(e) => SMono.just((Invocation.error(
+ invocation.processingContext.resolveBackReferences(invocation.invocation) match {
+ case Left(e) => SMono.just(InvocationWithContext(Invocation.error(
errorCode = ErrorCode.InvalidResultReference,
description = s"Failed resolving back-reference: ${e.message}",
- methodCallId = invocation.methodCallId), processingContext))
- case Right(resolvedInvocation) => processMethodWithMatchName(capabilities, resolvedInvocation, mailboxSession, processingContext)
- .map {
- case (invocation: Invocation, updatedProcessingContext: ProcessingContext) => (invocation, updatedProcessingContext.recordInvocation(invocation))
- }
+ methodCallId = invocation.invocation.methodCallId), invocation.processingContext))
+ case Right(resolvedInvocation) => processMethodWithMatchName(capabilities, InvocationWithContext(resolvedInvocation, invocation.processingContext), mailboxSession)
+ .map((invocationWithContext: InvocationWithContext) => InvocationWithContext(invocationWithContext.invocation, invocationWithContext.processingContext.recordInvocation(invocationWithContext.invocation)))
}
})
}
- private def processMethodWithMatchName(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): SMono[(Invocation, ProcessingContext)] =
- SMono.justOrEmpty(methodsByName.get(invocation.methodName))
+ private def processMethodWithMatchName(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession): SMono[InvocationWithContext] =
+ SMono.justOrEmpty(methodsByName.get(invocation.invocation.methodName))
.flatMap(method => validateCapabilities(capabilities, method.requiredCapabilities)
- .fold(e => SMono.just((Invocation.error(ErrorCode.UnknownMethod, e.description, invocation.methodCallId), processingContext)),
- _ => SMono.fromPublisher(method.process(capabilities, invocation, mailboxSession, processingContext))
+ .fold(e => SMono.just(InvocationWithContext(Invocation.error(ErrorCode.UnknownMethod, e.description, invocation.invocation.methodCallId), invocation.processingContext)),
+ _ => SMono.fromPublisher(method.process(capabilities, invocation, mailboxSession))
))
- .onErrorResume(throwable => SMono.just((Invocation.error(ErrorCode.ServerFail, throwable.getMessage, invocation.methodCallId), processingContext)))
- .switchIfEmpty(SMono.just((Invocation.error(ErrorCode.UnknownMethod, invocation.methodCallId), processingContext)))
+ .onErrorResume(throwable => SMono.just(InvocationWithContext(Invocation.error(ErrorCode.ServerFail, throwable.getMessage, invocation.invocation.methodCallId), invocation.processingContext)))
+ .switchIfEmpty(SMono.just(InvocationWithContext(Invocation.error(ErrorCode.UnknownMethod, invocation.invocation.methodCallId), invocation.processingContext)))
private def validateCapabilities(capabilities: Set[CapabilityIdentifier], requiredCapabilities: Capabilities): Either[MissingCapabilityException, Unit] = {
val missingCapabilities = requiredCapabilities.ids -- capabilities
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
index 77da9e6..18a2624 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
@@ -18,10 +18,9 @@
* ***************************************************************/
package org.apache.james.jmap.method
-import org.apache.james.jmap.http.SessionSupplier
import org.apache.james.jmap.json.Fixture.{invocation1, invocation2}
import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
-import org.apache.james.jmap.model.{CapabilityIdentifier, Invocation, JmapRfc8621Configuration}
+import org.apache.james.jmap.model.{CapabilityIdentifier, Invocation}
import org.apache.james.jmap.routes.ProcessingContext
import org.apache.james.mailbox.MailboxSession
import org.mockito.Mockito.mock
@@ -37,15 +36,15 @@ class CoreEchoMethodTest extends AnyWordSpec with Matchers {
"CoreEcho" should {
"Process" should {
"success and return the same with parameters as the invocation request" in {
- val expectedResponse: (Invocation, ProcessingContext) = (invocation1, ProcessingContext(Map.empty, Map.empty))
- val dataResponse = SMono.fromPublisher(echoMethod.process(capabilities, invocation1, mockedSession, ProcessingContext(Map.empty, Map.empty))).block()
+ val expectedResponse: InvocationWithContext = InvocationWithContext(invocation1, ProcessingContext(Map.empty, Map.empty))
+ val dataResponse = SMono.fromPublisher(echoMethod.process(capabilities, InvocationWithContext(invocation1,ProcessingContext(Map.empty, Map.empty)), mockedSession)).block()
dataResponse shouldBe expectedResponse
}
"success and not return anything else different than the original invocation" in {
- val wrongExpected: (Invocation, ProcessingContext) = (invocation2, ProcessingContext(Map.empty, Map.empty))
- val dataResponse = SMono.fromPublisher(echoMethod.process(capabilities, invocation1, mockedSession, ProcessingContext(Map.empty, Map.empty))).block()
+ val wrongExpected: InvocationWithContext = InvocationWithContext(invocation2, ProcessingContext(Map.empty, Map.empty))
+ val dataResponse = SMono.fromPublisher(echoMethod.process(capabilities, InvocationWithContext(invocation1, ProcessingContext(Map.empty, Map.empty)), mockedSession)).block()
dataResponse should not be(wrongExpected)
}
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
index 7e5298f..b9f23bc 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
@@ -437,7 +437,7 @@ class JMAPApiRoutesTest extends AnyFlatSpec with BeforeAndAfter with Matchers {
doThrow(new RuntimeException("Unexpected Exception occur, the others method may proceed normally"))
.doCallRealMethod()
.when(mockCoreEchoMethod)
- .process(any[Set[CapabilityIdentifier]], any(), any(), any())
+ .process(any[Set[CapabilityIdentifier]], any(), any())
when(mockCoreEchoMethod.methodName).thenReturn(MethodName("Core/echo"))
when(mockCoreEchoMethod.requiredCapabilities).thenReturn(Capabilities(CORE_CAPABILITY))
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 07/08: JAMES-3387 validate accountId for
vacationResponse/get
Posted by rc...@apache.org.
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 c532fadb010178d14ad69de846575c571e29a8fc
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Thu Sep 24 15:01:30 2020 +0200
JAMES-3387 validate accountId for vacationResponse/get
---
.../VacationResponseGetMethodContract.scala | 41 ++++++++++++++++
.../james/jmap/mail/VacationResponseGet.scala | 3 +-
.../jmap/method/VacationResponseGetMethod.scala | 57 ++++++++++------------
3 files changed, 70 insertions(+), 31 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/VacationResponseGetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseGetMethodContract.scala
index 268b840..1ca2caf 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseGetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseGetMethodContract.scala
@@ -62,6 +62,47 @@ trait VacationResponseGetMethodContract {
}
@Test
+ def vacationResponseGetShouldFailWhenWrongAccountId(server: GuiceJamesServer): Unit = {
+ val request =
+ s"""{
+ | "using": [
+ | "urn:ietf:params:jmap:core",
+ | "urn:ietf:params:jmap:mail",
+ | "urn:ietf:params:jmap:vacationresponse"],
+ | "methodCalls": [[
+ | "VacationResponse/get",
+ | {
+ | "accountId": "unknownAccountId",
+ | "ids": null
+ | },
+ | "c1"]]
+ |}""".stripMargin
+
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response).isEqualTo(
+ """{
+ | "sessionState": "75128aab4b1b",
+ | "methodResponses": [
+ | ["error", {
+ | "type": "accountNotFound"
+ | }, "c1"]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
@Tag(CategoryTags.BASIC_FEATURE)
def vacationResponseShouldBeDisabledByDefault(): Unit = {
val response = `given`
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/VacationResponseGet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/VacationResponseGet.scala
index 4329c84..5509e18 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/VacationResponseGet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/VacationResponseGet.scala
@@ -20,6 +20,7 @@
package org.apache.james.jmap.mail
import org.apache.james.jmap.mail.VacationResponse.UnparsedVacationResponseId
+import org.apache.james.jmap.method.WithAccountId
import org.apache.james.jmap.model.State.State
import org.apache.james.jmap.model.{AccountId, Properties}
@@ -27,7 +28,7 @@ case class VacationResponseIds(value: List[UnparsedVacationResponseId])
case class VacationResponseGetRequest(accountId: AccountId,
ids: Option[VacationResponseIds],
- properties: Option[Properties])
+ properties: Option[Properties]) extends WithAccountId
case class VacationResponseNotFound(value: Set[UnparsedVacationResponseId]) {
def merge(other: VacationResponseNotFound): VacationResponseNotFound = VacationResponseNotFound(this.value ++ other.value)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala
index a9a3a7f..2978afd 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala
@@ -34,7 +34,6 @@ import org.apache.james.jmap.model.{AccountId, Capabilities, ErrorCode, Invocati
import org.apache.james.jmap.routes.ProcessingContext
import org.apache.james.mailbox.MailboxSession
import org.apache.james.metrics.api.MetricFactory
-import org.reactivestreams.Publisher
import play.api.libs.json.{JsError, JsObject, JsSuccess}
import reactor.core.scala.publisher.{SFlux, SMono}
@@ -58,40 +57,38 @@ case class VacationResponseGetResult(vacationResponses: Set[VacationResponse], n
notFound = notFound)
}
-class VacationResponseGetMethod @Inject() (vacationRepository: VacationRepository,
- metricFactory: MetricFactory) extends Method {
+class VacationResponseGetMethod @Inject()(vacationRepository: VacationRepository,
+ val metricFactory: MetricFactory,
+ val sessionSupplier: SessionSupplier) extends MethodRequiringAccountId[VacationResponseGetRequest] {
override val methodName: MethodName = MethodName("VacationResponse/get")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY, VACATION_RESPONSE_CAPABILITY)
- override def process(capabilities: Set[CapabilityIdentifier],
- invocation: InvocationWithContext,
- mailboxSession: MailboxSession): Publisher[InvocationWithContext] = {
- metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
- asVacationResponseGetRequest(invocation.invocation.arguments)
- .fold(e => handleRequestValidationErrors(e, invocation.invocation.methodCallId),
- vacationResponseGetRequest => {
- val requestedProperties: Properties = vacationResponseGetRequest.properties.getOrElse(VacationResponse.allProperties)
- requestedProperties -- VacationResponse.allProperties match {
- case invalidProperties if invalidProperties.isEmpty() => getVacationResponse(vacationResponseGetRequest, invocation.processingContext, mailboxSession)
- .reduce(VacationResponseGetResult.empty, VacationResponseGetResult.merge)
- .map(vacationResult => vacationResult.asResponse(vacationResponseGetRequest.accountId))
- .map(vacationResponseGetResponse => Invocation(
- methodName = methodName,
- arguments = Arguments(VacationSerializer.serialize(vacationResponseGetResponse, requestedProperties).as[JsObject]),
- methodCallId = invocation.invocation.methodCallId))
- case invalidProperties: Properties =>
- SMono.just(Invocation.error(errorCode = ErrorCode.InvalidArguments,
- description = s"The following properties [${invalidProperties.format}] do not exist.",
- methodCallId = invocation.invocation.methodCallId))
- }
- })
- .map(InvocationWithContext(_, invocation.processingContext)))
+ override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: VacationResponseGetRequest): SMono[InvocationWithContext] = {
+ {
+ val requestedProperties: Properties = request.properties.getOrElse(VacationResponse.allProperties)
+ (requestedProperties -- VacationResponse.allProperties match {
+ case invalidProperties if invalidProperties.isEmpty() => getVacationResponse(request, invocation.processingContext, mailboxSession)
+ .reduce(VacationResponseGetResult.empty, VacationResponseGetResult.merge)
+ .map(vacationResult => vacationResult.asResponse(request.accountId))
+ .map(vacationResponseGetResponse => Invocation(
+ methodName = methodName,
+ arguments = Arguments(VacationSerializer.serialize(vacationResponseGetResponse, requestedProperties).as[JsObject]),
+ methodCallId = invocation.invocation.methodCallId))
+ case invalidProperties: Properties =>
+ SMono.just(Invocation.error(errorCode = ErrorCode.InvalidArguments,
+ description = s"The following properties [${invalidProperties.format}] do not exist.",
+ methodCallId = invocation.invocation.methodCallId))
+ }).map(InvocationWithContext(_, invocation.processingContext))
+ .onErrorResume{ case e: Exception => handleRequestValidationErrors(e, invocation.invocation.methodCallId)
+ .map(errorInvocation => InvocationWithContext(errorInvocation, invocation.processingContext))}
+ }
}
- private def asVacationResponseGetRequest(arguments: Arguments): Either[IllegalArgumentException, VacationResponseGetRequest] =
- VacationSerializer.deserializeVacationResponseGetRequest(arguments.value) match {
- case JsSuccess(vacationResponseGetRequest, _) => Right(vacationResponseGetRequest)
- case errors: JsError => Left(new IllegalArgumentException(ResponseSerializer.serialize(errors).toString))
+ override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[VacationResponseGetRequest] = asVacationResponseGetRequest(invocation.arguments)
+
+ private def asVacationResponseGetRequest(arguments: Arguments): SMono[VacationResponseGetRequest] = VacationSerializer.deserializeVacationResponseGetRequest(arguments.value) match {
+ case JsSuccess(vacationResponseGetRequest, _) => SMono.just(vacationResponseGetRequest)
+ case errors: JsError => SMono.raiseError(new IllegalArgumentException(ResponseSerializer.serialize(errors).toString))
}
private def handleRequestValidationErrors(exception: Exception, methodCallId: MethodCallId): SMono[Invocation] = exception match {
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 06/08: JAMES-3387 validate accountId form
mailbox/query
Posted by rc...@apache.org.
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 506563908bd4c62b4468065455278efd7b13ca0f
Author: Rémi Kowalski <rk...@linagora.com>
AuthorDate: Thu Sep 24 14:50:45 2020 +0200
JAMES-3387 validate accountId form mailbox/query
---
.../contract/MailboxQueryMethodContract.scala | 40 ++++++++++++++++++++++
.../org/apache/james/jmap/mail/MailboxQuery.scala | 3 +-
.../james/jmap/method/MailboxQueryMethod.scala | 33 +++++++++---------
3 files changed, 58 insertions(+), 18 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/MailboxQueryMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxQueryMethodContract.scala
index fe714be..76a6ec2 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxQueryMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxQueryMethodContract.scala
@@ -48,6 +48,46 @@ trait MailboxQueryMethodContract {
}
@Test
+ def mailboxQueryShouldFailWhenWrongAccountId(server: GuiceJamesServer): Unit = {
+ val request =
+ s"""{
+ | "using": [
+ | "urn:ietf:params:jmap:core",
+ | "urn:ietf:params:jmap:mail"],
+ | "methodCalls": [[
+ | "Mailbox/query",
+ | {
+ | "accountId": "unknownAccountId",
+ | "filter": {"role":"Inbox"}
+ | },
+ | "c1"]]
+ |}""".stripMargin
+
+ val response = `given`
+ .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+ .body(request)
+ .when
+ .post
+ .`then`
+ .log().ifValidationFails()
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response).isEqualTo(
+ """{
+ | "sessionState": "75128aab4b1b",
+ | "methodResponses": [
+ | ["error", {
+ | "type": "accountNotFound"
+ | }, "c1"]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
def roleShouldAllowToRetrieveTheInbox(server: GuiceJamesServer): Unit = {
val mailboxId: MailboxId = server.getProbe(classOf[MailboxProbeImpl])
.createMailbox(MailboxPath.forUser(BOB, "INBOX"))
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxQuery.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxQuery.scala
index 6d74b49..00b44e9 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxQuery.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxQuery.scala
@@ -19,13 +19,14 @@
package org.apache.james.jmap.mail
+import org.apache.james.jmap.method.WithAccountId
import org.apache.james.jmap.model.Limit.Limit
import org.apache.james.jmap.model.Position.Position
import org.apache.james.jmap.model.{AccountId, CanCalculateChanges, Position, QueryState}
import org.apache.james.mailbox.Role
import org.apache.james.mailbox.model.MailboxId
-case class MailboxQueryRequest(accountId: AccountId, filter: MailboxFilter)
+case class MailboxQueryRequest(accountId: AccountId, filter: MailboxFilter) extends WithAccountId
case class MailboxFilter(role: Role)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala
index ea0200b..8070ab7 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala
@@ -27,33 +27,32 @@ import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier
import org.apache.james.jmap.model.DefaultCapabilities.{CORE_CAPABILITY, MAIL_CAPABILITY}
import org.apache.james.jmap.model.Invocation.{Arguments, MethodName}
import org.apache.james.jmap.model._
-import org.apache.james.jmap.routes.ProcessingContext
import org.apache.james.mailbox.{MailboxSession, SystemMailboxesProvider}
import org.apache.james.metrics.api.MetricFactory
-import org.reactivestreams.Publisher
import play.api.libs.json.{JsError, JsSuccess}
import reactor.core.scala.publisher.{SFlux, SMono}
import reactor.core.scheduler.Schedulers
class MailboxQueryMethod @Inject()(systemMailboxesProvider: SystemMailboxesProvider,
- metricFactory: MetricFactory,
- val sessionSupplier: SessionSupplier) extends Method {
+ val metricFactory: MetricFactory,
+ val sessionSupplier: SessionSupplier) extends MethodRequiringAccountId[MailboxQueryRequest] {
override val methodName = MethodName("Mailbox/query")
override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY)
- override def process(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession): Publisher[InvocationWithContext] =
- metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
- asMailboxQueryRequest(invocation.invocation.arguments)
- .flatMap(processRequest(mailboxSession, invocation.invocation, _))
- .onErrorResume {
- case e: IllegalArgumentException => SMono.just(
- Invocation.error(
- errorCode = ErrorCode.InvalidArguments,
- description = e.getMessage,
- methodCallId = invocation.invocation.methodCallId))
- case e: Throwable => SMono.raiseError(e)
- }
- .map(invocationResult => InvocationWithContext(invocationResult, invocation.processingContext)))
+ override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: MailboxQueryRequest): SMono[InvocationWithContext] = {
+ processRequest(mailboxSession, invocation.invocation, request)
+ .onErrorResume {
+ case e: IllegalArgumentException => SMono.just(
+ Invocation.error(
+ errorCode = ErrorCode.InvalidArguments,
+ description = e.getMessage,
+ methodCallId = invocation.invocation.methodCallId))
+ case e: Throwable => SMono.raiseError(e)
+ }
+ .map(invocationResult => InvocationWithContext(invocationResult, invocation.processingContext))
+ }
+
+ override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[MailboxQueryRequest] = asMailboxQueryRequest(invocation.arguments)
private def processRequest(mailboxSession: MailboxSession, invocation: Invocation, request: MailboxQueryRequest): SMono[Invocation] = {
SFlux.fromPublisher(systemMailboxesProvider.getMailboxByRole(request.filter.role, mailboxSession.getUser))
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org