aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/pdsuidomain/services
diff options
context:
space:
mode:
authorvlad <vlad@driver.xyz>2017-06-27 17:13:02 -0700
committervlad <vlad@driver.xyz>2017-06-27 17:13:02 -0700
commit5832f63b84d7388441d1200f2442dc1e9de0225c (patch)
tree32f63acdc920c14effc3d0d2822c05c125ad49e4 /src/main/scala/xyz/driver/pdsuidomain/services
parent9dd50590d4c8f8b9442d7c21ddd1def9dd453d5e (diff)
downloadrest-query-5832f63b84d7388441d1200f2442dc1e9de0225c.tar.gz
rest-query-5832f63b84d7388441d1200f2442dc1e9de0225c.tar.bz2
rest-query-5832f63b84d7388441d1200f2442dc1e9de0225c.zip
All PDS UI domain models, API case classes, service traits and necessary utils moved to pdsui-commonv0.1.11
Diffstat (limited to 'src/main/scala/xyz/driver/pdsuidomain/services')
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala133
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala131
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala157
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala26
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala116
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala28
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala85
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala28
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/KeywordService.scala29
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala137
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala126
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala137
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala105
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala70
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala124
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala105
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala27
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/ScrapedTrialsService.scala54
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala28
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala132
20 files changed, 1778 insertions, 0 deletions
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala
new file mode 100644
index 0000000..bc59f0c
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala
@@ -0,0 +1,133 @@
+package xyz.driver.pdsuidomain.services
+
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db._
+import xyz.driver.pdsuicommon.domain.LongId
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities.Arm
+
+import scala.concurrent.Future
+
+object ArmService {
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Arm not found"
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+
+ case class Entity(x: Arm) extends GetByIdReply
+
+ type Error = GetByIdReply with DomainError
+
+ case object NotFoundError
+ extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext)
+ extends GetByIdReply with DomainError
+
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ type Error = GetListReply with DomainError
+
+ case class EntityList(xs: Seq[Arm], totalFound: Int) extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+
+ case class Updated(updated: Arm) extends UpdateReply
+
+ type Error = UpdateReply with DomainError
+
+ case object NotFoundError
+ extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+
+ case class AlreadyExistsError(x: Arm) extends UpdateReply with DomainError {
+ val userMessage = s"The arm with such name of trial already exists."
+ }
+
+ implicit def toPhiString(reply: UpdateReply): PhiString = reply match {
+ case Updated(x) => phi"Updated($x)"
+ case x: Error => DomainError.toPhiString(x)
+ }
+ }
+
+ sealed trait CreateReply
+ object CreateReply {
+ case class Created(x: Arm) extends CreateReply
+
+ type Error = CreateReply with DomainError
+
+ case object AuthorizationError
+ extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case class CommonError(userMessage: String)
+ extends CreateReply with DomainError
+
+ case class AlreadyExistsError(x: Arm) extends CreateReply with DomainError {
+ val userMessage = s"The arm with this name of trial already exists."
+ }
+
+ 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
+
+ case class CommonError(userMessage: String)
+ extends DeleteReply with DomainError
+ }
+}
+
+trait ArmService {
+
+ import ArmService._
+
+ def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def getById(armId: LongId[Arm])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def create(draftArm: Arm)(implicit requestContext: AuthenticatedRequestContext): Future[CreateReply]
+
+ def update(origArm: Arm, draftArm: Arm)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def delete(id: LongId[Arm])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala
new file mode 100644
index 0000000..e3d806c
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala
@@ -0,0 +1,131 @@
+package xyz.driver.pdsuidomain.services
+
+import java.time.LocalDateTime
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db._
+import xyz.driver.pdsuicommon.domain.LongId
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities._
+
+import scala.concurrent.Future
+
+object CriterionService {
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Criterion not found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ case class RichCriterion(criterion: Criterion,
+ armIds: Seq[LongId[Arm]],
+ labels: Seq[CriterionLabel])
+ object RichCriterion {
+ implicit def toPhiString(x: RichCriterion): PhiString = {
+ import x._
+ phi"RichCriterion(criterion=$criterion, armIds=$armIds, labels=$labels)"
+ }
+ }
+
+ sealed trait CreateReply
+ object CreateReply {
+ type Error = CreateReply with DomainError
+
+ case class Created(x: RichCriterion) extends CreateReply
+
+ case object AuthorizationError
+ extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String) extends CreateReply with DomainError
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+ case class Entity(x: RichCriterion) extends GetByIdReply
+
+ type Error = GetByIdReply with DomainError
+
+ case object NotFoundError
+ extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext)
+ extends GetByIdReply with DomainError
+
+ implicit def toPhiString(reply: GetByIdReply): PhiString = reply match {
+ case x: DomainError => phi"GetByIdReply.Error($x)"
+ case Entity(x) => phi"GetByIdReply.Entity($x)"
+ }
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[RichCriterion],
+ totalFound: Int,
+ lastUpdate: Option[LocalDateTime]) extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+ type Error = UpdateReply with DomainError
+
+ case class Updated(updated: RichCriterion) extends UpdateReply
+
+ case object NotFoundError
+ extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+ }
+
+ 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
+
+ case class CommonError(userMessage: String)
+ extends DeleteReply with DomainError
+ }
+}
+
+trait CriterionService {
+
+ import CriterionService._
+
+ def create(draftRichCriterion: RichCriterion)
+ (implicit requestContext: AuthenticatedRequestContext): Future[CreateReply]
+
+ def getById(id: LongId[Criterion])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def update(origRichCriterion: RichCriterion,
+ draftRichCriterion: RichCriterion)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def delete(id: LongId[Criterion])
+ (implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala
new file mode 100644
index 0000000..cd242c9
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala
@@ -0,0 +1,157 @@
+package xyz.driver.pdsuidomain.services
+
+import java.time.LocalDateTime
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db._
+import xyz.driver.pdsuicommon.domain.LongId
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities._
+
+import scala.concurrent.Future
+
+object DocumentService {
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Can not find the document"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+ case class Entity(x: Document) extends GetByIdReply
+
+ type Error = GetByIdReply with DomainError
+
+ case object NotFoundError
+ extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext)
+ extends GetByIdReply with DomainError
+
+ implicit def toPhiString(reply: GetByIdReply): PhiString = reply match {
+ case x: DomainError => phi"GetByIdReply.Error($x)"
+ case Entity(x) => phi"GetByIdReply.Entity($x)"
+ }
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[Document],
+ totalFound: Int,
+ lastUpdate: Option[LocalDateTime]) extends GetListReply
+
+ type Error = GetListReply with DomainError
+
+ case object AuthorizationError
+ extends GetListReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case class CommonError(userMessage: String) extends GetListReply with DomainError
+ }
+
+ sealed trait CreateReply
+ object CreateReply {
+ case class Created(x: Document) extends CreateReply
+
+ type Error = CreateReply with DomainError
+
+ case object NotFoundError
+ extends CreateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case class CommonError(userMessage: String)
+ extends CreateReply with DomainError
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+ case class Updated(updated: Document) extends UpdateReply
+
+ type Error = UpdateReply with DomainError
+
+ case object NotFoundError
+ extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+
+ implicit def toPhiString(reply: UpdateReply): PhiString = reply match {
+ case Updated(x) => phi"Updated($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
+
+ case class CommonError(userMessage: String)
+ extends DeleteReply with DomainError
+ }
+
+}
+
+trait DocumentService {
+
+ import DocumentService._
+
+
+ def getById(id: LongId[Document])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def create(draftDocument: Document)(implicit requestContext: AuthenticatedRequestContext): Future[CreateReply]
+
+ // Update operations are validated in internal.*Command
+ def update(orig: Document, draft: Document)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def delete(id: LongId[Document])
+ (implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply]
+
+ def start(orig: Document)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def submit(orig: Document)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def restart(orig: Document)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def flag(orig: Document)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def resolve(orig: Document)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def unassign(orig: Document)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def archive(orig: Document)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala
new file mode 100644
index 0000000..30fd348
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala
@@ -0,0 +1,26 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db.Sorting
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuidomain.entities.DocumentType
+import xyz.driver.pdsuidomain.services.DocumentTypeService.GetListReply
+
+import scala.concurrent.Future
+
+object DocumentTypeService {
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[DocumentType], totalFound: Int) extends GetListReply
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError {
+ def userMessage: String = "Access denied"
+ }
+ }
+}
+
+trait DocumentTypeService {
+
+ def getAll(sorting: Option[Sorting] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala
new file mode 100644
index 0000000..6cde411
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala
@@ -0,0 +1,116 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting}
+import xyz.driver.pdsuicommon.domain.LongId
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities._
+
+import scala.concurrent.Future
+
+object ExtractedDataService {
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Extracted data hasn't been found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ case class RichExtractedData(extractedData: ExtractedData,
+ labels: List[ExtractedDataLabel])
+
+ object RichExtractedData {
+ implicit def toPhiString(x: RichExtractedData): PhiString = {
+ import x._
+ phi"RichExtractedData(extractedData=$extractedData, labels=$labels)"
+ }
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+ type Error = GetByIdReply with DomainError
+ case class Entity(x: RichExtractedData) extends GetByIdReply
+
+ case object AuthorizationError
+ extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case object NotFoundError
+ extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case class CommonError(userMessage: String) extends GetByIdReply with DomainError
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[RichExtractedData], totalFound: Int) extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+ }
+
+ sealed trait CreateReply
+ object CreateReply {
+ type Error = CreateReply with DomainError
+ case class Created(x: RichExtractedData) extends CreateReply
+
+ case object AuthorizationError
+ extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String) extends CreateReply with DomainError
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+ type Error = UpdateReply with DomainError
+ case class Updated(updated: RichExtractedData) extends UpdateReply
+
+ case object AuthorizationError
+ extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case object NotFoundError
+ extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+ }
+
+ sealed trait DeleteReply
+ object DeleteReply {
+ type Error = DeleteReply with DomainError
+ case object Deleted extends DeleteReply
+
+ case object AuthorizationError
+ extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case object NotFoundError
+ extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case class CommonError(userMessage: String) extends DeleteReply with DomainError
+ }
+}
+
+trait ExtractedDataService {
+
+ import ExtractedDataService._
+
+ def getById(id: LongId[ExtractedData])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def create(draftRichExtractedData: RichExtractedData)
+ (implicit requestContext: AuthenticatedRequestContext): Future[CreateReply]
+
+ def update(origRichExtractedData: RichExtractedData,
+ draftRichExtractedData: RichExtractedData)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def delete(id: LongId[ExtractedData])
+ (implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala
new file mode 100644
index 0000000..64ce3ea
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala
@@ -0,0 +1,28 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db.Sorting
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuidomain.entities.Hypothesis
+
+import scala.concurrent.Future
+
+object HypothesisService {
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[Hypothesis], totalFound: Int) extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError {
+ def userMessage: String = "Access denied"
+ }
+ }
+}
+
+trait HypothesisService {
+
+ import HypothesisService._
+
+ def getAll(sorting: Option[Sorting] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala
new file mode 100644
index 0000000..d65c9f9
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala
@@ -0,0 +1,85 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting}
+import xyz.driver.pdsuicommon.domain.LongId
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities._
+
+import scala.concurrent.Future
+
+object InterventionService {
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Intervention not found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[InterventionWithArms], totalFound: Int)
+ extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+ case class Entity(x: InterventionWithArms) extends GetByIdReply
+
+ type Error = GetByIdReply with DomainError
+
+ case object NotFoundError
+ extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext)
+ extends GetByIdReply with DomainError
+
+ implicit def toPhiString(reply: GetByIdReply): PhiString = reply match {
+ case x: DomainError => phi"GetByIdReply.Error($x)"
+ case Entity(x) => phi"GetByIdReply.Entity($x)"
+ }
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+ type Error = UpdateReply with DomainError
+
+ case class Updated(updated: InterventionWithArms) extends UpdateReply
+
+ case object NotFoundError
+ extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+ }
+
+}
+
+trait InterventionService {
+
+ import InterventionService._
+
+ def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def getById(id: LongId[Intervention])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def update(origIntervention: InterventionWithArms,
+ draftIntervention: InterventionWithArms)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala
new file mode 100644
index 0000000..db7473e
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala
@@ -0,0 +1,28 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db.Sorting
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuidomain.entities.InterventionType
+
+import scala.concurrent.Future
+
+object InterventionTypeService {
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[InterventionType], totalFound: Int) extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError {
+ def userMessage: String = "Access denied"
+ }
+ }
+}
+
+trait InterventionTypeService {
+
+ import InterventionTypeService._
+
+ def getAll(sorting: Option[Sorting] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/KeywordService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/KeywordService.scala
new file mode 100644
index 0000000..5ee69a2
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/KeywordService.scala
@@ -0,0 +1,29 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db.Sorting
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuidomain.entities.KeywordWithLabels
+
+import scala.concurrent.Future
+
+object KeywordService {
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[KeywordWithLabels], totalFound: Int) extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError {
+ def userMessage: String = "Access denied"
+ }
+ }
+}
+
+trait KeywordService {
+
+ import KeywordService._
+
+ def getAll(sorting: Option[Sorting] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala
new file mode 100644
index 0000000..7b5aa66
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala
@@ -0,0 +1,137 @@
+package xyz.driver.pdsuidomain.services
+
+import java.time.LocalDateTime
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db._
+import xyz.driver.pdsuicommon.domain.LongId
+import xyz.driver.pdsuicommon.error._
+import xyz.driver.pdsuidomain.entities.MedicalRecord.PdfSource
+import xyz.driver.pdsuidomain.entities._
+
+import scala.concurrent.Future
+
+object MedicalRecordService {
+
+ type PdfSourceFetcher = (String, String) => Future[PdfSource]
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Medical record hasn't been found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+ case class Entity(x: MedicalRecord) extends GetByIdReply
+
+ type Error = GetByIdReply with DomainError
+
+ case object NotFoundError extends GetByIdReply
+ with DomainError.NotFoundError with DefaultNotFoundError
+
+ case class CommonError(userMessage: String) extends GetByIdReply
+ with DomainError
+
+ case object AuthorizationError extends GetByIdReply
+ with DomainError.AuthorizationError with DefaultAccessDeniedError
+ }
+
+ sealed trait GetPdfSourceReply
+ object GetPdfSourceReply {
+ type Error = GetPdfSourceReply with DomainError
+
+ case class Entity(x: PdfSource.Channel) extends GetPdfSourceReply
+
+ case object AuthorizationError
+ extends GetPdfSourceReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case object NotFoundError
+ extends GetPdfSourceReply with DomainError.NotFoundError {
+ def userMessage: String = "Medical record PDF hasn't been found"
+ }
+
+ case object RecordNotFoundError
+ extends GetPdfSourceReply with DomainError.NotFoundError with DefaultNotFoundError
+
+ case class CommonError(userMessage: String)
+ extends GetPdfSourceReply with DomainError
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[MedicalRecord], totalFound: Int, lastUpdate: Option[LocalDateTime])
+ extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+ }
+
+ sealed trait CreateReply
+ object CreateReply {
+ case class Created(x: MedicalRecord) extends CreateReply
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+ type Error = UpdateReply with DomainError
+
+ case class Updated(updated: MedicalRecord) extends UpdateReply
+
+ case object NotFoundError
+ extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+ }
+
+ case class Settings(pdfSourceBucket: String)
+}
+
+trait MedicalRecordService {
+
+ import MedicalRecordService._
+
+ def getById(recordId: LongId[MedicalRecord])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def getPdfSource(recordId: LongId[MedicalRecord])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetPdfSourceReply]
+
+ def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def create(draft: MedicalRecord): Future[CreateReply]
+
+ def update(origRecord: MedicalRecord,
+ draftRecord: MedicalRecord)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def start(orig: MedicalRecord)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def submit(orig: MedicalRecord)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def restart(orig: MedicalRecord)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def flag(orig: MedicalRecord)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def resolve(orig: MedicalRecord)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def unassign(orig: MedicalRecord)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def archive(orig: MedicalRecord)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala
new file mode 100644
index 0000000..ff95ed0
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala
@@ -0,0 +1,126 @@
+package xyz.driver.pdsuidomain.services
+
+import java.time.LocalDateTime
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db._
+import xyz.driver.pdsuicommon.domain._
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities._
+
+import scala.concurrent.Future
+
+object PatientCriterionService {
+
+ case class DraftPatientCriterion(id: LongId[PatientCriterion],
+ eligibilityStatus: Option[FuzzyValue],
+ isVerified: Option[Boolean]) {
+ def applyTo(orig: PatientCriterion) = {
+ orig.copy(
+ eligibilityStatus = eligibilityStatus.orElse(orig.eligibilityStatus),
+ isVerified = isVerified.getOrElse(orig.isVerified)
+ )
+ }
+ }
+
+ trait DefaultPatientNotFoundError {
+ def userMessage: String = "Patient not found"
+ }
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Patient criterion not found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ type Error = GetListReply with DomainError
+
+ case class EntityList(xs: Seq[(PatientCriterion, LongId[Label], List[Arm], Boolean)],
+ totalFound: Int,
+ lastUpdate: Option[LocalDateTime]) extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case object PatientNotFoundError
+ extends GetListReply with DomainError.NotFoundError with DefaultPatientNotFoundError
+
+ case class CommonError(userMessage: String)
+ extends GetListReply with DomainError
+
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+ type Error = GetByIdReply with DomainError
+
+ case class Entity(x: PatientCriterion,
+ labelId: LongId[Label],
+ armList: List[Arm],
+ criterionIsCompound: Boolean) extends GetByIdReply
+
+ case object AuthorizationError
+ extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case object NotFoundError
+ extends GetByIdReply with DomainError.NotFoundError with DefaultNotFoundError
+
+ case object PatientNotFoundError
+ extends GetByIdReply with DomainError.NotFoundError with DefaultPatientNotFoundError
+
+ case class CommonError(userMessage: String)
+ extends GetByIdReply with DomainError
+
+ implicit def toPhiString(reply: GetByIdReply): PhiString = reply match {
+ case x: DomainError => phi"GetByIdReply.Error($x)"
+ case Entity(x, labelId, armList, criterionIsCompound) =>
+ phi"GetByIdReply.Entity(entity=$x, labelId=$labelId, " +
+ phi"armList=$armList, criterionIsCompound=$criterionIsCompound)"
+ }
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+ type Error = UpdateReply with DomainError
+
+ case object Updated extends UpdateReply
+
+ case object AuthorizationError
+ extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case object PatientNotFoundError
+ extends UpdateReply with DomainError.NotFoundError with DefaultPatientNotFoundError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+ }
+}
+
+trait PatientCriterionService {
+
+ import PatientCriterionService._
+
+ def getAll(patientId: UuidId[Patient],
+ filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def getById(patientId: UuidId[Patient],
+ id: LongId[PatientCriterion])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def updateList(patientId: UuidId[Patient],
+ draftEntities: List[DraftPatientCriterion])
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def update(origEntity: PatientCriterion,
+ draftEntity: PatientCriterion,
+ patientId: UuidId[Patient])
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala
new file mode 100644
index 0000000..64b4b81
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala
@@ -0,0 +1,137 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting}
+import xyz.driver.pdsuicommon.domain.{LongId, UuidId}
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities.{Arm, Trial, _}
+
+import scala.concurrent.Future
+
+object PatientEligibleTrialService {
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Patient eligible trial not found"
+ }
+
+ trait DefaultPatientNotFoundError {
+ def userMessage: String = "Patient not found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ case class RichPatientEligibleTrial(trial: Trial,
+ group: PatientTrialArmGroupView,
+ arms: List[Arm])
+ object RichPatientEligibleTrial {
+ implicit def toPhiString(x: RichPatientEligibleTrial): PhiString = {
+ phi"RichPatientEligibleTrial(group=${x.group}, trial=${x.trial}, arms=${x.arms})"
+ }
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[RichPatientEligibleTrial], totalFound: Int)
+ extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case object PatientNotFoundError
+ extends GetListReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case class CommonError(userMessage: String) extends GetListReply with DomainError
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+ case class Entity(x: RichPatientEligibleTrial) extends GetByIdReply
+
+ type Error = GetByIdReply with DomainError
+
+ case object NotFoundError
+ extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object PatientNotFoundError
+ extends GetByIdReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String) extends GetByIdReply with DomainError
+
+ implicit def toPhiString(reply: GetByIdReply): PhiString = reply match {
+ case x: DomainError => phi"GetByIdReply.Error($x)"
+ case Entity(x) => phi"GetByIdReply.Entity($x)"
+ }
+ }
+
+ sealed trait GetCriterionListOfGroupReply
+ object GetCriterionListOfGroupReply {
+ case class EntityList(xs: Seq[(PatientCriterion, LongId[Label], List[Arm], Boolean)], totalFound: Int)
+ extends GetCriterionListOfGroupReply
+
+ type Error = GetCriterionListOfGroupReply with DomainError
+
+ case object AuthorizationError
+ extends GetCriterionListOfGroupReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case object NotFoundError
+ extends GetCriterionListOfGroupReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object PatientNotFoundError
+ extends GetCriterionListOfGroupReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case class CommonError(userMessage: String) extends GetCriterionListOfGroupReply with DomainError
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+ type Error = UpdateReply with DomainError
+
+ case class Updated(updated: RichPatientEligibleTrial) extends UpdateReply
+
+ case object NotFoundError
+ extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object PatientNotFoundError
+ extends UpdateReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+
+ implicit def toPhiString(reply: UpdateReply): PhiString = reply match {
+ case Updated(x) => phi"Updated($x)"
+ case x: Error => DomainError.toPhiString(x)
+ }
+ }
+}
+
+trait PatientEligibleTrialService {
+
+ import PatientEligibleTrialService._
+
+ def getAll(patientId: UuidId[Patient],
+ filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def getById(patientId: UuidId[Patient],
+ id: LongId[PatientTrialArmGroup])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def getCriterionListByGroupId(patientId: UuidId[Patient],
+ id: LongId[PatientTrialArmGroup])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetCriterionListOfGroupReply]
+
+ def update(origEligibleTrialWithTrial: RichPatientEligibleTrial,
+ draftPatientTrialArmGroup: PatientTrialArmGroupView)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala
new file mode 100644
index 0000000..dff595a
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala
@@ -0,0 +1,105 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting}
+import xyz.driver.pdsuicommon.domain.UuidId
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities.{Hypothesis, Patient, PatientHypothesis}
+
+import scala.concurrent.Future
+
+object PatientHypothesisService {
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Patient hypothesis not found"
+ }
+
+ trait DefaultPatientNotFoundError {
+ def userMessage: String = "Patient not found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[PatientHypothesis], totalFound: Int)
+ extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case object PatientNotFoundError
+ extends GetListReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case class CommonError(userMessage: String) extends GetListReply with DomainError
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+ case class Entity(x: PatientHypothesis) extends GetByIdReply
+
+ type Error = GetByIdReply with DomainError
+
+ case object NotFoundError
+ extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object PatientNotFoundError
+ extends GetByIdReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String) extends GetByIdReply with DomainError
+
+ implicit def toPhiString(reply: GetByIdReply): PhiString = reply match {
+ case x: DomainError => phi"GetByIdReply.Error($x)"
+ case Entity(x) => phi"GetByIdReply.Entity($x)"
+ }
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+ type Error = UpdateReply with DomainError
+
+ case class Updated(updated: PatientHypothesis) extends UpdateReply
+
+ case object NotFoundError
+ extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object PatientNotFoundError
+ extends UpdateReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+
+ implicit def toPhiString(reply: UpdateReply): PhiString = reply match {
+ case Updated(x) => phi"Updated($x)"
+ case x: Error => DomainError.toPhiString(x)
+ }
+ }
+}
+
+trait PatientHypothesisService {
+
+ import PatientHypothesisService._
+
+ def getAll(patientId: UuidId[Patient],
+ filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def getById(patientId: UuidId[Patient],
+ hypothesisId: UuidId[Hypothesis])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def update(origPatientHypothesis: PatientHypothesis,
+ draftPatientHypothesis: PatientHypothesis)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala
new file mode 100644
index 0000000..8e791d4
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala
@@ -0,0 +1,70 @@
+package xyz.driver.pdsuidomain.services
+
+import java.time.LocalDate
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db._
+import xyz.driver.pdsuicommon.domain.{LongId, UuidId}
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuidomain.entities._
+
+import scala.concurrent.Future
+
+object PatientLabelEvidenceService {
+
+ case class Aggregated(evidence: PatientLabelEvidence,
+ date: LocalDate,
+ documentType: String,
+ providerType: String)
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+ case class Entity(x: Aggregated) extends GetByIdReply
+
+ type Error = GetByIdReply with DomainError
+
+ case class NotFoundError(userMessage: String) extends GetByIdReply
+ with DomainError.NotFoundError
+
+ case class CommonError(userMessage: String) extends GetByIdReply
+ with DomainError
+
+ case object AuthorizationError extends GetByIdReply
+ with DomainError.AuthorizationError with DefaultAccessDeniedError
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[Aggregated], totalFound: Int)
+ extends GetListReply
+
+ type Error = GetListReply with DomainError
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String) extends GetListReply
+ with DomainError
+ }
+}
+
+trait PatientLabelEvidenceService {
+
+ import PatientLabelEvidenceService._
+
+ def getById(patientId: UuidId[Patient],
+ labelId: LongId[Label],
+ id: LongId[PatientLabelEvidence])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def getAll(patientId: UuidId[Patient],
+ labelId: LongId[Label],
+ filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala
new file mode 100644
index 0000000..1d488ad
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala
@@ -0,0 +1,124 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db._
+import xyz.driver.pdsuicommon.domain._
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities._
+
+import scala.concurrent.Future
+
+object PatientLabelService {
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Patient label not found"
+ }
+
+ trait DefaultPatientNotFoundError {
+ def userMessage: String = "Patient not found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[(PatientLabel, Boolean)], totalFound: Int)
+ extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case object PatientNotFoundError
+ extends GetListReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case class CommonError(userMessage: String) extends GetListReply with DomainError
+ }
+
+ sealed trait GetDefiningCriteriaListReply
+ object GetDefiningCriteriaListReply {
+ case class EntityList(xs: Seq[PatientLabel], totalFound: Int)
+ extends GetDefiningCriteriaListReply
+
+ case object AuthorizationError
+ extends GetDefiningCriteriaListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case object PatientNotFoundError
+ extends GetDefiningCriteriaListReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case class CommonError(userMessage: String) extends GetDefiningCriteriaListReply with DomainError
+ }
+
+ sealed trait GetByLabelIdReply
+ object GetByLabelIdReply {
+ case class Entity(x: PatientLabel, isVerified: Boolean) extends GetByLabelIdReply
+
+ type Error = GetByLabelIdReply with DomainError
+
+ case object NotFoundError
+ extends GetByLabelIdReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object PatientNotFoundError
+ extends GetByLabelIdReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends GetByLabelIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String) extends GetByLabelIdReply with DomainError
+
+ implicit def toPhiString(reply: GetByLabelIdReply): PhiString = reply match {
+ case x: DomainError => phi"GetByIdReply.Error($x)"
+ case Entity(x, y) => phi"GetByIdReply.Entity($x, $y)"
+ }
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+ type Error = UpdateReply with DomainError
+
+ case class Updated(updated: PatientLabel, isVerified: Boolean) extends UpdateReply
+
+ case object NotFoundError
+ extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object PatientNotFoundError
+ extends UpdateReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+
+ implicit def toPhiString(reply: UpdateReply): PhiString = reply match {
+ case Updated(x, y) => phi"Updated($x, $y)"
+ case x: Error => DomainError.toPhiString(x)
+ }
+ }
+}
+
+trait PatientLabelService {
+
+ import PatientLabelService._
+
+ def getAll(patientId: UuidId[Patient],
+ filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def getDefiningCriteriaList(patientId: UuidId[Patient],
+ hypothesisId: UuidId[Hypothesis],
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetDefiningCriteriaListReply]
+
+ def getByLabelIdOfPatient(patientId: UuidId[Patient],
+ labelId: LongId[Label])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByLabelIdReply]
+
+ def update(origPatientLabel: PatientLabel,
+ draftPatientLabel: PatientLabel)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala
new file mode 100644
index 0000000..3f8b606
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala
@@ -0,0 +1,105 @@
+package xyz.driver.pdsuidomain.services
+
+import java.time.LocalDateTime
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db._
+import xyz.driver.pdsuicommon.domain._
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities._
+
+import scala.concurrent.Future
+
+object PatientService {
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Patient not found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[Patient], totalFound: Int, lastUpdate: Option[LocalDateTime])
+ extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+ case class Entity(x: Patient) extends GetByIdReply
+
+ type Error = GetByIdReply with DomainError
+
+ case object NotFoundError
+ extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext)
+ extends GetByIdReply with DomainError
+
+ implicit def toPhiString(reply: GetByIdReply): PhiString = reply match {
+ case x: DomainError => phi"GetByIdReply.Error($x)"
+ case Entity(x) => phi"GetByIdReply.Entity($x)"
+ }
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+ type Error = UpdateReply with DomainError
+
+ case class Updated(updated: Patient) extends UpdateReply
+
+ case object NotFoundError
+ extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+
+ implicit def toPhiString(reply: UpdateReply): PhiString = reply match {
+ case Updated(x) => phi"Updated($x)"
+ case x: Error => DomainError.toPhiString(x)
+ }
+ }
+}
+
+trait PatientService {
+
+ import PatientService._
+
+ def getById(id: UuidId[Patient])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def unassign(origPatient: Patient)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def start(origPatient: Patient)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def submit(origPatient: Patient)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def restart(origPatient: Patient)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def flag(origPatient: Patient)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def resolve(origPatient: Patient)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala
new file mode 100644
index 0000000..49901a4
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala
@@ -0,0 +1,27 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db.Sorting
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuidomain.entities.ProviderType
+
+import scala.concurrent.Future
+
+object ProviderTypeService {
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[ProviderType], totalFound: Int) extends GetListReply
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError {
+ def userMessage: String = "Access denied"
+ }
+ }
+}
+
+trait ProviderTypeService {
+
+ import ProviderTypeService._
+
+ def getAll(sorting: Option[Sorting] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ScrapedTrialsService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ScrapedTrialsService.scala
new file mode 100644
index 0000000..4417a54
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/ScrapedTrialsService.scala
@@ -0,0 +1,54 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuidomain.entities.ScrapedTrial
+
+import scala.concurrent.Future
+
+object ScrapedTrialsService {
+
+ sealed trait GetRawTrialReply
+ object GetRawTrialReply {
+ type Error = GetRawTrialReply with DomainError
+
+ case class TrialRawEntity(rawTrial: ScrapedTrial) extends GetRawTrialReply
+
+ case object NotFoundError extends GetRawTrialReply with DomainError.NotFoundError {
+ override def userMessage: String = "Raw clinical trial not found"
+ }
+ }
+
+ sealed trait GetRawTrialOptReply
+ object GetRawTrialOptReply {
+ case class TrialRawEntity(rawTrial: Option[ScrapedTrial]) extends GetRawTrialOptReply
+ }
+
+ sealed trait GetAllRawTrialsExceptReply
+ object GetAllRawTrialsExceptReply {
+ case class MultipleRawTrials(rawTrials: Seq[ScrapedTrial])
+ extends GetAllRawTrialsExceptReply
+ }
+
+ sealed trait GetHtmlForReply
+ object GetHtmlForReply {
+ type TrialHtmlMap = Map[String, String]
+
+ /**
+ * @param trialHtmlMap nctId -> html
+ */
+ case class HtmlMap(trialHtmlMap: TrialHtmlMap) extends GetHtmlForReply
+ }
+}
+
+trait ScrapedTrialsService {
+
+ import ScrapedTrialsService._
+
+ def getRawTrial(nctId: String): Future[GetRawTrialReply]
+
+ def getRawTrialOpt(nctId: String): Future[GetRawTrialOptReply]
+
+ def getAllRawTrialsExcept(nctIds: Seq[String], limit: Int): Future[GetAllRawTrialsExceptReply]
+
+ def getHtmlFor(nctIds: Set[String]): Future[GetHtmlForReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala
new file mode 100644
index 0000000..d086c5f
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala
@@ -0,0 +1,28 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db.Sorting
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuidomain.entities.StudyDesign
+
+import scala.concurrent.Future
+
+object StudyDesignService {
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[StudyDesign], totalFound: Int) extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError {
+ def userMessage: String = "Access denied"
+ }
+ }
+}
+
+trait StudyDesignService {
+
+ import StudyDesignService._
+
+ def getAll(sorting: Option[Sorting] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala
new file mode 100644
index 0000000..4af4449
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala
@@ -0,0 +1,132 @@
+package xyz.driver.pdsuidomain.services
+
+
+import java.time.LocalDateTime
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db._
+import xyz.driver.pdsuicommon.domain.StringId
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities.Trial
+import xyz.driver.pdsuidomain.entities.Trial.PdfSource
+
+import scala.concurrent.Future
+
+object TrialService {
+
+ trait DefaultNotFoundError {
+ def userMessage: String = "Trial not found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[Trial], totalFound: Int, lastUpdate: Option[LocalDateTime])
+ extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+ }
+
+ sealed trait GetByIdReply
+ object GetByIdReply {
+ case class Entity(x: Trial) extends GetByIdReply
+
+ type Error = GetByIdReply with DomainError
+
+ case object NotFoundError
+ extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext)
+ extends GetByIdReply with DomainError
+
+ implicit def toPhiString(reply: GetByIdReply): PhiString = reply match {
+ case x: DomainError => phi"GetByIdReply.Error($x)"
+ case Entity(x) => phi"GetByIdReply.Entity($x)"
+ }
+ }
+
+ sealed trait GetPdfSourceReply
+ object GetPdfSourceReply {
+ type Error = GetPdfSourceReply with DomainError
+
+ case class Entity(x: PdfSource) extends GetPdfSourceReply
+
+ case object AuthorizationError
+ extends GetPdfSourceReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+
+ case object NotFoundError
+ extends GetPdfSourceReply with DomainError.NotFoundError {
+ def userMessage: String = "Trial's PDF hasn't been found"
+ }
+
+ case object TrialNotFoundError
+ extends GetPdfSourceReply with DomainError.NotFoundError with DefaultNotFoundError
+
+ case class CommonError(userMessage: String)
+ extends GetPdfSourceReply with DomainError
+ }
+
+ sealed trait UpdateReply
+ object UpdateReply {
+ type Error = UpdateReply with DomainError
+
+ case class Updated(updated: Trial) extends UpdateReply
+
+ case object NotFoundError
+ extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError
+
+ case object AuthorizationError
+ extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
+
+ case class CommonError(userMessage: String)
+ extends UpdateReply with DomainError
+
+ implicit def toPhiString(reply: UpdateReply): PhiString = reply match {
+ case Updated(x) => phi"Updated($x)"
+ case x: Error => DomainError.toPhiString(x)
+ }
+ }
+}
+
+trait TrialService {
+
+ import TrialService._
+
+ def getById(id: StringId[Trial])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply]
+
+ def getPdfSource(trialId: StringId[Trial])
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetPdfSourceReply]
+
+ def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ sorting: Option[Sorting] = None,
+ pagination: Option[Pagination] = None)
+ (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply]
+
+ def update(origTrial: Trial, draftTrial: Trial)
+ (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def start(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def submit(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def restart(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def flag(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def resolve(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def archive(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def unassign(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply]
+
+ def removeTrialDetails(trialId: StringId[Trial]): Unit
+}