From 538528da6c6fefa4bcdc9dacbe5dcb3b85dd4810 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 3 Aug 2023 18:01:51 -0600 Subject: [PATCH 01/12] Add basic config to proyect, fix DataExplorerSettings issue and basic SpraConfig --- build.sbt | 15 +--- .../src/main/resources/application.conf | 90 +++++++++++++++++++ spra-play-server/src/main/resources/routes | 6 ++ .../net/wiringbits/spra/admin/AppRouter.scala | 2 +- .../admin/config/DataExplorerSettings.scala | 5 +- .../spra/admin/config/SpraConfig.scala | 19 ++++ .../admin/controllers/AdminController.scala | 2 +- .../spra/admin/controllers/package.scala | 2 +- .../spra/admin/modules/ConfigModule.scala | 20 +++++ .../repositories/daos/DatabaseTablesDAO.scala | 2 +- .../admin/repositories/daos/package.scala | 2 +- .../spra/admin/services/AdminService.scala | 2 +- 12 files changed, 147 insertions(+), 20 deletions(-) create mode 100644 spra-play-server/src/main/resources/application.conf create mode 100644 spra-play-server/src/main/resources/routes create mode 100644 spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala create mode 100644 spra-play-server/src/main/scala/net/wiringbits/spra/admin/modules/ConfigModule.scala diff --git a/build.sbt b/build.sbt index 4e883a6..2350366 100644 --- a/build.sbt +++ b/build.sbt @@ -35,21 +35,9 @@ lazy val build = TaskKey[File]("build") lazy val baseServerSettings: Project => Project = { _.settings( scalacOptions ++= Seq( - "-Werror", "-unchecked", "-deprecation", - "-feature", - "-target:jvm-1.8", - "-encoding", - "UTF-8", - "-Xsource:3", - "-Wconf:src=src_managed/.*:silent", - "-Xlint:missing-interpolator", - "-Xlint:adapted-args", - "-Ywarn-dead-code", - "-Ywarn-numeric-widen", - "-Ywarn-value-discard", - "-Ywarn-unused" + "-feature" ), Compile / doc / scalacOptions ++= Seq("-no-link-warnings"), // Some options are very noisy when using the console and prevent us using it smoothly, let's disable them @@ -177,6 +165,7 @@ lazy val spraPlayServer = (project in file("spra-play-server")) fork := true, Test / fork := true, // allows for graceful shutdown of containers once the tests have finished running libraryDependencies ++= Seq( + guice, "org.playframework.anorm" %% "anorm" % "2.6.10", "com.typesafe.play" %% "play" % "2.8.13", "com.typesafe.play" %% "play-json" % "2.9.2", diff --git a/spra-play-server/src/main/resources/application.conf b/spra-play-server/src/main/resources/application.conf new file mode 100644 index 0000000..a84e33c --- /dev/null +++ b/spra-play-server/src/main/resources/application.conf @@ -0,0 +1,90 @@ +spra { + users = { + tableName = "users" # must + primaryKeyField = "user_id" #must + # referenceField + hiddenColumns = ["password", "email"] + nonEditableColumns = ["user_id", "email", "created_at", "verified_on", "name"] + canBeDeleted = false + # primaryKeyDataType + # columnTypeOverrides + filterableColumns = ["name", "last_name"] + } +} + +# https://www.playframework.com/documentation/latest/Configuration + +play.i18n.langs = ["en"] + +play.filters.hosts { + allowed = ["localhost", "localhost:9000", "127.0.0.1:9000"] + allowed += ${?APP_ALLOWED_HOST_1} + allowed += ${?APP_ALLOWED_HOST_2} +} + +play.http { + secret.key = "this doesn't matter no sessions are being used" + secret.key = ${?PLAY_APPLICATION_SECRET} + + errorHandler = "play.api.http.JsonHttpErrorHandler" +} + +play.filters.disabled += "play.filters.csrf.CSRFFilter" + +db.default { + driver = "org.postgresql.Driver" + host = "localhost:5432" + database = "wiringbits_db" + username = "postgres" + password = "postgres" + + host = ${?POSTGRES_HOST} + database = ${?POSTGRES_DATABASE} + username = ${?POSTGRES_USERNAME} + password = ${?POSTGRES_PASSWORD} + + url = "jdbc:postgresql://"${db.default.host}"/"${db.default.database} +} + +play.evolutions { + autoApply = true + + db.default { + enabled = true + # Important because when this is false, failed migrations won't get to the play_evolutions table + # preventing us to fix them manually + autocommit = true + } +} + +# Number of database connections +# See https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing +fixedConnectionPool = 9 + +play.db { + prototype { + hikaricp.minimumIdle = ${fixedConnectionPool} + hikaricp.maximumPoolSize = ${fixedConnectionPool} + } +} + +# Job queue sized to HikariCP connection pool +database.dispatcher { + executor = "thread-pool-executor" + throughput = 1 + thread-pool-executor { + fixed-pool-size = ${fixedConnectionPool} + } +} + +blocking.dispatcher { + executor = "thread-pool-executor" + throughput = 1 + thread-pool-executor { + // very high bound to process lots of blocking operations concurrently + fixed-pool-size = 5000 + } +} + +play.modules.enabled += "net.wiringbits.spra.admin.modules.ExecutorsModule" +play.modules.enabled += "net.wiringbits.spra.admin.modules.ConfigModule" diff --git a/spra-play-server/src/main/resources/routes b/spra-play-server/src/main/resources/routes new file mode 100644 index 0000000..1531894 --- /dev/null +++ b/spra-play-server/src/main/resources/routes @@ -0,0 +1,6 @@ +# Routes +# This file defines all application routes (Higher priority routes first) +# https://www.playframework.com/documentation/latest/ScalaRouting +# ~~~~ + +-> / net.wiringbits.spra.admin.AppRouter diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala index 7f2e346..e62fc50 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala @@ -5,7 +5,7 @@ import net.wiringbits.spra.admin.utils.StringToDataTypesExt import net.wiringbits.spra.admin.utils.models.{FilterParameter, PaginationParameter, QueryParameters, SortParameter} import play.api.routing.Router.Routes import play.api.routing.SimpleRouter -import play.api.routing.sird.* +import play.api.routing.sird._ import javax.inject.Inject diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerSettings.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerSettings.scala index e58f97f..05d3712 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerSettings.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerSettings.scala @@ -1,6 +1,9 @@ package net.wiringbits.spra.admin.config -case class DataExplorerSettings(baseUrl: String, tables: List[TableSettings]) { +class DataExplorerSettings(val baseUrl: String, val tables: List[TableSettings]) { + // TODO: remove this constructor + def this() = this("", List.empty) + def unsafeFindByName(tableName: String): TableSettings = { tables .find(_.tableName == tableName) diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala new file mode 100644 index 0000000..daf0550 --- /dev/null +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala @@ -0,0 +1,19 @@ +package net.wiringbits.spra.admin.config + +import play.api.Configuration + +case class SpraConfig(tables: List[String]) { + override def toString: String = { + s"SpraConfig(tables = $tables)" + } +} + +object SpraConfig { + + def apply(config: Configuration): SpraConfig = { +// val tables = config.get[Seq[String]]("tables") +// println(config.keys) + SpraConfig(config.subKeys.toList) + } + +} diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala index b63d47f..4be2b9b 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala @@ -3,7 +3,7 @@ package net.wiringbits.spra.admin.controllers import net.wiringbits.spra.admin.config.DataExplorerSettings import net.wiringbits.spra.admin.services.AdminService import net.wiringbits.spra.admin.utils.models.QueryParameters -import net.wiringbits.spra.api.models.* +import net.wiringbits.spra.api.models._ import org.slf4j.LoggerFactory import play.api.libs.json.Json import play.api.mvc.{AbstractController, ControllerComponents} diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala index 7787160..65fb34d 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala @@ -4,7 +4,7 @@ import net.wiringbits.spra.api.models.ErrorResponse import org.slf4j.LoggerFactory import play.api.libs.json.{JsValue, Json, Reads} import play.api.mvc.Results.InternalServerError -import play.api.mvc.* +import play.api.mvc._ import scala.concurrent.{ExecutionContext, Future} import scala.util.control.NonFatal diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/modules/ConfigModule.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/modules/ConfigModule.scala new file mode 100644 index 0000000..9000e9f --- /dev/null +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/modules/ConfigModule.scala @@ -0,0 +1,20 @@ +package net.wiringbits.spra.admin.modules + +import com.google.inject.{AbstractModule, Provides, Singleton} +import net.wiringbits.spra.admin.config.SpraConfig +import org.slf4j.LoggerFactory +import play.api.Configuration + +class ConfigModule extends AbstractModule { + + private val logger = LoggerFactory.getLogger(this.getClass) + + @Provides + @Singleton + def provideSpraConfig(global: Configuration): SpraConfig = { + val config = SpraConfig(global.get[Configuration]("spra")) + logger.info(s"Loaded configuration: $config") + config + } + +} diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala index 94ad1d2..175da01 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala @@ -2,7 +2,7 @@ package net.wiringbits.spra.admin.repositories.daos import anorm.{SqlParser, SqlStringInterpolation} import net.wiringbits.spra.admin.config.{CustomDataType, PrimaryKeyDataType, TableSettings} -import net.wiringbits.spra.admin.repositories.models.* +import net.wiringbits.spra.admin.repositories.models._ import net.wiringbits.spra.admin.utils.models.{FilterParameter, QueryParameters} import net.wiringbits.spra.admin.utils.{QueryBuilder, StringRegex} diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala index 691e958..6a1c6d7 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala @@ -1,6 +1,6 @@ package net.wiringbits.spra.admin.repositories -import anorm.* +import anorm._ import net.wiringbits.spra.admin.repositories.models.{DatabaseTable, ForeignKey, TableColumn} package object daos { diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala index c0d9361..8785647 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala @@ -5,7 +5,7 @@ import net.wiringbits.spra.admin.repositories.DatabaseTablesRepository import net.wiringbits.spra.admin.repositories.models.{ForeignKey, TableData} import net.wiringbits.spra.admin.utils.models.QueryParameters import net.wiringbits.spra.admin.utils.{MapStringHideExt, contentRangeHeader} -import net.wiringbits.spra.api.models.* +import net.wiringbits.spra.api.models._ import java.awt.image.BufferedImage import java.io.{ByteArrayInputStream, File} From d399185696c9997b5effa422cbadbc6beb5f25b4 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 3 Aug 2023 21:09:26 -0600 Subject: [PATCH 02/12] TableSettings config --- .../src/main/resources/application.conf | 16 +++-- .../net/wiringbits/spra/admin/AppRouter.scala | 5 +- .../spra/admin/config/SpraConfig.scala | 11 ++- .../spra/admin/config/TableSettings.scala | 67 ++++++++++++++++++- 4 files changed, 85 insertions(+), 14 deletions(-) diff --git a/spra-play-server/src/main/resources/application.conf b/spra-play-server/src/main/resources/application.conf index a84e33c..8cb4b57 100644 --- a/spra-play-server/src/main/resources/application.conf +++ b/spra-play-server/src/main/resources/application.conf @@ -1,13 +1,17 @@ spra { - users = { - tableName = "users" # must - primaryKeyField = "user_id" #must - # referenceField + users { + tableName = "users" + primaryKeyField = "user_id" + referenceField = "temp_id" hiddenColumns = ["password", "email"] nonEditableColumns = ["user_id", "email", "created_at", "verified_on", "name"] canBeDeleted = false - # primaryKeyDataType - # columnTypeOverrides + primaryKeyDataType = "UUID" + columnTypeOverrides { + user_id = "BinaryImage" + created_at = "BinaryImage" + verified_on = "BinaryImage" + } filterableColumns = ["name", "last_name"] } } diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala index e62fc50..85a2ba7 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala @@ -1,5 +1,6 @@ package net.wiringbits.spra.admin +import net.wiringbits.spra.admin.config.SpraConfig import net.wiringbits.spra.admin.controllers.{AdminController, ImagesController} import net.wiringbits.spra.admin.utils.StringToDataTypesExt import net.wiringbits.spra.admin.utils.models.{FilterParameter, PaginationParameter, QueryParameters, SortParameter} @@ -9,11 +10,13 @@ import play.api.routing.sird._ import javax.inject.Inject -class AppRouter @Inject() (adminController: AdminController, imagesController: ImagesController) extends SimpleRouter { +class AppRouter @Inject() (spraConfig: SpraConfig, adminController: AdminController, imagesController: ImagesController) + extends SimpleRouter { override def routes: Routes = { // get database tables case GET(p"/admin/tables") => + println(spraConfig) adminController.getTables() // get database table fields diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala index daf0550..5ee6d65 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala @@ -2,18 +2,17 @@ package net.wiringbits.spra.admin.config import play.api.Configuration -case class SpraConfig(tables: List[String]) { +case class SpraConfig(tablesSettings: List[TableSettings]) { override def toString: String = { - s"SpraConfig(tables = $tables)" + s"SpraConfig(tablesSettings = $tablesSettings)" } } object SpraConfig { - def apply(config: Configuration): SpraConfig = { -// val tables = config.get[Seq[String]]("tables") -// println(config.keys) - SpraConfig(config.subKeys.toList) + val tableNames = config.subKeys.toList + val tablesSettings = tableNames.map(config.get[TableSettings](_)) + SpraConfig(tablesSettings) } } diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala index d98d246..089ebcc 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala @@ -1,5 +1,10 @@ package net.wiringbits.spra.admin.config +import com.typesafe.config.Config +import play.api.ConfigLoader + +import scala.util.Try + /** @param tableName * name of table in database * @param primaryKeyField @@ -30,7 +35,67 @@ case class TableSettings( primaryKeyDataType: PrimaryKeyDataType = PrimaryKeyDataType.UUID, columnTypeOverrides: Map[String, CustomDataType] = Map.empty, filterableColumns: List[String] = List.empty -) +) { + override def toString: String = + s"""TableSettings(tableName = $tableName, primaryKeyField = $primaryKeyField, referenceField = $referenceField, + hiddenColumns = $hiddenColumns, nonEditableColumns = $nonEditableColumns, canBeDeleted = $canBeDeleted, + primaryKeyDataType = $primaryKeyDataType, columnTypeOverrides = $columnTypeOverrides, + filterableColumns = $filterableColumns)""" +} + +object TableSettings { + implicit val configLoader: ConfigLoader[TableSettings] = (config: Config, path: String) => { + import scala.jdk.CollectionConverters._ + val newConfig = config.getConfig(path) + + def get[A](path: String): A = { + Try(newConfig.getAnyRef(path).asInstanceOf[A]).getOrElse(throw new RuntimeException(s"Cannot find $path")) + } + + def getOption[A](path: String): Option[A] = { + Try(newConfig.getAnyRef(path).asInstanceOf[A]).toOption + } + + def getList[A](path: String): List[A] = { + Try(newConfig.getAnyRefList(path).asScala.toList.asInstanceOf[List[A]]).getOrElse(List.empty) + } + + def handleColumnTypeOverrides(): Map[String, CustomDataType] = { + Try( + newConfig + .getConfig("columnTypeOverrides") + .entrySet() + .asScala + .map { entry => + val value = entry.getValue.unwrapped().asInstanceOf[String] + value match { + case "BinaryImage" => entry.getKey -> CustomDataType.BinaryImage + case "Binary" => entry.getKey -> CustomDataType.Binary + case string => throw new RuntimeException(s"Invalid custom data type: $string") + } + } + .toMap + ).getOrElse(Map.empty) + } + + TableSettings( + tableName = get[String]("tableName"), + primaryKeyField = get[String]("primaryKeyField"), + referenceField = getOption[String]("referenceField"), + hiddenColumns = getList[String]("hiddenColumns"), + nonEditableColumns = getList[String]("nonEditableColumns"), + canBeDeleted = getOption[Boolean]("canBeDeleted").getOrElse(true), + primaryKeyDataType = getOption[String](" primaryKeyDataType") match { + case Some("UUID") | None => PrimaryKeyDataType.UUID + case Some("Serial") => PrimaryKeyDataType.Serial + case Some("BigSerial") => PrimaryKeyDataType.BigSerial + case string => throw new RuntimeException(s"Invalid primary key data type: $string") + }, + columnTypeOverrides = handleColumnTypeOverrides(), + filterableColumns = getList[String]("filterableColumns") + ) + } +} sealed trait PrimaryKeyDataType extends Product with Serializable object PrimaryKeyDataType { From e6b969ffdb41ae51b810ecea41fbcce15f0c1c19 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 4 Aug 2023 00:22:45 -0600 Subject: [PATCH 03/12] Implement SpraConfig into DataExplorerConfig --- .../src/main/resources/application.conf | 16 ++++---------- .../net/wiringbits/spra/admin/AppRouter.scala | 11 ++++++---- .../admin/config/DataExplorerConfig.scala | 20 +++++++++++++++++ .../admin/config/DataExplorerSettings.scala | 12 ---------- .../spra/admin/config/SpraConfig.scala | 18 --------------- .../admin/controllers/AdminController.scala | 6 ++--- .../spra/admin/modules/ConfigModule.scala | 6 ++--- .../DatabaseTablesRepository.scala | 22 +++++++++---------- .../spra/admin/services/AdminService.scala | 20 ++++++++--------- .../DataExplorerConfigValidatorTask.scala | 8 +++---- .../modules/DataExplorerTestModule.scala | 6 ++--- 11 files changed, 65 insertions(+), 80 deletions(-) create mode 100644 spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerConfig.scala delete mode 100644 spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerSettings.scala delete mode 100644 spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala diff --git a/spra-play-server/src/main/resources/application.conf b/spra-play-server/src/main/resources/application.conf index 8cb4b57..10c49aa 100644 --- a/spra-play-server/src/main/resources/application.conf +++ b/spra-play-server/src/main/resources/application.conf @@ -1,4 +1,7 @@ -spra { +dataExplorer { + baseUrl = "http://localhost:9000" + baseUrl = ${?DATA_EXPLORER_BASE_URL} + users { tableName = "users" primaryKeyField = "user_id" @@ -50,17 +53,6 @@ db.default { url = "jdbc:postgresql://"${db.default.host}"/"${db.default.database} } -play.evolutions { - autoApply = true - - db.default { - enabled = true - # Important because when this is false, failed migrations won't get to the play_evolutions table - # preventing us to fix them manually - autocommit = true - } -} - # Number of database connections # See https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing fixedConnectionPool = 9 diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala index 85a2ba7..9ce0943 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala @@ -1,6 +1,6 @@ package net.wiringbits.spra.admin -import net.wiringbits.spra.admin.config.SpraConfig +import net.wiringbits.spra.admin.config.DataExplorerConfig import net.wiringbits.spra.admin.controllers.{AdminController, ImagesController} import net.wiringbits.spra.admin.utils.StringToDataTypesExt import net.wiringbits.spra.admin.utils.models.{FilterParameter, PaginationParameter, QueryParameters, SortParameter} @@ -10,13 +10,16 @@ import play.api.routing.sird._ import javax.inject.Inject -class AppRouter @Inject() (spraConfig: SpraConfig, adminController: AdminController, imagesController: ImagesController) - extends SimpleRouter { +class AppRouter @Inject() ( + dataExplorerConfig: DataExplorerConfig, + adminController: AdminController, + imagesController: ImagesController +) extends SimpleRouter { override def routes: Routes = { // get database tables case GET(p"/admin/tables") => - println(spraConfig) + println(dataExplorerConfig) adminController.getTables() // get database table fields diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerConfig.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerConfig.scala new file mode 100644 index 0000000..4b8048a --- /dev/null +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerConfig.scala @@ -0,0 +1,20 @@ +package net.wiringbits.spra.admin.config + +import play.api.Configuration + +case class DataExplorerConfig(baseUrl: String, tablesSettings: List[TableSettings]) { + def unsafeFindByName(tableName: String): TableSettings = { + tablesSettings + .find(_.tableName == tableName) + .getOrElse(throw new RuntimeException(s"Cannot find config for table: $tableName")) + } +} + +object DataExplorerConfig { + def apply(config: Configuration): DataExplorerConfig = { + val baseUrl = config.get[String]("baseUrl") + val tableNames = config.subKeys.toList.filter(_ != "baseUrl") + val tablesSettings = tableNames.map(config.get[TableSettings](_)) + DataExplorerConfig(baseUrl, tablesSettings) + } +} diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerSettings.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerSettings.scala deleted file mode 100644 index 05d3712..0000000 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/DataExplorerSettings.scala +++ /dev/null @@ -1,12 +0,0 @@ -package net.wiringbits.spra.admin.config - -class DataExplorerSettings(val baseUrl: String, val tables: List[TableSettings]) { - // TODO: remove this constructor - def this() = this("", List.empty) - - def unsafeFindByName(tableName: String): TableSettings = { - tables - .find(_.tableName == tableName) - .getOrElse(throw new RuntimeException(s"Cannot find settings for table: $tableName")) - } -} diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala deleted file mode 100644 index 5ee6d65..0000000 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/SpraConfig.scala +++ /dev/null @@ -1,18 +0,0 @@ -package net.wiringbits.spra.admin.config - -import play.api.Configuration - -case class SpraConfig(tablesSettings: List[TableSettings]) { - override def toString: String = { - s"SpraConfig(tablesSettings = $tablesSettings)" - } -} - -object SpraConfig { - def apply(config: Configuration): SpraConfig = { - val tableNames = config.subKeys.toList - val tablesSettings = tableNames.map(config.get[TableSettings](_)) - SpraConfig(tablesSettings) - } - -} diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala index 4be2b9b..7df7c98 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala @@ -1,6 +1,6 @@ package net.wiringbits.spra.admin.controllers -import net.wiringbits.spra.admin.config.DataExplorerSettings +import net.wiringbits.spra.admin.config.DataExplorerConfig import net.wiringbits.spra.admin.services.AdminService import net.wiringbits.spra.admin.utils.models.QueryParameters import net.wiringbits.spra.api.models._ @@ -14,7 +14,7 @@ import scala.concurrent.ExecutionContext // TODO: Remove authentication, which should be provided by each app class AdminController @Inject() ( adminService: AdminService, - settings: DataExplorerSettings + dataExplorerConfig: DataExplorerConfig )(implicit cc: ControllerComponents, ec: ExecutionContext) extends AbstractController(cc) { private val logger = LoggerFactory.getLogger(this.getClass) @@ -63,7 +63,7 @@ class AdminController @Inject() ( } def update(tableName: String, primaryKeyValue: String) = handleJsonBody[Map[String, String]] { request => - val primaryKeyFieldName = settings.unsafeFindByName(tableName).primaryKeyField + val primaryKeyFieldName = dataExplorerConfig.unsafeFindByName(tableName).primaryKeyField val body = request.body.map { case ("id", value) => primaryKeyFieldName -> value case x => x diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/modules/ConfigModule.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/modules/ConfigModule.scala index 9000e9f..02cea57 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/modules/ConfigModule.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/modules/ConfigModule.scala @@ -1,7 +1,7 @@ package net.wiringbits.spra.admin.modules import com.google.inject.{AbstractModule, Provides, Singleton} -import net.wiringbits.spra.admin.config.SpraConfig +import net.wiringbits.spra.admin.config.DataExplorerConfig import org.slf4j.LoggerFactory import play.api.Configuration @@ -11,8 +11,8 @@ class ConfigModule extends AbstractModule { @Provides @Singleton - def provideSpraConfig(global: Configuration): SpraConfig = { - val config = SpraConfig(global.get[Configuration]("spra")) + def dataExplorerConfig(global: Configuration): DataExplorerConfig = { + val config = DataExplorerConfig(global.get[Configuration]("dataExplorer")) logger.info(s"Loaded configuration: $config") config } diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/DatabaseTablesRepository.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/DatabaseTablesRepository.scala index 0d3305e..47cf1b0 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/DatabaseTablesRepository.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/DatabaseTablesRepository.scala @@ -1,6 +1,6 @@ package net.wiringbits.spra.admin.repositories -import net.wiringbits.spra.admin.config.{DataExplorerSettings, TableSettings} +import net.wiringbits.spra.admin.config.{DataExplorerConfig, TableSettings} import net.wiringbits.spra.admin.executors.DatabaseExecutionContext import net.wiringbits.spra.admin.repositories.daos.DatabaseTablesDAO import net.wiringbits.spra.admin.repositories.models.{DatabaseTable, ForeignKey, TableColumn, TableData} @@ -12,7 +12,7 @@ import scala.concurrent.Future class DatabaseTablesRepository @Inject() (database: Database)(implicit ec: DatabaseExecutionContext, - tableSettings: DataExplorerSettings + dataExplorerConfig: DataExplorerConfig ) { def all(): Future[List[DatabaseTable]] = Future { database.withConnection { implicit conn => @@ -34,7 +34,7 @@ class DatabaseTablesRepository @Inject() (database: Database)(implicit def getMandatoryFields(tableName: String): Future[List[TableColumn]] = Future { database.withConnection { implicit conn => - val primaryKeyField = tableSettings.unsafeFindByName(tableName).primaryKeyField + val primaryKeyField = dataExplorerConfig.unsafeFindByName(tableName).primaryKeyField DatabaseTablesDAO.getMandatoryFields(tableName, primaryKeyField) } } @@ -42,7 +42,7 @@ class DatabaseTablesRepository @Inject() (database: Database)(implicit def getTableMetadata(settings: TableSettings, queryParameters: QueryParameters): Future[List[TableData]] = Future { database.withTransaction { implicit conn => val columns = DatabaseTablesDAO.getTableColumns(settings.tableName) - val rows = DatabaseTablesDAO.getTableData(settings, columns, queryParameters, tableSettings.baseUrl) + val rows = DatabaseTablesDAO.getTableData(settings, columns, queryParameters, dataExplorerConfig.baseUrl) val columnNames = getColumnNames(columns, settings.primaryKeyField) rows.map { row => val tableRow = row.convertToMap(columnNames) @@ -59,9 +59,9 @@ class DatabaseTablesRepository @Inject() (database: Database)(implicit def find(tableName: String, primaryKeyValue: String): Future[Option[TableData]] = Future { database.withTransaction { implicit conn => - val settings = tableSettings.unsafeFindByName(tableName) + val settings = dataExplorerConfig.unsafeFindByName(tableName) val columns = DatabaseTablesDAO.getTableColumns(tableName) - val maybe = DatabaseTablesDAO.find(settings, columns, primaryKeyValue, tableSettings.baseUrl) + val maybe = DatabaseTablesDAO.find(settings, columns, primaryKeyValue, dataExplorerConfig.baseUrl) val columnNames = getColumnNames(columns, settings.primaryKeyField) maybe.map(x => TableData(x.convertToMap(columnNames))) } @@ -69,8 +69,8 @@ class DatabaseTablesRepository @Inject() (database: Database)(implicit def create(tableName: String, body: Map[String, String]): Future[Unit] = Future { database.withConnection { implicit conn => - val primaryKeyField = tableSettings.unsafeFindByName(tableName).primaryKeyField - val primaryKeyType = tableSettings.unsafeFindByName(tableName).primaryKeyDataType + val primaryKeyField = dataExplorerConfig.unsafeFindByName(tableName).primaryKeyField + val primaryKeyType = dataExplorerConfig.unsafeFindByName(tableName).primaryKeyDataType DatabaseTablesDAO.create( tableName = tableName, body = body, @@ -83,7 +83,7 @@ class DatabaseTablesRepository @Inject() (database: Database)(implicit def update(tableName: String, primaryKeyValue: String, body: Map[String, String]): Future[Unit] = Future { database.withTransaction { implicit conn => - val settings = tableSettings.unsafeFindByName(tableName) + val settings = dataExplorerConfig.unsafeFindByName(tableName) val columns = DatabaseTablesDAO.getTableColumns(tableName) // hide non editable fields in case somebody edit it val bodyWithoutNonEditableColumns = body.filterNot { case (key, _) => @@ -110,8 +110,8 @@ class DatabaseTablesRepository @Inject() (database: Database)(implicit def delete(tableName: String, primaryKeyValue: String): Future[Unit] = Future { database.withConnection { implicit conn => - val primaryKeyField = tableSettings.unsafeFindByName(tableName).primaryKeyField - val primaryKeyType = tableSettings.unsafeFindByName(tableName).primaryKeyDataType + val primaryKeyField = dataExplorerConfig.unsafeFindByName(tableName).primaryKeyField + val primaryKeyType = dataExplorerConfig.unsafeFindByName(tableName).primaryKeyDataType DatabaseTablesDAO.delete( tableName = tableName, primaryKeyField = primaryKeyField, diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala index 8785647..e953a58 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala @@ -1,6 +1,6 @@ package net.wiringbits.spra.admin.services -import net.wiringbits.spra.admin.config.{CustomDataType, DataExplorerSettings, TableSettings} +import net.wiringbits.spra.admin.config.{CustomDataType, DataExplorerConfig, TableSettings} import net.wiringbits.spra.admin.repositories.DatabaseTablesRepository import net.wiringbits.spra.admin.repositories.models.{ForeignKey, TableData} import net.wiringbits.spra.admin.utils.models.QueryParameters @@ -17,7 +17,7 @@ import scala.util.Try class AdminService @Inject() ( databaseTablesRepository: DatabaseTablesRepository, - tableSettings: DataExplorerSettings + dataExplorerConfig: DataExplorerConfig )(implicit ec: ExecutionContext ) { @@ -30,7 +30,7 @@ class AdminService @Inject() ( val maybe = filteredForeignKeys.map(_.primaryTable).headOption maybe.map { tableName => - val maybe = tableSettings.unsafeFindByName(tableName).referenceField + val maybe = dataExplorerConfig.unsafeFindByName(tableName).referenceField val referenceField = maybe.getOrElse("id") AdminGetTables.Response.TableReference(referencedTable = tableName, referenceField = referenceField) } @@ -45,7 +45,7 @@ class AdminService @Inject() ( for { items <- Future.sequence { - tableSettings.tables.map { settings => + dataExplorerConfig.tablesSettings.map { settings => val hiddenColumns = settings.hiddenColumns for { tableColumns <- databaseTablesRepository.getTableColumns(settings.tableName) @@ -89,7 +89,7 @@ class AdminService @Inject() ( for { _ <- validations - settings = tableSettings.unsafeFindByName(tableName) + settings = dataExplorerConfig.unsafeFindByName(tableName) _ <- validateQueryParameters(tableName, queryParams) tableRows <- databaseTablesRepository.getTableMetadata(settings, queryParams) numberOfRecords <- databaseTablesRepository.numberOfRecords(tableName) @@ -120,7 +120,7 @@ class AdminService @Inject() ( _ <- validations maybe <- databaseTablesRepository.find(tableName, primaryKeyValue) tableRow = maybe.getOrElse(throw new RuntimeException(s"Cannot find item in $tableName with id $primaryKeyValue")) - settings = tableSettings.unsafeFindByName(tableName) + settings = dataExplorerConfig.unsafeFindByName(tableName) hiddenData = hideData(tableRow, settings.hiddenColumns) } yield hiddenData } @@ -132,7 +132,7 @@ class AdminService @Inject() ( for { _ <- validations - settings = tableSettings.unsafeFindByName(tableName) + settings = dataExplorerConfig.unsafeFindByName(tableName) tableRows <- Future.sequence { primaryKeyValues.map { primaryKeyValue => for { @@ -194,7 +194,7 @@ class AdminService @Inject() ( def delete(tableName: String, primaryKeyValue: String): Future[Unit] = { val validations = for { _ <- Future(validateTableName(tableName)) - settings = tableSettings.unsafeFindByName(tableName) + settings = dataExplorerConfig.unsafeFindByName(tableName) _ = if (settings.canBeDeleted) () else throw new RuntimeException(s"Table $tableName resources cannot be deleted") } yield () @@ -206,7 +206,7 @@ class AdminService @Inject() ( } private def validateTableName(tableName: String): Unit = { - val exists = tableSettings.tables.exists(_.tableName == tableName) + val exists = dataExplorerConfig.tablesSettings.exists(_.tableName == tableName) if (exists) () else throw new RuntimeException(s"Unexpected error because the DB table wasn't found: $tableName") } @@ -236,7 +236,7 @@ class AdminService @Inject() ( } for { _ <- validations - settings = tableSettings.unsafeFindByName(tableName) + settings = dataExplorerConfig.unsafeFindByName(tableName) _ = validateImageColumn(settings, columnName) maybe <- databaseTablesRepository.getImageData(settings, columnName, imageId) imageData = maybe.getOrElse(throw new RuntimeException(s"Image with id $imageId on $tableName doesn't exists")) diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/tasks/DataExplorerConfigValidatorTask.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/tasks/DataExplorerConfigValidatorTask.scala index 92dce77..90f7d9c 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/tasks/DataExplorerConfigValidatorTask.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/tasks/DataExplorerConfigValidatorTask.scala @@ -1,6 +1,6 @@ package net.wiringbits.spra.admin.tasks -import net.wiringbits.spra.admin.config.{DataExplorerSettings, TableSettings} +import net.wiringbits.spra.admin.config.{DataExplorerConfig, TableSettings} import net.wiringbits.spra.admin.repositories.daos.DatabaseTablesDAO import net.wiringbits.spra.admin.repositories.models.{DatabaseTable, TableColumn} import org.slf4j.LoggerFactory @@ -16,11 +16,11 @@ import scala.util.{Failure, Success, Try} * config, failing when there is a mismatch. * * @param database - * @param settings + * @param dataExplorerConfig */ class DataExplorerConfigValidatorTask @Inject() ( database: Database, - settings: DataExplorerSettings + dataExplorerConfig: DataExplorerConfig ) { private val logger = LoggerFactory.getLogger(this.getClass) @@ -37,7 +37,7 @@ class DataExplorerConfigValidatorTask @Inject() ( private def run(): Unit = { database.withConnection { implicit conn => val tables = DatabaseTablesDAO.all() - for (settingsTable <- settings.tables) { + for (settingsTable <- dataExplorerConfig.tablesSettings) { logger.info(s"Verifying ${settingsTable.tableName}") val fields = DatabaseTablesDAO.getTableColumns(settingsTable.tableName) validateSettings(settingsTable) diff --git a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/modules/DataExplorerTestModule.scala b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/modules/DataExplorerTestModule.scala index 1706fea..94c1e85 100644 --- a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/modules/DataExplorerTestModule.scala +++ b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/modules/DataExplorerTestModule.scala @@ -1,13 +1,13 @@ package net.wiringbits.spra.admin.modules import com.google.inject.{AbstractModule, Provides} -import net.wiringbits.spra.admin.config.{DataExplorerSettings, PrimaryKeyDataType, TableSettings} +import net.wiringbits.spra.admin.config.{DataExplorerConfig, PrimaryKeyDataType, TableSettings} class DataExplorerTestModule extends AbstractModule { @Provides() - def dataExplorerSettings: DataExplorerSettings = { - DataExplorerSettings("http://localhost:9000", settings) + def dataExplorerConfig: DataExplorerConfig = { + DataExplorerConfig("http://localhost:9000", settings) } val settings: List[TableSettings] = List( From 33ac1f45e2d6693837f21abb8cf2706ffdd2116b Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 4 Aug 2023 00:25:57 -0600 Subject: [PATCH 04/12] CORS --- spra-play-server/src/main/resources/application.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/spra-play-server/src/main/resources/application.conf b/spra-play-server/src/main/resources/application.conf index 10c49aa..f201f0e 100644 --- a/spra-play-server/src/main/resources/application.conf +++ b/spra-play-server/src/main/resources/application.conf @@ -37,6 +37,7 @@ play.http { } play.filters.disabled += "play.filters.csrf.CSRFFilter" +play.filters.enabled += "play.filters.cors.CORSFilter" db.default { driver = "org.postgresql.Driver" From d708abdc260b806a631fc6b1049cac028c80fdf6 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 4 Aug 2023 01:03:02 -0600 Subject: [PATCH 05/12] Fix filter and add more examples --- .../src/main/resources/application.conf | 23 ++++++++++++------- .../net/wiringbits/spra/admin/AppRouter.scala | 4 ++-- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/spra-play-server/src/main/resources/application.conf b/spra-play-server/src/main/resources/application.conf index f201f0e..87a1489 100644 --- a/spra-play-server/src/main/resources/application.conf +++ b/spra-play-server/src/main/resources/application.conf @@ -5,18 +5,25 @@ dataExplorer { users { tableName = "users" primaryKeyField = "user_id" - referenceField = "temp_id" hiddenColumns = ["password", "email"] - nonEditableColumns = ["user_id", "email", "created_at", "verified_on", "name"] + nonEditableColumns = ["user_id", "email", "created_at", "verified_on", "name", "last_name"] canBeDeleted = false - primaryKeyDataType = "UUID" - columnTypeOverrides { - user_id = "BinaryImage" - created_at = "BinaryImage" - verified_on = "BinaryImage" - } filterableColumns = ["name", "last_name"] } + + user_tokens { + tableName = "user_tokens" + primaryKeyField = "user_token_id" + nonEditableColumns = ["user_token_id", "user_id", "created_at", "expires_at"] + canBeDeleted = false + } + + user_logs { + tableName = "user_logs" + primaryKeyField = "user_log_id" + nonEditableColumns = ["user_log_id", "user_id", "created_at"] + canBeDeleted = false + } } # https://www.playframework.com/documentation/latest/Configuration diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala index 9ce0943..37f8b97 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala @@ -23,8 +23,8 @@ class AppRouter @Inject() ( adminController.getTables() // get database table fields - // example: GET http://localhost:9000/admin/tables/users?filters={}&range=[0, 9]&sort=["id", "ASC"] - case GET(p"/admin/tables/$tableName" ? q"filters=$filters" & q"range=$range" & q"sort=$sort") => + // example: GET http://localhost:9000/admin/tables/users?filter={}&range=[0, 9]&sort=["id", "ASC"] + case GET(p"/admin/tables/$tableName" ? q"filter=$filters" & q"range=$range" & q"sort=$sort") => val queryParams = QueryParameters( sort = SortParameter.fromString(sort), From d0b3a3aa83d51a251c96010505d12feff6e914ef Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 4 Aug 2023 01:04:58 -0600 Subject: [PATCH 06/12] Minor changes --- .../main/scala/net/wiringbits/spra/admin/AppRouter.scala | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala index 37f8b97..e7f5dad 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala @@ -1,6 +1,5 @@ package net.wiringbits.spra.admin -import net.wiringbits.spra.admin.config.DataExplorerConfig import net.wiringbits.spra.admin.controllers.{AdminController, ImagesController} import net.wiringbits.spra.admin.utils.StringToDataTypesExt import net.wiringbits.spra.admin.utils.models.{FilterParameter, PaginationParameter, QueryParameters, SortParameter} @@ -10,16 +9,11 @@ import play.api.routing.sird._ import javax.inject.Inject -class AppRouter @Inject() ( - dataExplorerConfig: DataExplorerConfig, - adminController: AdminController, - imagesController: ImagesController -) extends SimpleRouter { +class AppRouter @Inject() (adminController: AdminController, imagesController: ImagesController) extends SimpleRouter { override def routes: Routes = { // get database tables case GET(p"/admin/tables") => - println(dataExplorerConfig) adminController.getTables() // get database table fields From 4fa2bcf83d6de69652c978a2425707a374622bfa Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 4 Aug 2023 01:06:29 -0600 Subject: [PATCH 07/12] Remove space --- .../scala/net/wiringbits/spra/admin/config/TableSettings.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala index 089ebcc..b7596f7 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala @@ -85,7 +85,7 @@ object TableSettings { hiddenColumns = getList[String]("hiddenColumns"), nonEditableColumns = getList[String]("nonEditableColumns"), canBeDeleted = getOption[Boolean]("canBeDeleted").getOrElse(true), - primaryKeyDataType = getOption[String](" primaryKeyDataType") match { + primaryKeyDataType = getOption[String]("primaryKeyDataType") match { case Some("UUID") | None => PrimaryKeyDataType.UUID case Some("Serial") => PrimaryKeyDataType.Serial case Some("BigSerial") => PrimaryKeyDataType.BigSerial From 0f6713561f9dc7bcd8d0479bbcd9e655b4753ede Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 5 Aug 2023 00:00:49 -0600 Subject: [PATCH 08/12] .sbt config --- build.sbt | 70 +++++++++++++++++++-------------------------- project/plugins.sbt | 5 +++- 2 files changed, 34 insertions(+), 41 deletions(-) diff --git a/build.sbt b/build.sbt index 4e883a6..4c2448e 100644 --- a/build.sbt +++ b/build.sbt @@ -4,11 +4,13 @@ import java.nio.file.StandardCopyOption.REPLACE_EXISTING ThisBuild / versionScheme := Some("early-semver") // For all Sonatype accounts created on or after February 2021 ThisBuild / sonatypeCredentialHost := "s01.oss.sonatype.org" +ThisBuild / scalaVersion := "3.3.0" inThisBuild( List( organization := "net.wiringbits", name := "scala-postgres-react-admin", + scalaVersion := "3.3.0", homepage := Some(url("https://github.com/wiringbits/scala-postgres-react-admin")), licenses := List("MIT" -> url("https://www.opensource.org/licenses/mit-license.html")), developers := List( @@ -24,8 +26,12 @@ inThisBuild( resolvers += Resolver.sonatypeRepo("releases") -val playJson = "2.10.0-RC5" +val play = "2.9.0-M6" +val playJson = "2.10.0-RC9" val sttp = "3.5.0" +val anorm = "2.7.0" +val scalaTestPlusPlay = "6.0.0-M6" +val scalaTestPlusMockito = "3.2.15.0" val consoleDisabledOptions = Seq("-Xfatal-warnings", "-Ywarn-unused", "-Ywarn-unused-import") @@ -36,20 +42,20 @@ lazy val baseServerSettings: Project => Project = { _.settings( scalacOptions ++= Seq( "-Werror", - "-unchecked", - "-deprecation", - "-feature", - "-target:jvm-1.8", - "-encoding", - "UTF-8", - "-Xsource:3", - "-Wconf:src=src_managed/.*:silent", - "-Xlint:missing-interpolator", - "-Xlint:adapted-args", - "-Ywarn-dead-code", - "-Ywarn-numeric-widen", - "-Ywarn-value-discard", - "-Ywarn-unused" +// "-unchecked", +// "-deprecation", + "-feature" +// "-target:jvm-1.8", +// "-encoding", +// "UTF-8", +// "-Xsource:3", +// "-Wconf:src=src_managed/.*:silent", +// "-Xlint:missing-interpolator", +// "-Xlint:adapted-args", +// "-Ywarn-dead-code", +// "-Ywarn-numeric-widen", +// "-Ywarn-value-discard", +// "-Ywarn-unused" ), Compile / doc / scalacOptions ++= Seq("-no-link-warnings"), // Some options are very noisy when using the console and prevent us using it smoothly, let's disable them @@ -68,17 +74,17 @@ lazy val playSettings: Project => Project = { "-no-link-warnings" ), // remove play noisy warnings - play.sbt.routes.RoutesKeys.routesImport := Seq.empty, +// play.sbt.routes.RoutesKeys.routesImport := Seq.empty, libraryDependencies ++= Seq( evolutions, - "com.typesafe.play" %% "play-jdbc" % "2.8.13", + "com.typesafe.play" %% "play-jdbc" % "2.9.0-M6", "com.google.inject" % "guice" % "5.1.0" ), // test libraryDependencies ++= Seq( - "org.scalatestplus.play" %% "scalatestplus-play" % "5.1.0" % Test, - "org.mockito" %% "mockito-scala" % "1.17.5" % Test, - "org.mockito" %% "mockito-scala-scalatest" % "1.17.5" % Test + "org.scalatestplus.play" %% "scalatestplus-play" % "6.0.0-M6" % Test, + "org.scalatestplus" %% "mockito-4-6" % scalaTestPlusMockito % Test +// "org.mockito" %% "mockito-scala-scalatest" % mockito % Test ) ) } @@ -117,11 +123,6 @@ lazy val baseLibSettings: Project => Project = _.settings( // The common stuff for the server/client modules lazy val spraCommon = (crossProject(JSPlatform, JVMPlatform) in file("spra-common")) .configure(baseLibSettings) - .settings( - scalaVersion := "2.13.8", - crossScalaVersions := Seq("2.13.8", "3.1.2"), - name := "spra-common" - ) .jsConfigure(_.enablePlugins(ScalaJSPlugin, ScalaJSBundlerPlugin)) .jvmSettings( libraryDependencies ++= Seq( @@ -143,11 +144,6 @@ lazy val spraCommon = (crossProject(JSPlatform, JVMPlatform) in file("spra-commo lazy val spraApi = (crossProject(JSPlatform, JVMPlatform) in file("spra-api")) .configure(baseLibSettings) .dependsOn(spraCommon) - .settings( - scalaVersion := "2.13.8", - crossScalaVersions := Seq("2.13.8", "3.1.2"), - name := "spra-api" - ) .jsConfigure(_.enablePlugins(ScalaJSPlugin, ScalaJSBundlerPlugin)) .jvmSettings( libraryDependencies ++= Seq( @@ -168,18 +164,15 @@ lazy val spraApi = (crossProject(JSPlatform, JVMPlatform) in file("spra-api")) /** Includes the specific stuff to run the SPRA server side (play-specific) */ lazy val spraPlayServer = (project in file("spra-play-server")) + .enablePlugins(PlayScala) .dependsOn(spraApi.jvm, spraCommon.jvm) .configure(baseServerSettings, playSettings) .settings( - scalaVersion := "2.13.8", - crossScalaVersions := Seq("2.13.8"), - name := "spra-play-server", fork := true, Test / fork := true, // allows for graceful shutdown of containers once the tests have finished running libraryDependencies ++= Seq( - "org.playframework.anorm" %% "anorm" % "2.6.10", - "com.typesafe.play" %% "play" % "2.8.13", - "com.typesafe.play" %% "play-json" % "2.9.2", + "org.playframework.anorm" %% "anorm" % anorm, + "com.typesafe.play" %% "play-json" % playJson, "org.postgresql" % "postgresql" % "42.3.6", "com.github.jwt-scala" %% "jwt-core" % "9.0.5", "de.svenkubiak" % "jBCrypt" % "0.4.3", @@ -265,13 +258,10 @@ lazy val browserProject: Project => Project = ) lazy val spraWeb = (project in file("spra-web")) - .dependsOn(spraApi.js, spraPlayServer) + .dependsOn(spraApi.js) .configure(bundlerSettings, baseLibSettings, browserProject, spraWebBuildInfoSettings) .configure(_.enablePlugins(ScalaJSPlugin, ScalaJSBundlerPlugin)) .settings( - scalaVersion := "2.13.8", - crossScalaVersions := Seq("2.13.8", "3.1.2"), - name := "spra-web", Test / fork := false, // sjs needs this to run tests scalaJSUseMainModuleInitializer := true, scalaJSLinkerConfig := scalaJSLinkerConfig.value.withSourceMap(false), diff --git a/project/plugins.sbt b/project/plugins.sbt index 02301c9..9ad6a8b 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,6 +1,9 @@ +// while there are some eviction errors, plugins seem to be compatible so far +evictionErrorLevel := sbt.util.Level.Warn + addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.1.0") -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.13") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.9.0-M6") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.8.0") From 8e0903a434492d85c755e5c5590e451ff543217a Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 7 Aug 2023 20:12:14 -0600 Subject: [PATCH 09/12] Fix minor errors --- .../spra/admin/config/TableSettings.scala | 13 ++++--------- .../spra/admin/controllers/AdminController.scala | 5 +++-- .../wiringbits/spra/admin/controllers/package.scala | 2 +- .../main/scala/net/wiringbits/spra/ui/web/API.scala | 6 +++++- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala index b7596f7..a4f275b 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala @@ -97,16 +97,11 @@ object TableSettings { } } -sealed trait PrimaryKeyDataType extends Product with Serializable -object PrimaryKeyDataType { - final case object UUID extends PrimaryKeyDataType - final case object Serial extends PrimaryKeyDataType - final case object BigSerial extends PrimaryKeyDataType +enum PrimaryKeyDataType { + case UUID, Serial, BigSerial } -sealed trait CustomDataType extends Product with Serializable -object CustomDataType { - final case object BinaryImage extends CustomDataType +enum CustomDataType { // TODO: add support to binary files - final case object Binary extends CustomDataType + case BinaryImage, Binary } diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala index 7df7c98..b5701f3 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala @@ -32,7 +32,8 @@ class AdminController @Inject() ( _ <- adminUser(request) _ = logger.info(s"Get metadata for $tableName, parameters: $queryParams") (response, contentRange) <- adminService.tableMetadata(tableName, queryParams) - } yield Ok(Json.toJson(response)) + // Json.toJson doesn't support a List[Map[_, _]] so we need to map to convert it to List[JsonValue] + } yield Ok(Json.toJson(response.map(Json.toJson(_)))) .withHeaders(("Access-Control-Expose-Headers", "Content-Range"), ("Content-Range", contentRange)) } @@ -49,7 +50,7 @@ class AdminController @Inject() ( _ <- adminUser(request) _ = logger.info(s"Get data from $tableName where primaryKeys = ${primaryKeyValues.mkString(",")}") response <- adminService.find(tableName, primaryKeyValues) - } yield Ok(Json.toJson(response)) + } yield Ok(Json.toJson(response.map(Json.toJson(_)))) } def create(tableName: String) = handleJsonBody[AdminCreateTable.Request] { request => diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala index 65fb34d..5df84d2 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala @@ -1,6 +1,6 @@ package net.wiringbits.spra.admin -import net.wiringbits.spra.api.models.ErrorResponse +import net.wiringbits.spra.api.models.{ErrorResponse, errorResponseFormat} import org.slf4j.LoggerFactory import play.api.libs.json.{JsValue, Json, Reads} import play.api.mvc.Results.InternalServerError diff --git a/spra-web/src/main/scala/net/wiringbits/spra/ui/web/API.scala b/spra-web/src/main/scala/net/wiringbits/spra/ui/web/API.scala index 958441e..2a3b1f1 100644 --- a/spra-web/src/main/scala/net/wiringbits/spra/ui/web/API.scala +++ b/spra-web/src/main/scala/net/wiringbits/spra/ui/web/API.scala @@ -2,6 +2,10 @@ package net.wiringbits.spra.ui.web import net.wiringbits.spra.api.AdminDataExplorerApiClient import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits.global +import sttp.capabilities +import sttp.client3.SttpBackend + +import scala.concurrent.Future case class API(client: AdminDataExplorerApiClient, url: String) @@ -13,7 +17,7 @@ object API { } def apply(): API = { - implicit val sttpBackend = sttp.client3.FetchBackend() + implicit val sttpBackend: SttpBackend[Future, capabilities.WebSockets] = sttp.client3.FetchBackend() val admin = new AdminDataExplorerApiClient.DefaultImpl(AdminDataExplorerApiClient.Config(apiUrl)) API(admin, apiUrl) } From 8bc45469756808d77dccae04ae4a5d532dbb5f26 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 11 Aug 2023 16:41:20 -0600 Subject: [PATCH 10/12] Optimize imports --- .scalafmt.conf | 2 +- .../spra/api/AdminDataExplorerApiClient.scala | 15 ++++----------- .../net/wiringbits/spra/api/models/package.scala | 2 +- spra-play-server/src/main/resources/routes | 2 +- .../net/wiringbits/spra/admin/AppRouter.scala | 2 +- .../spra/admin/config/TableSettings.scala | 2 +- .../spra/admin/controllers/AdminController.scala | 2 +- .../spra/admin/controllers/package.scala | 2 +- .../repositories/daos/DatabaseTablesDAO.scala | 2 +- .../spra/admin/repositories/daos/package.scala | 2 +- .../spra/admin/services/AdminService.scala | 2 +- .../scala/controllers/AdminControllerSpec.scala | 2 +- .../scala/controllers/common/PlayAPISpec.scala | 2 +- .../controllers/common/PlayPostgresSpec.scala | 3 ++- .../wiringbits/spra/admin/QueryBuilderSpec.scala | 2 +- .../wiringbits/spra/admin/StringRegexSpec.scala | 2 +- .../net/wiringbits/spra/admin/UtilsSpec.scala | 2 +- .../spra/admin/models/FilterParameterSpec.scala | 2 +- .../admin/models/PaginationParameterSpec.scala | 2 +- .../spra/admin/models/SortParameterSpec.scala | 2 +- .../spra/ui/web/components/EditGuesser.scala | 2 +- .../spra/ui/web/components/ListGuesser.scala | 2 +- 22 files changed, 26 insertions(+), 32 deletions(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 6712df2..faed3ac 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -3,7 +3,7 @@ project.git = true project.excludeFilters = [ ] -runner.dialect=scala213 +runner.dialect=scala3 maxColumn = 120 assumeStandardLibraryStripMargin = false diff --git a/spra-api/shared/src/main/scala/net/wiringbits/spra/api/AdminDataExplorerApiClient.scala b/spra-api/shared/src/main/scala/net/wiringbits/spra/api/AdminDataExplorerApiClient.scala index 50639ae..07bc3e9 100644 --- a/spra-api/shared/src/main/scala/net/wiringbits/spra/api/AdminDataExplorerApiClient.scala +++ b/spra-api/shared/src/main/scala/net/wiringbits/spra/api/AdminDataExplorerApiClient.scala @@ -1,16 +1,9 @@ package net.wiringbits.spra.api -import net.wiringbits.spra.api.models.{ - AdminCreateTable, - AdminDeleteTable, - AdminGetTables, - AdminUpdateTable, - PlayErrorResponse -} -import net.wiringbits.spra.api.models._ -import play.api.libs.json._ -import sttp.client3._ -import sttp.model._ +import net.wiringbits.spra.api.models.* +import play.api.libs.json.* +import sttp.client3.* +import sttp.model.* import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success, Try} diff --git a/spra-api/shared/src/main/scala/net/wiringbits/spra/api/models/package.scala b/spra-api/shared/src/main/scala/net/wiringbits/spra/api/models/package.scala index 6745f8b..08eca61 100644 --- a/spra-api/shared/src/main/scala/net/wiringbits/spra/api/models/package.scala +++ b/spra-api/shared/src/main/scala/net/wiringbits/spra/api/models/package.scala @@ -1,6 +1,6 @@ package net.wiringbits.spra.api -import play.api.libs.json._ +import play.api.libs.json.* import java.time.Instant diff --git a/spra-play-server/src/main/resources/routes b/spra-play-server/src/main/resources/routes index 1531894..399e3c0 100644 --- a/spra-play-server/src/main/resources/routes +++ b/spra-play-server/src/main/resources/routes @@ -3,4 +3,4 @@ # https://www.playframework.com/documentation/latest/ScalaRouting # ~~~~ --> / net.wiringbits.spra.admin.AppRouter +-> / net.wiringbits.spra.admin.AppRouter diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala index e7f5dad..5c61967 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/AppRouter.scala @@ -5,7 +5,7 @@ import net.wiringbits.spra.admin.utils.StringToDataTypesExt import net.wiringbits.spra.admin.utils.models.{FilterParameter, PaginationParameter, QueryParameters, SortParameter} import play.api.routing.Router.Routes import play.api.routing.SimpleRouter -import play.api.routing.sird._ +import play.api.routing.sird.* import javax.inject.Inject diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala index a4f275b..ac9fa9f 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/config/TableSettings.scala @@ -45,7 +45,7 @@ case class TableSettings( object TableSettings { implicit val configLoader: ConfigLoader[TableSettings] = (config: Config, path: String) => { - import scala.jdk.CollectionConverters._ + import scala.jdk.CollectionConverters.* val newConfig = config.getConfig(path) def get[A](path: String): A = { diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala index b5701f3..b2ebbbe 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/AdminController.scala @@ -3,7 +3,7 @@ package net.wiringbits.spra.admin.controllers import net.wiringbits.spra.admin.config.DataExplorerConfig import net.wiringbits.spra.admin.services.AdminService import net.wiringbits.spra.admin.utils.models.QueryParameters -import net.wiringbits.spra.api.models._ +import net.wiringbits.spra.api.models.* import org.slf4j.LoggerFactory import play.api.libs.json.Json import play.api.mvc.{AbstractController, ControllerComponents} diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala index 5df84d2..a67865b 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/controllers/package.scala @@ -3,8 +3,8 @@ package net.wiringbits.spra.admin import net.wiringbits.spra.api.models.{ErrorResponse, errorResponseFormat} import org.slf4j.LoggerFactory import play.api.libs.json.{JsValue, Json, Reads} +import play.api.mvc.* import play.api.mvc.Results.InternalServerError -import play.api.mvc._ import scala.concurrent.{ExecutionContext, Future} import scala.util.control.NonFatal diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala index 175da01..94ad1d2 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala @@ -2,7 +2,7 @@ package net.wiringbits.spra.admin.repositories.daos import anorm.{SqlParser, SqlStringInterpolation} import net.wiringbits.spra.admin.config.{CustomDataType, PrimaryKeyDataType, TableSettings} -import net.wiringbits.spra.admin.repositories.models._ +import net.wiringbits.spra.admin.repositories.models.* import net.wiringbits.spra.admin.utils.models.{FilterParameter, QueryParameters} import net.wiringbits.spra.admin.utils.{QueryBuilder, StringRegex} diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala index 6a1c6d7..691e958 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala @@ -1,6 +1,6 @@ package net.wiringbits.spra.admin.repositories -import anorm._ +import anorm.* import net.wiringbits.spra.admin.repositories.models.{DatabaseTable, ForeignKey, TableColumn} package object daos { diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala index e953a58..c3cfdab 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala @@ -5,7 +5,7 @@ import net.wiringbits.spra.admin.repositories.DatabaseTablesRepository import net.wiringbits.spra.admin.repositories.models.{ForeignKey, TableData} import net.wiringbits.spra.admin.utils.models.QueryParameters import net.wiringbits.spra.admin.utils.{MapStringHideExt, contentRangeHeader} -import net.wiringbits.spra.api.models._ +import net.wiringbits.spra.api.models.* import java.awt.image.BufferedImage import java.io.{ByteArrayInputStream, File} diff --git a/spra-play-server/src/test/scala/controllers/AdminControllerSpec.scala b/spra-play-server/src/test/scala/controllers/AdminControllerSpec.scala index 6f01ddb..2a67426 100644 --- a/spra-play-server/src/test/scala/controllers/AdminControllerSpec.scala +++ b/spra-play-server/src/test/scala/controllers/AdminControllerSpec.scala @@ -311,7 +311,7 @@ class AdminControllerSpec extends PlayPostgresSpec { val nameLength = 7 Range.apply(0, createdUsers).foreach { i => val letter = Character.valueOf(('A' + i).toChar) - val name = StringUtils.repeat(letter, nameLength); + val name = StringUtils.repeat(letter, nameLength) val data = Map("name" -> name, "email" -> s"test@wiringbits$i.net", "password" -> "wiringbits") val request = AdminCreateTable.Request(data) client.createItem(usersSettings.tableName, request).futureValue diff --git a/spra-play-server/src/test/scala/controllers/common/PlayAPISpec.scala b/spra-play-server/src/test/scala/controllers/common/PlayAPISpec.scala index 441d2e5..9a10a89 100644 --- a/spra-play-server/src/test/scala/controllers/common/PlayAPISpec.scala +++ b/spra-play-server/src/test/scala/controllers/common/PlayAPISpec.scala @@ -6,7 +6,7 @@ import org.slf4j.LoggerFactory import play.api.inject.guice.GuiceApplicationBuilder import play.api.mvc.Result import play.api.test.FakeRequest -import play.api.test.Helpers._ +import play.api.test.Helpers.* import play.api.{Application, Mode} import java.net.URLEncoder diff --git a/spra-play-server/src/test/scala/controllers/common/PlayPostgresSpec.scala b/spra-play-server/src/test/scala/controllers/common/PlayPostgresSpec.scala index 3e7a97f..16083dd 100644 --- a/spra-play-server/src/test/scala/controllers/common/PlayPostgresSpec.scala +++ b/spra-play-server/src/test/scala/controllers/common/PlayPostgresSpec.scala @@ -9,6 +9,7 @@ import org.scalatestplus.play.guice.GuiceOneServerPerTest import org.testcontainers.utility.DockerImageName import play.api.inject.guice.GuiceApplicationBuilder import play.api.{Application, Configuration, Environment, Mode} +import sttp.client3.SttpBackend import scala.concurrent.{ExecutionContext, Future} import scala.util.control.NonFatal @@ -47,7 +48,7 @@ trait PlayPostgresSpec extends PlayAPISpec with TestContainerForEach with GuiceO def withApiClient[A](runTest: AdminDataExplorerApiClient => A): A = { import sttp.client3.asynchttpclient.future.AsyncHttpClientFutureBackend - implicit val sttpBackend = AsyncHttpClientFutureBackend() + implicit val sttpBackend: SttpBackend[Future, Any] = AsyncHttpClientFutureBackend() val config = AdminDataExplorerApiClient.Config(s"http://localhost:$port") val client = new AdminDataExplorerApiClient.DefaultImpl(config) diff --git a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/QueryBuilderSpec.scala b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/QueryBuilderSpec.scala index 64c0be0..718540b 100644 --- a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/QueryBuilderSpec.scala +++ b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/QueryBuilderSpec.scala @@ -2,7 +2,7 @@ package net.wiringbits.spra.admin import net.wiringbits.spra.admin.repositories.models.TableColumn import net.wiringbits.spra.admin.utils.QueryBuilder -import org.scalatest.matchers.must.Matchers.{be, convertToAnyMustWrapper} +import org.scalatest.matchers.must.Matchers.{be, must} import org.scalatest.wordspec.AnyWordSpec class QueryBuilderSpec extends AnyWordSpec { diff --git a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/StringRegexSpec.scala b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/StringRegexSpec.scala index a8334de..8078c67 100644 --- a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/StringRegexSpec.scala +++ b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/StringRegexSpec.scala @@ -1,7 +1,7 @@ package net.wiringbits.spra.admin import net.wiringbits.spra.admin.utils.StringRegex -import org.scalatest.matchers.must.Matchers.{be, convertToAnyMustWrapper} +import org.scalatest.matchers.must.Matchers.{be, must} import org.scalatest.wordspec.AnyWordSpec class StringRegexSpec extends AnyWordSpec { diff --git a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/UtilsSpec.scala b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/UtilsSpec.scala index d0fad12..4d7ec36 100644 --- a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/UtilsSpec.scala +++ b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/UtilsSpec.scala @@ -2,7 +2,7 @@ package net.wiringbits.spra.admin import net.wiringbits.spra.admin.utils.StringToDataTypesExt import org.scalatest.OptionValues.convertOptionToValuable -import org.scalatest.matchers.must.Matchers.{be, convertToAnyMustWrapper} +import org.scalatest.matchers.must.Matchers.{be, must} import org.scalatest.wordspec.AnyWordSpec class UtilsSpec extends AnyWordSpec { diff --git a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/FilterParameterSpec.scala b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/FilterParameterSpec.scala index b0eaf72..19b2183 100644 --- a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/FilterParameterSpec.scala +++ b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/FilterParameterSpec.scala @@ -1,7 +1,7 @@ package net.wiringbits.spra.admin.models import net.wiringbits.spra.admin.utils.models.FilterParameter -import org.scalatest.matchers.must.Matchers.{be, convertToAnyMustWrapper} +import org.scalatest.matchers.must.Matchers.{be, must} import org.scalatest.wordspec.AnyWordSpec class FilterParameterSpec extends AnyWordSpec { diff --git a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/PaginationParameterSpec.scala b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/PaginationParameterSpec.scala index c633ee1..28d505e 100644 --- a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/PaginationParameterSpec.scala +++ b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/PaginationParameterSpec.scala @@ -1,7 +1,7 @@ package net.wiringbits.spra.admin.models import net.wiringbits.spra.admin.utils.models.PaginationParameter -import org.scalatest.matchers.must.Matchers.{be, convertToAnyMustWrapper} +import org.scalatest.matchers.must.Matchers.{be, must} import org.scalatest.wordspec.AnyWordSpec import scala.util.Try diff --git a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/SortParameterSpec.scala b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/SortParameterSpec.scala index 6d4b932..ce16ba8 100644 --- a/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/SortParameterSpec.scala +++ b/spra-play-server/src/test/scala/net/wiringbits/spra/admin/models/SortParameterSpec.scala @@ -1,7 +1,7 @@ package net.wiringbits.spra.admin.models import net.wiringbits.spra.admin.utils.models.SortParameter -import org.scalatest.matchers.must.Matchers.{be, convertToAnyMustWrapper} +import org.scalatest.matchers.must.Matchers.{be, must} import org.scalatest.wordspec.AnyWordSpec class SortParameterSpec extends AnyWordSpec { diff --git a/spra-web/src/main/scala/net/wiringbits/spra/ui/web/components/EditGuesser.scala b/spra-web/src/main/scala/net/wiringbits/spra/ui/web/components/EditGuesser.scala index dd10477..fa5c767 100644 --- a/spra-web/src/main/scala/net/wiringbits/spra/ui/web/components/EditGuesser.scala +++ b/spra-web/src/main/scala/net/wiringbits/spra/ui/web/components/EditGuesser.scala @@ -1,8 +1,8 @@ package net.wiringbits.spra.ui.web.components import net.wiringbits.spra.api.models.AdminGetTables +import net.wiringbits.spra.ui.web.facades.reactadmin.* import net.wiringbits.spra.ui.web.facades.reactadmin.ReactAdmin.useEditContext -import net.wiringbits.spra.ui.web.facades.reactadmin._ import net.wiringbits.spra.ui.web.models.{ButtonAction, ColumnType, DataExplorerSettings} import net.wiringbits.spra.ui.web.utils.ResponseGuesser import org.scalajs.dom diff --git a/spra-web/src/main/scala/net/wiringbits/spra/ui/web/components/ListGuesser.scala b/spra-web/src/main/scala/net/wiringbits/spra/ui/web/components/ListGuesser.scala index 7a2043e..b90ee11 100644 --- a/spra-web/src/main/scala/net/wiringbits/spra/ui/web/components/ListGuesser.scala +++ b/spra-web/src/main/scala/net/wiringbits/spra/ui/web/components/ListGuesser.scala @@ -1,7 +1,7 @@ package net.wiringbits.spra.ui.web.components import net.wiringbits.spra.api.models.AdminGetTables -import net.wiringbits.spra.ui.web.facades.reactadmin._ +import net.wiringbits.spra.ui.web.facades.reactadmin.* import net.wiringbits.spra.ui.web.models.ColumnType import net.wiringbits.spra.ui.web.models.ColumnType.{Date, Email, Image, Number, Text} import net.wiringbits.spra.ui.web.utils.ResponseGuesser From dfeb511edf4d08b6ecc825abf5d952622035db77 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 11 Aug 2023 17:35:45 -0600 Subject: [PATCH 11/12] Fix web compilation --- build.sbt | 5 +++-- project/plugins.sbt | 4 ++-- spra-web/src/main/js/index.html | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/build.sbt b/build.sbt index 5439564..ba2afd3 100644 --- a/build.sbt +++ b/build.sbt @@ -268,10 +268,11 @@ lazy val spraWeb = (project in file("spra-web")) scalaJSLinkerConfig := scalaJSLinkerConfig.value.withSourceMap(false), webpackDevServerPort := 8081, webpackBundlingMode := BundlingMode.LibraryOnly(), + stFlavour := Flavour.Slinky, libraryDependencies ++= Seq( "org.scala-js" %%% "scala-js-macrotask-executor" % "1.0.0", - "me.shadaj" %%% "slinky-core" % "0.7.3", - "me.shadaj" %%% "slinky-web" % "0.7.3" + "me.shadaj" %%% "slinky-core" % "0.7.4", + "me.shadaj" %%% "slinky-web" % "0.7.4" ), Compile / npmDependencies ++= Seq( "react" -> "17.0.0", diff --git a/project/plugins.sbt b/project/plugins.sbt index 9ad6a8b..217461d 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,11 +1,11 @@ // while there are some eviction errors, plugins seem to be compatible so far evictionErrorLevel := sbt.util.Level.Warn -addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.1.0") +addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.3.1") addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.9.0-M6") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.8.0") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.13.1") addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.20.0") diff --git a/spra-web/src/main/js/index.html b/spra-web/src/main/js/index.html index 57e40ca..b614b8c 100644 --- a/spra-web/src/main/js/index.html +++ b/spra-web/src/main/js/index.html @@ -20,9 +20,9 @@ You need to enable JavaScript to run this app.
- - - + + + From c4dd7038ddcc130e67a58d98cad18fcde1ed7326 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 11 Aug 2023 17:39:26 -0600 Subject: [PATCH 12/12] Minor changes --- build.sbt | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/build.sbt b/build.sbt index ba2afd3..1fb3e06 100644 --- a/build.sbt +++ b/build.sbt @@ -42,20 +42,7 @@ lazy val baseServerSettings: Project => Project = { _.settings( scalacOptions ++= Seq( "-Werror", -// "-unchecked", -// "-deprecation", "-feature" -// "-target:jvm-1.8", -// "-encoding", -// "UTF-8", -// "-Xsource:3", -// "-Wconf:src=src_managed/.*:silent", -// "-Xlint:missing-interpolator", -// "-Xlint:adapted-args", -// "-Ywarn-dead-code", -// "-Ywarn-numeric-widen", -// "-Ywarn-value-discard", -// "-Ywarn-unused" ), Compile / doc / scalacOptions ++= Seq("-no-link-warnings"), // Some options are very noisy when using the console and prevent us using it smoothly, let's disable them @@ -73,8 +60,6 @@ lazy val playSettings: Project => Project = { Compile / doc / scalacOptions ++= Seq( "-no-link-warnings" ), - // remove play noisy warnings -// play.sbt.routes.RoutesKeys.routesImport := Seq.empty, libraryDependencies ++= Seq( evolutions, "com.typesafe.play" %% "play-jdbc" % "2.9.0-M6", @@ -84,7 +69,6 @@ lazy val playSettings: Project => Project = { libraryDependencies ++= Seq( "org.scalatestplus.play" %% "scalatestplus-play" % "6.0.0-M6" % Test, "org.scalatestplus" %% "mockito-4-6" % scalaTestPlusMockito % Test -// "org.mockito" %% "mockito-scala-scalatest" % mockito % Test ) ) } @@ -268,7 +252,6 @@ lazy val spraWeb = (project in file("spra-web")) scalaJSLinkerConfig := scalaJSLinkerConfig.value.withSourceMap(false), webpackDevServerPort := 8081, webpackBundlingMode := BundlingMode.LibraryOnly(), - stFlavour := Flavour.Slinky, libraryDependencies ++= Seq( "org.scala-js" %%% "scala-js-macrotask-executor" % "1.0.0", "me.shadaj" %%% "slinky-core" % "0.7.4",