From bcb370e35ff9c8846a101b712dec709f51d83025 Mon Sep 17 00:00:00 2001 From: augustnagro Date: Mon, 2 Dec 2024 22:41:50 -0800 Subject: [PATCH 1/5] upgrade to magnum 1.3.1 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 892f2d439..306ebb031 100644 --- a/build.sbt +++ b/build.sbt @@ -16,7 +16,7 @@ val tapirVersion = "1.11.4" val oxVersion = "0.3.9" val dbDependencies = Seq( - "com.augustnagro" %% "magnum" % "1.3.0", + "com.augustnagro" %% "magnum" % "1.3.1", "org.postgresql" % "postgresql" % "42.7.4", "com.zaxxer" % "HikariCP" % "6.0.0", "org.flywaydb" % "flyway-database-postgresql" % "10.20.0" From 72611b68a1467fd93788922b5dd48308df52e105 Mon Sep 17 00:00:00 2001 From: augustnagro Date: Mon, 2 Dec 2024 22:44:38 -0800 Subject: [PATCH 2/5] use SqlLogger.logSlowQueries --- .../bootzooka/infrastructure/DB.scala | 11 +++++--- .../bootzooka/infrastructure/Magnum.scala | 25 +------------------ 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/DB.scala b/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/DB.scala index 2a9e49018..905b8de6c 100644 --- a/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/DB.scala +++ b/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/DB.scala @@ -5,7 +5,7 @@ import org.flywaydb.core.Flyway import scala.concurrent.duration.* import Magnum.* -import com.augustnagro.magnum.connect +import com.augustnagro.magnum.{SqlLogger, Transactor, connect} import com.softwaremill.bootzooka.config.Sensitive import com.softwaremill.bootzooka.infrastructure.DB.LeftException import com.softwaremill.bootzooka.logging.Logging @@ -19,16 +19,21 @@ import scala.util.NotGiven import scala.util.control.{NoStackTrace, NonFatal} class DB(dataSource: DataSource & Closeable) extends Logging with AutoCloseable: + private val transactor = Transactor( + dataSource = dataSource, + sqlLogger = SqlLogger.logSlowQueries(200.millis) + ) + /** Runs `f` in a transaction. The transaction is commited if the result is a [[Right]], and rolled back otherwise. */ def transactEither[E, T](f: DbTx ?=> Either[E, T])(using IO): Either[E, T] = - try com.augustnagro.magnum.transact(dataSource)(Right(f.fold(e => throw LeftException(e), identity))) + try com.augustnagro.magnum.transact(transactor)(Right(f.fold(e => throw LeftException(e), identity))) catch case e: LeftException[E] => Left(e.left) /** Runs `f` in a transaction. The result cannot be an `Either`, as then [[transactEither]] should be used. The transaction is commited if * no exception is thrown. */ def transact[T](f: DbTx ?=> T)(using NotGiven[T <:< Either[_, _]], IO): T = - com.augustnagro.magnum.transact(dataSource)(f) + com.augustnagro.magnum.transact(transactor)(f) override def close(): Unit = IO.unsafe(dataSource.close()) diff --git a/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/Magnum.scala b/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/Magnum.scala index 1c619ec33..e220577a1 100644 --- a/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/Magnum.scala +++ b/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/Magnum.scala @@ -15,27 +15,4 @@ object Magnum extends Logging: given DbCodec[LowerCased] = DbCodec.StringCodec.biMap(_.toLowerCased, _.toString) // proxies to the magnum functions/types, so that we can have only one import - export com.augustnagro.magnum.sql - type DbTx = com.augustnagro.magnum.DbTx - type DbCon = com.augustnagro.magnum.DbCon - type DbCodec[E] = com.augustnagro.magnum.DbCodec[E] - - /** Logs the SQL queries which are slow or end up in an exception. */ - // TODO: https://github.com/AugustNagro/magnum/issues/32 -// private val SlowThreshold = 200.millis -// implicit def doobieLogHandler[M[_]: Sync]: LogHandler[M] = new LogHandler[M] { -// override def run(logEvent: LogEvent): M[Unit] = Sync[M].delay( -// logEvent match { -// case Success(sql, _, _, exec, processing) => -// if (exec > SlowThreshold || processing > SlowThreshold) { -// logger.warn(s"Slow query (execution: $exec, processing: $processing): $sql") -// } -// -// case ProcessingFailure(sql, args, _, exec, processing, failure) => -// logger.error(s"Processing failure (execution: $exec, processing: $processing): $sql | args: $args", failure) -// -// case ExecFailure(sql, args, _, exec, failure) => -// logger.error(s"Execution failure (execution: $exec): $sql | args: $args", failure) -// } -// ) -// } + export com.augustnagro.magnum.{sql, DbTx, DbCon, DbCodec} From 0ca3ff58cfedf00ac65c82f0fb28400b09f7fb66 Mon Sep 17 00:00:00 2001 From: augustnagro Date: Mon, 2 Dec 2024 22:51:11 -0800 Subject: [PATCH 3/5] use exports clause for userRepo in UserModel --- .../scala/com/softwaremill/bootzooka/user/UserModel.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/main/scala/com/softwaremill/bootzooka/user/UserModel.scala b/backend/src/main/scala/com/softwaremill/bootzooka/user/UserModel.scala index d6815d6ae..b035bff9c 100644 --- a/backend/src/main/scala/com/softwaremill/bootzooka/user/UserModel.scala +++ b/backend/src/main/scala/com/softwaremill/bootzooka/user/UserModel.scala @@ -15,8 +15,8 @@ class UserModel: private val userRepo = Repo[User, User, Id[User]] private val u = TableInfo[User, User, Id[User]] - def insert(user: User)(using DbTx): Unit = userRepo.insert(user) - def findById(id: Id[User])(using DbTx): Option[User] = userRepo.findById(id) + export userRepo.{insert, findById} + def findByEmail(email: LowerCased)(using DbTx): Option[User] = findBy( Spec[User].where(sql"${u.emailLowerCase} = $email") ) From bd4b1348de007f84755e4d0216868a61b00675e3 Mon Sep 17 00:00:00 2001 From: augustnagro Date: Mon, 2 Dec 2024 22:58:35 -0800 Subject: [PATCH 4/5] fix warnings --- .../scala/com/softwaremill/bootzooka/infrastructure/DB.scala | 2 +- .../com/softwaremill/bootzooka/security/ApiKeyService.scala | 1 - .../main/scala/com/softwaremill/bootzooka/security/Auth.scala | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/DB.scala b/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/DB.scala index 905b8de6c..82abd01c4 100644 --- a/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/DB.scala +++ b/backend/src/main/scala/com/softwaremill/bootzooka/infrastructure/DB.scala @@ -27,7 +27,7 @@ class DB(dataSource: DataSource & Closeable) extends Logging with AutoCloseable: /** Runs `f` in a transaction. The transaction is commited if the result is a [[Right]], and rolled back otherwise. */ def transactEither[E, T](f: DbTx ?=> Either[E, T])(using IO): Either[E, T] = try com.augustnagro.magnum.transact(transactor)(Right(f.fold(e => throw LeftException(e), identity))) - catch case e: LeftException[E] => Left(e.left) + catch case e: LeftException[?] => Left(e.asInstanceOf[LeftException[E]].left) /** Runs `f` in a transaction. The result cannot be an `Either`, as then [[transactEither]] should be used. The transaction is commited if * no exception is thrown. diff --git a/backend/src/main/scala/com/softwaremill/bootzooka/security/ApiKeyService.scala b/backend/src/main/scala/com/softwaremill/bootzooka/security/ApiKeyService.scala index 26a7ea16e..31cee80d2 100644 --- a/backend/src/main/scala/com/softwaremill/bootzooka/security/ApiKeyService.scala +++ b/backend/src/main/scala/com/softwaremill/bootzooka/security/ApiKeyService.scala @@ -26,4 +26,3 @@ class ApiKeyService(apiKeyModel: ApiKeyModel, idGenerator: IdGenerator, clock: C def invalidateAllForUser(userId: Id[User])(using DbTx): Unit = logger.debug(s"Invalidating all api keys for user $userId") apiKeyModel.deleteAllForUser(userId) - diff --git a/backend/src/main/scala/com/softwaremill/bootzooka/security/Auth.scala b/backend/src/main/scala/com/softwaremill/bootzooka/security/Auth.scala index 157b7b5bb..eff73c285 100644 --- a/backend/src/main/scala/com/softwaremill/bootzooka/security/Auth.scala +++ b/backend/src/main/scala/com/softwaremill/bootzooka/security/Auth.scala @@ -7,8 +7,8 @@ import com.softwaremill.bootzooka.logging.Logging import com.softwaremill.bootzooka.user.User import com.softwaremill.bootzooka.util.* import com.softwaremill.bootzooka.util.Strings.Id -import ox.{IO, either, sleep} import ox.either.{fail, ok} +import ox.{IO, sleep} import java.security.SecureRandom import java.time.Instant @@ -20,7 +20,7 @@ class Auth[T](authTokenOps: AuthTokenOps[T], db: DB, clock: Clock) extends Loggi private val random = SecureRandom.getInstance("NativePRNGNonBlocking") /** Authenticates using the given authentication token. If the token is invalid, a [[Fail.Unauthorized]] error is returned. Otherwise, - * returns the id of the authenticated user . + * returns the id of the authenticated user . */ def apply(id: Id[T])(using IO): Either[Fail.Unauthorized, Id[User]] = db.transact(authTokenOps.findById(id)) match { From 42cdb44ea3bb05480b5e1aac49bf371f94c4165a Mon Sep 17 00:00:00 2001 From: adamw Date: Fri, 6 Dec 2024 12:00:48 +0100 Subject: [PATCH 5/5] Add java platform logger <-> slf4j bridge --- build.sbt | 1 + 1 file changed, 1 insertion(+) diff --git a/build.sbt b/build.sbt index 306ebb031..013f2dc7f 100644 --- a/build.sbt +++ b/build.sbt @@ -45,6 +45,7 @@ val jsonDependencies = Seq( val loggingDependencies = Seq( "ch.qos.logback" % "logback-classic" % "1.5.11", "com.softwaremill.ox" %% "mdc-logback" % oxVersion, + "org.slf4j" % "slf4j-jdk-platform-logging" % "2.0.7" % Runtime, "org.codehaus.janino" % "janino" % "3.1.12" % Runtime, "net.logstash.logback" % "logstash-logback-encoder" % "8.0" % Runtime )