aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/pdsuicommon/domain
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/xyz/driver/pdsuicommon/domain')
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/domain/Email.scala3
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/domain/FuzzyValue.scala18
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala51
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/domain/PasswordHash.scala36
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala14
-rw-r--r--src/main/scala/xyz/driver/pdsuicommon/domain/User.scala74
6 files changed, 196 insertions, 0 deletions
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/pdsuicommon/domain/FuzzyValue.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/FuzzyValue.scala
new file mode 100644
index 0000000..e338b2e
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuicommon/domain/FuzzyValue.scala
@@ -0,0 +1,18 @@
+package xyz.driver.pdsuicommon.domain
+
+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
+ case object Maybe extends FuzzyValue
+
+ val All: Set[FuzzyValue] = Set(Yes, No, Maybe)
+
+ def fromBoolean(x: Boolean): FuzzyValue = if (x) Yes else No
+
+ implicit def toPhiString(x: FuzzyValue): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass))
+}
diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala
new file mode 100644
index 0000000..1bb70f8
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala
@@ -0,0 +1,51 @@
+package xyz.driver.pdsuicommon.domain
+
+import java.util.UUID
+
+import xyz.driver.pdsuicommon.logging._
+
+sealed trait Id[+T]
+
+case class CompoundId[Id1 <: Id[_], Id2 <: Id[_]](part1: Id1, part2: Id2) extends Id[(Id1, Id2)]
+
+case class LongId[+T](id: Long) extends Id[T] {
+ override def toString: String = id.toString
+
+ def is(longId: Long): Boolean = {
+ id == longId
+ }
+}
+
+object LongId {
+ implicit def toPhiString[T](x: LongId[T]): PhiString = Unsafe(s"LongId(${x.id})")
+}
+
+case class StringId[+T](id: String) extends Id[T] {
+ override def toString: String = id
+
+ def is(stringId: String): Boolean = {
+ id == stringId
+ }
+}
+
+object StringId {
+ implicit def toPhiString[T](x: StringId[T]): PhiString = Unsafe(s"StringId(${x.id})")
+}
+
+case class UuidId[+T](id: UUID) extends Id[T] {
+ override def toString: String = id.toString
+}
+
+object UuidId {
+
+ /**
+ * @note May fail, if `string` is invalid UUID.
+ */
+ def apply[T](string: String): UuidId[T] = new UuidId[T](UUID.fromString(string))
+
+ def apply[T](): UuidId[T] = new UuidId[T](UUID.randomUUID())
+
+ implicit def ordering[T] = Ordering.by[UuidId[T], String](_.toString)
+
+ implicit def toPhiString[T](x: UuidId[T]): PhiString = Unsafe(s"UuidId(${x.id})")
+}
diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/PasswordHash.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/PasswordHash.scala
new file mode 100644
index 0000000..82cba8d
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuicommon/domain/PasswordHash.scala
@@ -0,0 +1,36 @@
+package xyz.driver.pdsuicommon.domain
+
+import java.nio.charset.Charset
+
+import org.mindrot.jbcrypt.BCrypt
+
+final case class PasswordHash(value: Array[Byte]) {
+
+ lazy val hashString: String = new String(value, Charset.forName("UTF-8"))
+
+ override def toString: String = {
+ s"${this.getClass.getSimpleName}($hashString)"
+ }
+
+ override def equals(that: Any): Boolean = {
+ that match {
+ case thatHash: PasswordHash => java.util.Arrays.equals(this.value, thatHash.value)
+ case _ => false
+ }
+ }
+
+ override def hashCode(): Int =
+ 42 + java.util.Arrays.hashCode(this.value)
+
+ def is(password: String): Boolean =
+ BCrypt.checkpw(password, hashString)
+}
+
+object PasswordHash {
+
+ def apply(password: String): PasswordHash =
+ new PasswordHash(getHash(password))
+
+ 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/pdsuicommon/domain/TextJson.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala
new file mode 100644
index 0000000..ee4d884
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuicommon/domain/TextJson.scala
@@ -0,0 +1,14 @@
+package xyz.driver.pdsuicommon.domain
+
+import xyz.driver.pdsuicommon.logging._
+
+final case class TextJson[+T](content: T) {
+ def map[U](f: T => U): TextJson[U] = copy(f(content))
+}
+
+object TextJson {
+
+ implicit def toPhiString[T](x: TextJson[T])(implicit inner: T => PhiString): PhiString = {
+ phi"TextJson(${x.content})"
+ }
+}
diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala
new file mode 100644
index 0000000..acc3565
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala
@@ -0,0 +1,74 @@
+package xyz.driver.pdsuicommon.domain
+
+import java.time.LocalDateTime
+
+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,
+ name: String,
+ role: Role,
+ passwordHash: PasswordHash,
+ latestActivity: Option[LocalDateTime],
+ deleted: Option[LocalDateTime])
+
+object User {
+
+ sealed trait Role extends Product with Serializable {
+
+ /**
+ * Bit representation of this role
+ */
+ def bit: Int
+
+ def is(that: Role): Boolean = this == that
+
+ def oneOf(roles: Role*): Boolean = roles.contains(this)
+
+ def oneOf(roles: Set[Role]): Boolean = roles.contains(this)
+ }
+
+ object Role extends PhiLogging {
+ case object RecordAdmin extends Role {val bit = 1 << 0}
+ case object RecordCleaner extends Role {val bit = 1 << 1}
+ case object RecordOrganizer extends Role {val bit = 1 << 2}
+ case object DocumentExtractor extends Role {val bit = 1 << 3}
+ case object TrialSummarizer extends Role {val bit = 1 << 4}
+ case object CriteriaCurator extends Role {val bit = 1 << 5}
+ case object TrialAdmin extends Role {val bit = 1 << 6}
+ case object EligibilityVerifier extends Role{val bit = 1 << 7}
+ case object TreatmentMatchingAdmin extends Role{val bit = 1 << 8}
+ case object RoutesCurator extends Role{val bit = 1 << 9}
+
+ val RepRoles = Set[Role](RecordAdmin, RecordCleaner, RecordOrganizer, DocumentExtractor)
+
+ val TcRoles = Set[Role](TrialSummarizer, CriteriaCurator, TrialAdmin)
+
+ val TreatmentMatchingRoles = Set[Role](RoutesCurator, EligibilityVerifier, TreatmentMatchingAdmin)
+
+ val All = RepRoles ++ TcRoles ++ TreatmentMatchingRoles
+
+ def apply(bitMask: Int): Role = {
+ def extractRole(role: Role): Set[Role] =
+ if ((bitMask & role.bit) != 0) Set(role) else Set.empty[Role]
+
+ val roles = All.flatMap(extractRole)
+ roles.size match {
+ case 1 => roles.head
+ case _ =>
+ logger.error(phi"Can't convert a bit mask ${Unsafe(bitMask)} to any role")
+ throw new IllegalArgumentException()
+ }
+ }
+
+ implicit def toPhiString(x: Role): PhiString = Unsafe(Utils.getClassSimpleName(x.getClass))
+ }
+
+ implicit def toPhiString(x: User): PhiString = {
+ import x._
+ phi"User(id=$id, role=$role)"
+ }
+
+}