This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 6e15127facd944a90d318909d60707293dac79b9 Author: Benoit Tellier <btell...@linagora.com> AuthorDate: Fri Aug 14 10:34:45 2020 +0700 JAMES-3356 Refactoring: unify error handling for mailbox creation parsing/handling This makes it easier to follow the error management logic as it all goes though one place. Methods arguments within MailboxSetMethod are furthermore simplified. --- .../james/jmap/method/MailboxSetMethod.scala | 55 ++++++++++------------ 1 file changed, 25 insertions(+), 30 deletions(-) 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 ae3bec0..94b64b2 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 @@ -37,10 +37,9 @@ import play.api.libs.json._ import reactor.core.scala.publisher.{SFlux, SMono} import reactor.core.scheduler.Schedulers -import scala.collection.immutable - case class MailboxHasMailException(mailboxId: MailboxId) extends Exception case class MailboxHasChildException(mailboxId: MailboxId) extends Exception +case class MailboxCreationParseException(mailboxSetError: MailboxSetError) extends Exception sealed trait CreationResult { def mailboxCreationId: MailboxCreationId @@ -51,6 +50,7 @@ case class CreationFailure(mailboxCreationId: MailboxCreationId, exception: Exce case e: MailboxNotFoundException => MailboxSetError.invalidArgument(Some(SetErrorDescription(e.getMessage)), Some(Properties(List("parentId")))) case e: MailboxExistsException => MailboxSetError.invalidArgument(Some(SetErrorDescription(e.getMessage)), Some(Properties(List("name")))) case e: MailboxNameException => MailboxSetError.invalidArgument(Some(SetErrorDescription(e.getMessage)), Some(Properties(List("name")))) + case e: MailboxCreationParseException => e.mailboxSetError case _: InsufficientRightsException => MailboxSetError.forbidden(Some(SetErrorDescription("Insufficient rights")), Some(Properties(List("parentId")))) case _ => MailboxSetError.serverFail(Some(SetErrorDescription(exception.getMessage)), None) } @@ -107,27 +107,18 @@ class MailboxSetMethod @Inject()(serializer: Serializer, metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value, asMailboxSetRequest(invocation.arguments) .flatMap(mailboxSetRequest => { - val (unparsableCreateRequests, createRequests) = parseCreateRequests(mailboxSetRequest) for { - creationResults <- createMailboxes(mailboxSession, createRequests, processingContext) - deletionResults <- deleteMailboxes(mailboxSession, mailboxSetRequest.destroy.getOrElse(Seq()), processingContext) - } yield createResponse(invocation, mailboxSetRequest, unparsableCreateRequests, creationResults, deletionResults) + creationResults <- createMailboxes(mailboxSession, mailboxSetRequest, processingContext) + deletionResults <- deleteMailboxes(mailboxSession, mailboxSetRequest, processingContext) + } yield createResponse(invocation, mailboxSetRequest, creationResults, deletionResults) })) } - private def parseCreateRequests(mailboxSetRequest: MailboxSetRequest): (immutable.Iterable[(MailboxCreationId, MailboxSetError)], immutable.Iterable[(MailboxCreationId, MailboxCreationRequest)]) = { - mailboxSetRequest.create - .getOrElse(Map.empty) - .view - .mapValues(value => Json.fromJson(value)(serializer.mailboxCreationRequest)) - .toMap - .partitionMap { case (creationId, creationRequestParseResult) => - creationRequestParseResult match { - case JsSuccess(creationRequest, _) => Right((creationId, creationRequest)) - case JsError(errors) => Left(creationId, mailboxSetError(errors)) - } - } - } + def parseCreate(jsObject: JsObject): Either[MailboxCreationParseException, MailboxCreationRequest] = + Json.fromJson(jsObject)(serializer.mailboxCreationRequest) match { + case JsSuccess(creationRequest, _) => Right(creationRequest) + case JsError(errors) => Left(MailboxCreationParseException(mailboxSetError(errors))) + } private def mailboxSetError(errors: collection.Seq[(JsPath, collection.Seq[JsonValidationError])]): MailboxSetError = errors.head match { @@ -136,8 +127,8 @@ class MailboxSetMethod @Inject()(serializer: Serializer, case (path, _) => MailboxSetError.invalidArgument(Some(SetErrorDescription(s"Unknown error on property '$path'")), None) } - private def deleteMailboxes(mailboxSession: MailboxSession, deleteRequests: immutable.Iterable[UnparsedMailboxId], processingContext: ProcessingContext): SMono[DeletionResults] = { - SFlux.fromIterable(deleteRequests) + private def deleteMailboxes(mailboxSession: MailboxSession, mailboxSetRequest: MailboxSetRequest, processingContext: ProcessingContext): SMono[DeletionResults] = { + SFlux.fromIterable(mailboxSetRequest.destroy.getOrElse(Seq())) .flatMap(id => delete(mailboxSession, processingContext, id) .onErrorRecover(e => DeletionFailure(id, e))) .collectSeq() @@ -165,12 +156,15 @@ class MailboxSetMethod @Inject()(serializer: Serializer, } private def createMailboxes(mailboxSession: MailboxSession, - createRequests: immutable.Iterable[(MailboxCreationId, MailboxCreationRequest)], + mailboxSetRequest: MailboxSetRequest, processingContext: ProcessingContext): SMono[CreationResults] = { - SFlux.fromIterable(createRequests).flatMap { - case (mailboxCreationId: MailboxCreationId, mailboxCreationRequest: MailboxCreationRequest) => + SFlux.fromIterable(mailboxSetRequest.create + .getOrElse(Map.empty) + .view) + .flatMap { + case (mailboxCreationId: MailboxCreationId, jsObject: JsObject) => SMono.fromCallable(() => { - createMailbox(mailboxSession, mailboxCreationId, mailboxCreationRequest, processingContext) + createMailbox(mailboxSession, mailboxCreationId, jsObject, processingContext) }).subscribeOn(Schedulers.elastic()) } .collectSeq() @@ -179,9 +173,10 @@ class MailboxSetMethod @Inject()(serializer: Serializer, private def createMailbox(mailboxSession: MailboxSession, mailboxCreationId: MailboxCreationId, - mailboxCreationRequest: MailboxCreationRequest, + jsObject: JsObject, processingContext: ProcessingContext): CreationResult = { - resolvePath(mailboxSession, mailboxCreationRequest) + parseCreate(jsObject) + .flatMap(mailboxCreationRequest => resolvePath(mailboxSession, mailboxCreationRequest)) .map(path => createMailbox(mailboxSession, mailboxCreationId, processingContext, path)) .fold(e => CreationFailure(mailboxCreationId, e), r => r) } @@ -229,8 +224,8 @@ class MailboxSetMethod @Inject()(serializer: Serializer, } private def createResponse(invocation: Invocation, mailboxSetRequest: MailboxSetRequest, - unparsableCreateRequests: immutable.Iterable[(MailboxCreationId, MailboxSetError)], - creationResults: CreationResults, deletionResults: DeletionResults): Invocation = { + creationResults: CreationResults, + deletionResults: DeletionResults): Invocation = { val created: Map[MailboxCreationId, MailboxId] = creationResults.retrieveCreated Invocation(methodName, Arguments(serializer.serialize(MailboxSetResponse( @@ -251,7 +246,7 @@ class MailboxSetMethod @Inject()(serializer: Serializer, quotas = None, isSubscribed = IsSubscribed(true) )))).filter(_.nonEmpty), - notCreated = Some(unparsableCreateRequests.toMap ++ creationResults.retrieveErrors).filter(_.nonEmpty), + notCreated = Some(creationResults.retrieveErrors).filter(_.nonEmpty), updated = None, notUpdated = None, notDestroyed = Some(deletionResults.retrieveErrors).filter(_.nonEmpty) --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org