You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2021/11/10 07:54:58 UTC
[james-project] 01/02: JAMES-3539 Add PushSubscription/set update
expires method
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 6cf241938fcc4c838bba3a21185463d9db6c02f9
Author: Quan Tran <hq...@linagora.com>
AuthorDate: Tue Nov 2 11:51:36 2021 +0700
JAMES-3539 Add PushSubscription/set update expires method
---
.../james/jmap/api/model/PushSubscription.scala | 6 +-
.../PushSubscriptionSetMethodContract.scala | 248 ++++++++++++++++++++-
.../james/jmap/core/PushSubscriptionSet.scala | 41 +++-
.../jmap/json/PushSubscriptionSerializer.scala | 2 +-
.../PushSubscriptionSetCreatePerformer.scala | 5 +-
.../method/PushSubscriptionUpdatePerformer.scala | 22 +-
6 files changed, 303 insertions(+), 21 deletions(-)
diff --git a/server/data/data-jmap/src/main/scala/org/apache/james/jmap/api/model/PushSubscription.scala b/server/data/data-jmap/src/main/scala/org/apache/james/jmap/api/model/PushSubscription.scala
index 63a4108..69d4f77 100644
--- a/server/data/data-jmap/src/main/scala/org/apache/james/jmap/api/model/PushSubscription.scala
+++ b/server/data/data-jmap/src/main/scala/org/apache/james/jmap/api/model/PushSubscription.scala
@@ -150,7 +150,7 @@ case class PushSubscriptionNotFoundException(id: PushSubscriptionId) extends Run
object ExpireTimeInvalidException {
val TIME_FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssX")
}
-case class ExpireTimeInvalidException(expires: ZonedDateTime, message: String) extends RuntimeException(s"`${expires.format(TIME_FORMATTER)}` $message")
+case class ExpireTimeInvalidException(expires: ZonedDateTime, message: String) extends IllegalStateException(s"`${expires.format(TIME_FORMATTER)}` $message")
-case class DeviceClientIdInvalidException(deviceClientId: DeviceClientId, message: String) extends RuntimeException(s"`${deviceClientId.value}` $message")
-case class InvalidPushSubscriptionKeys(keys: PushSubscriptionKeys) extends RuntimeException
\ No newline at end of file
+case class DeviceClientIdInvalidException(deviceClientId: DeviceClientId, message: String) extends IllegalArgumentException(s"`${deviceClientId.value}` $message")
+case class InvalidPushSubscriptionKeys(keys: PushSubscriptionKeys) extends IllegalArgumentException
\ No newline at end of file
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/PushSubscriptionSetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/PushSubscriptionSetMethodContract.scala
index 03d3aa8..ac5a01d 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/PushSubscriptionSetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/PushSubscriptionSetMethodContract.scala
@@ -1109,7 +1109,8 @@ trait PushSubscriptionSetMethodContract {
| "notCreated": {
| "4f29": {
| "type": "invalidArguments",
- | "description": "`$invalidExpire` expires must be greater than now"
+ | "description": "`$invalidExpire` expires must be greater than now",
+ | "properties": ["expires"]
| }
| }
| },
@@ -1814,6 +1815,251 @@ trait PushSubscriptionSetMethodContract {
}
@Test
+ def updateValidExpiresShouldSucceed(server: GuiceJamesServer): Unit = {
+ val probe = server.getProbe(classOf[PushSubscriptionProbe])
+ val pushSubscription = probe
+ .createPushSubscription(username = BOB,
+ url = PushSubscriptionServerURL(new URL("https://example.com/push/?device=X8980fc&client=12c6d086")),
+ deviceId = DeviceClientId("12c6d086"),
+ types = Seq(MailboxTypeName, EmailDeliveryTypeName, EmailTypeName))
+
+ val validExpiresString = UTCDate(ZonedDateTime.now().plusDays(1)).asUTC.format(TIME_FORMATTER)
+ val request: String =
+ s"""{
+ | "using": ["urn:ietf:params:jmap:core"],
+ | "methodCalls": [
+ | [
+ | "PushSubscription/set",
+ | {
+ | "update": {
+ | "${pushSubscription.id.serialise}": {
+ | "expires": "$validExpiresString"
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ | }""".stripMargin
+
+ val response: String = `given`
+ .body(request)
+ .when
+ .post
+ .`then`
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response)
+ .isEqualTo(
+ s"""{
+ | "sessionState": "${SESSION_STATE.value}",
+ | "methodResponses": [
+ | [
+ | "PushSubscription/set",
+ | {
+ | "updated": {
+ | "${pushSubscription.id.serialise}": {}
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}""".stripMargin)
+
+ assertThat(probe.retrievePushSubscription(BOB, pushSubscription.id)
+ .expires.value.format(TIME_FORMATTER))
+ .isEqualTo(validExpiresString)
+ }
+
+ @Test
+ def updateInvalidExpiresStringShouldFail(server: GuiceJamesServer): Unit = {
+ val probe = server.getProbe(classOf[PushSubscriptionProbe])
+ val pushSubscription = probe
+ .createPushSubscription(username = BOB,
+ url = PushSubscriptionServerURL(new URL("https://example.com/push/?device=X8980fc&client=12c6d086")),
+ deviceId = DeviceClientId("12c6d086"),
+ types = Seq(MailboxTypeName, EmailDeliveryTypeName, EmailTypeName))
+
+ val invalidExpiresString = "whatever"
+ val request: String =
+ s"""{
+ | "using": ["urn:ietf:params:jmap:core"],
+ | "methodCalls": [
+ | [
+ | "PushSubscription/set",
+ | {
+ | "update": {
+ | "${pushSubscription.id.serialise}": {
+ | "expires": "$invalidExpiresString"
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ | }""".stripMargin
+
+ val response: String = `given`
+ .body(request)
+ .when
+ .post
+ .`then`
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response)
+ .isEqualTo(
+ s"""{
+ | "sessionState": "${SESSION_STATE.value}",
+ | "methodResponses": [
+ | [
+ | "PushSubscription/set",
+ | {
+ | "notUpdated": {
+ | "${pushSubscription.id.serialise}": {
+ | "type": "invalidArguments",
+ | "description": "This string can not be parsed to UTCDate",
+ | "properties": ["expires"]
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
+ def updateWithBiggerExpiresThanServerLimitShouldSetToServerLimitAndExplicitlyReturned(server: GuiceJamesServer): Unit = {
+ val probe = server.getProbe(classOf[PushSubscriptionProbe])
+ val pushSubscription = probe
+ .createPushSubscription(username = BOB,
+ url = PushSubscriptionServerURL(new URL("https://example.com/push/?device=X8980fc&client=12c6d086")),
+ deviceId = DeviceClientId("12c6d086"),
+ types = Seq(MailboxTypeName, EmailDeliveryTypeName, EmailTypeName))
+
+ val biggerExpiresString = UTCDate(ZonedDateTime.now().plusDays(10)).asUTC.format(TIME_FORMATTER)
+ val request: String =
+ s"""{
+ | "using": ["urn:ietf:params:jmap:core"],
+ | "methodCalls": [
+ | [
+ | "PushSubscription/set",
+ | {
+ | "update": {
+ | "${pushSubscription.id.serialise}": {
+ | "expires": "$biggerExpiresString"
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ | }""".stripMargin
+
+ val response: String = `given`
+ .body(request)
+ .when
+ .post
+ .`then`
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ val fixedExpires = probe.retrievePushSubscription(BOB, pushSubscription.id)
+ .expires.value.format(TIME_FORMATTER)
+
+ assertThatJson(response)
+ .isEqualTo(
+ s"""{
+ | "sessionState": "${SESSION_STATE.value}",
+ | "methodResponses": [
+ | [
+ | "PushSubscription/set",
+ | {
+ | "updated": {
+ | "${pushSubscription.id.serialise}": {
+ | "expires": "$fixedExpires"
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
+ def updateOutdatedExpiresShouldFail(server: GuiceJamesServer): Unit = {
+ val probe = server.getProbe(classOf[PushSubscriptionProbe])
+ val pushSubscription = probe
+ .createPushSubscription(username = BOB,
+ url = PushSubscriptionServerURL(new URL("https://example.com/push/?device=X8980fc&client=12c6d086")),
+ deviceId = DeviceClientId("12c6d086"),
+ types = Seq(MailboxTypeName, EmailDeliveryTypeName, EmailTypeName))
+
+ val invalidExpiresString = UTCDate(ZonedDateTime.now().minusDays(1)).asUTC.format(TIME_FORMATTER)
+ val request: String =
+ s"""{
+ | "using": ["urn:ietf:params:jmap:core"],
+ | "methodCalls": [
+ | [
+ | "PushSubscription/set",
+ | {
+ | "update": {
+ | "${pushSubscription.id.serialise}": {
+ | "expires": "$invalidExpiresString"
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ | }""".stripMargin
+
+ val response: String = `given`
+ .body(request)
+ .when
+ .post
+ .`then`
+ .statusCode(SC_OK)
+ .contentType(JSON)
+ .extract
+ .body
+ .asString
+
+ assertThatJson(response)
+ .isEqualTo(
+ s"""{
+ | "sessionState": "${SESSION_STATE.value}",
+ | "methodResponses": [
+ | [
+ | "PushSubscription/set",
+ | {
+ | "notUpdated": {
+ | "${pushSubscription.id.serialise}": {
+ | "type": "invalidArguments",
+ | "description": "`$invalidExpiresString` expires must be greater than now",
+ | "properties": ["expires"]
+ | }
+ | }
+ | },
+ | "c1"
+ | ]
+ | ]
+ |}""".stripMargin)
+ }
+
+ @Test
def updateShouldFailWhenUnknownProperty(server: GuiceJamesServer): Unit = {
val probe = server.getProbe(classOf[PushSubscriptionProbe])
val pushSubscription = probe
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/PushSubscriptionSet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/PushSubscriptionSet.scala
index 1b4fcd5..cef464d 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/PushSubscriptionSet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/PushSubscriptionSet.scala
@@ -19,6 +19,7 @@
package org.apache.james.jmap.core
+import java.time.ZonedDateTime
import java.util.UUID
import cats.implicits._
@@ -35,7 +36,7 @@ import org.apache.james.jmap.mail.{InvalidPropertyException, InvalidUpdateExcept
import org.apache.james.jmap.method.WithoutAccountId
import play.api.libs.json.{JsArray, JsObject, JsString, JsValue}
-import scala.util.Try
+import scala.util.{Failure, Success, Try}
case class PushSubscriptionSetRequest(create: Option[Map[PushSubscriptionCreationId, JsObject]],
update: Option[Map[UnparsedPushSubscriptionId, PushSubscriptionPatchObject]],
@@ -57,11 +58,7 @@ case class UnparsedPushSubscriptionId(id: Id) {
}).map(uuid => PushSubscriptionId(uuid))
}
-object PushSubscriptionUpdateResponse {
- def empty: PushSubscriptionUpdateResponse = PushSubscriptionUpdateResponse(JsObject(Map[String, JsValue]()))
-}
-
-case class PushSubscriptionUpdateResponse(value: JsObject)
+case class PushSubscriptionUpdateResponse(expires: Option[UTCDate])
object PushSubscriptionPatchObject {
type KeyConstraint = NonEmpty
@@ -80,6 +77,7 @@ case class PushSubscriptionPatchObject(value: Map[String, JsValue]) {
case (property, newValue) => property match {
case "verificationCode" => VerificationCodeUpdate.parse(newValue)
case "types" => TypesUpdate.parse(newValue, typeStateFactory)
+ case "expires" => ExpiresUpdate.parse(newValue)
case property => PushSubscriptionPatchObject.notFound(property)
}
})
@@ -98,6 +96,12 @@ case class PushSubscriptionPatchObject(value: Map[String, JsValue]) {
case _ => None
}).headOption
+ val expiresUpdate: Option[ExpiresUpdate] = updates
+ .flatMap(x => x match {
+ case Right(ExpiresUpdate(newExpires)) => Some(ExpiresUpdate(newExpires))
+ case _ => None
+ }).headOption
+
val typesUpdate: Option[TypesUpdate] = updates
.flatMap(x => x match {
case Right(TypesUpdate(newTypes)) => Some(TypesUpdate(newTypes))
@@ -108,7 +112,8 @@ case class PushSubscriptionPatchObject(value: Map[String, JsValue]) {
.map(e => Left(e))
.getOrElse(scala.Right(ValidatedPushSubscriptionPatchObject(
verificationCodeUpdate = verificationCodeUpdate.map(_.newVerificationCode),
- typesUpdate = typesUpdate.map(_.types))))
+ typesUpdate = typesUpdate.map(_.types),
+ expiresUpdate = expiresUpdate.map(expiresUpdate => PushSubscriptionExpiredTime(expiresUpdate.newExpires.asUTC)))))
}
}
@@ -134,22 +139,38 @@ object TypesUpdate {
}
}
+object ExpiresUpdate {
+ def parse(jsValue: JsValue): Either[PatchUpdateValidationException, Update] = jsValue match {
+ case JsString(aString) => toZonedDateTime(aString) match {
+ case Success(value) => Right(ExpiresUpdate(UTCDate(value)))
+ case Failure(e) => Left(InvalidUpdateException("expires", "This string can not be parsed to UTCDate"))
+ }
+ case _ => Left(InvalidUpdateException("expires", "Expecting a JSON string as an argument"))
+ }
+
+ private def toZonedDateTime(string: String): Try[ZonedDateTime] = Try(ZonedDateTime.parse(string))
+}
+
sealed trait Update
case class VerificationCodeUpdate(newVerificationCode: VerificationCode) extends Update
case class TypesUpdate(types: Set[TypeName]) extends Update
+case class ExpiresUpdate(newExpires: UTCDate) extends Update
object ValidatedPushSubscriptionPatchObject {
val verificationCodeProperty: NonEmptyString = "verificationCode"
val typesProperty: NonEmptyString = "types"
+ val expiresUpdate: NonEmptyString = "expires"
}
case class ValidatedPushSubscriptionPatchObject(verificationCodeUpdate: Option[VerificationCode],
- typesUpdate: Option[Set[TypeName]]) {
- val shouldUpdate: Boolean = verificationCodeUpdate.isDefined || typesUpdate.isDefined
+ typesUpdate: Option[Set[TypeName]],
+ expiresUpdate: Option[PushSubscriptionExpiredTime]) {
+ val shouldUpdate: Boolean = verificationCodeUpdate.isDefined || typesUpdate.isDefined || expiresUpdate.isDefined
val updatedProperties: Properties = Properties(Set(
verificationCodeUpdate.map(_ => ValidatedPushSubscriptionPatchObject.verificationCodeProperty),
- typesUpdate.map(_ => ValidatedPushSubscriptionPatchObject.typesProperty))
+ typesUpdate.map(_ => ValidatedPushSubscriptionPatchObject.typesProperty),
+ expiresUpdate.map(_ => ValidatedPushSubscriptionPatchObject.expiresUpdate))
.flatMap(_.toList))
}
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/PushSubscriptionSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/PushSubscriptionSerializer.scala
index 1e3d2a3..920290d 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/PushSubscriptionSerializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/PushSubscriptionSerializer.scala
@@ -85,7 +85,7 @@ class PushSubscriptionSerializer @Inject()(typeStateFactory: TypeStateFactory) {
private implicit val pushSubscriptionGetResponseWrites: OWrites[PushSubscriptionGetResponse] = Json.writes[PushSubscriptionGetResponse]
private implicit val pushSubscriptionCreationResponseWrites: Writes[PushSubscriptionCreationResponse] = Json.writes[PushSubscriptionCreationResponse]
- private implicit val pushSubscriptionUpdateResponseWrites: Writes[PushSubscriptionUpdateResponse] = Json.valueWrites[PushSubscriptionUpdateResponse]
+ private implicit val pushSubscriptionUpdateResponseWrites: Writes[PushSubscriptionUpdateResponse] = Json.writes[PushSubscriptionUpdateResponse]
private implicit val pushSubscriptionMapSetErrorForCreationWrites: Writes[Map[PushSubscriptionCreationId, SetError]] =
mapWrites[PushSubscriptionCreationId, SetError](_.serialise, setErrorWrites)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/PushSubscriptionSetCreatePerformer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/PushSubscriptionSetCreatePerformer.scala
index 4fa1e55..d1940db 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/PushSubscriptionSetCreatePerformer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/PushSubscriptionSetCreatePerformer.scala
@@ -2,11 +2,12 @@ package org.apache.james.jmap.method
import java.nio.charset.StandardCharsets
+import eu.timepit.refined.auto._
import javax.inject.Inject
import org.apache.james.jmap.api.model.{DeviceClientIdInvalidException, ExpireTimeInvalidException, PushSubscriptionCreationRequest, PushSubscriptionExpiredTime, PushSubscriptionId, PushSubscriptionKeys, PushSubscriptionServerURL, VerificationCode}
import org.apache.james.jmap.api.pushsubscription.PushSubscriptionRepository
import org.apache.james.jmap.core.SetError.SetErrorDescription
-import org.apache.james.jmap.core.{PushSubscriptionCreation, PushSubscriptionCreationId, PushSubscriptionCreationParseException, PushSubscriptionCreationResponse, PushSubscriptionSetRequest, SetError}
+import org.apache.james.jmap.core.{Properties, PushSubscriptionCreation, PushSubscriptionCreationId, PushSubscriptionCreationParseException, PushSubscriptionCreationResponse, PushSubscriptionSetRequest, SetError}
import org.apache.james.jmap.json.{PushSerializer, PushSubscriptionSerializer}
import org.apache.james.jmap.method.PushSubscriptionSetCreatePerformer.{CreationFailure, CreationResult, CreationResults, CreationSuccess}
import org.apache.james.jmap.pushsubscription.{PushRequest, PushTTL, WebPushClient}
@@ -23,7 +24,7 @@ object PushSubscriptionSetCreatePerformer {
case class CreationFailure(clientId: PushSubscriptionCreationId, e: Throwable) extends CreationResult {
def asMessageSetError: SetError = e match {
case e: PushSubscriptionCreationParseException => e.setError
- case e: ExpireTimeInvalidException => SetError.invalidArguments(SetErrorDescription(e.getMessage))
+ case e: ExpireTimeInvalidException => SetError.invalidArguments(SetErrorDescription(e.getMessage), Some(Properties("expires")))
case e: DeviceClientIdInvalidException => SetError.invalidArguments(SetErrorDescription(e.getMessage))
case e: IllegalArgumentException => SetError.invalidArguments(SetErrorDescription(e.getMessage))
case _ => SetError.serverFail(SetErrorDescription(e.getMessage))
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/PushSubscriptionUpdatePerformer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/PushSubscriptionUpdatePerformer.scala
index f3a42e5..49fd7e6 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/PushSubscriptionUpdatePerformer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/PushSubscriptionUpdatePerformer.scala
@@ -23,10 +23,10 @@ import com.google.common.collect.ImmutableSet
import eu.timepit.refined.auto._
import javax.inject.Inject
import org.apache.james.jmap.api.change.TypeStateFactory
-import org.apache.james.jmap.api.model.{PushSubscription, PushSubscriptionId, PushSubscriptionNotFoundException, TypeName, VerificationCode}
+import org.apache.james.jmap.api.model.{ExpireTimeInvalidException, PushSubscription, PushSubscriptionExpiredTime, PushSubscriptionId, PushSubscriptionNotFoundException, TypeName, VerificationCode}
import org.apache.james.jmap.api.pushsubscription.PushSubscriptionRepository
import org.apache.james.jmap.core.SetError.SetErrorDescription
-import org.apache.james.jmap.core.{Properties, PushSubscriptionPatchObject, PushSubscriptionSetRequest, PushSubscriptionUpdateResponse, SetError, UnparsedPushSubscriptionId, ValidatedPushSubscriptionPatchObject}
+import org.apache.james.jmap.core.{Properties, PushSubscriptionPatchObject, PushSubscriptionSetRequest, PushSubscriptionUpdateResponse, SetError, UTCDate, UnparsedPushSubscriptionId, ValidatedPushSubscriptionPatchObject}
import org.apache.james.jmap.mail.{InvalidPropertyException, InvalidUpdateException, UnsupportedPropertyUpdatedException}
import org.apache.james.jmap.method.PushSubscriptionSetUpdatePerformer.{PushSubscriptionUpdateFailure, PushSubscriptionUpdateResult, PushSubscriptionUpdateResults, PushSubscriptionUpdateSuccess, WrongVerificationCodeException}
import org.apache.james.mailbox.MailboxSession
@@ -37,7 +37,7 @@ import scala.jdk.CollectionConverters._
object PushSubscriptionSetUpdatePerformer {
case class WrongVerificationCodeException() extends RuntimeException()
sealed trait PushSubscriptionUpdateResult
- case class PushSubscriptionUpdateSuccess(id: PushSubscriptionId) extends PushSubscriptionUpdateResult
+ case class PushSubscriptionUpdateSuccess(id: PushSubscriptionId, serverExpires: Option[UTCDate] = None) extends PushSubscriptionUpdateResult
case class PushSubscriptionUpdateFailure(id: UnparsedPushSubscriptionId, exception: Throwable) extends PushSubscriptionUpdateResult {
def asSetError: SetError = exception match {
case _: WrongVerificationCodeException => SetError.invalidProperties(SetErrorDescription("Wrong verification code"), Some(Properties("verificationCode")))
@@ -46,13 +46,14 @@ object PushSubscriptionSetUpdatePerformer {
case e: InvalidUpdateException => SetError.invalidArguments(SetErrorDescription(s"${e.cause}"), Some(Properties(e.property)))
case e: IllegalArgumentException => SetError.invalidArguments(SetErrorDescription(e.getMessage), None)
case e: PushSubscriptionNotFoundException => SetError.notFound(SetErrorDescription(e.getMessage))
+ case e: ExpireTimeInvalidException => SetError.invalidArguments(SetErrorDescription(e.getMessage), Some(Properties("expires")))
case _ => SetError.serverFail(SetErrorDescription(exception.getMessage))
}
}
case class PushSubscriptionUpdateResults(results: Seq[PushSubscriptionUpdateResult]) {
def updated: Map[PushSubscriptionId, PushSubscriptionUpdateResponse] =
results.flatMap(result => result match {
- case success: PushSubscriptionUpdateSuccess => Some((success.id, PushSubscriptionUpdateResponse.empty))
+ case success: PushSubscriptionUpdateSuccess => Some((success.id, PushSubscriptionUpdateResponse(success.serverExpires)))
case _ => None
}).toMap
def notUpdated: Map[UnparsedPushSubscriptionId, SetError] = results.flatMap(result => result match {
@@ -94,6 +95,9 @@ class PushSubscriptionUpdatePerformer @Inject()(pushSubscriptionRepository: Push
.getOrElse(SMono.empty),
validatedPatch.typesUpdate
.map(types => updateTypes(pushSubscription, types, mailboxSession))
+ .getOrElse(SMono.empty),
+ validatedPatch.expiresUpdate
+ .map(expires => updateExpires(pushSubscription, expires, mailboxSession))
.getOrElse(SMono.empty))
.last())
} else {
@@ -111,4 +115,14 @@ class PushSubscriptionUpdatePerformer @Inject()(pushSubscriptionRepository: Push
private def updateTypes(pushSubscription: PushSubscription, types: Set[TypeName], mailboxSession: MailboxSession): SMono[PushSubscriptionUpdateResult] =
SMono(pushSubscriptionRepository.updateTypes(mailboxSession.getUser, pushSubscription.id, types.asJava))
.`then`(SMono.just(PushSubscriptionUpdateSuccess(pushSubscription.id)))
+
+ private def updateExpires(pushSubscription: PushSubscription, inputExpires: PushSubscriptionExpiredTime, mailboxSession: MailboxSession): SMono[PushSubscriptionUpdateResult] =
+ SMono(pushSubscriptionRepository.updateExpireTime(mailboxSession.getUser, pushSubscription.id, inputExpires.value))
+ .map(toPushSubscriptionUpdate(pushSubscription, inputExpires, _))
+
+ private def toPushSubscriptionUpdate(pushSubscription: PushSubscription, inputExpires: PushSubscriptionExpiredTime, updatedExpires: PushSubscriptionExpiredTime): PushSubscriptionUpdateResult =
+ PushSubscriptionUpdateSuccess(pushSubscription.id, Some(updatedExpires)
+ .filter(updatedExpires => !updatedExpires.equals(inputExpires))
+ .map(_.value)
+ .map(UTCDate(_)))
}
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org