From 49cda2524a2537cb9330af488ca9c30e435f5849 Mon Sep 17 00:00:00 2001 From: kseniya Date: Fri, 22 Sep 2017 18:09:32 +0700 Subject: Added create and delete endpoint to intervention service --- .../json/intervention/ApiPartialIntervention.scala | 50 +++++++++++++++++++--- .../pdsuidomain/services/InterventionService.scala | 36 ++++++++++++++++ .../services/rest/RestInterventionService.scala | 23 +++++++++- 3 files changed, 103 insertions(+), 6 deletions(-) diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiPartialIntervention.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiPartialIntervention.scala index aa55506..09e0b23 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiPartialIntervention.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiPartialIntervention.scala @@ -1,11 +1,19 @@ package xyz.driver.pdsuidomain.formats.json.intervention -import xyz.driver.pdsuicommon.domain.LongId -import xyz.driver.pdsuidomain.entities.{InterventionArm, InterventionWithArms} +import play.api.data.validation.Invalid +import xyz.driver.pdsuicommon.domain.{LongId, StringId} +import xyz.driver.pdsuidomain.entities.{Intervention, InterventionArm, InterventionWithArms, Trial} import play.api.libs.functional.syntax._ import play.api.libs.json._ +import xyz.driver.pdsuicommon.json.JsonValidationException +import xyz.driver.pdsuicommon.validation.{AdditionalConstraints, JsonValidationErrors} -final case class ApiPartialIntervention(typeId: Option[Long], +import scala.collection.breakOut +import scala.util.Try + +final case class ApiPartialIntervention(name: Option[String], + trialId: Option[String], + typeId: Option[Long], dosage: Option[String], isActive: Option[Boolean], arms: Option[List[Long]]) { @@ -22,19 +30,51 @@ final case class ApiPartialIntervention(typeId: Option[Long], arms = draftArmList.getOrElse(orig.arms) ) } + + //TODO: need to discuss + def toDomain: Try[InterventionWithArms] = Try { + val validation = Map(JsPath \ "trialId" -> AdditionalConstraints.optionNonEmptyConstraint(trialId)) + + val validationErrors: JsonValidationErrors = validation.collect({ + case (fieldName, e: Invalid) => (fieldName, e.errors) + })(breakOut) + + if (validationErrors.isEmpty) { + InterventionWithArms( + intervention = Intervention( + id = LongId(0), + trialId = trialId.map(StringId[Trial]).get, + name = name.getOrElse(""), + originalName = name.getOrElse(""), + typeId = typeId.map(LongId(_)), + originalType = Option(""), + dosage = dosage.getOrElse(""), + originalDosage = dosage.getOrElse(""), + isActive = isActive.getOrElse(false) + ), + arms = arms.map(_.map(x => InterventionArm(LongId(x), LongId(0)))).getOrElse(List.empty) + ) + } else { + throw new JsonValidationException(validationErrors) + } + } } object ApiPartialIntervention { private val reads: Reads[ApiPartialIntervention] = ( - (JsPath \ "typeId").readNullable[Long] and + (JsPath \ "name").readNullable[String] and + (JsPath \ "trialId").readNullable[String] and + (JsPath \ "typeId").readNullable[Long] and (JsPath \ "dosage").readNullable[String] and (JsPath \ "isActive").readNullable[Boolean] and (JsPath \ "arms").readNullable[List[Long]] )(ApiPartialIntervention.apply _) private val writes: Writes[ApiPartialIntervention] = ( - (JsPath \ "typeId").writeNullable[Long] and + (JsPath \ "name").writeNullable[String] and + (JsPath \ "trialId").writeNullable[String] and + (JsPath \ "typeId").writeNullable[Long] and (JsPath \ "dosage").writeNullable[String] and (JsPath \ "isActive").writeNullable[Boolean] and (JsPath \ "arms").writeNullable[List[Long]] diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala index 439e456..1e7c7f1 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala @@ -61,6 +61,37 @@ object InterventionService { final case class CommonError(userMessage: String) extends UpdateReply with DomainError } + sealed trait CreateReply + object CreateReply { + final case class Created(x: InterventionWithArms) extends CreateReply + + type Error = CreateReply with DomainError + + case object AuthorizationError + extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + + final case class CommonError(userMessage: String) extends CreateReply with DomainError + + implicit def toPhiString(reply: CreateReply): PhiString = reply match { + case Created(x) => phi"Created($x)" + case x: Error => DomainError.toPhiString(x) + } + } + + sealed trait DeleteReply + object DeleteReply { + case object Deleted extends DeleteReply + + type Error = DeleteReply with DomainError + + case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError + + case object AuthorizationError + extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError + + final case class CommonError(userMessage: String) extends DeleteReply with DomainError + } + } trait InterventionService { @@ -76,4 +107,9 @@ trait InterventionService { def update(origIntervention: InterventionWithArms, draftIntervention: InterventionWithArms)( implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + + def create(draftIntervention: InterventionWithArms)( + implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] + + def delete(id: LongId[Intervention])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionService.scala index e593c3b..025a48a 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionService.scala @@ -1,7 +1,6 @@ package xyz.driver.pdsuidomain.services.rest import scala.concurrent.{ExecutionContext, Future} - import akka.http.scaladsl.marshalling.Marshal import akka.http.scaladsl.model._ import akka.stream.Materializer @@ -61,4 +60,26 @@ class RestInterventionService(transport: ServiceTransport, baseUri: Uri)( } } + def create(draftIntervention: InterventionWithArms)( + implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] = { + for { + entity <- Marshal(ApiIntervention.fromDomain(draftIntervention)).to[RequestEntity] + request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/intervention")).withEntity(entity) + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiIntervention](response) + } yield { + CreateReply.Created(reply.toDomain) + } + } + + def delete(id: LongId[Intervention])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] = { + val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/intervention/$id")) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + _ <- apiResponse[HttpEntity](response) + } yield { + DeleteReply.Deleted + } + } + } -- cgit v1.2.3