diff options
Diffstat (limited to 'src/main/scala/xyz/driver')
103 files changed, 1960 insertions, 221 deletions
diff --git a/src/main/scala/xyz/driver/common/domain/Category.scala b/src/main/scala/xyz/driver/common/domain/Category.scala deleted file mode 100644 index e130367..0000000 --- a/src/main/scala/xyz/driver/common/domain/Category.scala +++ /dev/null @@ -1,21 +0,0 @@ -package xyz.driver.common.domain - -import xyz.driver.common.logging._ - -case class Category(id: LongId[Category], name: String) - -object Category { - implicit def toPhiString(x: Category): PhiString = { - import x._ - phi"Category(id=$id, name=${Unsafe(name)})" - } -} - -case class CategoryWithLabels(category: Category, labels: List[Label]) - -object CategoryWithLabels { - implicit def toPhiString(x: CategoryWithLabels): PhiString = { - import x._ - phi"CategoryWithLabels(category=$category, labels=$labels)" - } -} diff --git a/src/main/scala/xyz/driver/common/domain/Email.scala b/src/main/scala/xyz/driver/common/domain/Email.scala deleted file mode 100644 index c3bcf3f..0000000 --- a/src/main/scala/xyz/driver/common/domain/Email.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.common.domain - -case class Email(value: String) diff --git a/src/main/scala/xyz/driver/common/domain/Label.scala b/src/main/scala/xyz/driver/common/domain/Label.scala deleted file mode 100644 index 2214216..0000000 --- a/src/main/scala/xyz/driver/common/domain/Label.scala +++ /dev/null @@ -1,15 +0,0 @@ -package xyz.driver.common.domain - -import xyz.driver.common.logging._ - -case class Label(id: LongId[Label], - categoryId: LongId[Category], - name: String, - description: String) - -object Label { - implicit def toPhiString(x: Label): PhiString = { - import x._ - phi"Label($id, categoryId=${Unsafe(categoryId)}, name=${Unsafe(name)}, description=${Unsafe(description)})" - } -} diff --git a/src/main/scala/xyz/driver/common/error/IncorrectIdException.scala b/src/main/scala/xyz/driver/common/error/IncorrectIdException.scala deleted file mode 100644 index a91065c..0000000 --- a/src/main/scala/xyz/driver/common/error/IncorrectIdException.scala +++ /dev/null @@ -1,3 +0,0 @@ -package xyz.driver.common.error - -case class IncorrectIdException(message: String) extends Exception(message) diff --git a/src/main/scala/xyz/driver/common/Config.scala b/src/main/scala/xyz/driver/pdsuicommon/Config.scala index d37a20a..e55e521 100644 --- a/src/main/scala/xyz/driver/common/Config.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/Config.scala @@ -1,4 +1,4 @@ -package xyz.driver.common +package xyz.driver.pdsuicommon import pureconfig._ @@ -18,5 +18,4 @@ object Config { case Right(x) => Success(x) case Left(e) => Failure(new RuntimeException(e.toString)) } - } diff --git a/src/main/scala/xyz/driver/common/TimeLogger.scala b/src/main/scala/xyz/driver/pdsuicommon/TimeLogger.scala index 154847c..41c83d5 100644 --- a/src/main/scala/xyz/driver/common/TimeLogger.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/TimeLogger.scala @@ -1,9 +1,9 @@ -package xyz.driver.common +package xyz.driver.pdsuicommon import java.time.{LocalDateTime, ZoneId} -import xyz.driver.common.domain.{LongId, User} -import xyz.driver.common.logging._ +import xyz.driver.pdsuicommon.domain.{LongId, User} +import xyz.driver.pdsuicommon.logging._ object TimeLogger extends PhiLogging { @@ -11,5 +11,4 @@ object TimeLogger extends PhiLogging { val now = LocalDateTime.now(ZoneId.of("Z")) logger.info(phi"User id=$userId performed an action at ${Unsafe(label)}=$now with a ${Unsafe(obj)} ") } - } diff --git a/src/main/scala/xyz/driver/common/acl/ACL.scala b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala index 35c2661..0110f46 100644 --- a/src/main/scala/xyz/driver/common/acl/ACL.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala @@ -1,14 +1,14 @@ -package xyz.driver.common.acl +package xyz.driver.pdsuicommon.acl -import xyz.driver.common.logging._ -import xyz.driver.common.auth.AuthenticatedRequestContext +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext /** * @see https://driverinc.atlassian.net/wiki/display/RA/User+permissions#UserPermissions-AccessControlList */ object ACL extends PhiLogging { - import xyz.driver.common.domain.User.Role + import xyz.driver.pdsuicommon.domain.User.Role import Role._ type AclCheck = Role => Boolean diff --git a/src/main/scala/xyz/driver/common/auth/AnonymousRequestContext.scala b/src/main/scala/xyz/driver/pdsuicommon/auth/AnonymousRequestContext.scala index 2e4b55c..7b223ef 100644 --- a/src/main/scala/xyz/driver/common/auth/AnonymousRequestContext.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/auth/AnonymousRequestContext.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.auth +package xyz.driver.pdsuicommon.auth class AnonymousRequestContext(val requestId: RequestId) { @@ -8,5 +8,4 @@ class AnonymousRequestContext(val requestId: RequestId) { } override def hashCode(): Int = requestId.hashCode() - } diff --git a/src/main/scala/xyz/driver/common/auth/AuthenticatedRequestContext.scala b/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala index b211e12..0f5de30 100644 --- a/src/main/scala/xyz/driver/common/auth/AuthenticatedRequestContext.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala @@ -1,7 +1,7 @@ -package xyz.driver.common.auth +package xyz.driver.pdsuicommon.auth -import xyz.driver.common.logging._ -import xyz.driver.common.domain.User +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.domain.User class AuthenticatedRequestContext(val executor: User, override val requestId: RequestId) extends AnonymousRequestContext(requestId) { @@ -18,7 +18,6 @@ class AuthenticatedRequestContext(val executor: User, val first = initial * 17 + executor.hashCode() first * 17 + requestId.hashCode() } - } object AuthenticatedRequestContext { @@ -28,5 +27,4 @@ object AuthenticatedRequestContext { implicit def toPhiString(x: AuthenticatedRequestContext): PhiString = { phi"AuthenticatedRequestContext(executor=${x.executor}, requestId=${x.requestId})" } - } diff --git a/src/main/scala/xyz/driver/common/auth/RequestId.scala b/src/main/scala/xyz/driver/pdsuicommon/auth/RequestId.scala index 771145c..9982bb0 100644 --- a/src/main/scala/xyz/driver/common/auth/RequestId.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/auth/RequestId.scala @@ -1,8 +1,8 @@ -package xyz.driver.common.auth +package xyz.driver.pdsuicommon.auth -import xyz.driver.common.logging._ -import xyz.driver.common.auth.RequestId._ -import xyz.driver.common.utils.RandomUtils +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.auth.RequestId._ +import xyz.driver.pdsuicommon.utils.RandomUtils final case class RequestId(value: String = RandomUtils.randomString(IdLength)) @@ -11,5 +11,4 @@ object RequestId { private val IdLength = 20 implicit def toPhiString(x: RequestId): PhiString = phi"RequestId(${Unsafe(x.value)})" - } diff --git a/src/main/scala/xyz/driver/common/compat/EitherOps.scala b/src/main/scala/xyz/driver/pdsuicommon/compat/EitherOps.scala index b3b45e6..96fb0c3 100644 --- a/src/main/scala/xyz/driver/common/compat/EitherOps.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/compat/EitherOps.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.compat +package xyz.driver.pdsuicommon.compat final class EitherOps[A, B](val self: Either[A, B]) extends AnyVal { diff --git a/src/main/scala/xyz/driver/common/compat/Implicits.scala b/src/main/scala/xyz/driver/pdsuicommon/compat/Implicits.scala index 860989b..147c9e8 100644 --- a/src/main/scala/xyz/driver/common/compat/Implicits.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/compat/Implicits.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.compat +package xyz.driver.pdsuicommon.compat object Implicits { diff --git a/src/main/scala/xyz/driver/common/concurrent/BridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala index 6ecb299..320666d 100644 --- a/src/main/scala/xyz/driver/common/concurrent/BridgeUploadQueue.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala @@ -1,10 +1,10 @@ -package xyz.driver.common.concurrent +package xyz.driver.pdsuicommon.concurrent import java.time.LocalDateTime -import xyz.driver.common.concurrent.BridgeUploadQueue.Item -import xyz.driver.common.domain.LongId -import xyz.driver.common.logging._ +import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.logging._ import scala.concurrent.Future @@ -70,9 +70,7 @@ object BridgeUploadQueue { import x._ phi"Dependency(kind=${Unsafe(kind)}, tag=${Unsafe(tag)})" } - } - } trait BridgeUploadQueue { diff --git a/src/main/scala/xyz/driver/common/concurrent/BridgeUploadQueueRepositoryAdapter.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapter.scala index c6a2144..8c87b60 100644 --- a/src/main/scala/xyz/driver/common/concurrent/BridgeUploadQueueRepositoryAdapter.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapter.scala @@ -1,14 +1,14 @@ -package xyz.driver.common.concurrent +package xyz.driver.pdsuicommon.concurrent import java.time.LocalDateTime import java.time.temporal.ChronoUnit -import xyz.driver.common.concurrent.BridgeUploadQueue.Item -import xyz.driver.common.concurrent.BridgeUploadQueueRepositoryAdapter.Strategy -import xyz.driver.common.db.Transactions -import xyz.driver.common.db.repositories.BridgeUploadQueueRepository -import xyz.driver.common.domain.LongId -import xyz.driver.common.logging._ +import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item +import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueueRepositoryAdapter.Strategy +import xyz.driver.pdsuicommon.db.Transactions +import xyz.driver.pdsuicommon.db.repositories.BridgeUploadQueueRepository +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.logging._ import scala.concurrent.duration.{Duration, FiniteDuration} import scala.concurrent.{ExecutionContext, Future} @@ -30,7 +30,7 @@ object BridgeUploadQueueRepositoryAdapter { */ final case class LimitExponential(startInterval: FiniteDuration, intervalFactor: Double, - maxInterval: FiniteDuration, + maxInterval: FiniteDuration, onComplete: OnComplete) extends Strategy { override def on(attempt: Int): OnAttempt = { diff --git a/src/main/scala/xyz/driver/common/concurrent/Cron.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala index 9dd3155..a6e9d2c 100644 --- a/src/main/scala/xyz/driver/common/concurrent/Cron.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.concurrent +package xyz.driver.pdsuicommon.concurrent import java.io.Closeable import java.util.concurrent.ConcurrentHashMap @@ -7,8 +7,8 @@ import java.util.{Timer, TimerTask} import com.typesafe.scalalogging.StrictLogging import org.slf4j.MDC -import xyz.driver.common.error.ExceptionFormatter -import xyz.driver.common.utils.RandomUtils +import xyz.driver.pdsuicommon.error.ExceptionFormatter +import xyz.driver.pdsuicommon.utils.RandomUtils import scala.concurrent.duration.FiniteDuration import scala.concurrent.{ExecutionContext, Future} @@ -56,7 +56,6 @@ class Cron(settings: Cron.Settings) extends Closeable with StrictLogging { override def close(): Unit = { timer.cancel() } - } object Cron { @@ -93,5 +92,4 @@ object Cron { } } } - } diff --git a/src/main/scala/xyz/driver/common/concurrent/InMemoryBridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala index b19be42..bff566b 100644 --- a/src/main/scala/xyz/driver/common/concurrent/InMemoryBridgeUploadQueue.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala @@ -1,10 +1,10 @@ -package xyz.driver.common.concurrent +package xyz.driver.pdsuicommon.concurrent import java.util.concurrent.LinkedBlockingQueue -import xyz.driver.common.concurrent.BridgeUploadQueue.Item -import xyz.driver.common.domain.LongId -import xyz.driver.common.logging.PhiLogging +import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.logging.PhiLogging import scala.collection.JavaConverters._ import scala.concurrent.Future diff --git a/src/main/scala/xyz/driver/common/concurrent/MdcExecutionContext.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcExecutionContext.scala index cd2b394..3dee8ea 100644 --- a/src/main/scala/xyz/driver/common/concurrent/MdcExecutionContext.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcExecutionContext.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.concurrent +package xyz.driver.pdsuicommon.concurrent import org.slf4j.MDC diff --git a/src/main/scala/xyz/driver/common/concurrent/MdcThreadFactory.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcThreadFactory.scala index 9e59a64..d1dc3ae 100644 --- a/src/main/scala/xyz/driver/common/concurrent/MdcThreadFactory.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/MdcThreadFactory.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.concurrent +package xyz.driver.pdsuicommon.concurrent import java.util.concurrent.ThreadFactory diff --git a/src/main/scala/xyz/driver/common/db/DbCommand.scala b/src/main/scala/xyz/driver/pdsuicommon/db/DbCommand.scala index fec8b9f..911ecee 100644 --- a/src/main/scala/xyz/driver/common/db/DbCommand.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/DbCommand.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.db +package xyz.driver.pdsuicommon.db import scala.concurrent.Future diff --git a/src/main/scala/xyz/driver/common/db/DbCommandFactory.scala b/src/main/scala/xyz/driver/pdsuicommon/db/DbCommandFactory.scala index 84c1383..f12b437 100644 --- a/src/main/scala/xyz/driver/common/db/DbCommandFactory.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/DbCommandFactory.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.db +package xyz.driver.pdsuicommon.db import scala.concurrent.{ExecutionContext, Future} diff --git a/src/main/scala/xyz/driver/common/db/EntityExtractorDerivation.scala b/src/main/scala/xyz/driver/pdsuicommon/db/EntityExtractorDerivation.scala index 0396ea5..e13ea39 100644 --- a/src/main/scala/xyz/driver/common/db/EntityExtractorDerivation.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/EntityExtractorDerivation.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.db +package xyz.driver.pdsuicommon.db import java.sql.ResultSet @@ -14,9 +14,6 @@ trait EntityExtractorDerivation[Naming <: NamingStrategy] { /** * Simple Quill extractor derivation for [[T]] * Only case classes available. Type parameters is not supported - * - * @tparam T - * @return */ def entityExtractor[T]: (ResultSet => T) = macro EntityExtractorDerivation.impl[T] } diff --git a/src/main/scala/xyz/driver/common/db/EntityNotFoundException.scala b/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala index d4c11ac..3b3bbdf 100644 --- a/src/main/scala/xyz/driver/common/db/EntityNotFoundException.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala @@ -1,6 +1,6 @@ -package xyz.driver.common.db +package xyz.driver.pdsuicommon.db -import xyz.driver.common.domain.Id +import xyz.driver.pdsuicommon.domain.Id class EntityNotFoundException private(id: String, tableName: String) extends RuntimeException(s"Entity with id $id is not found in $tableName table") { diff --git a/src/main/scala/xyz/driver/common/db/MysqlQueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/MysqlQueryBuilder.scala index d6b53d9..672a34e 100644 --- a/src/main/scala/xyz/driver/common/db/MysqlQueryBuilder.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/MysqlQueryBuilder.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.db +package xyz.driver.pdsuicommon.db import java.sql.ResultSet @@ -8,7 +8,7 @@ import scala.collection.breakOut import scala.concurrent.{ExecutionContext, Future} object MysqlQueryBuilder { - import xyz.driver.common.db.QueryBuilder._ + import xyz.driver.pdsuicommon.db.QueryBuilder._ def apply[T](tableName: String, lastUpdateFieldName: Option[String], diff --git a/src/main/scala/xyz/driver/common/db/Pagination.scala b/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala index d4a96d3..e72b5c2 100644 --- a/src/main/scala/xyz/driver/common/db/Pagination.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala @@ -1,6 +1,6 @@ -package xyz.driver.common.db +package xyz.driver.pdsuicommon.db -import xyz.driver.common.logging._ +import xyz.driver.pdsuicommon.logging._ /** * @param pageNumber Starts with 1 @@ -16,5 +16,4 @@ object Pagination { import x._ phi"Pagination(pageSize=${Unsafe(pageSize)}, pageNumber=${Unsafe(pageNumber)})" } - } diff --git a/src/main/scala/xyz/driver/common/db/QueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala index f0beca6..9b798d8 100644 --- a/src/main/scala/xyz/driver/common/db/QueryBuilder.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala @@ -1,12 +1,12 @@ -package xyz.driver.common.db +package xyz.driver.pdsuicommon.db import java.sql.PreparedStatement import java.time.LocalDateTime import io.getquill.NamingStrategy import io.getquill.context.sql.idiom.SqlIdiom -import xyz.driver.common.db.Sorting.{Dimension, Sequential} -import xyz.driver.common.db.SortingOrder.{Ascending, Descending} +import xyz.driver.pdsuicommon.db.Sorting.{Dimension, Sequential} +import xyz.driver.pdsuicommon.db.SortingOrder.{Ascending, Descending} import scala.collection.mutable.ListBuffer import scala.concurrent.{ExecutionContext, Future} diff --git a/src/main/scala/xyz/driver/common/db/SearchFilterExpr.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala index 06b21cd..60db303 100644 --- a/src/main/scala/xyz/driver/common/db/SearchFilterExpr.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala @@ -1,6 +1,6 @@ -package xyz.driver.common.db +package xyz.driver.pdsuicommon.db -import xyz.driver.common.logging._ +import xyz.driver.pdsuicommon.logging._ sealed trait SearchFilterExpr { def find(p: SearchFilterExpr => Boolean): Option[SearchFilterExpr] diff --git a/src/main/scala/xyz/driver/common/db/Sorting.scala b/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala index 70c25f2..4b2427c 100644 --- a/src/main/scala/xyz/driver/common/db/Sorting.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala @@ -1,6 +1,6 @@ -package xyz.driver.common.db +package xyz.driver.pdsuicommon.db -import xyz.driver.common.logging._ +import xyz.driver.pdsuicommon.logging._ import scala.collection.generic.CanBuildFrom diff --git a/src/main/scala/xyz/driver/common/db/SqlContext.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SqlContext.scala index 4b9d676..5aa0084 100644 --- a/src/main/scala/xyz/driver/common/db/SqlContext.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/SqlContext.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.db +package xyz.driver.pdsuicommon.db import java.io.Closeable import java.net.URI @@ -7,14 +7,15 @@ import java.util.UUID import java.util.concurrent.Executors import javax.sql.DataSource -import xyz.driver.common.logging.{PhiLogging, Unsafe} -import xyz.driver.common.concurrent.MdcExecutionContext -import xyz.driver.common.db.SqlContext.Settings -import xyz.driver.common.domain._ -import xyz.driver.common.error.IncorrectIdException -import xyz.driver.common.utils.JsonSerializer +import xyz.driver.pdsuicommon.logging.{PhiLogging, Unsafe} +import xyz.driver.pdsuicommon.concurrent.MdcExecutionContext +import xyz.driver.pdsuicommon.db.SqlContext.Settings +import xyz.driver.pdsuicommon.domain._ +import xyz.driver.pdsuicommon.error.IncorrectIdException +import xyz.driver.pdsuicommon.utils.JsonSerializer import com.typesafe.config.Config import io.getquill._ +import xyz.driver.pdsuidomain.entities.{CaseId, RecordRequestId} import scala.concurrent.ExecutionContext import scala.util.control.NonFatal @@ -169,7 +170,6 @@ class SqlContext(dataSource: DataSource with Closeable, settings: Settings) } } - implicit val encodeRecordRequestId = MappedEncoding[RecordRequestId, String](_.id.toString) implicit val decodeRecordRequestId = MappedEncoding[String, RecordRequestId] { x => RecordRequestId(UUID.fromString(x)) @@ -180,5 +180,4 @@ class SqlContext(dataSource: DataSource with Closeable, settings: Settings) // scalastyle:off def <=(right: LocalDateTime): Quoted[Boolean] = quote(infix"$left <= $right".as[Boolean]) } - } diff --git a/src/main/scala/xyz/driver/common/db/Transactions.scala b/src/main/scala/xyz/driver/pdsuicommon/db/Transactions.scala index 2f5a2cc..72c358a 100644 --- a/src/main/scala/xyz/driver/common/db/Transactions.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/Transactions.scala @@ -1,6 +1,6 @@ -package xyz.driver.common.db +package xyz.driver.pdsuicommon.db -import xyz.driver.common.logging.PhiLogging +import xyz.driver.pdsuicommon.logging.PhiLogging import scala.concurrent.Future import scala.util.{Failure, Success, Try} diff --git a/src/main/scala/xyz/driver/common/db/repositories/BridgeUploadQueueRepository.scala b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala index e0d6ff2..edef2eb 100644 --- a/src/main/scala/xyz/driver/common/db/repositories/BridgeUploadQueueRepository.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala @@ -1,7 +1,7 @@ -package xyz.driver.common.db.repositories +package xyz.driver.pdsuicommon.db.repositories -import xyz.driver.common.concurrent.BridgeUploadQueue -import xyz.driver.common.domain.LongId +import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue +import xyz.driver.pdsuicommon.domain.LongId import scala.concurrent.Future diff --git a/src/main/scala/xyz/driver/common/db/repositories/Repository.scala b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/Repository.scala index ae2a3e6..d671e80 100644 --- a/src/main/scala/xyz/driver/common/db/repositories/Repository.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/Repository.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.db.repositories +package xyz.driver.pdsuicommon.db.repositories // For further usage and migration to Postgres and slick trait Repository extends RepositoryLogging diff --git a/src/main/scala/xyz/driver/common/db/repositories/RepositoryLogging.scala b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/RepositoryLogging.scala index cb2c438..d1ec1da 100644 --- a/src/main/scala/xyz/driver/common/db/repositories/RepositoryLogging.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/RepositoryLogging.scala @@ -1,6 +1,6 @@ -package xyz.driver.common.db.repositories +package xyz.driver.pdsuicommon.db.repositories -import xyz.driver.common.logging._ +import xyz.driver.pdsuicommon.logging._ trait RepositoryLogging extends PhiLogging { diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/Email.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/Email.scala new file mode 100644 index 0000000..092ad40 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/domain/Email.scala @@ -0,0 +1,3 @@ +package xyz.driver.pdsuicommon.domain + +final case class Email(value: String) diff --git a/src/main/scala/xyz/driver/common/domain/FuzzyValue.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/FuzzyValue.scala index 584f8f7..e338b2e 100644 --- a/src/main/scala/xyz/driver/common/domain/FuzzyValue.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/domain/FuzzyValue.scala @@ -1,9 +1,10 @@ -package xyz.driver.common.domain +package xyz.driver.pdsuicommon.domain -import xyz.driver.common.logging._ -import xyz.driver.common.utils.Utils +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.utils.Utils sealed trait FuzzyValue + object FuzzyValue { case object Yes extends FuzzyValue case object No extends FuzzyValue diff --git a/src/main/scala/xyz/driver/common/domain/Id.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala index 9f9604e..1bb70f8 100644 --- a/src/main/scala/xyz/driver/common/domain/Id.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala @@ -1,8 +1,8 @@ -package xyz.driver.common.domain +package xyz.driver.pdsuicommon.domain import java.util.UUID -import xyz.driver.common.logging._ +import xyz.driver.pdsuicommon.logging._ sealed trait Id[+T] diff --git a/src/main/scala/xyz/driver/common/domain/PasswordHash.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/PasswordHash.scala index 7b25799..82cba8d 100644 --- a/src/main/scala/xyz/driver/common/domain/PasswordHash.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/domain/PasswordHash.scala @@ -1,10 +1,10 @@ -package xyz.driver.common.domain +package xyz.driver.pdsuicommon.domain import java.nio.charset.Charset import org.mindrot.jbcrypt.BCrypt -case class PasswordHash(value: Array[Byte]) { +final case class PasswordHash(value: Array[Byte]) { lazy val hashString: String = new String(value, Charset.forName("UTF-8")) @@ -19,24 +19,18 @@ case class PasswordHash(value: Array[Byte]) { } } - override def hashCode(): Int = { + override def hashCode(): Int = 42 + java.util.Arrays.hashCode(this.value) - } - def is(password: String): Boolean = { + def is(password: String): Boolean = BCrypt.checkpw(password, hashString) - } - } object PasswordHash { - def apply(password: String): PasswordHash = { + def apply(password: String): PasswordHash = new PasswordHash(getHash(password)) - } - private def getHash(str: String): Array[Byte] = { + private def getHash(str: String): Array[Byte] = BCrypt.hashpw(str, BCrypt.gensalt()).getBytes(Charset.forName("UTF-8")) - } - } diff --git a/src/main/scala/xyz/driver/common/domain/TextJson.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala index af18723..ee4d884 100644 --- a/src/main/scala/xyz/driver/common/domain/TextJson.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala @@ -1,8 +1,8 @@ -package xyz.driver.common.domain +package xyz.driver.pdsuicommon.domain -import xyz.driver.common.logging._ +import xyz.driver.pdsuicommon.logging._ -case class TextJson[+T](content: T) { +final case class TextJson[+T](content: T) { def map[U](f: T => U): TextJson[U] = copy(f(content)) } diff --git a/src/main/scala/xyz/driver/common/domain/User.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala index 83d861f..acc3565 100644 --- a/src/main/scala/xyz/driver/common/domain/User.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala @@ -1,10 +1,10 @@ -package xyz.driver.common.domain +package xyz.driver.pdsuicommon.domain import java.time.LocalDateTime -import xyz.driver.common.logging._ -import xyz.driver.common.domain.User.Role -import xyz.driver.common.utils.Utils +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.domain.User.Role +import xyz.driver.pdsuicommon.utils.Utils case class User(id: LongId[User], email: Email, diff --git a/src/main/scala/xyz/driver/common/error/DomainError.scala b/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala index d277543..4bf90d1 100644 --- a/src/main/scala/xyz/driver/common/error/DomainError.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/error/DomainError.scala @@ -1,7 +1,7 @@ -package xyz.driver.common.error +package xyz.driver.pdsuicommon.error -import xyz.driver.common.logging.{PhiString, Unsafe} -import xyz.driver.common.utils.Utils +import xyz.driver.pdsuicommon.logging.{PhiString, Unsafe} +import xyz.driver.pdsuicommon.utils.Utils trait DomainError { @@ -27,5 +27,4 @@ object DomainError { // so we should prevent it to be printed in logs. Unsafe(Utils.getClassSimpleName(x.getClass)) } - } diff --git a/src/main/scala/xyz/driver/common/error/ExceptionFormatter.scala b/src/main/scala/xyz/driver/pdsuicommon/error/ExceptionFormatter.scala index 33dd94c..1e3e4c4 100644 --- a/src/main/scala/xyz/driver/common/error/ExceptionFormatter.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/error/ExceptionFormatter.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.error +package xyz.driver.pdsuicommon.error import java.io.{ByteArrayOutputStream, PrintStream} @@ -15,5 +15,4 @@ object ExceptionFormatter { ps.close() baos.toString() } - } diff --git a/src/main/scala/xyz/driver/common/error/FailedValidationException.scala b/src/main/scala/xyz/driver/pdsuicommon/error/FailedValidationException.scala index 018ce58..7137255 100644 --- a/src/main/scala/xyz/driver/common/error/FailedValidationException.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/error/FailedValidationException.scala @@ -1,5 +1,5 @@ -package xyz.driver.common.error +package xyz.driver.pdsuicommon.error -import xyz.driver.common.validation.ValidationError +import xyz.driver.pdsuicommon.validation.ValidationError class FailedValidationException(val error: ValidationError) extends RuntimeException("The validation is failed") diff --git a/src/main/scala/xyz/driver/pdsuicommon/error/IncorrectIdException.scala b/src/main/scala/xyz/driver/pdsuicommon/error/IncorrectIdException.scala new file mode 100644 index 0000000..5705229 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/error/IncorrectIdException.scala @@ -0,0 +1,3 @@ +package xyz.driver.pdsuicommon.error + +final case class IncorrectIdException(message: String) extends Exception(message) diff --git a/src/main/scala/xyz/driver/common/http/AsyncHttpClientFetcher.scala b/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala index 5d54f0d..4b0d897 100644 --- a/src/main/scala/xyz/driver/common/http/AsyncHttpClientFetcher.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.http +package xyz.driver.pdsuicommon.http import java.io.Closeable import java.net.URL @@ -7,8 +7,8 @@ import java.util.concurrent.{ExecutorService, Executors} import com.typesafe.scalalogging.StrictLogging import org.asynchttpclient._ import org.slf4j.MDC -import xyz.driver.common.concurrent.MdcThreadFactory -import xyz.driver.common.utils.RandomUtils +import xyz.driver.pdsuicommon.concurrent.MdcThreadFactory +import xyz.driver.pdsuicommon.utils.RandomUtils import scala.concurrent.duration.FiniteDuration import scala.concurrent.{ExecutionContext, Future, Promise} diff --git a/src/main/scala/xyz/driver/common/http/AsyncHttpClientUploader.scala b/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientUploader.scala index 97c96cd..6ad404f 100644 --- a/src/main/scala/xyz/driver/common/http/AsyncHttpClientUploader.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientUploader.scala @@ -1,12 +1,12 @@ -package xyz.driver.common.http +package xyz.driver.pdsuicommon.http import java.io.Closeable import java.net.URI import java.util.concurrent.{ExecutorService, Executors} -import xyz.driver.common.concurrent.MdcThreadFactory -import xyz.driver.common.http.AsyncHttpClientUploader._ -import xyz.driver.common.utils.RandomUtils +import xyz.driver.pdsuicommon.concurrent.MdcThreadFactory +import xyz.driver.pdsuicommon.http.AsyncHttpClientUploader._ +import xyz.driver.pdsuicommon.utils.RandomUtils import com.typesafe.scalalogging.StrictLogging import org.asynchttpclient._ import org.slf4j.MDC @@ -90,14 +90,13 @@ class AsyncHttpClientUploader(settings: Settings) extends Closeable with StrictL httpClient.close() es.shutdown() } - } object AsyncHttpClientUploader { - case class Settings(connectTimeout: FiniteDuration, - requestTimeout: FiniteDuration, - defaultHeaders: Map[String, String] = Map.empty) + final case class Settings(connectTimeout: FiniteDuration, + requestTimeout: FiniteDuration, + defaultHeaders: Map[String, String] = Map.empty) sealed trait Method @@ -110,7 +109,5 @@ object AsyncHttpClientUploader { case object Post extends Method { override val toString = "POST" } - } - } diff --git a/src/main/scala/xyz/driver/common/http/package.scala b/src/main/scala/xyz/driver/pdsuicommon/http/package.scala index 3aff80c..20b1c97 100644 --- a/src/main/scala/xyz/driver/common/http/package.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/http/package.scala @@ -1,4 +1,4 @@ -package xyz.driver.common +package xyz.driver.pdsuicommon import java.net.URL diff --git a/src/main/scala/xyz/driver/common/logging/DefaultPhiLogger.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/DefaultPhiLogger.scala index ca25c44..3b0c1ad 100644 --- a/src/main/scala/xyz/driver/common/logging/DefaultPhiLogger.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/logging/DefaultPhiLogger.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.logging +package xyz.driver.pdsuicommon.logging import org.slf4j.{Logger => Underlying} diff --git a/src/main/scala/xyz/driver/common/logging/Implicits.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/Implicits.scala index e486cc1..cf095e3 100644 --- a/src/main/scala/xyz/driver/common/logging/Implicits.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/logging/Implicits.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.logging +package xyz.driver.pdsuicommon.logging import java.io.File import java.net.{URI, URL} diff --git a/src/main/scala/xyz/driver/common/logging/PhiLogger.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogger.scala index c8907a8..741ef18 100644 --- a/src/main/scala/xyz/driver/common/logging/PhiLogger.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogger.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.logging +package xyz.driver.pdsuicommon.logging trait PhiLogger { diff --git a/src/main/scala/xyz/driver/common/logging/PhiLogging.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogging.scala index b8cdcf0..e7730ea 100644 --- a/src/main/scala/xyz/driver/common/logging/PhiLogging.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiLogging.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.logging +package xyz.driver.pdsuicommon.logging import org.slf4j.LoggerFactory diff --git a/src/main/scala/xyz/driver/common/logging/PhiString.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiString.scala index ce1b90c..78ac62e 100644 --- a/src/main/scala/xyz/driver/common/logging/PhiString.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiString.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.logging +package xyz.driver.pdsuicommon.logging class PhiString(private[logging] val text: String) { // scalastyle:off diff --git a/src/main/scala/xyz/driver/common/logging/PhiStringContext.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiStringContext.scala index 8b3c9d0..97819de 100644 --- a/src/main/scala/xyz/driver/common/logging/PhiStringContext.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/logging/PhiStringContext.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.logging +package xyz.driver.pdsuicommon.logging final class PhiStringContext(val sc: StringContext) extends AnyVal { def phi(args: PhiString*): PhiString = { diff --git a/src/main/scala/xyz/driver/common/logging/Unsafe.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala index c605c85..3b0acb0 100644 --- a/src/main/scala/xyz/driver/common/logging/Unsafe.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.logging +package xyz.driver.pdsuicommon.logging /** * Use it with care! diff --git a/src/main/scala/xyz/driver/common/logging/package.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/package.scala index 479f59e..2905108 100644 --- a/src/main/scala/xyz/driver/common/logging/package.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/logging/package.scala @@ -1,3 +1,3 @@ -package xyz.driver.common +package xyz.driver.pdsuicommon package object logging extends Implicits diff --git a/src/main/scala/xyz/driver/common/pdf/PdfRenderer.scala b/src/main/scala/xyz/driver/pdsuicommon/pdf/PdfRenderer.scala index 9882f5d..93be2cc 100644 --- a/src/main/scala/xyz/driver/common/pdf/PdfRenderer.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/pdf/PdfRenderer.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.pdf +package xyz.driver.pdsuicommon.pdf import java.nio.file.Path @@ -9,5 +9,4 @@ trait PdfRenderer { def delete(documentName: String): Unit def getPath(fileName: String): Path - } diff --git a/src/main/scala/xyz/driver/common/pdf/WkHtmlToPdfRenderer.scala b/src/main/scala/xyz/driver/pdsuicommon/pdf/WkHtmlToPdfRenderer.scala index 0e0b338..9c14646 100644 --- a/src/main/scala/xyz/driver/common/pdf/WkHtmlToPdfRenderer.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/pdf/WkHtmlToPdfRenderer.scala @@ -1,11 +1,11 @@ -package xyz.driver.common.pdf +package xyz.driver.pdsuicommon.pdf import java.io.IOException import java.nio.file._ import io.github.cloudify.scala.spdf._ -import xyz.driver.common.logging._ -import xyz.driver.common.pdf.WkHtmlToPdfRenderer.Settings +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.pdf.WkHtmlToPdfRenderer.Settings object WkHtmlToPdfRenderer { @@ -22,9 +22,7 @@ object WkHtmlToPdfRenderer { dirPath.toAbsolutePath.normalize() } - } - } class WkHtmlToPdfRenderer(settings: Settings) extends PdfRenderer with PhiLogging { diff --git a/src/main/scala/xyz/driver/common/resources/ResourcesStorage.scala b/src/main/scala/xyz/driver/pdsuicommon/resources/ResourcesStorage.scala index f52d992..2be7ed7 100644 --- a/src/main/scala/xyz/driver/common/resources/ResourcesStorage.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/resources/ResourcesStorage.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.resources +package xyz.driver.pdsuicommon.resources import scala.io.{Codec, Source} @@ -8,7 +8,6 @@ trait ResourcesStorage { * @param resourcePath Don't forget / at start */ def getFirstLine(resourcePath: String): String - } object RealResourcesStorage extends ResourcesStorage { @@ -29,11 +28,9 @@ object RealResourcesStorage extends ResourcesStorage { throw new RuntimeException(s"Can not find the '$resourcePath'!") } } - } object FakeResourcesStorage extends ResourcesStorage { def getFirstLine(resourcePath: String): String = "" - } diff --git a/src/main/scala/xyz/driver/common/utils/Computation.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/Computation.scala index a435afe..e609ab0 100644 --- a/src/main/scala/xyz/driver/common/utils/Computation.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/Computation.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.utils +package xyz.driver.pdsuicommon.utils import scala.concurrent.{ExecutionContext, Future} @@ -106,5 +106,4 @@ object Computation { def fromFuture[T](input: Future[T])(implicit ec: ExecutionContext): Computation[Nothing, T] = Computation { input.map { x => Right(x) } } - } diff --git a/src/main/scala/xyz/driver/common/utils/FutureUtils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala index 6933c63..9eecb7f 100644 --- a/src/main/scala/xyz/driver/common/utils/FutureUtils.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.utils +package xyz.driver.pdsuicommon.utils import scala.concurrent.{ExecutionContext, Future} import scala.util.Try @@ -15,5 +15,4 @@ object FutureUtils { } future.value.get } - } diff --git a/src/main/scala/xyz/driver/common/utils/Implicits.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala index bdccaac..c8af125 100644 --- a/src/main/scala/xyz/driver/common/utils/Implicits.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.utils +package xyz.driver.pdsuicommon.utils import scala.collection.generic.CanBuildFrom diff --git a/src/main/scala/xyz/driver/common/utils/JsonSerializer.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/JsonSerializer.scala index 936a983..8c8fd4e 100644 --- a/src/main/scala/xyz/driver/common/utils/JsonSerializer.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/JsonSerializer.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.utils +package xyz.driver.pdsuicommon.utils import java.text.SimpleDateFormat @@ -23,5 +23,4 @@ object JsonSerializer { def deserialize[T](value: String)(implicit m: Manifest[T]): T = { mapper.readValue(value) } - } diff --git a/src/main/scala/xyz/driver/common/utils/MapOps.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/MapOps.scala index 759fdea..79f73a4 100644 --- a/src/main/scala/xyz/driver/common/utils/MapOps.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/MapOps.scala @@ -1,6 +1,7 @@ -package xyz.driver.common.utils +package xyz.driver.pdsuicommon.utils final class MapOps[K, V](val self: Map[K, V]) extends AnyVal { + def swap: Map[V, Set[K]] = { self .toList diff --git a/src/main/scala/xyz/driver/common/utils/RandomUtils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/RandomUtils.scala index d4cd4dc..faf8703 100644 --- a/src/main/scala/xyz/driver/common/utils/RandomUtils.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/RandomUtils.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.utils +package xyz.driver.pdsuicommon.utils import java.util.concurrent.ThreadLocalRandom @@ -16,5 +16,4 @@ object RandomUtils { chars(i) })(breakOut) } - } diff --git a/src/main/scala/xyz/driver/common/utils/ServiceUtils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/ServiceUtils.scala index dd309fb..979c483 100644 --- a/src/main/scala/xyz/driver/common/utils/ServiceUtils.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/ServiceUtils.scala @@ -1,14 +1,14 @@ -package xyz.driver.common.utils +package xyz.driver.pdsuicommon.utils -import xyz.driver.common.db.SearchFilterBinaryOperation.Eq -import xyz.driver.common.db.SearchFilterExpr -import xyz.driver.common.db.SearchFilterExpr.{Atom, Dimension} -import xyz.driver.common.logging._ +import xyz.driver.pdsuicommon.db.SearchFilterBinaryOperation.Eq +import xyz.driver.pdsuicommon.db.SearchFilterExpr +import xyz.driver.pdsuicommon.db.SearchFilterExpr.{Atom, Dimension} +import xyz.driver.pdsuicommon.logging._ import scala.util.{Failure, Success, Try} - object ServiceUtils extends PhiLogging { + def findEqFilter(filter: SearchFilterExpr, fieldName: String): Option[SearchFilterExpr] = { findEqFilter(filter, Dimension(None, fieldName)) } diff --git a/src/main/scala/xyz/driver/common/utils/Utils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/Utils.scala index 39f1294..ad605e9 100644 --- a/src/main/scala/xyz/driver/common/utils/Utils.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/Utils.scala @@ -1,4 +1,4 @@ -package xyz.driver.common.utils +package xyz.driver.pdsuicommon.utils import java.time.LocalDateTime diff --git a/src/main/scala/xyz/driver/common/validation/ValidationError.scala b/src/main/scala/xyz/driver/pdsuicommon/validation/ValidationError.scala index 6db445d..9f466f8 100644 --- a/src/main/scala/xyz/driver/common/validation/ValidationError.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/validation/ValidationError.scala @@ -1,3 +1,3 @@ -package xyz.driver.common.validation +package xyz.driver.pdsuicommon.validation final case class ValidationError(message: String) diff --git a/src/main/scala/xyz/driver/common/validation/Validators.scala b/src/main/scala/xyz/driver/pdsuicommon/validation/Validators.scala index 8d807f4..5dd244e 100644 --- a/src/main/scala/xyz/driver/common/validation/Validators.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/validation/Validators.scala @@ -1,7 +1,7 @@ -package xyz.driver.common.validation +package xyz.driver.pdsuicommon.validation -import xyz.driver.common.logging._ -import xyz.driver.common.utils.JsonSerializer +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.utils.JsonSerializer import scala.util.control.NonFatal @@ -37,5 +37,4 @@ object Validators extends PhiLogging { def success[T](result: T): Either[Nothing, T] = Right(result) def fail(message: String): Either[ValidationError, Nothing] = Left(ValidationError(message)) - } diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Arm.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Arm.scala new file mode 100644 index 0000000..17a913d --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Arm.scala @@ -0,0 +1,21 @@ +package xyz.driver.pdsuidomain.entities + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.domain.{LongId, StringId} +import xyz.driver.pdsuicommon.logging._ + +case class Arm(id: LongId[Arm], + name: String, + originalName: String, + trialId: StringId[Trial], + deleted: Option[LocalDateTime] = None) + +object Arm { + + implicit def toPhiString(x: Arm): PhiString = { + import x._ + phi"Arm(id=$id, name=${Unsafe(x.name)}, trialId=${Unsafe(x.trialId)})" + } +} + diff --git a/src/main/scala/xyz/driver/common/domain/CaseId.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/CaseId.scala index bb11f90..751545e 100644 --- a/src/main/scala/xyz/driver/common/domain/CaseId.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/CaseId.scala @@ -1,8 +1,8 @@ -package xyz.driver.common.domain +package xyz.driver.pdsuidomain.entities import java.util.UUID -case class CaseId(id: String) +final case class CaseId(id: String) object CaseId { diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala new file mode 100644 index 0000000..0dfb33f --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala @@ -0,0 +1,55 @@ +package xyz.driver.pdsuidomain.entities + +import xyz.driver.pdsuicommon.domain.{LongId, StringId} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.Criterion.Meta.Evidence + +final case class Criterion(id: LongId[Criterion], + trialId: StringId[Trial], + text: Option[String], + isCompound: Boolean, + meta: String) { + + def isValid(): Boolean = text.nonEmpty && Option(meta).isDefined +} + +object Criterion { + + final case class Meta(evidence: Evidence) + + object Meta { + final case class Evidence(pageRatio: Double, start: TextLayerPosition, end: TextLayerPosition) + final case class TextLayerPosition(page: Integer, index: Integer, offset: Integer) + } + + implicit def toPhiString(x: Criterion): PhiString = { + import x._ + phi"Criterion(id=$id, trialId=$trialId, isCompound=$isCompound)" + } +} + +final case class CriterionArm(criterionId: LongId[Criterion], armId: LongId[Arm]) + +object CriterionArm { + + implicit def toPhiString(x: CriterionArm): PhiString = { + import x._ + phi"CriterionArm(criterionId=$criterionId, armId=$armId)" + } +} + +final case class CriterionLabel(id: LongId[CriterionLabel], + labelId: Option[LongId[Label]], + criterionId: LongId[Criterion], + categoryId: Option[LongId[Category]], + value: Option[Boolean], + isDefining: Boolean) + +object CriterionLabel { + + implicit def toPhiString(x: CriterionLabel): PhiString = { + import x._ + phi"CriterionLabel(id=$id, labelId=$labelId, criterionId=$criterionId, " + + phi"categoryId=$categoryId, value=$value, isDefining=$isDefining)" + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/DirectReport.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/DirectReport.scala new file mode 100644 index 0000000..c9d1d88 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/DirectReport.scala @@ -0,0 +1,42 @@ +package xyz.driver.pdsuidomain.entities + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.domain.UuidId +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.utils.Utils +import xyz.driver.pdsuidomain.entities.DirectReport.ReportType + +object DirectReport { + + sealed trait ReportType extends Product with Serializable { + def oneOf(xs: ReportType*): Boolean = xs.contains(this) + + def oneOf(xs: Set[ReportType]): Boolean = xs.contains(this) + } + + object ReportType { + case object IHC extends ReportType + case object DNA extends ReportType + case object CFDNA extends ReportType + + val All = Set(IHC, DNA, CFDNA) + implicit def toPhiString(x: ReportType): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) + } + + implicit def toPhiString(x: DirectReport): PhiString = { + import x._ + phi"DirectReport(id=$id, patientId=$patientId, reportType=$reportType, date=${Unsafe(date)}, " + + phi"documentType=${Unsafe(documentType)}, providerType=${Unsafe(providerType)}, " + + phi"providerName=${Unsafe(providerName)})" + } + +} + +case class DirectReport(id: UuidId[DirectReport], + patientId: UuidId[Patient], + reportType: ReportType, + date: LocalDateTime, + documentType: String, + providerType: String, + providerName: String) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Document.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Document.scala new file mode 100644 index 0000000..8c2616a --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Document.scala @@ -0,0 +1,153 @@ +package xyz.driver.pdsuidomain.entities + +import java.time.LocalDateTime + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.core.{JsonGenerator, JsonParser} +import com.fasterxml.jackson.databind._ +import com.fasterxml.jackson.databind.annotation.{JsonDeserialize, JsonSerialize} +import xyz.driver.pdsuicommon.domain.{LongId, TextJson, User} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.utils.Utils +import xyz.driver.pdsuicommon.validation.Validators +import xyz.driver.pdsuicommon.validation.Validators.Validator +import xyz.driver.pdsuidomain.entities.Document.Meta +import xyz.driver.pdsuicommon.compat.Implicits._ + + +final case class ProviderType(id: LongId[ProviderType], name: String) + +object ProviderType { + implicit def toPhiString(x: ProviderType): PhiString = { + import x._ + phi"ProviderType(id=$id, category=${Unsafe(name)})" + } +} + +final case class DocumentType(id: LongId[DocumentType], name: String) + +object DocumentType { + implicit def toPhiString(x: DocumentType): PhiString = { + import x._ + phi"DocumentType(id=$id, name=${Unsafe(name)})" + } +} + +object Document { + + case class Meta(predicted: Option[Boolean], startPage: Double, endPage: Double) { + /** + * Return a regular meta: this meta is considered as not predicted + */ + def confirmed: Meta = copy(predicted = predicted.map(_ => false)) + } + + class DocumentStatusSerializer extends JsonSerializer[Status] { + def serialize(value: Status, gen: JsonGenerator, serializers: SerializerProvider): Unit = { + gen.writeString(value.toString.toUpperCase) + } + } + + class DocumentStatusDeserializer extends JsonDeserializer[Status] { + def deserialize(parser: JsonParser, context: DeserializationContext): Status = { + val value = parser.getValueAsString + Option(value).fold[Document.Status](Status.New /* Default document status */) { v => + Status.All.find(_.toString.toUpperCase == v) match { + case None => throw new RuntimeJsonMappingException(s"$v is not valid Document.Status") + case Some(status) => status + } + } + } + } + + // Product with Serializable fixes issue: + // Set(New, Organized) has type Set[Status with Product with Serializable] + @JsonDeserialize(using = classOf[DocumentStatusDeserializer]) + @JsonSerialize(using = classOf[DocumentStatusSerializer]) + sealed trait Status extends Product with Serializable { + + def oneOf(xs: Status*): Boolean = xs.contains(this) + + def oneOf(xs: Set[Status]): Boolean = xs.contains(this) + + } + object Status { + case object New extends Status + case object Organized extends Status + case object Extracted extends Status + case object Done extends Status + case object Flagged extends Status + case object Archived extends Status + + val All = Set[Status](New, Organized, Extracted, Done, Flagged, Archived) + val AllPrevious = Set[Status](Organized, Extracted) + + implicit def toPhiString(x: Status): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) + } + + implicit def toPhiString(x: Document): PhiString = { + import x._ + phi"Document(id=$id, status=$status, assignee=$assignee, previousAssignee=$previousAssignee, recordId=$recordId)" + } + + val validator: Validator[Document, Document] = { input => + for { + typeId <- Validators.nonEmpty("typeId")(input.typeId) + + providerTypeId <- Validators.nonEmpty("providerTypeId")(input.providerTypeId) + + meta <- Validators.nonEmpty("meta")(input.meta) + + startDate <- Validators.nonEmpty("startDate")(input.startDate) + + isOrderRight <- input.endDate match { + case Some(endDate) if startDate.isAfter(endDate) => + Validators.fail("The start date should be less, than the end one") + + case _ => Validators.success(true) + } + + areDatesInThePast <- { + val dates = List(input.startDate, input.endDate).flatten + val now = LocalDateTime.now() + val hasInvalid = dates.exists(_.isAfter(now)) + + if (hasInvalid) Validators.fail("Dates should be in the past") + else Validators.success(true) + } + } yield input + } + +} + +@JsonIgnoreProperties(value = Array("valid")) +case class Document(id: LongId[Document] = LongId(0L), + status: Document.Status, + previousStatus: Option[Document.Status], + assignee: Option[LongId[User]], + previousAssignee: Option[LongId[User]], + recordId: LongId[MedicalRecord], + physician: Option[String], + typeId: Option[LongId[DocumentType]], // not null + providerName: Option[String], // not null + providerTypeId: Option[LongId[ProviderType]], // not null + meta: Option[TextJson[Meta]], // not null + startDate: Option[LocalDateTime], // not null + endDate: Option[LocalDateTime], + lastUpdate: LocalDateTime) { + + import Document.Status._ + + if (previousStatus.nonEmpty) { + assert(AllPrevious.contains(previousStatus.get), + s"Previous status has invalid value: ${previousStatus.get}") + } + + // TODO: with the current business logic code this constraint sometimes harmful + // require(status match { + // case Document.Status.New if assignee.isDefined => false + // case Document.Status.Done if assignee.isDefined => false + // case _ => true + // }, "Assignee can't be defined in New or Done statuses") + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala new file mode 100644 index 0000000..9972142 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/ExtractedData.scala @@ -0,0 +1,48 @@ +package xyz.driver.pdsuidomain.entities + +import xyz.driver.pdsuicommon.domain.{FuzzyValue, LongId, TextJson} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.ExtractedData.Meta + +final case class ExtractedData(id: LongId[ExtractedData] = LongId(0L), + documentId: LongId[Document], + keywordId: Option[LongId[Keyword]], + evidenceText: Option[String], + meta: Option[TextJson[Meta]]) { + + def isValid: Boolean = evidenceText.getOrElse("") != "" && meta.nonEmpty + +} + +object ExtractedData { + + final case class Meta(keyword: Meta.Keyword, evidence: Meta.Evidence) + + object Meta { + + final case class Evidence(pageRatio: Double, start: TextLayerPosition, end: TextLayerPosition) + + final case class TextLayerPosition(page: Integer, index: Integer, offset: Integer) + + final case class Keyword(page: Integer, pageRatio: Option[Double], index: Integer, sortIndex: String) + } + + implicit def toPhiString(x: ExtractedData): PhiString = { + import x._ + phi"ExtractedData(id=$id, documentId=$documentId, keywordId=$keywordId)" + } +} + +object ExtractedDataLabel { + + implicit def toPhiString(x: ExtractedDataLabel): PhiString = { + import x._ + phi"ExtractedDataLabel(id=$id, dataId=$dataId, labelId=$labelId, categoryId=$categoryId, value=$value)" + } +} + +final case class ExtractedDataLabel(id: LongId[ExtractedDataLabel], + dataId: LongId[ExtractedData], + labelId: Option[LongId[Label]], + categoryId: Option[LongId[Category]], + value: Option[FuzzyValue]) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Hypothesis.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Hypothesis.scala new file mode 100644 index 0000000..eb2b95e --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Hypothesis.scala @@ -0,0 +1,16 @@ +package xyz.driver.pdsuidomain.entities + +import xyz.driver.pdsuicommon.domain.UuidId +import xyz.driver.pdsuicommon.logging._ + +final case class Hypothesis(id: UuidId[Hypothesis], + name: String, + treatmentType: String, + description: String) + +object Hypothesis { + implicit def toPhiString(x: Hypothesis): PhiString = { + import x._ + phi"Hypothesis(id=$id, name=${Unsafe(name)})" + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala new file mode 100644 index 0000000..6ff1a67 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala @@ -0,0 +1,48 @@ +package xyz.driver.pdsuidomain.entities + +import xyz.driver.pdsuicommon.domain.{LongId, StringId} +import xyz.driver.pdsuicommon.logging._ + + +final case class InterventionType(id: LongId[InterventionType], name: String) + +object InterventionType { + implicit def toPhiString(x: InterventionType): PhiString = { + import x._ + phi"InterventionType(id=$id, name=${Unsafe(name)})" + } +} + +final case class InterventionArm(armId: LongId[Arm], interventionId: LongId[Intervention]) + +object InterventionArm { + implicit def toPhiString(x: InterventionArm): PhiString = { + import x._ + phi"InterventionArm(armId=$armId, interventionId=$interventionId)" + } +} + +final case class Intervention(id: LongId[Intervention], + trialId: StringId[Trial], + name: String, + originalName: String, + typeId: Option[LongId[InterventionType]], + originalType: Option[String], + description: String, + isActive: Boolean) + +object Intervention { + implicit def toPhiString(x: Intervention): PhiString = { + import x._ + phi"Intervention(id=$id, trialId=$trialId, name=${Unsafe(name)}, typeId=$typeId, isActive=$isActive)" + } +} + +final case class InterventionWithArms(intervention: Intervention, arms: List[InterventionArm]) + +object InterventionWithArms { + implicit def toPhiString(x: InterventionWithArms): PhiString = { + import x._ + phi"InterventionWithArms(intervention=$intervention, arms=$arms)" + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Keyword.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Keyword.scala new file mode 100644 index 0000000..3683efc --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Keyword.scala @@ -0,0 +1,31 @@ +package xyz.driver.pdsuidomain.entities + +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.logging._ + +final case class Keyword(id: LongId[Keyword], keyword: String) + +object Keyword { + implicit def toPhiString(x: Keyword): PhiString = { + import x._ + phi"Keyword(id=$id, keyword=${Unsafe(keyword)})" + } +} + +final case class KeywordWithLabels(keyword: Keyword, labels: List[Label]) + +object KeywordWithLabels { + implicit def toPhiString(x: KeywordWithLabels): PhiString = { + import x._ + phi"KeywordWithLabels(keyword=$keyword, $labels)" + } +} + +final case class KeywordLabel(keywordId: LongId[Keyword], labelId: LongId[Label]) + +object KeywordLabel { + implicit def toPhiString(x: KeywordLabel): PhiString = { + import x._ + phi"KeywordLabel($keywordId, $labelId)" + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Label.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Label.scala new file mode 100644 index 0000000..7f9c2aa --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Label.scala @@ -0,0 +1,34 @@ +package xyz.driver.pdsuidomain.entities + +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.logging._ + +final case class Category(id: LongId[Category], name: String) + +object Category { + implicit def toPhiString(x: Category): PhiString = { + import x._ + phi"Category(id=$id, name=${Unsafe(name)})" + } +} + +final case class Label(id: LongId[Label], + categoryId: LongId[Category], + name: String, + description: String) + +object Label { + implicit def toPhiString(x: Label): PhiString = { + import x._ + phi"Label($id, categoryId=${Unsafe(categoryId)}, name=${Unsafe(name)}, description=${Unsafe(description)})" + } +} + +final case class CategoryWithLabels(category: Category, labels: List[Label]) + +object CategoryWithLabels { + implicit def toPhiString(x: CategoryWithLabels): PhiString = { + import x._ + phi"CategoryWithLabels(category=$category, labels=$labels)" + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecord.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecord.scala new file mode 100644 index 0000000..977f4cc --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecord.scala @@ -0,0 +1,164 @@ +package xyz.driver.pdsuidomain.entities + +import java.nio.channels.ReadableByteChannel +import java.time.LocalDateTime + +import com.fasterxml.jackson.annotation.JsonSubTypes.Type +import com.fasterxml.jackson.annotation.{JsonProperty, JsonSubTypes, JsonTypeInfo} +import xyz.driver.pdsuicommon.domain.{LongId, TextJson, User, UuidId} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.utils.Utils +import xyz.driver.pdsuidomain.entities.MedicalRecord.Meta +import xyz.driver.pdsuidomain.entities.MedicalRecord.Meta.{Duplicate, Reorder, Rotation} + +object MedicalRecord { + + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") + @JsonSubTypes(Array( + new Type(value = classOf[Duplicate], name = "duplicate"), + new Type(value = classOf[Reorder], name = "reorder"), + new Type(value = classOf[Rotation], name = "rotation") + )) + trait Meta { + @JsonProperty("type") def metaType: String + def predicted: Option[Boolean] + + /** + * Return a regular meta: this meta is considered as not predicted + */ + def confirmed: Meta + } + + object Meta { + + case class Duplicate(predicted: Option[Boolean], + startPage: Double, + endPage: Double, + startOriginalPage: Double, + endOriginalPage: Option[Double] + ) extends Meta { + override val metaType = "duplicate" + override def confirmed: Duplicate = copy(predicted = predicted.map(_ => false)) + } + + object Duplicate { + implicit def toPhiString(x: Duplicate): PhiString = { + import x._ + phi"Duplicate(predicted=${x.predicted}, startPage=${Unsafe(startPage)}, endPage=${Unsafe(endPage)}, " + + phi"startOriginalPage=${Unsafe(startOriginalPage)}, endOriginalPage=${Unsafe(endOriginalPage)}" + } + } + + + case class Reorder(predicted: Option[Boolean], + items: Seq[Int] + ) extends Meta { + override val metaType = "reorder" + override def confirmed: Reorder = copy(predicted = predicted.map(_ => false)) + } + + object Reorder { + implicit def toPhiString(x: Reorder): PhiString = { + import x._ + phi"Reorder(predicted=${x.predicted}, items=${Unsafe(items.toString)})" + } + } + + + case class Rotation(predicted: Option[Boolean], + items: Map[String, Int] + ) extends Meta { + override val metaType = "rotation" + override def confirmed: Rotation = copy(predicted = predicted.map(_ => false)) + } + + object Rotation { + implicit def toPhiString(x: Rotation): PhiString = { + import x._ + phi"Rotation(predicted=${x.predicted}, items=${Unsafe(items.toString)})" + } + } + + + implicit def toPhiString(input: Meta): PhiString = input match { + case x: Duplicate => Duplicate.toPhiString(x) + case x: Reorder => Reorder.toPhiString(x) + case x: Rotation => Rotation.toPhiString(x) + } + + } + + // Product with Serializable fixes issue: + // Set(New, Cleaned) has type Set[Status with Product with Serializable] + sealed trait Status extends Product with Serializable { + + def oneOf(xs: Status*): Boolean = xs.contains(this) + + def oneOf(xs: Set[Status]): Boolean = xs.contains(this) + + } + object Status { + case object Unprocessed extends Status + case object PreCleaning extends Status + case object New extends Status + case object Cleaned extends Status + case object PreOrganized extends Status + case object PreOrganizing extends Status + case object Reviewed extends Status + case object Organized extends Status + case object Done extends Status + case object Flagged extends Status + case object Archived extends Status + + val All = Set[Status]( + Unprocessed, PreCleaning, New, Cleaned, PreOrganized, PreOrganizing, Reviewed, Organized, Done, Flagged, Archived + ) + + val AllPrevious = Set[Status](New, Cleaned, Reviewed, Organized) + + implicit def toPhiString(x: Status): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) + } + + sealed trait PdfSource + + object PdfSource { + case object Empty extends PdfSource + /** @param createResource Constructor of the resource which is represents the file */ + case class Channel(createResource: () => ReadableByteChannel) extends PdfSource + } + + implicit def toPhiString(x: MedicalRecord): PhiString = { + import x._ + phi"MedicalRecord(id=$id, status=$status, assignee=$assignee, previousAssignee=$previousAssignee)" + } +} + +case class MedicalRecord(id: LongId[MedicalRecord], + status: MedicalRecord.Status, + previousStatus: Option[MedicalRecord.Status], + assignee: Option[LongId[User]], + previousAssignee: Option[LongId[User]], + patientId: UuidId[Patient], + requestId: RecordRequestId, + disease: String, + caseId: Option[CaseId], + physician: Option[String], + sourceName: String, + meta: Option[TextJson[List[Meta]]], + predictedMeta: Option[TextJson[List[Meta]]], + predictedDocuments: Option[TextJson[List[Document]]], + lastUpdate: LocalDateTime) { + + import MedicalRecord.Status._ + + if (previousStatus.nonEmpty) { + assert(AllPrevious.contains(previousStatus.get), + s"Previous status has invalid value: ${previousStatus.get}") + } + + // TODO: with the current business logic code this constraint sometimes harmful + // require(status match { + // case MedicalRecord.Status.Done if assignee.isDefined => false + // case _ => true + // }, "Assignee can't be defined in Done status") +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Message.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Message.scala new file mode 100644 index 0000000..2a73922 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Message.scala @@ -0,0 +1,34 @@ +package xyz.driver.pdsuidomain.entities + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.domain.{LongId, StringId, User, UuidId} +import xyz.driver.pdsuicommon.logging._ + +final case class Message(id: LongId[Message], + text: String, + lastUpdate: LocalDateTime, + userId: LongId[User], + isDraft: Boolean, + recordId: Option[LongId[MedicalRecord]], + documentId: Option[LongId[Document]], + patientId: Option[UuidId[Patient]], + trialId: Option[StringId[Trial]], + startPage: Option[Double], + endPage: Option[Double], + evidence: Option[String], + archiveRequired: Option[Boolean], + meta: Option[String]) + +object Message { + implicit def toPhiString(x: Message): PhiString = { + import x._ + + val entityId = recordId + .orElse(documentId) + .orElse(patientId) + .map(_.toString) + + phi"Message(id=$id, userId=$userId, isDraft=$isDraft, entityId=${Unsafe(entityId)}" + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Patient.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Patient.scala new file mode 100644 index 0000000..7767db0 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Patient.scala @@ -0,0 +1,63 @@ +package xyz.driver.pdsuidomain.entities + +import java.time.{LocalDate, LocalDateTime} + +import xyz.driver.pdsuicommon.domain.{LongId, User, UuidId} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.utils.Utils + +object Patient { + + // Product with Serizalizable fixes issue: + // Set(New, Verified) has type Set[Status with Product with Serializable] + sealed trait Status extends Product with Serializable { + def oneOf(xs: Status*): Boolean = xs.contains(this) + + def oneOf(xs: Set[Status]): Boolean = xs.contains(this) + } + + object Status { + case object New extends Status + case object Verified extends Status + case object Reviewed extends Status + case object Curated extends Status + case object Flagged extends Status + case object Done extends Status + + val AllPrevious = Set[Status]( + New, Verified, Reviewed, Curated + ) + + val All = Set[Status]( + New, Verified, Reviewed, Curated, Flagged, Done + ) + + implicit def toPhiString(x: Status): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) + } + + implicit def toPhiString(x: Patient): PhiString = { + import x._ + phi"Patient(id=$id, status=$status, previousStatus=$previousStatus, " + + phi"assignee=$assignee, previousAssignee=$previousAssignee)" + } +} + +case class Patient(id: UuidId[Patient], + status: Patient.Status, + name: String, + dob: LocalDate, + assignee: Option[LongId[User]], + previousStatus: Option[Patient.Status], + previousAssignee: Option[LongId[User]], + isUpdateRequired: Boolean, + condition: String, + orderId: PatientOrderId, + lastUpdate: LocalDateTime) { + + import Patient.Status._ + + if (previousStatus.nonEmpty) { + assert(AllPrevious.contains(previousStatus.get), + s"Previous status has invalid value: ${previousStatus.get}") + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientEligibleTrial.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientEligibleTrial.scala new file mode 100644 index 0000000..8d5af0d --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientEligibleTrial.scala @@ -0,0 +1,155 @@ +package xyz.driver.pdsuidomain.entities + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.domain.{FuzzyValue, LongId, StringId, UuidId} +import xyz.driver.pdsuicommon.logging._ + +object PatientCriterion { + implicit def toPhiString(x: PatientCriterion): PhiString = { + import x._ + phi"PatientCriterion(id=$id, patientLabelId=$patientLabelId, trialId=${Unsafe(trialId)}, nctId=${Unsafe(nctId)}, " + + phi"criterionId=$criterionId, criterionValue=${Unsafe(criterionValue)}, " + + phi"isImplicitMatch=$criterionIsDefining), criterionIsDefining=${Unsafe(criterionIsDefining)}, " + + phi"eligibilityStatus=${Unsafe(eligibilityStatus)}, verifiedEligibilityStatus=${Unsafe(verifiedEligibilityStatus)}, " + + phi"isVerified=${Unsafe(isVerified)}, lastUpdate=${Unsafe(lastUpdate)}" + } + + /** + * @see https://driverinc.atlassian.net/wiki/display/MTCH/EV+Business+Process + */ + def getEligibilityStatus(criterionValue: Option[Boolean], + primaryValue: Option[FuzzyValue]): Option[FuzzyValue] = { + primaryValue match { + case None => None + case Some(FuzzyValue.Maybe) => Some(FuzzyValue.Maybe) + case Some(_) if criterionValue.isEmpty => Some(FuzzyValue.Maybe) + case Some(status) => Some(FuzzyValue.fromBoolean( + FuzzyValue.fromBoolean(criterionValue.getOrElse( + throw new IllegalArgumentException("Criterion should not be empty")) + ) == status + )) + } + } + +} + +/** + * @param eligibilityStatus - a value, that selects an eligibility verifier (EV) + * @param verifiedEligibilityStatus - a copy of eligibilityStatus, when a patient goes to routes curator (RC) + * @param isVerified - is EV selected the eligibilityStatus? + */ +final case class PatientCriterion(id: LongId[PatientCriterion], + patientLabelId: LongId[PatientLabel], + trialId: Long, + nctId: StringId[Trial], + criterionId: LongId[Criterion], + criterionText: String, + criterionValue: Option[Boolean], + criterionIsDefining: Boolean, + eligibilityStatus: Option[FuzzyValue], + verifiedEligibilityStatus: Option[FuzzyValue], + isVerified: Boolean, + isVisible: Boolean, + lastUpdate: LocalDateTime) { + def isIneligible: Boolean = eligibilityStatus.contains(FuzzyValue.No) && isVerified +} + +object PatientTrialArm { + + implicit def toPhiString(x: PatientTrialArm): PhiString = { + import x._ + phi"PatientTrialArm(armId=$armId, trialArmGroupId=$trialArmGroupId)" + } +} + +final case class PatientTrialArm(armId: LongId[Arm], trialArmGroupId: LongId[PatientTrialArmGroup]) + +object PatientEligibleTrial { + implicit def toPhiString(x: PatientEligibleTrial): PhiString = { + import x._ + phi"PatientEligibleTrial(id=$id, patientId=$patientId, trialId=$trialId, hypothesisId=$hypothesisId)" + } +} + +final case class PatientEligibleTrial(id: UuidId[PatientEligibleTrial], + patientId: UuidId[Patient], + trialId: StringId[Trial], + hypothesisId: UuidId[Hypothesis]) + +object PatientTrialArmGroup { + + implicit def toPhiString(x: PatientTrialArmGroup): PhiString = { + import x._ + phi"PatientTrialArmGroup(id=$id, eligibleTrialId=$eligibleTrialId, " + + phi"eligibilityStatus=${Unsafe(eligibilityStatus)}, isVerified=$isVerified)" + } + + /** + * @see https://driverinc.atlassian.net/wiki/display/DMPD/EV+Business+Process + */ + def getEligibilityStatusForEvToRc(criterionList: List[(Option[Boolean], Option[FuzzyValue])]): Option[FuzzyValue] = { + def isEligible = { + // Eligible, if for all (verified for EV) label-criteria eligibilityStatus=NULL or YES and at least one has status=YES + // If method executes from PatientService (when EV submit patient) need to check value PatientCriterion.isVerified + val verifiedList = criterionList.filter { case (isVerifiedOpt, _) => isVerifiedOpt.isEmpty || isVerifiedOpt.get } + verifiedList.forall { case (_, eligibilityStatus) => + eligibilityStatus.isEmpty || eligibilityStatus.contains(FuzzyValue.Yes) + } && verifiedList.exists { case (_, eligibilityStatus) => eligibilityStatus.contains(FuzzyValue.Yes) } + } + + if (criterionList.exists { case (isVerified, eligibilityStatus) => + eligibilityStatus.contains(FuzzyValue.No) && (isVerified.isEmpty || isVerified.get) + }) { Some(FuzzyValue.No) + } else if (criterionList.forall { case (_, eligibilityStatus) => eligibilityStatus.isEmpty }) { + None + } else if (isEligible) { + Some(FuzzyValue.Yes) + } else { + Some(FuzzyValue.Maybe) + } + } + + /** + * @see https://driverinc.atlassian.net/wiki/display/DMPD/EV+Business+Process + */ + def getEligibilityStatusForRc(criterionList: TraversableOnce[PatientCriterion]): Option[FuzzyValue] = { + def isEligible: Boolean = criterionList.forall(_.verifiedEligibilityStatus.contains(FuzzyValue.Yes)) + def isIneligible: Boolean = criterionList.exists(_.verifiedEligibilityStatus.contains(FuzzyValue.No)) + def isUnknown: Boolean = criterionList.forall(_.verifiedEligibilityStatus.isEmpty) + + if (isEligible) Some(FuzzyValue.Yes) + else if (isIneligible) Some(FuzzyValue.No) + else if (isUnknown) None + else Some(FuzzyValue.Maybe) + } +} + +final case class PatientTrialArmGroup(id: LongId[PatientTrialArmGroup], + eligibleTrialId: UuidId[PatientEligibleTrial], + eligibilityStatus: Option[FuzzyValue], + isVerified: Boolean) + +object PatientTrialArmGroupView { + + implicit def toPhiString(x: PatientTrialArmGroupView): PhiString = { + import x._ + phi"PatientTrialArmGroupView(id=$id, patientId=$patientId, trialId=$trialId, hypothesisId=$hypothesisId, " + + phi"eligibilityStatus=${Unsafe(eligibilityStatus)}, isVerified=$isVerified)" + } +} + +final case class PatientTrialArmGroupView(id: LongId[PatientTrialArmGroup], + patientId: UuidId[Patient], + trialId: StringId[Trial], + hypothesisId: UuidId[Hypothesis], + eligibilityStatus: Option[FuzzyValue], + isVerified: Boolean) { + + def applyTo(trialArmGroup: PatientTrialArmGroup) = { + trialArmGroup.copy( + eligibilityStatus = this.eligibilityStatus, + isVerified = this.isVerified + ) + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientHypothesis.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientHypothesis.scala new file mode 100644 index 0000000..146b1c3 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientHypothesis.scala @@ -0,0 +1,18 @@ +package xyz.driver.pdsuidomain.entities + +import xyz.driver.pdsuicommon.domain.UuidId +import xyz.driver.pdsuicommon.logging._ + +object PatientHypothesis { + implicit def toPhiString(x: PatientHypothesis): PhiString = { + import x._ + phi"PatientHypothesis(id=$id, patientId=$patientId, hypothesisId=$hypothesisId, " + + phi"rationale=${Unsafe(rationale)}, matchedTrials=${Unsafe(matchedTrials)})" + } +} + +case class PatientHypothesis(id: UuidId[PatientHypothesis], + patientId: UuidId[Patient], + hypothesisId: UuidId[Hypothesis], + rationale: Option[String], + matchedTrials: Long) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientLabel.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientLabel.scala new file mode 100644 index 0000000..633a347 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientLabel.scala @@ -0,0 +1,38 @@ +package xyz.driver.pdsuidomain.entities + +import xyz.driver.pdsuicommon.domain.{FuzzyValue, LongId, UuidId} +import xyz.driver.pdsuicommon.logging._ + +object PatientLabel { + implicit def toPhiString(x: PatientLabel): PhiString = { + import x._ + phi"PatientLabel(id=$id, patientId=$patientId, labelId=$labelId, " + + phi"score=${Unsafe(score)}, primaryValue=${Unsafe(primaryValue)}, " + + phi"verifiedPrimaryValue=${Unsafe(verifiedPrimaryValue)})" + } +} + +final case class PatientLabel(id: LongId[PatientLabel], + patientId: UuidId[Patient], + labelId: LongId[Label], + score: Int, + primaryValue: Option[FuzzyValue], + verifiedPrimaryValue: Option[FuzzyValue], + isImplicitMatch: Boolean, + isVisible: Boolean) + +object PatientLabelEvidence { + implicit def toPhiString(x: PatientLabelEvidence): PhiString = { + import x._ + phi"PatientLabelEvidence(id=$id, patientLabelId=$patientLabelId, value=${Unsafe(value)}, " + + phi"documentId=$documentId, evidenceId=$evidenceId, reportId=$reportId)" + } +} + +final case class PatientLabelEvidence(id: LongId[PatientLabelEvidence], + patientLabelId: LongId[PatientLabel], + value: FuzzyValue, + evidenceText: String, + reportId: Option[UuidId[DirectReport]], + documentId: Option[LongId[Document]], + evidenceId: Option[LongId[ExtractedData]]) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/PatientOrderId.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientOrderId.scala new file mode 100644 index 0000000..50a97ce --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/PatientOrderId.scala @@ -0,0 +1,14 @@ +package xyz.driver.pdsuidomain.entities + +import java.util.UUID + +final case class PatientOrderId(id: UUID) { + override def toString: String = id.toString +} + +object PatientOrderId { + + def apply() = new PatientOrderId(UUID.randomUUID()) + + def apply(x: String) = new PatientOrderId(UUID.fromString(x)) +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/RawPatientDocument.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/RawPatientDocument.scala new file mode 100644 index 0000000..88e1a45 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/RawPatientDocument.scala @@ -0,0 +1,28 @@ +package xyz.driver.pdsuidomain.entities + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.domain.{LongId, UuidId} +import xyz.driver.pdsuicommon.logging._ + +case class RawPatientDocument(disease: String, + patientId: UuidId[Patient], + requestId: RecordRequestId, + recordId: LongId[MedicalRecord], + recordStatus: MedicalRecord.Status, + documentId: LongId[Document], + documentType: String, + documentProviderType: String, + documentStartDate: LocalDateTime, + documentStatus: Document.Status) + +object RawPatientDocument { + + implicit def toPhiString(x: RawPatientDocument): PhiString = { + import x._ + phi"RawPatientDocument(disease=${Unsafe(disease)}, patientId=$patientId, requestId=$requestId, " + + phi"recordId=$recordId, recordStatus=$recordStatus, documentId=$documentId, " + + phi"documentType=${Unsafe(documentType)}, providerType=${Unsafe(documentProviderType)}, " + + phi"startDate=$documentStartDate, documentStatus=$documentStatus)" + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/RawPatientLabel.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/RawPatientLabel.scala new file mode 100644 index 0000000..e0cf06b --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/RawPatientLabel.scala @@ -0,0 +1,33 @@ +package xyz.driver.pdsuidomain.entities + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.domain.{FuzzyValue, LongId, UuidId} +import xyz.driver.pdsuicommon.logging._ + +case class RawPatientLabel(patientId: UuidId[Patient], + labelId: LongId[Label], + label: String, + value: FuzzyValue, + evidenceId: LongId[ExtractedData], + evidenceText: String, + disease: String, + documentId: LongId[Document], + requestId: RecordRequestId, + documentType: String, + providerType: String, + startDate: LocalDateTime, + endDate: Option[LocalDateTime]) + +object RawPatientLabel { + + implicit def toPhiString(x: RawPatientLabel): PhiString = { + import x._ + phi"RawPatientLabel(patientId=$patientId, labelId=$labelId, label=${Unsafe(label)}, value=$value," + + phi"evidenceId=${Unsafe(evidenceId)}, " + + phi"evidenceText=${Unsafe(evidenceText)}, documentId=$documentId, requestId=${Unsafe(requestId)}, " + + phi"documentType=${Unsafe(documentType)}, providerType=${Unsafe(providerType)}, " + + phi"startDate=$startDate, endDate=$endDate)" + } + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/RawTrialLabel.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/RawTrialLabel.scala new file mode 100644 index 0000000..e3b323f --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/RawTrialLabel.scala @@ -0,0 +1,32 @@ +package xyz.driver.pdsuidomain.entities + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} +import xyz.driver.pdsuicommon.logging._ + +case class RawTrialLabel(nctId: StringId[Trial], + trialId: UuidId[Trial], + condition: String, + lastReviewed: LocalDateTime, + armName: String, + armId: LongId[Arm], + labelId: LongId[Label], + label: String, + value: Option[Boolean], + criterionId: LongId[Criterion], + criteria: String, + criterionArmId: LongId[Arm], + isCompound: Boolean, + isDefining: Boolean) + +object RawTrialLabel { + + implicit def toPhiString(x: RawTrialLabel): PhiString = { + import x._ + phi"RawTrialLabel(nctId=$nctId, trialId=$trialId, condition=${Unsafe(condition)}, lastReviewed=$lastReviewed, " + + phi"armId=$armId, armName=${Unsafe(armName)}, labelId=$labelId, label=${Unsafe(label)}, value=$value, " + + phi"criterionId=$criterionId, criteria=${Unsafe(criteria)}, criterionArmId=$criterionArmId, " + + phi"isCompound=$isCompound, isDefining=$isDefining)" + } +} diff --git a/src/main/scala/xyz/driver/common/domain/RecordRequestId.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/RecordRequestId.scala index 901ff66..5df87c2 100644 --- a/src/main/scala/xyz/driver/common/domain/RecordRequestId.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/RecordRequestId.scala @@ -1,10 +1,9 @@ -package xyz.driver.common.domain +package xyz.driver.pdsuidomain.entities import java.util.UUID +import xyz.driver.pdsuicommon.logging._ -import xyz.driver.common.logging._ - -case class RecordRequestId(id: UUID) { +final case class RecordRequestId(id: UUID) { override def toString: String = id.toString } diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala new file mode 100644 index 0000000..2477c22 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala @@ -0,0 +1,102 @@ +package xyz.driver.pdsuidomain.entities + +import java.nio.file.Path +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.domain.{LongId, StringId, User, UuidId} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.utils.Utils +import xyz.driver.pdsuidomain.entities.Trial.{Condition, Status} + + +final case class StudyDesign(id: LongId[StudyDesign], name: String) + +object StudyDesign { + implicit def toPhiString(x: StudyDesign): PhiString = { + import x._ + phi"StudyDesign(id=$id, category=${Unsafe(name)})" + } +} + +object Trial { + + sealed trait Status { + def oneOf(xs: Status*): Boolean = xs.contains(this) + def oneOf(xs: Set[Status]): Boolean = xs.contains(this) + } + + object Status { + case object New extends Status + case object ReviewSummary extends Status + case object Summarized extends Status + case object PendingUpdate extends Status + case object Update extends Status + case object ReviewCriteria extends Status + case object Done extends Status + case object Flagged extends Status + case object Archived extends Status + + val All = Set[Status]( + New, ReviewSummary, Summarized, PendingUpdate, Update, ReviewCriteria, Done, Flagged, Archived + ) + + val AllPrevious = Set[Status](New, ReviewSummary, Summarized, ReviewCriteria) + + implicit def toPhiString(x: Status): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass)) + } + + case class PdfSource(path: Path) extends AnyVal + + implicit def toPhiString(x: Trial): PhiString = { + import x._ + phi"Trial(id=$id, externalId=$externalId, status=$status, previousStatus=$previousStatus, " + + phi"assignee=$assignee, previousAssignee=$previousAssignee, isSummaryReviewed=$isSummaryReviewed, " + + phi"isCriteriaReviewed=$isCriteriaReviewed)" + } + + case class Locations(locations: List[String]) + + sealed trait Condition + + object Condition { + + case object Breast extends Condition + case object Lung extends Condition + case object Prostate extends Condition + + val All = Set(Breast, Lung, Prostate) + } +} + +final case class Trial(id: StringId[Trial], + externalId: UuidId[Trial], + status: Status, + assignee: Option[LongId[User]], + previousStatus: Option[Status], + previousAssignee: Option[LongId[User]], + lastUpdate: LocalDateTime, + condition: Condition, + phase: String, + hypothesisId: Option[UuidId[Hypothesis]], + studyDesignId: Option[LongId[StudyDesign]], + originalStudyDesign: Option[String], + isPartner: Boolean, + overview: Option[String], + overviewTemplate: String, + isUpdated: Boolean, + title: String, + originalTitle: String, + isSummaryReviewed: Boolean, + isCriteriaReviewed: Boolean, + eligibilityCriteriaChecksum: String, + briefSummaryChecksum: String, + detailedDescriptionChecksum: String, + armDescriptionChecksum: String) { + + import Trial.Status._ + + if (previousStatus.nonEmpty) { + assert(AllPrevious.contains(previousStatus.get), + s"Previous status has invalid value: ${previousStatus.get}") + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabel.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabel.scala new file mode 100644 index 0000000..7d5de79 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabel.scala @@ -0,0 +1,30 @@ +package xyz.driver.pdsuidomain.entities.export.patient + +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.{Label, RawPatientLabel} + +case class ExportPatientLabel(id: LongId[Label], + name: String, + evidences: List[ExportPatientLabelEvidence]) + +object ExportPatientLabel extends PhiLogging { + + implicit def toPhiString(x: ExportPatientLabel): PhiString = { + import x._ + phi"ExportPatientLabel(id=$id, evidences=$evidences)" + } + + def fromRaw(labelId: LongId[Label], rawPatientLabels: List[RawPatientLabel]): ExportPatientLabel = { + val firstLabel = rawPatientLabels.headOption + if (firstLabel.isEmpty) { + logger.warn(phi"rawPatientLabels is empty, labelId: $labelId") + } + + ExportPatientLabel( + id = labelId, + name = firstLabel.map(_.label).getOrElse(""), + evidences = rawPatientLabels.map(ExportPatientLabelEvidence.fromRaw) + ) + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidence.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidence.scala new file mode 100644 index 0000000..ff0fb6c --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidence.scala @@ -0,0 +1,32 @@ +package xyz.driver.pdsuidomain.entities.export.patient + +import xyz.driver.pdsuicommon.domain.{FuzzyValue, LongId} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.{ExtractedData, RawPatientLabel} + +case class ExportPatientLabelEvidence(id: LongId[ExtractedData], + value: FuzzyValue, + evidenceText: String, + document: ExportPatientLabelEvidenceDocument) + +object ExportPatientLabelEvidence { + + implicit def toPhiString(x: ExportPatientLabelEvidence): PhiString = { + import x._ + phi"ExportPatientLabelEvidence(id=${Unsafe(id)}, value=$value, " + + phi"evidenceText=${Unsafe(evidenceText)}, document=$document)" + } + + def fromRaw(x: RawPatientLabel) = ExportPatientLabelEvidence( + id = x.evidenceId, + value = x.value, + evidenceText = x.evidenceText, + document = ExportPatientLabelEvidenceDocument( + x.documentId, + x.requestId, + x.documentType, + x.providerType, + x.startDate + ) + ) +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidenceDocument.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidenceDocument.scala new file mode 100644 index 0000000..d696569 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientLabelEvidenceDocument.scala @@ -0,0 +1,30 @@ +package xyz.driver.pdsuidomain.entities.export.patient + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.{Document, RawPatientLabel, RecordRequestId} + +case class ExportPatientLabelEvidenceDocument(documentId: LongId[Document], + requestId: RecordRequestId, + documentType: String, + providerType: String, + date: LocalDateTime) + +object ExportPatientLabelEvidenceDocument extends PhiLogging { + + implicit def toPhiString(x: ExportPatientLabelEvidenceDocument): PhiString = { + import x._ + phi"ExportPatientLabelEvidenceDocument(documentId=$documentId, requestId=$requestId, " + + phi"documentType=${Unsafe(documentType)}, providerType=${Unsafe(providerType)}, date=$date)" + } + + def fromRaw(x: RawPatientLabel) = ExportPatientLabelEvidenceDocument( + documentId = x.documentId, + requestId = x.requestId, + documentType = x.documentType, + providerType = x.providerType, + date = x.startDate + ) +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientWithLabels.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientWithLabels.scala new file mode 100644 index 0000000..418f20b --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/patient/ExportPatientWithLabels.scala @@ -0,0 +1,26 @@ +package xyz.driver.pdsuidomain.entities.export.patient + +import xyz.driver.pdsuicommon.domain.UuidId +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.{Patient, RawPatientLabel} + +import scala.collection.breakOut + +case class ExportPatientWithLabels(patientId: UuidId[Patient], labelVersion: Long, labels: List[ExportPatientLabel]) + +object ExportPatientWithLabels { + + implicit def toPhiString(x: ExportPatientWithLabels): PhiString = { + import x._ + phi"ExportPatientWithLabels(patientId=$patientId, version=${Unsafe(labelVersion)}, labels=$labels)" + } + + def fromRaw(patientId: UuidId[Patient], + rawPatientRefs: List[RawPatientLabel]) = ExportPatientWithLabels( + patientId = patientId, + labelVersion = 1L, // TODO It is needed to replace this mock label version. + labels = rawPatientRefs + .groupBy(_.labelId) + .map(Function.tupled(ExportPatientLabel.fromRaw))(breakOut) + ) +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrial.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrial.scala new file mode 100644 index 0000000..a3a0e90 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrial.scala @@ -0,0 +1,27 @@ +package xyz.driver.pdsuidomain.entities.export.trial + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.domain.{StringId, UuidId} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.Trial + +case class ExportTrial(nctId: StringId[Trial], + trialId: UuidId[Trial], + condition: Trial.Condition, + lastReviewed: LocalDateTime) + +object ExportTrial { + + implicit def toPhiString(x: ExportTrial): PhiString = { + import x._ + phi"ExportTrial(nctId=$nctId, trialId=$trialId, condition=${Unsafe(condition)}, lastReviewed=$lastReviewed)" + } + + def fromDomain(x: Trial) = ExportTrial( + nctId = x.id, + trialId = x.externalId, + condition = x.condition, + lastReviewed = x.lastUpdate + ) +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala new file mode 100644 index 0000000..abdade4 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala @@ -0,0 +1,15 @@ +package xyz.driver.pdsuidomain.entities.export.trial + +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.Arm + +case class ExportTrialArm(armId: LongId[Arm], armName: String) + +object ExportTrialArm { + + implicit def toPhiString(x: ExportTrialArm): PhiString = { + import x._ + phi"ExportTrialArm(armId=$armId, armName=${Unsafe(armName)})" + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala new file mode 100644 index 0000000..1dccaa5 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala @@ -0,0 +1,32 @@ +package xyz.driver.pdsuidomain.entities.export.trial + +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.{Arm, Criterion, Label, RawTrialLabel} + +case class ExportTrialLabelCriterion(criterionId: LongId[Criterion], + value: Option[Boolean], + labelId: LongId[Label], + armIds: Set[LongId[Arm]], + criteria: String, + isCompound: Boolean, + isDefining: Boolean) + +object ExportTrialLabelCriterion { + + implicit def toPhiString(x: ExportTrialLabelCriterion): PhiString = { + import x._ + phi"TrialLabelCriterion(criterionId=$criterionId, value=$value, labelId=$labelId, " + + phi"criteria=${Unsafe(criteria)}, isCompound=$isCompound, isDefining=$isDefining)" + } + + def fromRaw(x: RawTrialLabel, armIds: Set[LongId[Arm]]) = ExportTrialLabelCriterion( + criterionId = x.criterionId, + value = x.value, + labelId = x.labelId, + armIds = armIds, + criteria = x.criteria, + isCompound = x.isCompound, + isDefining = x.isDefining + ) +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala new file mode 100644 index 0000000..251f6fb --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala @@ -0,0 +1,51 @@ +package xyz.driver.pdsuidomain.entities.export.trial + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.domain.{StringId, UuidId} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.{RawTrialLabel, Trial} + +import scala.collection.breakOut + +case class ExportTrialWithLabels(nctId: StringId[Trial], + trialId: UuidId[Trial], + condition: String, + lastReviewed: LocalDateTime, + labelVersion: Long, + arms: List[ExportTrialArm], + criteria: List[ExportTrialLabelCriterion]) + +object ExportTrialWithLabels { + + implicit def toPhiString(x: ExportTrialWithLabels): PhiString = { + import x._ + phi"TrialWithLabels(nctId=$nctId, trialId=$trialId, condition=${Unsafe(condition)}, " + + phi"lastReviewed=$lastReviewed, labelVersion=${Unsafe(labelVersion)}, arms=$arms, criteria=$criteria)" + } + + def fromRaw(rawData: List[RawTrialLabel]): ExportTrialWithLabels = { + val trials: Set[StringId[Trial]] = rawData.map(_.nctId)(breakOut) + + assert(trials.size == 1, "There are more than one trials in the rawData") + val trial = rawData.head + + ExportTrialWithLabels( + nctId = trial.nctId, + trialId = trial.trialId, + condition = trial.condition, + lastReviewed = trial.lastReviewed, + labelVersion = 1, // TODO It is needed to replace this mock label version. + arms = rawData.groupBy(_.armId).map { case (armId, rawTrials) => + ExportTrialArm(armId, rawTrials.head.armName) + }(breakOut), + criteria = rawData.groupBy { x => + (x.criterionId, x.labelId) + }.map { + case (_, rawTrialLabels) => + val armIds = rawTrialLabels.map(_.criterionArmId).toSet + ExportTrialLabelCriterion.fromRaw(rawTrialLabels.head, armIds) + }(breakOut) + ) + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/CategoryService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/CategoryService.scala new file mode 100644 index 0000000..31ccff7 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/CategoryService.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.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.CategoryWithLabels + +import scala.concurrent.Future + +object CategoryService { + sealed trait GetListReply + object GetListReply { + case class EntityList(xs: Seq[CategoryWithLabels], totalFound: Int) extends GetListReply + + case object AuthorizationError + extends GetListReply with DomainError.AuthorizationError { + def userMessage: String = "Access denied" + } + } +} + +trait CategoryService extends PhiLogging { + + import CategoryService._ + + def getAll(sorting: Option[Sorting] = None)(implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] +} 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..eaffb2a --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/ExportService.scala @@ -0,0 +1,60 @@ +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.{StringId, UuidId} +import xyz.driver.pdsuicommon.error.DomainError +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.{Patient, Trial} +import xyz.driver.pdsuidomain.entities.export.patient.ExportPatientWithLabels +import xyz.driver.pdsuidomain.entities.export.trial.{ExportTrial, ExportTrialWithLabels} + +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 extends PhiLogging { + + 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] + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/LabelService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/LabelService.scala new file mode 100644 index 0000000..25291f1 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/LabelService.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.pdsuicommon.logging.PhiLogging +import xyz.driver.pdsuidomain.entities.Label + +import scala.concurrent.Future + +object LabelService { + + sealed trait GetListReply + object GetListReply { + case class EntityList(xs: Seq[Label], totalFound: Int) extends GetListReply + + case object AuthorizationError + extends GetListReply with DomainError.AuthorizationError { + def userMessage: String = "Access denied" + } + } +} + +trait LabelService extends PhiLogging { + import LabelService._ + + def getAll(sorting: Option[Sorting] = None) + (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/MessageService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/MessageService.scala new file mode 100644 index 0000000..56140ce --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/MessageService.scala @@ -0,0 +1,100 @@ +package xyz.driver.pdsuidomain.services + +import java.time.LocalDateTime + +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 + +object MessageService { + + 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: Message) + 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: Message) + extends GetByIdReply + 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 GetListReply + object GetListReply { + type Error = GetListReply with DomainError + case class EntityList(xs: Seq[Message], 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: Message) + extends UpdateReply + case object AuthorizationError + extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError + 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 DomainError.AuthorizationError with DefaultAccessDeniedError + case object NotFoundError + extends DeleteReply with DomainError.NotFoundError with DefaultNotFoundError + case class CommonError(userMessage: String) + extends DeleteReply with DomainError + } + +} + +trait MessageService extends PhiLogging { + + import MessageService._ + + def create(draftMessage: Message)(implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] + + def getById(messageId: LongId[Message])(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(origMessage: Message, draftMessage: Message) + (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + + def delete(messageId: LongId[Message]) + (implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/UserService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/UserService.scala new file mode 100644 index 0000000..350720e --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/UserService.scala @@ -0,0 +1,143 @@ +package xyz.driver.pdsuidomain.services + +import xyz.driver.pdsuicommon.auth.{AnonymousRequestContext, AuthenticatedRequestContext} +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 + +object UserService { + + trait DefaultCredentialsError { + def userMessage: String = "Incorrect email/password. Try again." + } + + trait DefaultAccessDeniedError { + def userMessage: String = "Access denied" + } + + trait DefaultNotFoundError { + def userMessage: String = "User not found" + } + + sealed trait ActivateExecutorReply + object ActivateExecutorReply { + type Error = ActivateExecutorReply with DomainError + case class Entity(x: User) extends ActivateExecutorReply + case object NotFoundError + extends ActivateExecutorReply with DomainError.NotFoundError { + val userMessage = "Info about you is not found on the server" + } + } + + sealed trait GetByIdReply + object GetByIdReply { + type Error = GetByIdReply with DomainError + case class Entity(x: User) 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 GetByEmailReply + object GetByEmailReply { + case class Entity(x: User) extends GetByEmailReply + case object NotFoundError + extends GetByEmailReply with DefaultNotFoundError with DomainError.NotFoundError { + override def userMessage: String = "Incorrect email. Try again." + } + } + + sealed trait GetByCredentialsReply + object GetByCredentialsReply { + case class Entity(x: User) extends GetByCredentialsReply + case object AuthenticationError + extends GetByCredentialsReply with DefaultCredentialsError with DomainError.AuthenticationError + case object NotFoundError + extends GetByCredentialsReply with DomainError.NotFoundError with DefaultNotFoundError + } + + sealed trait GetListReply + object GetListReply { + case class EntityList(xs: Seq[User], totalFound: Int) extends GetListReply + case object AuthorizationError + extends GetListReply with DomainError.AuthorizationError with DefaultNotFoundError + } + + sealed trait CreateReply + object CreateReply { + type Error = CreateReply with DomainError + case class Created(x: User) extends CreateReply + case object AuthorizationError + extends CreateReply with DefaultNotFoundError with DomainError.AuthorizationError + case class UserAlreadyExistsError(email: Email) + extends CreateReply with DomainError { + val userMessage = s"The user with this email already exists." + } + case class CommonError(userMessage: String) + extends CreateReply with DomainError + } + + sealed trait UpdateReply + object UpdateReply { + type Error = UpdateReply with DomainError + case class Updated(updated: User) extends UpdateReply + case object AuthorizationError + extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + 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 class AuthorizationError(user: User) + extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError + case object AssignedToRecordAndDocumentError + extends DeleteReply with DomainError { + val userMessage = "User is can not be deleted because he has record and document in work" + } + case object NotFoundError + extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError + case class CommonError(userMessage: String) + extends DeleteReply with DomainError + } + +} + +trait UserService extends PhiLogging { + + import UserService._ + + /** + * Utility method for getting request executor. + */ + def activateExecutor(executorId: LongId[User]) + (implicit requestContext: AnonymousRequestContext): Future[ActivateExecutorReply] + + def getById(userId: LongId[User])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + + def getByEmail(email: Email) + (implicit requestContext: AnonymousRequestContext): Future[GetByEmailReply] + + def getByCredentials(email: Email, password: String) + (implicit requestContext: AnonymousRequestContext): Future[GetByCredentialsReply] + + def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Option[Sorting] = None, + pagination: Option[Pagination] = None) + (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + + def create(draftUser: User)(implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] + + def update(origUser: User, draftUser: User) + (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + + def delete(userId: LongId[User])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/storage/MedicalRecordDocumentStorage.scala b/src/main/scala/xyz/driver/pdsuidomain/storage/MedicalRecordDocumentStorage.scala new file mode 100644 index 0000000..d50be2c --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/storage/MedicalRecordDocumentStorage.scala @@ -0,0 +1,27 @@ +package xyz.driver.pdsuidomain.storage + +import com.google.cloud.storage.StorageOptions +import com.typesafe.scalalogging.StrictLogging +import xyz.driver.pdsuidomain.entities.MedicalRecord.PdfSource + +import scala.concurrent.{ExecutionContext, Future, blocking} + +object MedicalRecordDocumentStorage extends StrictLogging { + private val storage = StorageOptions.getDefaultInstance.getService + + def fetchPdf(bucket: String, path: String) + (implicit ec: ExecutionContext): Future[PdfSource] = { + logger.trace(s"fetchPdf(bucket=$bucket, path=$path)") + Future { + blocking { + Option(storage.get(bucket, path)) match { + case Some(blob) => + PdfSource.Channel(() => blob.reader()) + case None => + logger.error(s"Failed to find the pdf file $path in bucket: $bucket") + PdfSource.Empty + } + } + } + } +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/storage/RequestStorage.scala b/src/main/scala/xyz/driver/pdsuidomain/storage/RequestStorage.scala new file mode 100644 index 0000000..d9651ca --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/storage/RequestStorage.scala @@ -0,0 +1,52 @@ +package xyz.driver.pdsuidomain.storage + +import xyz.driver.pdsuicommon.domain.{LongId, UuidId} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.{Arm, Patient} + +import scala.collection.concurrent.TrieMap + +object RequestStorage { + type Key = (UuidId[Patient], String) + type Value = Set[LongId[Arm]] +} + +class RequestStorage extends PhiLogging { + import RequestStorage._ + + private val storage = new TrieMap[Key, Value]() + + def put(patientId: UuidId[Patient], + disease: String, + ineligibleArms: Set[LongId[Arm]]): Unit = { + logger.debug(phi"put($patientId, ${Unsafe(disease)}, $ineligibleArms") + val key = (patientId, disease.toLowerCase) + get(patientId, disease.toLowerCase) match { + case Some(oldValue) => + logger.trace(phi"Requested ineligible arms=$oldValue, replace it") + storage.replace(key, oldValue, ineligibleArms) + case None => + logger.trace(phi"Put request into storage") + storage.put(key, ineligibleArms) + } + } + + def get(patientId: UuidId[Patient], disease: String): Option[Value] = { + logger.debug(phi"get($patientId,${Unsafe(disease)}") + val key = (patientId, disease.toLowerCase) + storage.get(key) + } + + def contains(patientId: UuidId[Patient], + disease: String, + value: Set[LongId[Arm]]): Boolean = { + logger.debug(phi"contains(key=($patientId,${Unsafe(disease)}),value=$value") + get(patientId, disease.toLowerCase).contains(value) + } + + def remove(patientId: UuidId[Patient], disease: String): Unit = { + logger.debug(phi"remove($patientId,${Unsafe(disease)}") + val key = (patientId, disease.toLowerCase) + storage.remove(key) + } +} |