diff options
Diffstat (limited to 'src/main/scala/xyz/driver/pdsuidomain/services/rest')
9 files changed, 641 insertions, 0 deletions
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestArmService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestArmService.scala new file mode 100644 index 0000000..0a29c08 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestArmService.scala @@ -0,0 +1,81 @@ +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.ActorMaterializer +import xyz.driver.core.rest.{Pagination => _, _} +import xyz.driver.pdsuicommon.auth._ +import xyz.driver.pdsuicommon.db._ +import xyz.driver.pdsuicommon.domain._ +import xyz.driver.pdsuidomain.entities._ +import xyz.driver.pdsuidomain.formats.json.ListResponse +import xyz.driver.pdsuidomain.formats.json.arm.ApiArm +import xyz.driver.pdsuidomain.services.ArmService + +class RestArmService(transport: ServiceTransport, baseUri: Uri)(implicit protected val materializer: ActorMaterializer, + protected val exec: ExecutionContext) + extends ArmService with RestHelper { + + import xyz.driver.pdsuicommon.serialization.PlayJsonSupport._ + import xyz.driver.pdsuidomain.services.ArmService._ + + def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Option[Sorting] = None, + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] = { + val request = HttpRequest( + HttpMethods.GET, + endpointUri(baseUri, "/v1/arm", filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ListResponse[ApiArm]](response) + } yield { + GetListReply.EntityList(reply.items.map(_.toDomain), reply.meta.itemsCount) + } + } + + def getById(armId: LongId[Arm])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] = { + val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/arm/$armId")) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiArm](response) + } yield { + GetByIdReply.Entity(reply.toDomain) + } + } + + def create(draftArm: Arm)(implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] = { + for { + entity <- Marshal(ApiArm.fromDomain(draftArm)).to[RequestEntity] + request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/arm")).withEntity(entity) + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiArm](response) + } yield { + CreateReply.Created(reply.toDomain) + } + } + + def update(origArm: Arm, draftArm: Arm)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = { + val id = origArm.id + val request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/arm/$id")) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiArm](response) + } yield { + UpdateReply.Updated(reply.toDomain) + } + } + + def delete(id: LongId[Arm])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] = { + val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/arm/$id")) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiArm](response) + } yield { + DeleteReply.Deleted + } + } + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestCriterionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestCriterionService.scala new file mode 100644 index 0000000..7470de1 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestCriterionService.scala @@ -0,0 +1,86 @@ +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.ActorMaterializer +import xyz.driver.core.rest.{Pagination => _, _} +import xyz.driver.pdsuicommon.auth._ +import xyz.driver.pdsuicommon.db._ +import xyz.driver.pdsuicommon.domain._ +import xyz.driver.pdsuidomain.entities._ +import xyz.driver.pdsuidomain.formats.json.ListResponse +import xyz.driver.pdsuidomain.services.CriterionService + +class RestCriterionService(transport: ServiceTransport, baseUri: Uri)( + implicit protected val materializer: ActorMaterializer, + protected val exec: ExecutionContext) + extends CriterionService with RestHelper { + + import xyz.driver.pdsuicommon.serialization.PlayJsonSupport._ + import xyz.driver.pdsuidomain.formats.json.criterion.ApiCriterion + import xyz.driver.pdsuidomain.services.CriterionService._ + + def create(draftRichCriterion: RichCriterion)( + implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] = { + for { + entity <- Marshal(ApiCriterion.fromDomain(draftRichCriterion)).to[RequestEntity] + request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/criterion")).withEntity(entity) + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiCriterion](response) + } yield { + CreateReply.Created(reply.toDomain) + } + } + + def getById(id: LongId[Criterion])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] = { + val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/criterion/$id")) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiCriterion](response) + } yield { + GetByIdReply.Entity(reply.toDomain) + } + } + + def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Option[Sorting] = None, + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] = { + val request = HttpRequest(HttpMethods.GET, + endpointUri(baseUri, + s"/v1/criterion", + filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ListResponse[ApiCriterion]](response) + } yield { + GetListReply.EntityList(reply.items.map(_.toDomain), reply.meta.itemsCount, reply.meta.lastUpdate) + } + } + + def update(origRichCriterion: RichCriterion, draftRichCriterion: RichCriterion)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = { + val id = origRichCriterion.criterion.id + for { + entity <- Marshal(ApiCriterion.fromDomain(draftRichCriterion)).to[RequestEntity] + request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/criterion/$id")).withEntity(entity) + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiCriterion](response) + } yield { + UpdateReply.Updated(reply.toDomain) + } + } + + def delete(id: LongId[Criterion])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] = { + val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/criterion/$id")) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiCriterion](response) + } yield { + DeleteReply.Deleted + } + } + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala new file mode 100644 index 0000000..bc886ba --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHelper.scala @@ -0,0 +1,125 @@ +package xyz.driver.pdsuidomain.services.rest + +import scala.concurrent.{ExecutionContext, Future} + +import akka.http.scaladsl.model.{HttpResponse, ResponseEntity, StatusCodes, Uri} +import akka.http.scaladsl.unmarshalling.{Unmarshal, Unmarshaller} +import akka.stream.Materializer +import xyz.driver.core.rest.ServiceRequestContext +import xyz.driver.pdsuicommon.auth.{AnonymousRequestContext, AuthenticatedRequestContext} +import xyz.driver.pdsuicommon.db.{ + Pagination, + SearchFilterBinaryOperation, + SearchFilterExpr, + SearchFilterNAryOperation, + Sorting, + SortingOrder +} +import xyz.driver.pdsuicommon.error._ + +trait RestHelper { + + implicit protected val materializer: Materializer + implicit protected val exec: ExecutionContext + + protected def endpointUri(baseUri: Uri, path: String) = + baseUri.withPath(Uri.Path(path)) + + protected def endpointUri(baseUri: Uri, path: String, query: Seq[(String, String)]) = + baseUri.withPath(Uri.Path(path)).withQuery(Uri.Query(query: _*)) + + def sortingQuery(sorting: Option[Sorting]): Seq[(String, String)] = { + def dimensionQuery(dimension: Sorting.Dimension) = { + val ord = dimension.order match { + case SortingOrder.Ascending => "" + case SortingOrder.Descending => "-" + } + s"$ord${dimension.name}" + } + + sorting match { + case None => Seq.empty + case Some(dimension: Sorting.Dimension) => Seq("sort" -> dimensionQuery(dimension)) + case Some(Sorting.Sequential(dimensions)) => Seq("sort" -> dimensions.map(dimensionQuery).mkString(",")) + } + } + + def filterQuery(expr: SearchFilterExpr): Seq[(String, String)] = { + def opToString(op: SearchFilterBinaryOperation) = op match { + case SearchFilterBinaryOperation.Eq => "eq" + case SearchFilterBinaryOperation.NotEq => "ne" + case SearchFilterBinaryOperation.Like => "like" + case SearchFilterBinaryOperation.Gt => "gt" + case SearchFilterBinaryOperation.GtEq => "ge" + case SearchFilterBinaryOperation.Lt => "lt" + case SearchFilterBinaryOperation.LtEq => "le" + } + + def exprToQuery(expr: SearchFilterExpr): Seq[(String, String)] = expr match { + case SearchFilterExpr.Empty => Seq.empty + case SearchFilterExpr.Atom.Binary(dimension, op, value) => + Seq("filters" -> s"${dimension.name} ${opToString(op)} $value") + case SearchFilterExpr.Atom.NAry(dimension, SearchFilterNAryOperation.In, values) => + Seq("filters" -> s"${dimension.name} in ${values.mkString(",")}") + case SearchFilterExpr.Intersection(ops) => + ops.flatMap(op => exprToQuery(op)) + case expr => sys.error(s"No parser available for filter expression $expr.") + } + + exprToQuery(expr) + } + + def paginationQuery(pagination: Option[Pagination]): Seq[(String, String)] = pagination match { + case None => Seq.empty + case Some(pp) => + Seq( + "pageNumber" -> pp.pageNumber.toString, + "pageSize" -> pp.pageSize.toString + ) + } + + /** Utility method to parse responses from records-acquisition-server. + * + * Non-2xx HTTP error codes will be cause the returned future to fail with a corresponding + * `DomainException`. + * @tparam ApiReply The type of the serialized reply object, contained in the HTTP entity + * @param response The HTTP response to parse. + * @param unmarshaller An unmarshaller that converts a successful response to an api reply. + */ + def apiResponse[ApiReply](response: HttpResponse)( + implicit unmarshaller: Unmarshaller[ResponseEntity, ApiReply]): Future[ApiReply] = { + + def extractErrorMessage(response: HttpResponse): Future[String] = { + import xyz.driver.pdsuicommon.serialization.PlayJsonSupport._ + Unmarshal(response.entity) + .to[ErrorsResponse] + .transform( + response => response.errors.map(_.message).mkString(", "), + ex => new DomainException("Response has invalid format", ex) + ) + } + + if (response.status.isSuccess) { + Unmarshal(response.entity).to[ApiReply] + } else { + extractErrorMessage(response).flatMap { message => + Future.failed(response.status match { + case StatusCodes.Unauthorized => new AuthenticationException(message) + case StatusCodes.Forbidden => new AuthorizationException(message) + case StatusCodes.NotFound => new NotFoundException(message) + case other => + new DomainException(s"Unhandled domain error for HTTP status ${other.value}. ${message}") + }) + } + } + } + + implicit def toServiceRequestContext(requestContext: AnonymousRequestContext): ServiceRequestContext = { + val auth: Map[String, String] = requestContext match { + case ctx: AuthenticatedRequestContext => Map("Auth-token" -> ctx.authToken) + case _ => Map() + } + new ServiceRequestContext(contextHeaders = auth) + } + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala new file mode 100644 index 0000000..37b28ae --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestHypothesisService.scala @@ -0,0 +1,33 @@ +package xyz.driver.pdsuidomain.services.rest + +import scala.concurrent.{ExecutionContext, Future} + +import akka.http.scaladsl.model._ +import akka.stream.ActorMaterializer +import xyz.driver.core.rest._ +import xyz.driver.pdsuicommon.auth._ +import xyz.driver.pdsuicommon.db._ +import xyz.driver.pdsuidomain.formats.json.ListResponse +import xyz.driver.pdsuidomain.formats.json.hypothesis.ApiHypothesis +import xyz.driver.pdsuidomain.services.HypothesisService + +class RestHypothesisService(transport: ServiceTransport, baseUri: Uri)( + implicit protected val materializer: ActorMaterializer, + protected val exec: ExecutionContext) + extends HypothesisService with RestHelper { + + import xyz.driver.pdsuicommon.serialization.PlayJsonSupport._ + import xyz.driver.pdsuidomain.services.HypothesisService._ + + def getAll(sorting: Option[Sorting] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] = { + val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, "/v1/hypothesis", sortingQuery(sorting))) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ListResponse[ApiHypothesis]](response) + } yield { + GetListReply.EntityList(reply.items.map(_.toDomain), reply.meta.itemsCount) + } + } + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionService.scala new file mode 100644 index 0000000..aa59657 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionService.scala @@ -0,0 +1,64 @@ +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.ActorMaterializer +import xyz.driver.core.rest.{Pagination => _, _} +import xyz.driver.pdsuicommon.auth._ +import xyz.driver.pdsuicommon.db._ +import xyz.driver.pdsuicommon.domain._ +import xyz.driver.pdsuidomain.entities._ +import xyz.driver.pdsuidomain.formats.json.ListResponse +import xyz.driver.pdsuidomain.formats.json.intervention.ApiIntervention +import xyz.driver.pdsuidomain.services.InterventionService + +class RestInterventionService(transport: ServiceTransport, baseUri: Uri)( + implicit protected val materializer: ActorMaterializer, + protected val exec: ExecutionContext) + extends InterventionService with RestHelper { + + import xyz.driver.pdsuicommon.serialization.PlayJsonSupport._ + import xyz.driver.pdsuidomain.services.InterventionService._ + + def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Option[Sorting] = None, + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] = { + val request = HttpRequest(HttpMethods.GET, + endpointUri(baseUri, + "/v1/intervention", + filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ListResponse[ApiIntervention]](response) + } yield { + GetListReply.EntityList(reply.items.map(_.toDomain), reply.meta.itemsCount) + } + } + + def getById(id: LongId[Intervention])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] = { + val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/intervention/$id")) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiIntervention](response) + } yield { + GetByIdReply.Entity(reply.toDomain) + } + } + + def update(origIntervention: InterventionWithArms, draftIntervention: InterventionWithArms)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = { + val id = origIntervention.intervention.id + for { + entity <- Marshal(ApiIntervention.fromDomain(draftIntervention)).to[RequestEntity] + request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/intervention/$id")).withEntity(entity) + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiIntervention](response) + } yield { + UpdateReply.Updated(reply.toDomain) + } + } + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionTypeService.scala new file mode 100644 index 0000000..fad2841 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestInterventionTypeService.scala @@ -0,0 +1,36 @@ +package xyz.driver.pdsuidomain.services.rest + +import scala.concurrent.{ExecutionContext, Future} + +import akka.http.scaladsl.model._ +import akka.stream.ActorMaterializer +import xyz.driver.core.rest._ +import xyz.driver.pdsuicommon.auth._ +import xyz.driver.pdsuicommon.db._ +import xyz.driver.pdsuidomain.formats.json.intervention.ApiInterventionType +import xyz.driver.pdsuidomain.services.InterventionTypeService + +class RestInterventionTypeService(transport: ServiceTransport, baseUri: Uri)( + implicit protected val materializer: ActorMaterializer, + protected val exec: ExecutionContext) + extends InterventionTypeService with RestHelper { + + import xyz.driver.pdsuicommon.serialization.PlayJsonSupport._ + import xyz.driver.pdsuidomain.formats.json.ListResponse + import xyz.driver.pdsuidomain.services.InterventionTypeService._ + + def getAll(sorting: Option[Sorting] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] = { + val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, "/v1/intervention-type", sortingQuery(sorting))) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ListResponse[ApiInterventionType]](response) + } yield { + { + val domain = reply.items.map(_.toDomain) + GetListReply.EntityList(domain.toList, reply.meta.itemsCount) + } + } + } + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestMessageService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestMessageService.scala new file mode 100644 index 0000000..1527ad5 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestMessageService.scala @@ -0,0 +1,88 @@ +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.ActorMaterializer +import xyz.driver.core.rest.{Pagination => _, _} +import xyz.driver.pdsuicommon.auth._ +import xyz.driver.pdsuicommon.db._ +import xyz.driver.pdsuicommon.domain._ +import xyz.driver.pdsuidomain.entities._ +import xyz.driver.pdsuidomain.formats.json.ListResponse +import xyz.driver.pdsuidomain.formats.json.message.ApiMessage +import xyz.driver.pdsuidomain.services.MessageService + +class RestMessageService(transport: ServiceTransport, baseUri: Uri)( + implicit protected val materializer: ActorMaterializer, + protected val exec: ExecutionContext) + extends MessageService with RestHelper { + + import xyz.driver.pdsuicommon.serialization.PlayJsonSupport._ + import xyz.driver.pdsuidomain.services.MessageService._ + + def create(draftMessage: Message)(implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] = { + for { + entity <- Marshal(ApiMessage.fromDomain(draftMessage)).to[RequestEntity] + request = HttpRequest(HttpMethods.POST, endpointUri(baseUri, "/v1/message")).withEntity(entity) + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiMessage](response) + } yield { + CreateReply.Created(reply.toDomain) + } + } + + def getById(messageId: LongId[Message])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] = { + import xyz.driver.pdsuicommon.db.SearchFilterBinaryOperation._ + import xyz.driver.pdsuicommon.db.SearchFilterExpr._ + val filter = Atom.Binary("id", Eq, messageId) + getAll(filter).map({ + case GetListReply.EntityList(messages, _, _) if messages.isEmpty => + GetByIdReply.NotFoundError + case GetListReply.EntityList(messages, _, _) => + GetByIdReply.Entity(messages.head) + case GetListReply.AuthorizationError => + GetByIdReply.AuthorizationError + }) + } + + def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Option[Sorting] = None, + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] = { + val request = HttpRequest( + HttpMethods.GET, + endpointUri(baseUri, "/v1/message", filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ListResponse[ApiMessage]](response) + } yield { + GetListReply.EntityList(reply.items.map(_.toDomain), reply.meta.itemsCount, reply.meta.lastUpdate) + } + } + + def update(origMessage: Message, draftMessage: Message)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = { + for { + entity <- Marshal(ApiMessage.fromDomain(draftMessage)).to[RequestEntity] + id = origMessage.id.id + request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/message/$id")).withEntity(entity) + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiMessage](response) + } yield { + UpdateReply.Updated(reply.toDomain) + } + } + + def delete(messageId: LongId[Message])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] = { + val request = HttpRequest(HttpMethods.DELETE, endpointUri(baseUri, s"/v1/message/${messageId.id}")) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiMessage](response) + } yield { + DeleteReply.Deleted + } + } + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestStudyDesignService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestStudyDesignService.scala new file mode 100644 index 0000000..4fba287 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestStudyDesignService.scala @@ -0,0 +1,33 @@ +package xyz.driver.pdsuidomain.services.rest + +import scala.concurrent.{ExecutionContext, Future} + +import akka.http.scaladsl.model._ +import akka.stream.ActorMaterializer +import xyz.driver.core.rest._ +import xyz.driver.pdsuicommon.auth._ +import xyz.driver.pdsuicommon.db._ +import xyz.driver.pdsuidomain.formats.json.ListResponse +import xyz.driver.pdsuidomain.formats.json.studydesign.ApiStudyDesign +import xyz.driver.pdsuidomain.services.StudyDesignService + +class RestStudyDesignService(transport: ServiceTransport, baseUri: Uri)( + implicit protected val materializer: ActorMaterializer, + protected val exec: ExecutionContext) + extends StudyDesignService with RestHelper { + + import xyz.driver.pdsuicommon.serialization.PlayJsonSupport._ + import xyz.driver.pdsuidomain.services.StudyDesignService._ + + def getAll(sorting: Option[Sorting] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] = { + val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, "/v1/study-design", sortingQuery(sorting))) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ListResponse[ApiStudyDesign]](response) + } yield { + GetListReply.EntityList(reply.items.map(_.toDomain), reply.meta.itemsCount) + } + } + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestTrialService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestTrialService.scala new file mode 100644 index 0000000..e1f9d87 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestTrialService.scala @@ -0,0 +1,95 @@ +package xyz.driver.pdsuidomain.services.rest + +import scala.NotImplementedError +import scala.concurrent.{ExecutionContext, Future} + +import akka.http.scaladsl.marshalling.Marshal +import akka.http.scaladsl.model._ +import akka.stream.ActorMaterializer +import xyz.driver.core.rest.{Pagination => _, _} +import xyz.driver.pdsuicommon.auth._ +import xyz.driver.pdsuicommon.db._ +import xyz.driver.pdsuicommon.domain._ +import xyz.driver.pdsuidomain.entities._ +import xyz.driver.pdsuidomain.formats.json.ListResponse +import xyz.driver.pdsuidomain.formats.json.trial.ApiTrial +import xyz.driver.pdsuidomain.services.TrialService + +class RestTrialService(transport: ServiceTransport, baseUri: Uri)( + implicit protected val materializer: ActorMaterializer, + protected val exec: ExecutionContext) + extends TrialService with RestHelper { + + import xyz.driver.pdsuicommon.serialization.PlayJsonSupport._ + import xyz.driver.pdsuidomain.services.TrialService._ + + def getById(id: StringId[Trial])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] = { + val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/trial/$id")) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiTrial](response) + } yield { + GetByIdReply.Entity(reply.toDomain) + } + } + + def getPdfSource(trialId: StringId[Trial])( + implicit requestContext: AuthenticatedRequestContext): Future[GetPdfSourceReply] = + Future.failed(new NotImplementedError("Streaming PDF over network is not supported.")) + + def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Option[Sorting] = None, + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] = { + val request = HttpRequest( + HttpMethods.GET, + endpointUri(baseUri, "/v1/trial", filterQuery(filter) ++ sortingQuery(sorting) ++ paginationQuery(pagination))) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ListResponse[ApiTrial]](response) + } yield { + GetListReply.EntityList(reply.items.map(_.toDomain), reply.meta.itemsCount, reply.meta.lastUpdate) + } + } + + def update(origTrial: Trial, draftTrial: Trial)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = { + val id = origTrial.id.id + for { + entity <- Marshal(ApiTrial.fromDomain(draftTrial)).to[RequestEntity] + request = HttpRequest(HttpMethods.PATCH, endpointUri(baseUri, s"/v1/trial/$id")).withEntity(entity) + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiTrial](response) + } yield { + UpdateReply.Updated(reply.toDomain) + } + } + + private def singleAction(origTrial: Trial, action: String)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = { + val id = origTrial.id.id + val request = HttpRequest(HttpMethods.GET, endpointUri(baseUri, s"/v1/trial/$id/$action")) + for { + response <- transport.sendRequestGetResponse(requestContext)(request) + reply <- apiResponse[ApiTrial](response) + } yield { + UpdateReply.Updated(reply.toDomain) + } + } + + def start(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = + singleAction(origTrial, "start") + def submit(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = + singleAction(origTrial, "submit") + def restart(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = + singleAction(origTrial, "restart") + def flag(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = + singleAction(origTrial, "flag") + def resolve(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = + singleAction(origTrial, "resolve") + def archive(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = + singleAction(origTrial, "archive") + def unassign(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] = + singleAction(origTrial, "unassign") + +} |