diff options
author | Jakob Odersky <jakob@driver.xyz> | 2017-07-05 19:02:13 -0700 |
---|---|---|
committer | Jakob Odersky <jakob@driver.xyz> | 2017-07-12 21:04:25 -0700 |
commit | f9ac0adf5c3bcfcde03bd3ea2bc2471b0d0f99fe (patch) | |
tree | 9e26568fe6598074a6de8815b465cbfc7ff69b7c /src/main/scala/xyz/driver/pdsuicommon | |
parent | 3d902b5197db861c30325c159dc10cfb211ae209 (diff) | |
download | rest-query-f9ac0adf5c3bcfcde03bd3ea2bc2471b0d0f99fe.tar.gz rest-query-f9ac0adf5c3bcfcde03bd3ea2bc2471b0d0f99fe.tar.bz2 rest-query-f9ac0adf5c3bcfcde03bd3ea2bc2471b0d0f99fe.zip |
Implement REST services for trial curation
Diffstat (limited to 'src/main/scala/xyz/driver/pdsuicommon')
13 files changed, 90 insertions, 54 deletions
diff --git a/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala b/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala index a1f93cd..e9da132 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/auth/AuthenticatedRequestContext.scala @@ -3,7 +3,7 @@ package xyz.driver.pdsuicommon.auth import xyz.driver.pdsuicommon.logging._ import xyz.driver.pdsuicommon.domain.User -class AuthenticatedRequestContext(val executor: User, override val requestId: RequestId) +class AuthenticatedRequestContext(val executor: User, override val requestId: RequestId, val authToken: String = "") extends AnonymousRequestContext(requestId) { override def equals(that: Any): Boolean = { @@ -22,9 +22,10 @@ class AuthenticatedRequestContext(val executor: User, override val requestId: Re object AuthenticatedRequestContext { - def apply(executor: User) = new AuthenticatedRequestContext(executor, RequestId()) + def apply(executor: User, authToken: String) = new AuthenticatedRequestContext(executor, RequestId(), authToken) implicit def toPhiString(x: AuthenticatedRequestContext): PhiString = { phi"AuthenticatedRequestContext(executor=${x.executor}, requestId=${x.requestId})" } + } diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapter.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapter.scala index 48c81c2..3bf9192 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapter.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapter.scala @@ -77,8 +77,8 @@ object BridgeUploadQueueRepositoryAdapter { sealed trait OnAttempt object OnAttempt { - case object Complete extends OnAttempt - case class Continue(interval: Duration) extends OnAttempt + case object Complete extends OnAttempt + final case class Continue(interval: Duration) extends OnAttempt implicit def toPhiString(x: OnAttempt): PhiString = Unsafe(x.toString) } diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala index dd84beb..6659088 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/Cron.scala @@ -45,9 +45,9 @@ class Cron(settings: Cron.Settings) extends Closeable with StrictLogging { * Checks unused jobs */ def verify(): Unit = { - import scala.collection.JavaConversions.asScalaSet + import scala.collection.JavaConverters._ - val unusedJobs = settings.intervals.keySet -- jobs.toSet + val unusedJobs = settings.intervals.keySet -- jobs.asScala.toSet unusedJobs.foreach { job => logger.warn(s"The job '$job' is listed, but not registered or ignored") } @@ -60,7 +60,7 @@ class Cron(settings: Cron.Settings) extends Closeable with StrictLogging { object Cron { - case class Settings(disable: String, intervals: Map[String, FiniteDuration]) + final case class Settings(disable: String, intervals: Map[String, FiniteDuration]) private class SingletonTask(taskName: String, job: () => Future[Unit])(implicit ec: ExecutionContext) extends TimerTask with StrictLogging { diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala index 0bc8220..2f7fe6c 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala @@ -11,7 +11,7 @@ object SafeBridgeUploadQueue { trait Tag extends Product with Serializable - case class SafeTask[T <: Tag](tag: T, private[SafeBridgeUploadQueue] val queueItem: BridgeUploadQueue.Item) + final case class SafeTask[T <: Tag](tag: T, private[SafeBridgeUploadQueue] val queueItem: BridgeUploadQueue.Item) object SafeTask { implicit def toPhiString[T <: Tag](x: SafeTask[T]): PhiString = { diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/MySqlContext.scala b/src/main/scala/xyz/driver/pdsuicommon/db/MySqlContext.scala index f804e87..c547bf4 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/MySqlContext.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/MySqlContext.scala @@ -18,20 +18,20 @@ import scala.util.{Failure, Success, Try} object MySqlContext extends PhiLogging { - case class DbCredentials(user: String, - password: String, - host: String, - port: Int, - dbName: String, - dbCreateFlag: Boolean, - dbContext: String, - connectionParams: String, - url: String) + final case class DbCredentials(user: String, + password: String, + host: String, + port: Int, + dbName: String, + dbCreateFlag: Boolean, + dbContext: String, + connectionParams: String, + url: String) - case class Settings(credentials: DbCredentials, - connection: Config, - connectionAttemptsOnStartup: Int, - threadPoolSize: Int) + final case class Settings(credentials: DbCredentials, + connection: Config, + connectionAttemptsOnStartup: Int, + threadPoolSize: Int) def apply(settings: Settings): MySqlContext = { // Prevent leaking credentials to a log diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala b/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala index e72b5c2..92689dd 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/Pagination.scala @@ -5,7 +5,7 @@ import xyz.driver.pdsuicommon.logging._ /** * @param pageNumber Starts with 1 */ -case class Pagination(pageSize: Int, pageNumber: Int) +final case class Pagination(pageSize: Int, pageNumber: Int) object Pagination { diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala index f941627..aa32166 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala @@ -23,15 +23,15 @@ object QueryBuilder { */ type Binder = PreparedStatement => PreparedStatement - case class TableData(tableName: String, - lastUpdateFieldName: Option[String] = None, - nullableFields: Set[String] = Set.empty) + final case class TableData(tableName: String, + lastUpdateFieldName: Option[String] = None, + nullableFields: Set[String] = Set.empty) val AllFields = Set("*") } -case class TableLink(keyColumnName: String, foreignTableName: String, foreignKeyColumnName: String) +final case class TableLink(keyColumnName: String, foreignTableName: String, foreignKeyColumnName: String) object QueryBuilderParameters { val AllFields = Set("*") @@ -57,10 +57,11 @@ sealed trait QueryBuilderParameters { def toSql(countQuery: Boolean, fields: Set[String], namingStrategy: NamingStrategy): (String, QueryBuilder.Binder) = { val escapedTableName = namingStrategy.table(tableData.tableName) val fieldsSql: String = if (countQuery) { - "count(*)" + (tableData.lastUpdateFieldName match { + val suffix: String = (tableData.lastUpdateFieldName match { case Some(lastUpdateField) => s", max($escapedTableName.${namingStrategy.column(lastUpdateField)})" case None => "" }) + "count(*)" + suffix } else { if (fields == QueryBuilderParameters.AllFields) { s"$escapedTableName.*" @@ -260,11 +261,11 @@ sealed trait QueryBuilderParameters { } -case class PostgresQueryBuilderParameters(tableData: QueryBuilder.TableData, - links: Map[String, TableLink] = Map.empty, - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Sorting = Sorting.Empty, - pagination: Option[Pagination] = None) +final case class PostgresQueryBuilderParameters(tableData: QueryBuilder.TableData, + links: Map[String, TableLink] = Map.empty, + filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Sorting = Sorting.Empty, + pagination: Option[Pagination] = None) extends QueryBuilderParameters { def limitToSql(): String = { @@ -279,11 +280,11 @@ case class PostgresQueryBuilderParameters(tableData: QueryBuilder.TableData, /** * @param links Links to another tables grouped by foreignTableName */ -case class MysqlQueryBuilderParameters(tableData: QueryBuilder.TableData, - links: Map[String, TableLink] = Map.empty, - filter: SearchFilterExpr = SearchFilterExpr.Empty, - sorting: Sorting = Sorting.Empty, - pagination: Option[Pagination] = None) +final case class MysqlQueryBuilderParameters(tableData: QueryBuilder.TableData, + links: Map[String, TableLink] = Map.empty, + filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Sorting = Sorting.Empty, + pagination: Option[Pagination] = None) extends QueryBuilderParameters { def limitToSql(): String = diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala index 4b66f22..0577921 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala @@ -16,7 +16,7 @@ object SearchFilterExpr { value = "false" ) - case class Dimension(tableName: Option[String], name: String) { + final case class Dimension(tableName: Option[String], name: String) { def isForeign: Boolean = tableName.isDefined } @@ -33,13 +33,13 @@ object SearchFilterExpr { } object Atom { - case class Binary(dimension: Dimension, op: SearchFilterBinaryOperation, value: AnyRef) extends Atom + final case class Binary(dimension: Dimension, op: SearchFilterBinaryOperation, value: AnyRef) extends Atom object Binary { def apply(field: String, op: SearchFilterBinaryOperation, value: AnyRef): Binary = Binary(Dimension(None, field), op, value) } - case class NAry(dimension: Dimension, op: SearchFilterNAryOperation, values: Seq[AnyRef]) extends Atom + final case class NAry(dimension: Dimension, op: SearchFilterNAryOperation, values: Seq[AnyRef]) extends Atom object NAry { def apply(field: String, op: SearchFilterNAryOperation, values: Seq[AnyRef]): NAry = NAry(Dimension(None, field), op, values) diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala b/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala index b796b83..a2c5a75 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/Sorting.scala @@ -23,11 +23,11 @@ object Sorting { * @param name Dimension name * @param order Order */ - case class Dimension(tableName: Option[String], name: String, order: SortingOrder) extends Sorting { + final case class Dimension(tableName: Option[String], name: String, order: SortingOrder) extends Sorting { def isForeign: Boolean = tableName.isDefined } - case class Sequential(sorting: Seq[Dimension]) extends Sorting { + final case class Sequential(sorting: Seq[Dimension]) extends Sorting { override def toString: String = if (isEmpty(this)) "Empty" else super.toString } diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala index 1bb70f8..e238245 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/domain/Id.scala @@ -6,9 +6,9 @@ import xyz.driver.pdsuicommon.logging._ sealed trait Id[+T] -case class CompoundId[Id1 <: Id[_], Id2 <: Id[_]](part1: Id1, part2: Id2) extends Id[(Id1, Id2)] +final case class CompoundId[Id1 <: Id[_], Id2 <: Id[_]](part1: Id1, part2: Id2) extends Id[(Id1, Id2)] -case class LongId[+T](id: Long) extends Id[T] { +final case class LongId[+T](id: Long) extends Id[T] { override def toString: String = id.toString def is(longId: Long): Boolean = { @@ -20,7 +20,7 @@ object LongId { implicit def toPhiString[T](x: LongId[T]): PhiString = Unsafe(s"LongId(${x.id})") } -case class StringId[+T](id: String) extends Id[T] { +final case class StringId[+T](id: String) extends Id[T] { override def toString: String = id def is(stringId: String): Boolean = { @@ -32,7 +32,7 @@ object StringId { implicit def toPhiString[T](x: StringId[T]): PhiString = Unsafe(s"StringId(${x.id})") } -case class UuidId[+T](id: UUID) extends Id[T] { +final case class UuidId[+T](id: UUID) extends Id[T] { override def toString: String = id.toString } diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala index 8d2d86d..4920176 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala @@ -8,13 +8,13 @@ import xyz.driver.pdsuicommon.logging._ import xyz.driver.pdsuicommon.domain.User.Role import xyz.driver.pdsuicommon.utils.Utils -case class User(id: StringId[User], - email: Email, - name: String, - role: Role, - passwordHash: PasswordHash, - latestActivity: Option[LocalDateTime], - deleted: Option[LocalDateTime]) +final case class User(id: StringId[User], + email: Email, + name: String, + role: Role, + passwordHash: PasswordHash, + latestActivity: Option[LocalDateTime], + deleted: Option[LocalDateTime]) object User { diff --git a/src/main/scala/xyz/driver/pdsuicommon/json/JsResultOps.scala b/src/main/scala/xyz/driver/pdsuicommon/json/JsResultOps.scala index 07dfefc..4ff4034 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/json/JsResultOps.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/json/JsResultOps.scala @@ -7,7 +7,7 @@ import scala.util.{Failure, Success, Try} final class JsResultOps[T](val self: JsResult[T]) extends AnyVal { def toTry: Try[T] = { - self.fold( + self.fold[Try[T]]( errors => Failure(new JsonValidationException(errors)), Success(_) ) diff --git a/src/main/scala/xyz/driver/pdsuicommon/serialization/PlayJsonSupport.scala b/src/main/scala/xyz/driver/pdsuicommon/serialization/PlayJsonSupport.scala new file mode 100644 index 0000000..5158dab --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/serialization/PlayJsonSupport.scala @@ -0,0 +1,34 @@ +package xyz.driver.pdsuicommon.serialization + +import akka.http.scaladsl.server.{RejectionError, ValidationRejection} +import akka.http.scaladsl.unmarshalling.Unmarshaller +import play.api.libs.json.{Reads, Writes} +import play.api.libs.json.Json +import akka.http.scaladsl.marshalling.ToEntityMarshaller +import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller +import akka.http.scaladsl.model.MediaTypes.`application/json` + +trait PlayJsonSupport { + import akka.http.scaladsl.marshalling.Marshaller + + implicit def playJsonUnmarshaller[A: Reads]: FromEntityUnmarshaller[A] = { + val reads = implicitly[Reads[A]] + Unmarshaller.stringUnmarshaller + .forContentTypes(`application/json`) + .map(Json.parse) + .map(reads.reads) + .map(_.recoverTotal { error => + throw RejectionError(ValidationRejection(s"Error reading JSON response as ${reads}.")) + }) + } + + implicit def playJsonMarshaller[A: Writes]: ToEntityMarshaller[A] = { + Marshaller + .stringMarshaller(`application/json`) + .compose(Json.prettyPrint) + .compose(implicitly[Writes[A]].writes) + } + +} + +object PlayJsonSupport extends PlayJsonSupport |