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 <[email protected]> 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: [email protected] For additional commands, e-mail: [email protected]
