aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/pdsuidomain/services
diff options
context:
space:
mode:
authorvlad <vlad@driver.xyz>2017-06-30 19:38:37 -0700
committervlad <vlad@driver.xyz>2017-06-30 19:38:37 -0700
commit96d81a36286e41035ff4068859a3b0f9da924fbc (patch)
tree8d9f0014140d1f07ca449b56adaba8ccb3d2fc59 /src/main/scala/xyz/driver/pdsuidomain/services
parenta997aa6539d1f0af4ab4fc395ff2033335da312a (diff)
downloadrest-query-96d81a36286e41035ff4068859a3b0f9da924fbc.tar.gz
rest-query-96d81a36286e41035ff4068859a3b0f9da924fbc.tar.bz2
rest-query-96d81a36286e41035ff4068859a3b0f9da924fbc.zip
Latest PDS UI utils including all the domain stuffv0.1.12
Diffstat (limited to 'src/main/scala/xyz/driver/pdsuidomain/services')
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala12
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/CategoryService.scala3
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala2
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/ExportService.scala64
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/LabelService.scala3
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/LinkedPatientService.scala62
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/MailService.scala39
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/MessageService.scala4
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala7
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala8
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala19
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/QueueUploadService.scala78
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/UserHistoryService.scala31
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/UserService.scala4
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/fake/StubMailService.scala13
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/rest/SendGridMailService.scala45
16 files changed, 361 insertions, 33 deletions
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala
index 43e46ed..8c89505 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala
@@ -33,7 +33,6 @@ object ArmService {
case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext)
extends GetByIdReply with DomainError
-
}
sealed trait GetListReply
@@ -44,13 +43,12 @@ object ArmService {
case object AuthorizationError
extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
-
}
sealed trait UpdateReply
object UpdateReply {
- case class Updated(updated: Arm) extends UpdateReply
+ final case class Updated(updated: Arm) extends UpdateReply
type Error = UpdateReply with DomainError
@@ -59,9 +57,9 @@ object ArmService {
case object AuthorizationError
extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
- case class CommonError(userMessage: String) extends UpdateReply with DomainError
+ final case class CommonError(userMessage: String) extends UpdateReply with DomainError
- case class AlreadyExistsError(x: Arm) extends UpdateReply with DomainError {
+ final case class AlreadyExistsError(x: Arm) extends UpdateReply with DomainError {
val userMessage = s"The arm with such name of trial already exists."
}
@@ -80,9 +78,9 @@ object ArmService {
case object AuthorizationError
extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError
- case class CommonError(userMessage: String) extends CreateReply with DomainError
+ final case class CommonError(userMessage: String) extends CreateReply with DomainError
- case class AlreadyExistsError(x: Arm) extends CreateReply with DomainError {
+ final case class AlreadyExistsError(x: Arm) extends CreateReply with DomainError {
val userMessage = s"The arm with this name of trial already exists."
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/CategoryService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/CategoryService.scala
index a735ade..f8d820b 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/CategoryService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/CategoryService.scala
@@ -3,7 +3,6 @@ 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.pdsuicommon.logging._
import xyz.driver.pdsuidomain.entities.CategoryWithLabels
import scala.concurrent.Future
@@ -19,7 +18,7 @@ object CategoryService {
}
}
-trait CategoryService extends PhiLogging {
+trait CategoryService {
import CategoryService._
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala
index ffa252c..2c01a7e 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala
@@ -99,7 +99,6 @@ object DocumentService {
case class CommonError(userMessage: String) extends DeleteReply with DomainError
}
-
}
trait DocumentService {
@@ -115,7 +114,6 @@ trait DocumentService {
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]
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ExportService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ExportService.scala
new file mode 100644
index 0000000..8fb399a
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/ExportService.scala
@@ -0,0 +1,64 @@
+package xyz.driver.pdsuidomain.services
+
+import java.time.LocalDateTime
+
+import xyz.driver.pdsuicommon.auth.AnonymousRequestContext
+import xyz.driver.pdsuicommon.db.SearchFilterExpr
+import xyz.driver.pdsuicommon.domain._
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuidomain.entities.export.patient.ExportPatientWithLabels
+import xyz.driver.pdsuidomain.entities.export.trial.{ExportTrial, ExportTrialWithLabels}
+import xyz.driver.pdsuidomain.entities.{MedicalRecord, Patient, Trial}
+
+import scala.concurrent.Future
+
+object ExportService {
+
+ sealed trait GetPatientReply
+ object GetPatientReply {
+ type Error = GetPatientReply with DomainError
+
+ case class Entity(x: ExportPatientWithLabels) extends GetPatientReply
+
+ case object NotFoundError extends GetPatientReply with DomainError.NotFoundError {
+ def userMessage: String = "Patient not found"
+ }
+ }
+
+ sealed trait GetTrialListReply
+ object GetTrialListReply {
+ case class EntityList(xs: Seq[ExportTrial], totalFound: Int, lastUpdate: Option[LocalDateTime])
+ extends GetTrialListReply
+ }
+
+ sealed trait GetTrialReply
+ object GetTrialReply {
+ type Error = GetTrialReply with DomainError
+
+ case class Entity(x: ExportTrialWithLabels) extends GetTrialReply
+
+ case object NotFoundError extends GetTrialReply with DomainError.NotFoundError {
+ def userMessage: String = "Trial not found"
+ }
+ }
+}
+
+trait ExportService {
+
+ import ExportService._
+
+ def getPatient(id: UuidId[Patient])
+ (implicit requestContext: AnonymousRequestContext): Future[GetPatientReply]
+
+ def getTrialList(filter: SearchFilterExpr = SearchFilterExpr.Empty)
+ (implicit requestContext: AnonymousRequestContext): Future[GetTrialListReply]
+
+ def getTrial(trialId: StringId[Trial], condition: String)
+ (implicit requestContext: AnonymousRequestContext): Future[GetTrialReply]
+
+ def getRecords(patientId: UuidId[Patient])
+ (implicit requestContext: AnonymousRequestContext): Future[MedicalRecordService.GetListReply]
+
+ def getRecordPdf(recordId: LongId[MedicalRecord])
+ (implicit requestContext: AnonymousRequestContext): Future[MedicalRecordService.GetPdfSourceReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/LabelService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/LabelService.scala
index 0677584..aadc5fb 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/LabelService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/LabelService.scala
@@ -3,7 +3,6 @@ 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.pdsuicommon.logging.PhiLogging
import xyz.driver.pdsuidomain.entities.Label
import scala.concurrent.Future
@@ -20,7 +19,7 @@ object LabelService {
}
}
-trait LabelService extends PhiLogging {
+trait LabelService {
import LabelService._
def getAll(sorting: Option[Sorting] = None)(
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/LinkedPatientService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/LinkedPatientService.scala
new file mode 100644
index 0000000..8fc1662
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/LinkedPatientService.scala
@@ -0,0 +1,62 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.domain._
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.entities.{LinkedPatient, Patient, Trial}
+
+import scala.concurrent.Future
+
+object LinkedPatientService {
+
+ trait DefaultTrialNotFoundError {
+ def userMessage: String = "Trial not found"
+ }
+
+ trait DefaultPatientNotFoundError {
+ def userMessage: String = "Patient not found"
+ }
+
+ final case class RichLinkedPatient(email: Email,
+ name: String,
+ patientId: UuidId[Patient],
+ trialId: StringId[Trial]) {
+ def toLinkedPatient(user: User) = LinkedPatient(
+ userId = user.id,
+ patientId = patientId,
+ trialId = trialId
+ )
+ }
+
+ object RichLinkedPatient {
+ implicit def toPhiString(x: RichLinkedPatient): PhiString = {
+ import x._
+ phi"RichLinkedPatient(email=${Unsafe(email)}, patientId=$patientId, trialId=$trialId)"
+ }
+ }
+
+ sealed trait CreateReply
+ object CreateReply {
+ type Error = CreateReply with DomainError
+
+ /**
+ * @param createdUser None if a user was created before
+ */
+ final case class Created(x: RichLinkedPatient, createdUser: Option[User]) extends CreateReply
+
+ case object PatientNotFoundError
+ extends CreateReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ case object TrialNotFoundError
+ extends CreateReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
+ final case class CommonError(userMessage: String) extends CreateReply with DomainError
+ }
+}
+
+trait LinkedPatientService {
+
+ import LinkedPatientService._
+
+ def create(entity: RichLinkedPatient): Future[CreateReply]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/MailService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/MailService.scala
new file mode 100644
index 0000000..3022716
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/MailService.scala
@@ -0,0 +1,39 @@
+package xyz.driver.pdsuidomain.services
+
+import java.io.{InputStream, StringReader, StringWriter}
+
+import xyz.driver.pdsuidomain.services.MailService.Template
+import com.github.mustachejava.DefaultMustacheFactory
+import com.twitter.mustache.ScalaObjectHandler
+
+import scala.io.Source
+
+object MailService {
+
+ trait Template {
+ val subject: String
+ def parameters: Map[String, Any]
+ def filename: String
+ val contentType: String = "text/html"
+
+ protected val factory = new DefaultMustacheFactory()
+ factory.setObjectHandler(new ScalaObjectHandler)
+
+ protected def inputStream: InputStream = getClass.getClassLoader.getResourceAsStream(filename)
+ protected def templateContent: String = Source.fromInputStream(inputStream).getLines().mkString
+
+ def content: String = {
+ val template = factory.compile(new StringReader(templateContent), filename)
+ val writer = new StringWriter
+ template
+ .execute(writer, parameters)
+ .close()
+ writer.toString
+ }
+ }
+}
+
+trait MailService {
+
+ def sendTo(email: String, template: Template): Boolean
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/MessageService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/MessageService.scala
index 8ce06f2..df57e17 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/MessageService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/MessageService.scala
@@ -6,7 +6,6 @@ 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.Message
import scala.concurrent.Future
@@ -66,10 +65,9 @@ object MessageService {
case object NotFoundError extends DeleteReply with DomainError.NotFoundError with DefaultNotFoundError
case class CommonError(userMessage: String) extends DeleteReply with DomainError
}
-
}
-trait MessageService extends PhiLogging {
+trait MessageService {
import MessageService._
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala
index 593e2ce..e23dfc5 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala
@@ -84,7 +84,10 @@ object PatientCriterionService {
object UpdateReply {
type Error = UpdateReply with DomainError
- case object Updated extends UpdateReply
+ case class Updated(x: PatientCriterion, labelId: LongId[Label], armList: List[Arm], criterionIsCompound: Boolean)
+ extends UpdateReply
+
+ case object UpdatedList extends UpdateReply
case object AuthorizationError
extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError
@@ -101,7 +104,7 @@ trait PatientCriterionService {
import PatientCriterionService._
def getAll(patientId: UuidId[Patient],
- filter: SearchFilterExpr = SearchFilterExpr.Empty,
+ origFilter: 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/PatientHypothesisService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala
index 39ee2b1..a15e11f 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala
@@ -25,7 +25,7 @@ object PatientHypothesisService {
sealed trait GetListReply
object GetListReply {
- case class EntityList(xs: Seq[PatientHypothesis], totalFound: Int) extends GetListReply
+ case class EntityList(xs: Seq[(PatientHypothesis, Boolean)], totalFound: Int) extends GetListReply
case object AuthorizationError
extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
@@ -38,7 +38,7 @@ object PatientHypothesisService {
sealed trait GetByIdReply
object GetByIdReply {
- case class Entity(x: PatientHypothesis) extends GetByIdReply
+ case class Entity(x: PatientHypothesis, isRequired: Boolean) extends GetByIdReply
type Error = GetByIdReply with DomainError
@@ -53,8 +53,8 @@ object PatientHypothesisService {
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)"
+ case x: DomainError => phi"GetByIdReply.Error($x)"
+ case Entity(x, isRequired) => phi"GetByIdReply.Entity($x, $isRequired)"
}
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala
index f6039f0..2586798 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala
@@ -1,7 +1,5 @@
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}
@@ -12,21 +10,23 @@ import scala.concurrent.Future
object PatientLabelEvidenceService {
- case class Aggregated(evidence: PatientLabelEvidence, date: LocalDate, documentType: String, providerType: String)
-
trait DefaultAccessDeniedError {
def userMessage: String = "Access denied"
}
+ trait DefaultPatientNotFoundError {
+ def userMessage: String = "Patient not found"
+ }
+
sealed trait GetByIdReply
object GetByIdReply {
- case class Entity(x: Aggregated) extends GetByIdReply
+ case class Entity(x: PatientLabelEvidenceView) extends GetByIdReply
type Error = GetByIdReply with DomainError
- case class NotFoundError(userMessage: String) extends GetByIdReply with DomainError.NotFoundError
+ final case class NotFoundError(userMessage: String) extends GetByIdReply with DomainError.NotFoundError
- case class CommonError(userMessage: String) extends GetByIdReply with DomainError
+ final case class CommonError(userMessage: String) extends GetByIdReply with DomainError
case object AuthorizationError
extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
@@ -34,10 +34,13 @@ object PatientLabelEvidenceService {
sealed trait GetListReply
object GetListReply {
- case class EntityList(xs: Seq[Aggregated], totalFound: Int) extends GetListReply
+ case class EntityList(xs: Seq[PatientLabelEvidenceView], totalFound: Int) extends GetListReply
type Error = GetListReply with DomainError
+ case object PatientNotFoundError
+ extends GetListReply with DefaultPatientNotFoundError with DomainError.NotFoundError
+
case object AuthorizationError
extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/QueueUploadService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/QueueUploadService.scala
new file mode 100644
index 0000000..55a408f
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/QueueUploadService.scala
@@ -0,0 +1,78 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue
+import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting}
+import xyz.driver.pdsuicommon.error.DomainError
+
+import scala.concurrent.Future
+
+object QueueUploadService {
+ trait DefaultNotFoundError {
+ def userMessage: String = "Message not found"
+ }
+
+ trait DefaultAccessDeniedError {
+ def userMessage: String = "Access denied"
+ }
+
+ sealed trait CreateReply
+ object CreateReply {
+ type Error = CreateReply with DomainError
+
+ case class Created(x: BridgeUploadQueue.Item) 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 {
+ type Error = GetByIdReply with DomainError
+
+ case class Entity(x: BridgeUploadQueue.Item) extends GetByIdReply
+ case object AuthorizationError extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+ case object NotFoundError extends GetByIdReply with DomainError.NotFoundError with DefaultNotFoundError
+ case class CommonError(userMessage: String) extends GetByIdReply with DomainError
+ }
+
+ sealed trait GetListReply
+ object GetListReply {
+ type Error = GetListReply with DomainError
+
+ case class EntityList(xs: Seq[BridgeUploadQueue.Item],
+ totalFound: Int) extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+ }
+
+ sealed trait ResetReply
+ object ResetReply {
+ type Error = ResetReply with DomainError
+
+ case class Updated(updated: BridgeUploadQueue.Item) extends ResetReply
+ case object AuthorizationError extends ResetReply with DomainError.AuthorizationError with DefaultAccessDeniedError
+ case object NotFoundError extends ResetReply with DefaultNotFoundError with DomainError.NotFoundError
+ case class CommonError(userMessage: String) extends ResetReply with DomainError
+ }
+}
+
+trait QueueUploadService {
+
+ import QueueUploadService._
+
+ def create(kind: String, tag: String)
+ (implicit requestContext: AuthenticatedRequestContext): Future[CreateReply]
+
+ def getById(kind: String, tag: String)
+ (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 reset(kind: String, tag: String)
+ (implicit requestContext: AuthenticatedRequestContext): Future[ResetReply]
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/UserHistoryService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/UserHistoryService.scala
new file mode 100644
index 0000000..3034027
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/UserHistoryService.scala
@@ -0,0 +1,31 @@
+package xyz.driver.pdsuidomain.services
+
+import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext
+import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting}
+import xyz.driver.pdsuicommon.error.DomainError
+import xyz.driver.pdsuidomain.entities.UserHistory
+
+import scala.concurrent.Future
+
+object UserHistoryService {
+
+ sealed trait GetListReply
+ object GetListReply {
+ case class EntityList(xs: Seq[UserHistory], totalFound: Int) extends GetListReply
+
+ case object AuthorizationError
+ extends GetListReply with DomainError.AuthorizationError {
+ def userMessage: String = "Access denied"
+ }
+ }
+}
+
+trait UserHistoryService {
+
+ import UserHistoryService._
+
+ def getAll(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/UserService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/UserService.scala
index 79e9835..a1d4800 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/services/UserService.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/UserService.scala
@@ -4,7 +4,6 @@ import xyz.driver.pdsuicommon.auth.{AnonymousRequestContext, AuthenticatedReques
import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting}
import xyz.driver.pdsuicommon.domain.{Email, LongId, User}
import xyz.driver.pdsuicommon.error.DomainError
-import xyz.driver.pdsuicommon.logging._
import scala.concurrent.Future
@@ -95,10 +94,9 @@ object UserService {
case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError
case class CommonError(userMessage: String) extends DeleteReply with DomainError
}
-
}
-trait UserService extends PhiLogging {
+trait UserService {
import UserService._
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/fake/StubMailService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/fake/StubMailService.scala
new file mode 100644
index 0000000..932da67
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/fake/StubMailService.scala
@@ -0,0 +1,13 @@
+package xyz.driver.pdsuidomain.services.fake
+
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.services.MailService
+import xyz.driver.pdsuidomain.services.MailService.Template
+
+object StubMailService extends MailService with PhiLogging {
+
+ override def sendTo(email: String, template: Template): Boolean = {
+ logger.debug(phi"sendTo(email=${Unsafe(email)}")
+ true
+ }
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/SendGridMailService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/SendGridMailService.scala
new file mode 100644
index 0000000..37dc758
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/SendGridMailService.scala
@@ -0,0 +1,45 @@
+package xyz.driver.pdsuidomain.services.rest
+
+import com.sendgrid._
+import xyz.driver.pdsuicommon.logging._
+import xyz.driver.pdsuidomain.services.MailService
+import xyz.driver.pdsuidomain.services.MailService.Template
+import xyz.driver.pdsuidomain.services.rest.SendGridMailService._
+
+import scala.util.control.NonFatal
+
+object SendGridMailService {
+
+ private val ExpectedHttpCode = 202
+
+ case class Settings(provider: String, frontEndUrl: String, apiKey: String, from: String)
+}
+
+class SendGridMailService(settings: Settings) extends MailService with PhiLogging {
+
+ def sendTo(email: String, template: Template): Boolean = {
+ val to = new Email(email)
+ val content = new Content(template.contentType, template.content)
+ val mail = new Mail(new Email(settings.from), template.subject, to, content)
+
+ val request = new Request()
+ val sendGrid = new SendGrid(settings.apiKey)
+
+ try {
+ request.method = Method.POST
+ request.endpoint = "mail/send"
+ request.body = mail.build()
+ val response = sendGrid.api(request)
+ if (response.statusCode != ExpectedHttpCode) {
+ logger.error(phi"Unexpected response: ${Unsafe(response.statusCode)}, ${Unsafe(response.body.take(100))}")
+ }
+
+ response.statusCode == ExpectedHttpCode
+ }
+ catch {
+ case NonFatal(e) =>
+ logger.error(phi"Can not send an email: $e")
+ false
+ }
+ }
+}