diff --git a/.scalafix.conf b/.scalafix.conf index 6f2dc788..da1f0418 100644 --- a/.scalafix.conf +++ b/.scalafix.conf @@ -1,5 +1,4 @@ rules = [ - ProcedureSyntax OrganizeImports ] OrganizeImports { @@ -10,4 +9,5 @@ OrganizeImports { groups = ["re:javax?\\.", "scala.", "re:(cats|fs2)\\.", "sharry.", "*"] importSelectorsOrder = Ascii removeUnused = true + targetDialect = Scala3 } \ No newline at end of file diff --git a/.scalafmt.conf b/.scalafmt.conf index 893865bc..7aec7c06 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,7 +1,7 @@ version = "3.8.1" preset = default -runner.dialect = scala213source3 +runner.dialect = scala3 align.preset = some maxColumn = 90 diff --git a/build.sbt b/build.sbt index 135de189..cbfe2ce1 100644 --- a/build.sbt +++ b/build.sbt @@ -13,7 +13,7 @@ val scalafixSettings = Seq( val sharedSettings = Seq( organization := "com.github.eikek", - scalaVersion := "2.13.14", + scalaVersion := "3.4.2", scalacOptions ++= Seq( "-deprecation", "-encoding", @@ -22,12 +22,10 @@ val sharedSettings = Seq( "-feature", "-Werror", // fail when there are warnings "-unchecked", - // remove -byname-implicit, once https://github.com/scala/bug/issues/12072 is resolved - "-Xlint:-byname-implicit,_", - "-Wdead-code", - "-Wunused", - "-Wvalue-discard", - "-Wnumeric-widen" + "-Wunused:imports", + "-Wunused:locals", + "-Wunused:explicits", + "-Wvalue-discard" ), Compile / console / scalacOptions := Seq(), Test / console / scalacOptions := Seq() @@ -124,7 +122,6 @@ val loggingApi = project .settings(testSettingsMUnit) .settings( name := "sharry-logging-api", - addCompilerPlugin(Dependencies.kindProjectorPlugin), libraryDependencies ++= Dependencies.circeCore ++ Dependencies.fs2 ++ @@ -141,8 +138,7 @@ val common = project libraryDependencies ++= Dependencies.fs2 ++ Dependencies.fs2io ++ - Dependencies.circe ++ - Dependencies.pureconfig + Dependencies.circe ) val loggingScribe = project @@ -152,7 +148,6 @@ val loggingScribe = project .settings(testSettingsMUnit) .settings( name := "sharry-logging-scribe", - addCompilerPlugin(Dependencies.kindProjectorPlugin), libraryDependencies ++= Dependencies.scribe ++ Dependencies.circeCore ++ @@ -284,11 +279,10 @@ val restserver = project Dependencies.http4s ++ Dependencies.http4sclient ++ Dependencies.circe ++ - Dependencies.pureconfig ++ + Dependencies.typesafeConfig ++ + Dependencies.ciris ++ Dependencies.yamusca ++ Dependencies.webjars, - addCompilerPlugin(Dependencies.kindProjectorPlugin), - addCompilerPlugin(Dependencies.betterMonadicFor), buildInfoPackage := "sharry.restserver", reStart / javaOptions ++= Seq( diff --git a/flake.nix b/flake.nix index 5a0dc49e..d62936ab 100644 --- a/flake.nix +++ b/flake.nix @@ -72,7 +72,7 @@ SHARRY_BACKEND_MAIL_SMTP_PORT = "25"; SHARRY_BACKEND_MAIL_SMTP_USER = "admin"; SHARRY_BACKEND_MAIL_SMTP_PASSWORD = "admin"; - SHARRY_BACKEND_MAIL_SMTP_SSL__TYPE = "none"; + SHARRY_BACKEND_MAIL_SMTP_SSL_TYPE = "none"; }; dev-vm = pkgs.mkShellNoCC { @@ -91,7 +91,7 @@ SHARRY_BACKEND_MAIL_SMTP_PORT = "10025"; SHARRY_BACKEND_MAIL_SMTP_USER = "admin"; SHARRY_BACKEND_MAIL_SMTP_PASSWORD = "admin"; - SHARRY_BACKEND_MAIL_SMTP_SSL__TYPE = "none"; + SHARRY_BACKEND_MAIL_SMTP_SSL_TYPE = "none"; }; ci = pkgs.mkShellNoCC { buildInputs = ciPkgs; diff --git a/modules/backend/src/main/scala/sharry/backend/BackendApp.scala b/modules/backend/src/main/scala/sharry/backend/BackendApp.scala index e8a809bf..da47451e 100644 --- a/modules/backend/src/main/scala/sharry/backend/BackendApp.scala +++ b/modules/backend/src/main/scala/sharry/backend/BackendApp.scala @@ -2,10 +2,10 @@ package sharry.backend import scala.concurrent.ExecutionContext -import cats.effect._ +import cats.effect.* import fs2.io.file.Files -import sharry.backend.account._ +import sharry.backend.account.* import sharry.backend.alias.OAlias import sharry.backend.auth.Login import sharry.backend.config.Config diff --git a/modules/backend/src/main/scala/sharry/backend/account/NewAccount.scala b/modules/backend/src/main/scala/sharry/backend/account/NewAccount.scala index 323d7aa1..a8ab2330 100644 --- a/modules/backend/src/main/scala/sharry/backend/account/NewAccount.scala +++ b/modules/backend/src/main/scala/sharry/backend/account/NewAccount.scala @@ -1,9 +1,9 @@ package sharry.backend.account import cats.effect.Sync -import cats.implicits._ +import cats.implicits.* -import sharry.common._ +import sharry.common.* case class NewAccount( id: Ident, diff --git a/modules/backend/src/main/scala/sharry/backend/account/OAccount.scala b/modules/backend/src/main/scala/sharry/backend/account/OAccount.scala index 354bf218..25ca3030 100644 --- a/modules/backend/src/main/scala/sharry/backend/account/OAccount.scala +++ b/modules/backend/src/main/scala/sharry/backend/account/OAccount.scala @@ -1,18 +1,18 @@ package sharry.backend.account import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import fs2.Stream import sharry.backend.PasswordCrypt -import sharry.backend.share.{Queries => ShareQueries} -import sharry.common._ +import sharry.backend.share.Queries as ShareQueries +import sharry.common.* import sharry.store.AddResult import sharry.store.Store -import sharry.store.records._ +import sharry.store.records.* -import doobie._ +import doobie.* trait OAccount[F[_]] { @@ -45,7 +45,7 @@ object OAccount { def apply[F[_]: Async](store: Store[F]): Resource[F, OAccount[F]] = Resource.pure[F, OAccount[F]](new OAccount[F] { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def changePassword(id: Ident, oldPw: Password, newPw: Password): F[AddResult] = { val update = diff --git a/modules/backend/src/main/scala/sharry/backend/account/Queries.scala b/modules/backend/src/main/scala/sharry/backend/account/Queries.scala index 3259b4fd..fbab2394 100644 --- a/modules/backend/src/main/scala/sharry/backend/account/Queries.scala +++ b/modules/backend/src/main/scala/sharry/backend/account/Queries.scala @@ -2,13 +2,13 @@ package sharry.backend.account import fs2.Stream -import sharry.common._ -import sharry.store.doobie.DoobieMeta._ -import sharry.store.doobie._ -import sharry.store.records._ +import sharry.common.* +import sharry.store.doobie.* +import sharry.store.doobie.DoobieMeta.* +import sharry.store.records.* -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* object Queries { diff --git a/modules/backend/src/main/scala/sharry/backend/alias/OAlias.scala b/modules/backend/src/main/scala/sharry/backend/alias/OAlias.scala index aaa92ba1..806394b3 100644 --- a/modules/backend/src/main/scala/sharry/backend/alias/OAlias.scala +++ b/modules/backend/src/main/scala/sharry/backend/alias/OAlias.scala @@ -1,18 +1,18 @@ package sharry.backend.alias import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import fs2.Stream import sharry.backend.alias.OAlias.{AliasDetail, AliasInput} -import sharry.common._ +import sharry.common.* import sharry.store.AddResult import sharry.store.Store import sharry.store.records.RAlias import sharry.store.records.RAliasMember -import doobie._ +import doobie.* trait OAlias[F[_]] { @@ -40,7 +40,7 @@ object OAlias { def apply[F[_]: Async](store: Store[F]): Resource[F, OAlias[F]] = Resource.pure[F, OAlias[F]](new OAlias[F] { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def create(detail: AliasInput): F[AddResult] = store.add( diff --git a/modules/backend/src/main/scala/sharry/backend/auth/AddAccount.scala b/modules/backend/src/main/scala/sharry/backend/auth/AddAccount.scala index 87947bef..21cea225 100644 --- a/modules/backend/src/main/scala/sharry/backend/auth/AddAccount.scala +++ b/modules/backend/src/main/scala/sharry/backend/auth/AddAccount.scala @@ -1,11 +1,11 @@ package sharry.backend.auth import cats.data.Kleisli -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.account.{NewAccount, OAccount} -import sharry.common._ +import sharry.common.* import sharry.store.records.RAccount object AddAccount { diff --git a/modules/backend/src/main/scala/sharry/backend/auth/AuthConfig.scala b/modules/backend/src/main/scala/sharry/backend/auth/AuthConfig.scala index 4125d64d..bee1ac9e 100644 --- a/modules/backend/src/main/scala/sharry/backend/auth/AuthConfig.scala +++ b/modules/backend/src/main/scala/sharry/backend/auth/AuthConfig.scala @@ -1,5 +1,5 @@ package sharry.backend.auth -import sharry.common._ +import sharry.common.* import scodec.bits.ByteVector diff --git a/modules/backend/src/main/scala/sharry/backend/auth/AuthToken.scala b/modules/backend/src/main/scala/sharry/backend/auth/AuthToken.scala index d82d93b3..dcf48f8a 100644 --- a/modules/backend/src/main/scala/sharry/backend/auth/AuthToken.scala +++ b/modules/backend/src/main/scala/sharry/backend/auth/AuthToken.scala @@ -2,11 +2,11 @@ package sharry.backend.auth import java.time.Instant -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.Common -import sharry.backend.auth.AuthToken._ +import sharry.backend.auth.AuthToken.* import sharry.common.util.SignUtil import sharry.common.{AccountId, Duration} diff --git a/modules/backend/src/main/scala/sharry/backend/auth/CommandAuth.scala b/modules/backend/src/main/scala/sharry/backend/auth/CommandAuth.scala index 7cd19588..3be19889 100644 --- a/modules/backend/src/main/scala/sharry/backend/auth/CommandAuth.scala +++ b/modules/backend/src/main/scala/sharry/backend/auth/CommandAuth.scala @@ -1,22 +1,22 @@ package sharry.backend.auth -import scala.sys.process._ +import scala.sys.process.* import cats.data.Kleisli -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* -import sharry.common._ +import sharry.common.* -import yamusca.implicits._ -import yamusca.imports._ +import yamusca.implicits.* +import yamusca.imports.* final class CommandAuth[F[_]: Async]( cfg: AuthConfig, ops: AddAccount.AccountOps[F], runner: CommandAuth.RunCommand[F] ) { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def login: LoginModule[F] = LoginModule.whenEnabled(cfg.command.enabled)( @@ -69,7 +69,7 @@ object CommandAuth { def systemProcess[F[_]: Sync]: RunCommand[F] = new RunCommand[F] { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def exec(up: UserPassData, cfg: AuthConfig.Command): F[Boolean] = Sync[F].delay { diff --git a/modules/backend/src/main/scala/sharry/backend/auth/FixedAuth.scala b/modules/backend/src/main/scala/sharry/backend/auth/FixedAuth.scala index e161c195..f233a27b 100644 --- a/modules/backend/src/main/scala/sharry/backend/auth/FixedAuth.scala +++ b/modules/backend/src/main/scala/sharry/backend/auth/FixedAuth.scala @@ -1,10 +1,10 @@ package sharry.backend.auth -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* -import sharry.backend.account._ -import sharry.common._ +import sharry.backend.account.* +import sharry.common.* /** Provides authentication from the configuration. * @@ -17,7 +17,7 @@ import sharry.common._ */ final class FixedAuth[F[_]: Async](cfg: AuthConfig, op: OAccount[F]) { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def login: LoginModule[F] = LoginModule { up => diff --git a/modules/backend/src/main/scala/sharry/backend/auth/HttpAuth.scala b/modules/backend/src/main/scala/sharry/backend/auth/HttpAuth.scala index 368680bd..5b9dcc2b 100644 --- a/modules/backend/src/main/scala/sharry/backend/auth/HttpAuth.scala +++ b/modules/backend/src/main/scala/sharry/backend/auth/HttpAuth.scala @@ -3,13 +3,13 @@ package sharry.backend.auth import java.nio.charset.StandardCharsets import cats.data.Kleisli -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* -import sharry.common._ +import sharry.common.* -import yamusca.implicits._ -import yamusca.imports._ +import yamusca.implicits.* +import yamusca.imports.* final class HttpAuth[F[_]: Async]( cfg: AuthConfig, @@ -17,7 +17,7 @@ final class HttpAuth[F[_]: Async]( runner: HttpAuth.RunRequest[F] ) { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def login: LoginModule[F] = LoginModule.whenEnabled(cfg.http.enabled)( diff --git a/modules/backend/src/main/scala/sharry/backend/auth/HttpBasicAuth.scala b/modules/backend/src/main/scala/sharry/backend/auth/HttpBasicAuth.scala index 9c8e2376..6c5c3a4a 100644 --- a/modules/backend/src/main/scala/sharry/backend/auth/HttpBasicAuth.scala +++ b/modules/backend/src/main/scala/sharry/backend/auth/HttpBasicAuth.scala @@ -1,13 +1,13 @@ package sharry.backend.auth import java.nio.charset.StandardCharsets -import java.{util => ju} +import java.util as ju import cats.data.Kleisli -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* -import sharry.common._ +import sharry.common.* final class HttpBasicAuth[F[_]: Async]( cfg: AuthConfig, @@ -15,7 +15,7 @@ final class HttpBasicAuth[F[_]: Async]( runner: HttpBasicAuth.RunRequest[F] ) { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def login: LoginModule[F] = LoginModule.whenEnabled(cfg.httpBasic.enabled)( diff --git a/modules/backend/src/main/scala/sharry/backend/auth/InternalAuth.scala b/modules/backend/src/main/scala/sharry/backend/auth/InternalAuth.scala index 6757ff1b..649c73f6 100644 --- a/modules/backend/src/main/scala/sharry/backend/auth/InternalAuth.scala +++ b/modules/backend/src/main/scala/sharry/backend/auth/InternalAuth.scala @@ -1,17 +1,17 @@ package sharry.backend.auth import cats.data.Kleisli -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.PasswordCrypt import sharry.backend.account.OAccount -import sharry.common._ +import sharry.common.* import sharry.store.records.RAccount final class InternalAuth[F[_]: Async](cfg: AuthConfig, op: OAccount[F]) { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def login: LoginModule[F] = LoginModule.enabledState(cfg.internal.enabled, op, AccountSource.intern)( diff --git a/modules/backend/src/main/scala/sharry/backend/auth/Login.scala b/modules/backend/src/main/scala/sharry/backend/auth/Login.scala index 647fb7c1..c83ce96c 100644 --- a/modules/backend/src/main/scala/sharry/backend/auth/Login.scala +++ b/modules/backend/src/main/scala/sharry/backend/auth/Login.scala @@ -2,8 +2,8 @@ package sharry.backend.auth import cats.data.Kleisli import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.account.OAccount import sharry.common.Ident @@ -21,7 +21,7 @@ object Login { def apply[F[_]: Async](oacc: OAccount[F]): Resource[F, Login[F]] = Resource.pure[F, Login[F]](new Login[F] { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def loginSession(config: AuthConfig)(sessionKey: String): F[LoginResult] = AuthToken.fromString(sessionKey) match { @@ -65,7 +65,7 @@ object Login { CommandAuth[F](cfg, ops, CommandAuth.RunCommand.systemProcess[F]).withPosition ).sortBy(_._1).map(_._2) - LoginModule.combine[F](modules: _*) + LoginModule.combine[F](modules*) } } diff --git a/modules/backend/src/main/scala/sharry/backend/auth/LoginModule.scala b/modules/backend/src/main/scala/sharry/backend/auth/LoginModule.scala index b3e6e89b..3b10054b 100644 --- a/modules/backend/src/main/scala/sharry/backend/auth/LoginModule.scala +++ b/modules/backend/src/main/scala/sharry/backend/auth/LoginModule.scala @@ -5,10 +5,10 @@ import cats.Monad import cats.data.Kleisli import cats.data.OptionT import cats.effect.Sync -import cats.implicits._ +import cats.implicits.* import sharry.backend.account.OAccount -import sharry.common._ +import sharry.common.* object LoginModule { diff --git a/modules/backend/src/main/scala/sharry/backend/auth/UserPassData.scala b/modules/backend/src/main/scala/sharry/backend/auth/UserPassData.scala index 26402aee..3d1c2be9 100644 --- a/modules/backend/src/main/scala/sharry/backend/auth/UserPassData.scala +++ b/modules/backend/src/main/scala/sharry/backend/auth/UserPassData.scala @@ -1,10 +1,10 @@ package sharry.backend.auth -import sharry.backend.mustache.YamuscaCommon._ +import sharry.backend.mustache.YamuscaCommon.* import sharry.common.Password -import yamusca.derive._ -import yamusca.implicits._ -import yamusca.imports._ +import yamusca.derive.* +import yamusca.implicits.* +import yamusca.imports.* case class UserPassData(user: String, pass: Password) {} diff --git a/modules/backend/src/main/scala/sharry/backend/config/Config.scala b/modules/backend/src/main/scala/sharry/backend/config/Config.scala index 6a814622..2549eb3d 100644 --- a/modules/backend/src/main/scala/sharry/backend/config/Config.scala +++ b/modules/backend/src/main/scala/sharry/backend/config/Config.scala @@ -1,7 +1,7 @@ package sharry.backend.config import cats.data.ValidatedNec -import cats.syntax.all._ +import cats.syntax.all.* import sharry.backend.auth.AuthConfig import sharry.backend.job.CleanupConfig diff --git a/modules/backend/src/main/scala/sharry/backend/config/FilesConfig.scala b/modules/backend/src/main/scala/sharry/backend/config/FilesConfig.scala index 6d8ffd9f..e8d3dd42 100644 --- a/modules/backend/src/main/scala/sharry/backend/config/FilesConfig.scala +++ b/modules/backend/src/main/scala/sharry/backend/config/FilesConfig.scala @@ -1,7 +1,7 @@ package sharry.backend.config import cats.data.{Validated, ValidatedNec} -import cats.syntax.all._ +import cats.syntax.all.* import sharry.common.Ident import sharry.store.FileStoreConfig diff --git a/modules/backend/src/main/scala/sharry/backend/files/OFiles.scala b/modules/backend/src/main/scala/sharry/backend/files/OFiles.scala index c087b8ad..a77626a4 100644 --- a/modules/backend/src/main/scala/sharry/backend/files/OFiles.scala +++ b/modules/backend/src/main/scala/sharry/backend/files/OFiles.scala @@ -1,8 +1,8 @@ package sharry.backend.files import cats.data.OptionT -import cats.effect._ -import cats.syntax.all._ +import cats.effect.* +import cats.syntax.all.* import sharry.backend.config.FilesConfig import sharry.common.Ident @@ -26,7 +26,7 @@ object OFiles { fileConfig: FilesConfig ): OFiles[F] = new OFiles[F] { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def computeBackgroundChecksum: Resource[F, F[Outcome[F, Throwable, Unit]]] = Async[F].background( diff --git a/modules/backend/src/main/scala/sharry/backend/job/CleanupConfig.scala b/modules/backend/src/main/scala/sharry/backend/job/CleanupConfig.scala index ca9578fe..2d075326 100644 --- a/modules/backend/src/main/scala/sharry/backend/job/CleanupConfig.scala +++ b/modules/backend/src/main/scala/sharry/backend/job/CleanupConfig.scala @@ -1,5 +1,5 @@ package sharry.backend.job -import sharry.common._ +import sharry.common.* case class CleanupConfig(enabled: Boolean, interval: Duration, invalidAge: Duration) {} diff --git a/modules/backend/src/main/scala/sharry/backend/job/PeriodicCleanup.scala b/modules/backend/src/main/scala/sharry/backend/job/PeriodicCleanup.scala index 6639e247..5348f0b4 100644 --- a/modules/backend/src/main/scala/sharry/backend/job/PeriodicCleanup.scala +++ b/modules/backend/src/main/scala/sharry/backend/job/PeriodicCleanup.scala @@ -1,11 +1,11 @@ package sharry.backend.job -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import fs2.Stream -import sharry.backend.share._ -import sharry.backend.signup._ +import sharry.backend.share.* +import sharry.backend.signup.* import sharry.logging.Logger object PeriodicCleanup { diff --git a/modules/backend/src/main/scala/sharry/backend/mail/MailConfig.scala b/modules/backend/src/main/scala/sharry/backend/mail/MailConfig.scala index c8c2c401..e36cbe6f 100644 --- a/modules/backend/src/main/scala/sharry/backend/mail/MailConfig.scala +++ b/modules/backend/src/main/scala/sharry/backend/mail/MailConfig.scala @@ -1,9 +1,9 @@ package sharry.backend.mail -import sharry.common._ +import sharry.common.* -import emil.{MailConfig => EmilConfig, _} -import yamusca.imports._ +import emil.{MailConfig as EmilConfig, *} +import yamusca.imports.* case class MailConfig( enabled: Boolean, diff --git a/modules/backend/src/main/scala/sharry/backend/mail/NotifyData.scala b/modules/backend/src/main/scala/sharry/backend/mail/NotifyData.scala index 45cc00aa..f894053f 100644 --- a/modules/backend/src/main/scala/sharry/backend/mail/NotifyData.scala +++ b/modules/backend/src/main/scala/sharry/backend/mail/NotifyData.scala @@ -1,7 +1,7 @@ package sharry.backend.mail import sharry.backend.mail.NotifyData.AccountInfo -import sharry.common._ +import sharry.common.* final case class NotifyData( aliasId: Ident, diff --git a/modules/backend/src/main/scala/sharry/backend/mail/OMail.scala b/modules/backend/src/main/scala/sharry/backend/mail/OMail.scala index ae69a63f..2105902a 100644 --- a/modules/backend/src/main/scala/sharry/backend/mail/OMail.scala +++ b/modules/backend/src/main/scala/sharry/backend/mail/OMail.scala @@ -2,17 +2,17 @@ package sharry.backend.mail import cats.data.EitherT import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.mail.MailConfig.MailTpl -import sharry.common._ +import sharry.common.* import sharry.store.Store -import emil.builder._ -import emil.javamail.syntax._ -import emil.{MailConfig => _, _} -import yamusca.implicits._ +import emil.builder.* +import emil.javamail.syntax.* +import emil.{MailConfig as _, *} +import yamusca.implicits.* trait OMail[F[_]] { @@ -44,7 +44,7 @@ object OMail { emil: Emil[F] ): Resource[F, OMail[F]] = Resource.pure[F, OMail[F]](new OMail[F] { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def notifyAliasUpload( aliasId: Ident, shareId: Ident, @@ -90,7 +90,7 @@ object OMail { ) ) } - res <- OptionT.liftF(templates.traverse((send _).tupled)) + res <- OptionT.liftF(templates.traverse(send.tupled)) failedReceiver = res .filter(_.isError) .flatMap(_.receiver) diff --git a/modules/backend/src/main/scala/sharry/backend/mail/Queries.scala b/modules/backend/src/main/scala/sharry/backend/mail/Queries.scala index 80d3f8c8..12f410e7 100644 --- a/modules/backend/src/main/scala/sharry/backend/mail/Queries.scala +++ b/modules/backend/src/main/scala/sharry/backend/mail/Queries.scala @@ -2,13 +2,13 @@ package sharry.backend.mail import cats.data.OptionT -import sharry.common._ -import sharry.store.doobie.DoobieMeta._ -import sharry.store.doobie._ -import sharry.store.records._ +import sharry.common.* +import sharry.store.doobie.* +import sharry.store.doobie.DoobieMeta.* +import sharry.store.records.* -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* import emil.MailAddress object Queries { diff --git a/modules/backend/src/main/scala/sharry/backend/mail/TemplateData.scala b/modules/backend/src/main/scala/sharry/backend/mail/TemplateData.scala index d2dcaac2..3b3879db 100644 --- a/modules/backend/src/main/scala/sharry/backend/mail/TemplateData.scala +++ b/modules/backend/src/main/scala/sharry/backend/mail/TemplateData.scala @@ -1,11 +1,11 @@ package sharry.backend.mail -import sharry.backend.mustache.YamuscaCommon._ -import sharry.common._ +import sharry.backend.mustache.YamuscaCommon.* +import sharry.common.* -import yamusca.derive._ -import yamusca.implicits._ -import yamusca.imports._ +import yamusca.derive.* +import yamusca.implicits.* +import yamusca.imports.* case class TemplateData( user: Ident, diff --git a/modules/backend/src/main/scala/sharry/backend/mustache/YamuscaCommon.scala b/modules/backend/src/main/scala/sharry/backend/mustache/YamuscaCommon.scala index 0dd50a39..6b8a1ea4 100644 --- a/modules/backend/src/main/scala/sharry/backend/mustache/YamuscaCommon.scala +++ b/modules/backend/src/main/scala/sharry/backend/mustache/YamuscaCommon.scala @@ -1,8 +1,8 @@ package sharry.backend.mustache -import sharry.common._ +import sharry.common.* -import yamusca.imports._ +import yamusca.imports.* trait YamuscaCommon { diff --git a/modules/backend/src/main/scala/sharry/backend/share/ByteResult.scala b/modules/backend/src/main/scala/sharry/backend/share/ByteResult.scala index 452b1f38..68be3e5b 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/ByteResult.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/ByteResult.scala @@ -1,7 +1,7 @@ package sharry.backend.share import cats.data.OptionT -import cats.effect._ +import cats.effect.* import sharry.common.Ident import sharry.store.Store diff --git a/modules/backend/src/main/scala/sharry/backend/share/DescriptionTemplate.scala b/modules/backend/src/main/scala/sharry/backend/share/DescriptionTemplate.scala index f071d3dd..fec3dad7 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/DescriptionTemplate.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/DescriptionTemplate.scala @@ -1,11 +1,11 @@ package sharry.backend.share import sharry.backend.mustache.YamuscaCommon -import sharry.common._ +import sharry.common.* -import yamusca.derive._ -import yamusca.implicits._ -import yamusca.imports._ +import yamusca.derive.* +import yamusca.implicits.* +import yamusca.imports.* final class DescriptionTemplate(sd: ShareDetail) { diff --git a/modules/backend/src/main/scala/sharry/backend/share/FileData.scala b/modules/backend/src/main/scala/sharry/backend/share/FileData.scala index e4991e96..96d9614a 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/FileData.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/FileData.scala @@ -1,6 +1,6 @@ package sharry.backend.share -import sharry.common._ +import sharry.common.* case class FileData( id: Ident, diff --git a/modules/backend/src/main/scala/sharry/backend/share/OShare.scala b/modules/backend/src/main/scala/sharry/backend/share/OShare.scala index fb115628..df9e63f1 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/OShare.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/OShare.scala @@ -1,17 +1,17 @@ package sharry.backend.share import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import fs2.Stream import sharry.backend.PasswordCrypt -import sharry.common._ +import sharry.common.* import sharry.logging.Logger import sharry.store.AddResult import sharry.store.PermanentError import sharry.store.Store -import sharry.store.records._ +import sharry.store.records.* import binny.{ByteRange, ChunkDef, Hint} import scodec.bits.ByteVector @@ -144,7 +144,7 @@ object OShare { cfg: ShareConfig ): Resource[F, OShare[F]] = Resource.pure[F, OShare[F]](new OShare[F] { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def create(data: ShareData[F], accId: AccountId): F[UploadResult[Ident]] = { val createShare = for { diff --git a/modules/backend/src/main/scala/sharry/backend/share/Queries.scala b/modules/backend/src/main/scala/sharry/backend/share/Queries.scala index 4d7b29b2..48d90b56 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/Queries.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/Queries.scala @@ -1,18 +1,18 @@ package sharry.backend.share import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.syntax.all.* import fs2.Stream -import sharry.common._ +import sharry.common.* import sharry.store.Store -import sharry.store.doobie.DoobieMeta._ -import sharry.store.doobie._ -import sharry.store.records._ +import sharry.store.doobie.* +import sharry.store.doobie.DoobieMeta.* +import sharry.store.records.* -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* object Queries { val logger = sharry.logging.getLogger[ConnectionIO] @@ -384,7 +384,7 @@ object Queries { fids <- allFileIds _ <- store.transact(RShare.delete(share)) _ <- - if (background) Async[F].start(deleteAllFiles(fids)) + if (background) Async[F].start(deleteAllFiles(fids)).void else deleteAllFiles(fids) } yield () } diff --git a/modules/backend/src/main/scala/sharry/backend/share/ShareConfig.scala b/modules/backend/src/main/scala/sharry/backend/share/ShareConfig.scala index ae39920f..09adbd57 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/ShareConfig.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/ShareConfig.scala @@ -1,6 +1,6 @@ package sharry.backend.share -import sharry.common._ +import sharry.common.* import sharry.store.DomainCheckConfig case class ShareConfig( diff --git a/modules/backend/src/main/scala/sharry/backend/share/ShareData.scala b/modules/backend/src/main/scala/sharry/backend/share/ShareData.scala index efd69761..5b60c360 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/ShareData.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/ShareData.scala @@ -2,7 +2,7 @@ package sharry.backend.share import fs2.Stream -import sharry.common._ +import sharry.common.* case class ShareData[F[_]]( validity: Duration, diff --git a/modules/backend/src/main/scala/sharry/backend/share/ShareDetail.scala b/modules/backend/src/main/scala/sharry/backend/share/ShareDetail.scala index 555c050d..8d6a9d83 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/ShareDetail.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/ShareDetail.scala @@ -1,7 +1,7 @@ package sharry.backend.share import sharry.common.LenientUri -import sharry.store.records._ +import sharry.store.records.* case class ShareDetail( share: RShare, diff --git a/modules/backend/src/main/scala/sharry/backend/share/ShareId.scala b/modules/backend/src/main/scala/sharry/backend/share/ShareId.scala index cab54010..41f9fee7 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/ShareId.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/ShareId.scala @@ -1,6 +1,6 @@ package sharry.backend.share -import sharry.common._ +import sharry.common.* sealed trait ShareId { diff --git a/modules/backend/src/main/scala/sharry/backend/share/ShareItem.scala b/modules/backend/src/main/scala/sharry/backend/share/ShareItem.scala index 5b9aeeec..dd29b902 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/ShareItem.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/ShareItem.scala @@ -1,6 +1,6 @@ package sharry.backend.share -import sharry.common._ +import sharry.common.* import sharry.store.records.RShare case class ShareItem( diff --git a/modules/backend/src/main/scala/sharry/backend/share/ShareResult.scala b/modules/backend/src/main/scala/sharry/backend/share/ShareResult.scala index 70e64204..686d0e8c 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/ShareResult.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/ShareResult.scala @@ -1,7 +1,7 @@ package sharry.backend.share import cats.Applicative -import cats.implicits._ +import cats.implicits.* sealed trait ShareResult[+A] { diff --git a/modules/backend/src/main/scala/sharry/backend/share/UploadResult.scala b/modules/backend/src/main/scala/sharry/backend/share/UploadResult.scala index 67db1977..cb49ba57 100644 --- a/modules/backend/src/main/scala/sharry/backend/share/UploadResult.scala +++ b/modules/backend/src/main/scala/sharry/backend/share/UploadResult.scala @@ -1,9 +1,9 @@ package sharry.backend.share import cats.Applicative -import cats.implicits._ +import cats.implicits.* -import sharry.common._ +import sharry.common.* sealed trait UploadResult[+A] { diff --git a/modules/backend/src/main/scala/sharry/backend/signup/OSignup.scala b/modules/backend/src/main/scala/sharry/backend/signup/OSignup.scala index 5b94007e..bb1ae24f 100644 --- a/modules/backend/src/main/scala/sharry/backend/signup/OSignup.scala +++ b/modules/backend/src/main/scala/sharry/backend/signup/OSignup.scala @@ -1,10 +1,10 @@ package sharry.backend.signup -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* -import sharry.backend.account._ -import sharry.common._ +import sharry.backend.account.* +import sharry.common.* import sharry.store.records.RInvitation import sharry.store.{AddResult, Store} @@ -23,7 +23,7 @@ object OSignup { def apply[F[_]: Async](store: Store[F]): Resource[F, OSignup[F]] = Resource.pure[F, OSignup[F]](new OSignup[F] { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def newInvite(cfg: SignupConfig)(password: Password): F[NewInviteResult] = if (cfg.mode != SignupMode.Invite) diff --git a/modules/backend/src/main/scala/sharry/backend/signup/SignupConfig.scala b/modules/backend/src/main/scala/sharry/backend/signup/SignupConfig.scala index ca88c2a7..c57a6d76 100644 --- a/modules/backend/src/main/scala/sharry/backend/signup/SignupConfig.scala +++ b/modules/backend/src/main/scala/sharry/backend/signup/SignupConfig.scala @@ -1,6 +1,6 @@ package sharry.backend.signup -import sharry.common._ +import sharry.common.* case class SignupConfig(mode: SignupMode, inviteTime: Duration, invitePassword: Password) diff --git a/modules/backend/src/test/scala/sharry/backend/auth/LoginModuleTest.scala b/modules/backend/src/test/scala/sharry/backend/auth/LoginModuleTest.scala index 5e5831d2..f7e42ca6 100644 --- a/modules/backend/src/test/scala/sharry/backend/auth/LoginModuleTest.scala +++ b/modules/backend/src/test/scala/sharry/backend/auth/LoginModuleTest.scala @@ -1,20 +1,20 @@ package sharry.backend.auth import cats.data.Kleisli -import cats.effect._ +import cats.effect.* import cats.effect.unsafe.implicits.global -import cats.implicits._ +import cats.implicits.* import sharry.backend.account.OAccount import sharry.backend.auth.AddAccount.AccountOps -import sharry.common._ +import sharry.common.* import sharry.store.Store import sharry.store.StoreFixture import sharry.store.doobie.Sql import sharry.store.records.RAccount -import _root_.doobie._ -import munit._ +import _root_.doobie.* +import munit.* import scodec.bits.ByteVector class LoginModuleTest extends FunSuite { diff --git a/modules/backend/src/test/scala/sharry/backend/mail/QueriesTest.scala b/modules/backend/src/test/scala/sharry/backend/mail/QueriesTest.scala index 390976aa..90f256d6 100644 --- a/modules/backend/src/test/scala/sharry/backend/mail/QueriesTest.scala +++ b/modules/backend/src/test/scala/sharry/backend/mail/QueriesTest.scala @@ -1,13 +1,13 @@ package sharry.backend.mail -import cats.effect._ +import cats.effect.* -import sharry.common._ -import sharry.store._ +import sharry.common.* +import sharry.store.* import sharry.store.records.RAccount import emil.MailAddress -import munit._ +import munit.* class QueriesTest extends FunSuite with StoreFixture { @@ -30,7 +30,7 @@ class QueriesTest extends FunSuite with StoreFixture { for { _ <- store.transact(RAccount.insert(account, "warn")) e <- store.transact(Queries.getEmail(accountId)) - _ <- IO(assertEquals(e, Some(MailAddress(Some("jdoe"), "test@test.com")))) + _ <- IO(assertEquals(e, Some(MailAddress.unsafe(Some("jdoe"), "test@test.com")))) } yield () } } diff --git a/modules/common/src/main/scala/sharry/common/AccountId.scala b/modules/common/src/main/scala/sharry/common/AccountId.scala index db618a88..b0eaca9a 100644 --- a/modules/common/src/main/scala/sharry/common/AccountId.scala +++ b/modules/common/src/main/scala/sharry/common/AccountId.scala @@ -1,6 +1,6 @@ package sharry.common -import cats.implicits._ +import cats.implicits.* case class AccountId(id: Ident, userLogin: Ident, admin: Boolean, alias: Option[Ident]) { diff --git a/modules/common/src/main/scala/sharry/common/AccountState.scala b/modules/common/src/main/scala/sharry/common/AccountState.scala index 4044b598..1c5e330e 100644 --- a/modules/common/src/main/scala/sharry/common/AccountState.scala +++ b/modules/common/src/main/scala/sharry/common/AccountState.scala @@ -1,6 +1,6 @@ package sharry.common -import io.circe._ +import io.circe.* sealed trait AccountState { self: Product => final def name: String = diff --git a/modules/common/src/main/scala/sharry/common/BaseJsonCodecs.scala b/modules/common/src/main/scala/sharry/common/BaseJsonCodecs.scala index d0edb896..59a3d025 100644 --- a/modules/common/src/main/scala/sharry/common/BaseJsonCodecs.scala +++ b/modules/common/src/main/scala/sharry/common/BaseJsonCodecs.scala @@ -2,7 +2,7 @@ package sharry.common import java.time.Instant -import io.circe._ +import io.circe.* object BaseJsonCodecs { diff --git a/modules/common/src/main/scala/sharry/common/Duration.scala b/modules/common/src/main/scala/sharry/common/Duration.scala index 815ce3b0..aaf55e74 100644 --- a/modules/common/src/main/scala/sharry/common/Duration.scala +++ b/modules/common/src/main/scala/sharry/common/Duration.scala @@ -1,12 +1,12 @@ package sharry.common -import java.time.{Duration => JDur} +import java.time.Duration as JDur import java.util.concurrent.TimeUnit -import scala.concurrent.duration.{Duration => SDur, FiniteDuration} +import scala.concurrent.duration.{Duration as SDur, FiniteDuration} import cats.effect.Sync -import cats.implicits._ +import cats.implicits.* import io.circe.Decoder import io.circe.Encoder @@ -63,6 +63,13 @@ object Duration { val zero: Duration = new Duration(0L) + def fromString(s: String): Either[String, Duration] = + s.toLongOption match + case Some(n) => Right(millis(n)) + case None => + try Right(apply(scala.concurrent.duration.Duration(s))) + catch case ex: Throwable => Left(s"Invalid duration '$s': ${ex.getMessage}") + def apply(d: SDur): Duration = new Duration(d.toNanos) diff --git a/modules/common/src/main/scala/sharry/common/EnvMode.scala b/modules/common/src/main/scala/sharry/common/EnvMode.scala index 4a57dada..a32420e5 100644 --- a/modules/common/src/main/scala/sharry/common/EnvMode.scala +++ b/modules/common/src/main/scala/sharry/common/EnvMode.scala @@ -1,6 +1,6 @@ package sharry.common -import cats.implicits._ +import cats.implicits.* sealed trait EnvMode { self: Product => diff --git a/modules/common/src/main/scala/sharry/common/LenientUri.scala b/modules/common/src/main/scala/sharry/common/LenientUri.scala index 51697d70..6e21b6d4 100644 --- a/modules/common/src/main/scala/sharry/common/LenientUri.scala +++ b/modules/common/src/main/scala/sharry/common/LenientUri.scala @@ -5,9 +5,9 @@ import java.net.URL import java.net.URLEncoder import cats.data.NonEmptyList +import cats.effect.* import cats.effect.Resource -import cats.effect._ -import cats.implicits._ +import cats.implicits.* import fs2.Stream import sharry.common.LenientUri.Path @@ -232,7 +232,7 @@ object LenientUri { } } - private[this] val delims: Set[Char] = ",/?:@&$# %".toSet + private val delims: Set[Char] = ",/?:@&$# %".toSet private def percent(s: String): String = "%" + ByteVector.encodeUtf8(s).fold(throw _, identity).toHex diff --git a/modules/common/src/main/scala/sharry/common/SignupMode.scala b/modules/common/src/main/scala/sharry/common/SignupMode.scala index ccc2c231..12000f65 100644 --- a/modules/common/src/main/scala/sharry/common/SignupMode.scala +++ b/modules/common/src/main/scala/sharry/common/SignupMode.scala @@ -1,6 +1,6 @@ package sharry.common -import io.circe._ +import io.circe.* sealed trait SignupMode { self: Product => final def name: String = diff --git a/modules/common/src/main/scala/sharry/common/ThreadFactories.scala b/modules/common/src/main/scala/sharry/common/ThreadFactories.scala index 64206f98..a6ed5cbc 100644 --- a/modules/common/src/main/scala/sharry/common/ThreadFactories.scala +++ b/modules/common/src/main/scala/sharry/common/ThreadFactories.scala @@ -6,9 +6,9 @@ import java.util.concurrent.ForkJoinWorkerThread import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.{Executors, ThreadFactory} -import scala.concurrent._ +import scala.concurrent.* -import cats.effect._ +import cats.effect.* object ThreadFactories { diff --git a/modules/common/src/main/scala/sharry/common/config/Implicits.scala b/modules/common/src/main/scala/sharry/common/config/Implicits.scala deleted file mode 100644 index fbd52d1f..00000000 --- a/modules/common/src/main/scala/sharry/common/config/Implicits.scala +++ /dev/null @@ -1,68 +0,0 @@ -package sharry.common.config - -import java.nio.file.{Path => JPath} - -import scala.reflect.ClassTag - -import fs2.io.file.Path - -import sharry.common._ - -import com.comcast.ip4s.{Host, Port} -import pureconfig._ -import pureconfig.configurable.genericMapReader -import pureconfig.error.{CannotConvert, FailureReason} -import scodec.bits.ByteVector - -trait Implicits { - implicit val pathReader: ConfigReader[Path] = - ConfigReader[JPath].map(Path.fromNioPath) - - implicit val lenientUriReader: ConfigReader[LenientUri] = - ConfigReader[String].emap(reason(LenientUri.parse)) - - implicit val durationReader: ConfigReader[Duration] = - ConfigReader[scala.concurrent.duration.Duration].map(sd => Duration(sd)) - - implicit val passwordReader: ConfigReader[Password] = - ConfigReader[String].map(Password(_)) - - implicit val identReader: ConfigReader[Ident] = - ConfigReader[String].emap(reason(Ident.fromString)) - - implicit def identMapReader[B: ConfigReader]: ConfigReader[Map[Ident, B]] = - genericMapReader[Ident, B](reason(Ident.fromString)) - - implicit val byteVectorReader: ConfigReader[ByteVector] = - ConfigReader[String].emap(reason { str => - if (str.startsWith("hex:")) - ByteVector.fromHex(str.drop(4)).toRight("Invalid hex value.") - else if (str.startsWith("b64:")) - ByteVector.fromBase64(str.drop(4)).toRight("Invalid Base64 string.") - else ByteVector.encodeUtf8(str).left.map(_.getMessage()) - }) - - implicit val byteSizeReader: ConfigReader[ByteSize] = - ConfigReader[String].emap(reason(ByteSize.parse)) - - implicit val signupModeReader: ConfigReader[SignupMode] = - ConfigReader[String].emap(reason(SignupMode.fromString)) - - implicit val portReader: ConfigReader[Port] = - ConfigReader[Int].emap(reason(n => Port.fromInt(n).toRight(s"Invalid port: $n"))) - - implicit val hostReader: ConfigReader[Host] = - ConfigReader[String].emap( - reason(s => Host.fromString(s).toRight(s"Invalid host address: $s")) - ) - - def reason[I, A: ClassTag]( - f: I => Either[String, A] - ): I => Either[FailureReason, A] = - in => - f(in).left.map(str => - CannotConvert(in.toString, implicitly[ClassTag[A]].runtimeClass.toString, str) - ) -} - -object Implicits extends Implicits diff --git a/modules/common/src/main/scala/sharry/common/syntax/StreamSyntax.scala b/modules/common/src/main/scala/sharry/common/syntax/StreamSyntax.scala index 43320501..3dac6d57 100644 --- a/modules/common/src/main/scala/sharry/common/syntax/StreamSyntax.scala +++ b/modules/common/src/main/scala/sharry/common/syntax/StreamSyntax.scala @@ -1,11 +1,11 @@ package sharry.common.syntax import cats.effect.Sync -import cats.implicits._ +import cats.implicits.* import fs2.Stream -import io.circe._ -import io.circe.parser._ +import io.circe.* +import io.circe.parser.* trait StreamSyntax { diff --git a/modules/common/src/main/scala/sharry/common/syntax/StringSyntax.scala b/modules/common/src/main/scala/sharry/common/syntax/StringSyntax.scala index d0af4148..cc109a7a 100644 --- a/modules/common/src/main/scala/sharry/common/syntax/StringSyntax.scala +++ b/modules/common/src/main/scala/sharry/common/syntax/StringSyntax.scala @@ -1,9 +1,9 @@ package sharry.common.syntax -import cats.implicits._ +import cats.implicits.* import io.circe.Decoder -import io.circe.parser._ +import io.circe.parser.* trait StringSyntax { diff --git a/modules/common/src/main/scala/sharry/common/util/Random.scala b/modules/common/src/main/scala/sharry/common/util/Random.scala index 2bf55c32..d0f38481 100644 --- a/modules/common/src/main/scala/sharry/common/util/Random.scala +++ b/modules/common/src/main/scala/sharry/common/util/Random.scala @@ -1,6 +1,6 @@ package sharry.common.util -import cats.effect._ +import cats.effect.* import scodec.bits.ByteVector diff --git a/modules/logging/api/src/main/scala/sharry/logging/AndThenLogger.scala b/modules/logging/api/src/main/scala/sharry/logging/AndThenLogger.scala index 6a107e1c..83c31a24 100644 --- a/modules/logging/api/src/main/scala/sharry/logging/AndThenLogger.scala +++ b/modules/logging/api/src/main/scala/sharry/logging/AndThenLogger.scala @@ -7,7 +7,7 @@ package sharry.logging import cats.data.NonEmptyList -import cats.syntax.all._ +import cats.syntax.all.* import cats.{Applicative, Id} final private[logging] class AndThenLogger[F[_]: Applicative]( diff --git a/modules/logging/api/src/main/scala/sharry/logging/LazyMap.scala b/modules/logging/api/src/main/scala/sharry/logging/LazyMap.scala index f1940018..cc053345 100644 --- a/modules/logging/api/src/main/scala/sharry/logging/LazyMap.scala +++ b/modules/logging/api/src/main/scala/sharry/logging/LazyMap.scala @@ -2,7 +2,7 @@ package sharry.logging import sharry.logging.LazyMap.Val -final class LazyMap[A, B]( +final class LazyMap[A, B] private ( private val values: Map[A, Val[B]] ) { lazy val toMap: Map[A, B] = values.view.mapValues(_.value).toMap @@ -24,7 +24,7 @@ final class LazyMap[A, B]( } object LazyMap { - private[this] val emptyMap = new LazyMap[Any, Any](Map.empty) + private val emptyMap = new LazyMap[Any, Any](Map.empty) def empty[A, B]: LazyMap[A, B] = emptyMap.asInstanceOf[LazyMap[A, B]] diff --git a/modules/logging/api/src/main/scala/sharry/logging/LogConfig.scala b/modules/logging/api/src/main/scala/sharry/logging/LogConfig.scala index d1b72ed4..24a50d0c 100644 --- a/modules/logging/api/src/main/scala/sharry/logging/LogConfig.scala +++ b/modules/logging/api/src/main/scala/sharry/logging/LogConfig.scala @@ -37,10 +37,9 @@ object LogConfig { case object Plain extends Format case object Fancy extends Format case object Json extends Format - case object Logfmt extends Format val all: NonEmptyList[Format] = - NonEmptyList.of(Plain, Fancy, Json, Logfmt) + NonEmptyList.of(Plain, Fancy, Json) def fromString(str: String): Either[String, Format] = all.find(_.name.equalsIgnoreCase(str)).toRight(s"Invalid format name: $str") diff --git a/modules/logging/api/src/main/scala/sharry/logging/LogEvent.scala b/modules/logging/api/src/main/scala/sharry/logging/LogEvent.scala index f241169f..75c14151 100644 --- a/modules/logging/api/src/main/scala/sharry/logging/LogEvent.scala +++ b/modules/logging/api/src/main/scala/sharry/logging/LogEvent.scala @@ -7,7 +7,7 @@ package sharry.logging import io.circe.{Encoder, Json} -import sourcecode._ +import sourcecode.* final case class LogEvent( level: Level, diff --git a/modules/logging/api/src/main/scala/sharry/logging/Logger.scala b/modules/logging/api/src/main/scala/sharry/logging/Logger.scala index 4ea37d7e..6198d410 100644 --- a/modules/logging/api/src/main/scala/sharry/logging/Logger.scala +++ b/modules/logging/api/src/main/scala/sharry/logging/Logger.scala @@ -10,12 +10,12 @@ import java.io.PrintStream import java.time.Instant import cats.effect.{Ref, Sync} -import cats.syntax.applicative._ -import cats.syntax.functor._ -import cats.syntax.order._ +import cats.syntax.applicative.* +import cats.syntax.functor.* +import cats.syntax.order.* import cats.{Applicative, Id} -import sourcecode._ +import sourcecode.* trait Logger[F[_]] extends LoggerExtension[F] { diff --git a/modules/logging/api/src/main/scala/sharry/logging/LoggerExtension.scala b/modules/logging/api/src/main/scala/sharry/logging/LoggerExtension.scala index 7607ac31..363a036f 100644 --- a/modules/logging/api/src/main/scala/sharry/logging/LoggerExtension.scala +++ b/modules/logging/api/src/main/scala/sharry/logging/LoggerExtension.scala @@ -11,8 +11,8 @@ import fs2.Stream trait LoggerExtension[F[_]] { self: Logger[F] => - def stream: Logger[Stream[F, *]] = - new Logger[Stream[F, *]] { + def stream: Logger[[X] =>> Stream[F, X]] = + new Logger[[X] =>> Stream[F, X]] { def log(ev: LogEvent) = Stream.eval(self.log(ev)) diff --git a/modules/logging/scribe/src/main/scala/sharry/logging/impl/JsonWriter.scala b/modules/logging/scribe/src/main/scala/sharry/logging/impl/JsonWriter.scala deleted file mode 100644 index b07838f8..00000000 --- a/modules/logging/scribe/src/main/scala/sharry/logging/impl/JsonWriter.scala +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2020 Eike K. & Contributors - * - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package sharry.logging.impl - -import io.circe.syntax._ -import scribe._ -import scribe.output._ -import scribe.output.format.OutputFormat -import scribe.writer._ - -final case class JsonWriter(writer: Writer, compact: Boolean = true) extends Writer { - override def write( - record: LogRecord, - output: LogOutput, - outputFormat: OutputFormat - ): Unit = { - val r = Record.fromLogRecord(record) - val json = r.asJson - val jsonString = if (compact) json.noSpaces else json.spaces2 - writer.write(record, new TextOutput(jsonString), outputFormat) - } -} diff --git a/modules/logging/scribe/src/main/scala/sharry/logging/impl/LogfmtWriter.scala b/modules/logging/scribe/src/main/scala/sharry/logging/impl/LogfmtWriter.scala deleted file mode 100644 index 4d597f4a..00000000 --- a/modules/logging/scribe/src/main/scala/sharry/logging/impl/LogfmtWriter.scala +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2020 Eike K. & Contributors - * - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package sharry.logging.impl - -import io.circe.syntax._ -import scribe._ -import scribe.output._ -import scribe.output.format.OutputFormat -import scribe.writer._ - -// https://brandur.org/logfmt -final case class LogfmtWriter(writer: Writer) extends Writer { - override def write( - record: LogRecord, - output: LogOutput, - outputFormat: OutputFormat - ): Unit = { - val r = Record.fromLogRecord(record) - val data = r.data - .map { case (k, v) => - s"$k=${v.noSpaces}" - } - .mkString(" ") - val logfmtStr = - s"""level=${r.level.asJson.noSpaces} levelValue=${r.levelValue} message=${r.message.asJson.noSpaces} fileName=${r.fileName.asJson.noSpaces} className=${r.className.asJson.noSpaces} methodName=${r.methodName.asJson.noSpaces} line=${r.line.asJson.noSpaces} column=${r.column.asJson.noSpaces} $data timestamp=${r.timeStamp} date=${r.date} time=${r.time}""" - writer.write(record, new TextOutput(logfmtStr), outputFormat) - } -} diff --git a/modules/logging/scribe/src/main/scala/sharry/logging/impl/Record.scala b/modules/logging/scribe/src/main/scala/sharry/logging/impl/Record.scala deleted file mode 100644 index f83631d0..00000000 --- a/modules/logging/scribe/src/main/scala/sharry/logging/impl/Record.scala +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2020 Eike K. & Contributors - * - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package sharry.logging.impl - -import sharry.logging.impl.Record._ - -import io.circe.syntax._ -import io.circe.{Encoder, Json} -import perfolation._ -import scribe.LogRecord -import scribe.mdc.MDC -import scribe.message.Message - -// From: https://github.com/outr/scribe/blob/8e99521e1ee1f0c421629764dd96e4eb193d84bd/json/shared/src/main/scala/scribe/json/JsonWriter.scala -// which would introduce jackson and other dependencies. Modified to work with circe. -// Original licensed under MIT. - -private[impl] case class Record( - level: String, - levelValue: Double, - message: String, - additionalMessages: List[String], - fileName: String, - className: String, - methodName: Option[String], - line: Option[Int], - column: Option[Int], - data: Map[String, Json], - traces: List[Trace], - timeStamp: Long, - date: String, - time: String -) - -private[impl] object Record { - - def fromLogRecord(record: LogRecord): Record = { - val l = record.timeStamp - val traces = record.messages.collect { - case message: Message[_] if message.value.isInstanceOf[Throwable] => - throwable2Trace(message.value.asInstanceOf[Throwable]) - } - val (firstMessage, additionalMessages) = record.messages match { - case h :: rest => - (h.logOutput.plainText, rest.map(_.logOutput.plainText)) - case Nil => - ("", Nil) - } - - Record( - level = record.level.name, - levelValue = record.levelValue, - message = firstMessage, - additionalMessages = additionalMessages, - fileName = record.fileName, - className = record.className, - methodName = record.methodName, - line = record.line, - column = record.column, - data = (record.data ++ MDC.map).map { case (key, value) => - value() match { - case value: Json => key -> value - case value: Int => key -> value.asJson - case value: Long => key -> value.asJson - case value: Double => key -> value.asJson - case any => key -> Json.fromString(any.toString) - } - }, - traces = traces, - timeStamp = l, - date = l.t.F, - time = s"${l.t.T}.${l.t.L}${l.t.z}" - ) - } - - private def throwable2Trace(throwable: Throwable): Trace = { - val elements = throwable.getStackTrace.toList.map { e => - TraceElement(e.getClassName, e.getMethodName, e.getLineNumber) - } - Trace( - throwable.getLocalizedMessage, - elements, - Option(throwable.getCause).map(throwable2Trace) - ) - } - - implicit val jsonEncoder: Encoder[Record] = - Encoder.forProduct14( - "level", - "levelValue", - "message", - "additionalMessages", - "fileName", - "className", - "methodName", - "line", - "column", - "data", - "traces", - "timestamp", - "date", - "time" - )(r => Record.unapply(r).get) - - case class Trace(message: String, elements: List[TraceElement], cause: Option[Trace]) - - object Trace { - implicit def jsonEncoder: Encoder[Trace] = - Encoder.forProduct3("message", "elements", "cause")(r => Trace.unapply(r).get) - - implicit def openEncoder: Encoder[Option[Trace]] = - Encoder.instance(opt => opt.map(jsonEncoder.apply).getOrElse(Json.Null)) - } - - case class TraceElement(`class`: String, method: String, line: Int) - - object TraceElement { - implicit val jsonEncoder: Encoder[TraceElement] = - Encoder.forProduct3("class", "method", "line")(r => TraceElement.unapply(r).get) - } -} diff --git a/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeConfigure.scala b/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeConfigure.scala index 768e51f6..ea34791c 100644 --- a/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeConfigure.scala +++ b/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeConfigure.scala @@ -39,6 +39,7 @@ object ScribeConfigure { format: LogConfig.Format, level: Level ): Unit = { + val writer = scribe.json.ScribeCirceJsonSupport.writer(SystemOutWriter) val mods: List[scribe.Logger => scribe.Logger] = List( _.clearHandlers(), _.withMinimumLevel(ScribeWrapper.convertLevel(level)), @@ -50,9 +51,7 @@ object ScribeConfigure { case Format.Plain => l.withHandler(formatter = Formatter.classic, writer = SystemOutWriter) case Format.Json => - l.withHandler(writer = JsonWriter(SystemOutWriter)) - case Format.Logfmt => - l.withHandler(writer = LogfmtWriter(SystemOutWriter)) + l.withHandler(writer = writer) } } else l, _.replace() diff --git a/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeWrapper.scala b/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeWrapper.scala index a4b69677..73077cdb 100644 --- a/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeWrapper.scala +++ b/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeWrapper.scala @@ -39,10 +39,10 @@ private[logging] object ScribeWrapper { case Level.Trace => scribe.Level.Trace } - private[this] def emptyMDC: MDC = + private def emptyMDC: MDC = new MDCMap(None) - private[this] def convert(ev: LogEvent) = { + private def convert(ev: LogEvent) = { val level = convertLevel(ev.level) val additional: List[LoggableMessage] = ev.additional .map { diff --git a/modules/logging/scribe/src/main/scala/sharry/logging/package.scala b/modules/logging/scribe/src/main/scala/sharry/logging/package.scala index 14e23d66..7d1fd6b2 100644 --- a/modules/logging/scribe/src/main/scala/sharry/logging/package.scala +++ b/modules/logging/scribe/src/main/scala/sharry/logging/package.scala @@ -7,7 +7,7 @@ package sharry import cats.Id -import cats.effect._ +import cats.effect.* import sharry.logging.impl.ScribeWrapper @@ -27,7 +27,7 @@ package object logging { def getLogger[F[_]: Sync](name: String): Logger[F] = new ScribeWrapper.Impl[F](scribe.Logger(name)) - def getLogger[F[_]: Sync](clazz: Class[_]): Logger[F] = + def getLogger[F[_]: Sync](clazz: Class[?]): Logger[F] = new ScribeWrapper.Impl[F](scribe.Logger(clazz.getName)) } diff --git a/modules/logging/scribe/src/test/scala/docspell/logging/TestLoggingConfig.scala b/modules/logging/scribe/src/test/scala/docspell/logging/TestLoggingConfig.scala index be4137c4..727ffeb6 100644 --- a/modules/logging/scribe/src/test/scala/docspell/logging/TestLoggingConfig.scala +++ b/modules/logging/scribe/src/test/scala/docspell/logging/TestLoggingConfig.scala @@ -6,7 +6,7 @@ package docspell.logging -import sharry.logging._ +import sharry.logging.* import sharry.logging.impl.ScribeConfigure import munit.Suite diff --git a/modules/microsite/docs/doc/configure.md b/modules/microsite/docs/doc/configure.md index c7a028fd..13d581a7 100644 --- a/modules/microsite/docs/doc/configure.md +++ b/modules/microsite/docs/doc/configure.md @@ -11,6 +11,14 @@ that is not given, the defaults are used. The config file overrides default values, so only values that differ from the defaults are necessary to specify. +Environment variables can be used as well to override values from the +config file. Variable names always start with `SHARRY_` and the +remainder can be derived from the corresponding config option by +replacing period `.` and dash `-` by an underscore `_`, but excluding +the root namespace `sharry.restserver`. For example, the config option +`sharry.restserver.bind.address` would be `SHARRY_BIND_ADDRESS` as +environment variable. A value given as environment variable has +priority. ## File Format @@ -23,6 +31,19 @@ allows comments and has some [advanced features](https://github.com/lightbend/config/blob/master/README.md#features-of-hocon). Please refer to their documentation for more on this. +The hocon format allows to include environment variables, allowing to +mix and match both variants if desired. For example: + +```conf +… + mode = "open" + mode = ${?SHARRY_BACKEND_SIGNUP_MODE} +… +``` + +would use the value `"open"` if the environment varible +`SHARRY_BACKEND_SIGNUP_MODE` is not defined, because it would +overwrite the previously defined value. ## Important Config Options @@ -97,7 +118,7 @@ sharry.restserver.backend.share { # # See issue https://github.com/eikek/sharry/issues/255 – the # example is a virus check via a postgresql extension "snakeoil". - database-domain-checks = [ + database-domain-checks = { # Example: This message originates from postgres with an # enabled snakeoil extension. This extension allows to virus # check byte arrays. It must be setup such that the `bytea` @@ -107,11 +128,12 @@ sharry.restserver.backend.share { # CREATE EXTENSION pg_snakeoil; # CREATE DOMAIN public.safe_bytea as bytea CHECK (not so_is_infected(value)); # ALTER TABLE public.filechunk ALTER COLUMN chunkdata TYPE safe_bytea; - { enabled = false + snakeoil = { + enabled = false native = "domain safe_bytea violates check constraint" message = "The uploaded file contains a virus!" } - ] + } } ``` @@ -479,24 +501,25 @@ The `oauth` login module can be configured with multiple such providers. Here is an example: ``` -oauth = [ - { - enabled = false - id = "github" - name = "Github" - icon = "fab fa-github" - authorize-url = "https://github.com/login/oauth/authorize" - token-url = "https://github.com/login/oauth/access_token" - user-url = "https://api.github.com/user" - user-id-key = "login" - scope = "" - client-id = "" - client-secret = "" - } -] -``` - -Each such entry in the array results in a button on the login screen. +oauth = { + github = { + enabled = false + name = "Github" + icon = "fab fa-github" + authorize-url = "https://github.com/login/oauth/authorize" + token-url = "https://github.com/login/oauth/access_token" + user-url = "https://api.github.com/user" + user-id-key = "login" + scope = "" + client-id = "" + client-secret = "" + } +} +``` + +Each such entry in the `oauth` object results in a button on the login +screen. The key (`github` in the above example) is used to refer to +this provider as its id. diff --git a/modules/restserver/src/main/resources/reference.conf b/modules/restserver/src/main/resources/reference.conf index fe83db83..93211f57 100644 --- a/modules/restserver/src/main/resources/reference.conf +++ b/modules/restserver/src/main/resources/reference.conf @@ -11,9 +11,7 @@ sharry.restserver { # Where the server binds to. bind { address = "localhost" - address = ${?SHARRY_BIND_ADDRESS} port = 9090 - port = ${?SHARRY_BIND_PORT} } file-download { @@ -242,10 +240,9 @@ sharry.restserver { # denoting the user name # - user-email-key: the name of the field in the json response # that denotes the users email. - oauth = [ - { + oauth = { + "github" = { enabled = false - id = "github" name = "Github" icon = "fab fa-github" scope = "" @@ -256,9 +253,8 @@ sharry.restserver { client-id = "" client-secret = "" }, - { + "google" = { enabled = false - id = "google" name = "Google" icon = "fab fa-google" scope = "" @@ -269,9 +265,8 @@ sharry.restserver { client-id = "" client-secret = "" }, - { + "aad" = { enabled = false - id = "aad" name = "Azure AD" icon = "fab fa-microsoft" scope = "openid" @@ -283,7 +278,7 @@ sharry.restserver { client-id = "" client-secret = "" } - ] + } # Allows to inspect the request headers for finding already # authorized user name/email. If enabled and during login the @@ -303,11 +298,8 @@ sharry.restserver { # use the PostgreSQL compatibility mode. jdbc { url = "jdbc:h2://"${java.io.tmpdir}"/sharry-demo.db;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE" - url = ${?SHARRY_BACKEND_JDBC_URL} user = "sa" - user = ${?SHARRY_BACKEND_JDBC_USER} password = "" - password = ${?SHARRY_BACKEND_JDBC_PASSWORD} } # How files are stored. @@ -398,7 +390,6 @@ sharry.restserver { # invitation key. Invitation keys can be generated by an admin. # - closed: signing up is disabled. mode = "open" - mode = ${?SHARRY_BACKEND_SIGNUP_MODE} # If mode == 'invite', this is the period an invitation token is # considered valid. @@ -409,7 +400,6 @@ sharry.restserver { # invitation keys. Generating such keys is only permitted to # admin users. invite-password = "generate-invite" - invite-password = ${?SHARRY_BACKEND_SIGNUP_INVITE__PASSWORD} } @@ -433,7 +423,7 @@ sharry.restserver { # # See issue https://github.com/eikek/sharry/issues/255 – the # example is a virus check via a postgresql extension "snakeoil". - database-domain-checks = [ + database-domain-checks = { # Example: This message originates from postgres with an # enabled snakeoil extension. This extension allows to virus # check byte arrays. It must be setup such that the `bytea` @@ -443,11 +433,12 @@ sharry.restserver { # CREATE EXTENSION pg_snakeoil; # CREATE DOMAIN public.safe_bytea as bytea CHECK (not so_is_infected(value)); # ALTER TABLE public.filechunk ALTER COLUMN chunkdata TYPE safe_bytea; - { enabled = false + snakeoil = { + enabled = false native = "domain safe_bytea violates check constraint" message = "The uploaded file contains a virus!" } - ] + } } cleanup { @@ -476,20 +467,15 @@ sharry.restserver { smtp { # Host and port of the SMTP server host = "localhost" - host = ${?SHARRY_BACKEND_MAIL_SMTP_HOST} port = 25 - port = ${?SHARRY_BACKEND_MAIL_SMTP_PORT} # User credentials to authenticate at the server. If the user # is empty, mails are sent without authentication. user = "" - user = ${?SHARRY_BACKEND_MAIL_SMTP_USER} password = "" - password = ${?SHARRY_BACKEND_MAIL_SMTP_PASSWORD} # One of: none, starttls, ssl ssl-type = "starttls" - ssl-type = ${?SHARRY_BACKEND_MAIL_SMTP_SSL__TYPE} # In case of self-signed certificates or other problems like # that, checking certificates can be disabled. diff --git a/modules/restserver/src/main/scala/sharry/restserver/CookieData.scala b/modules/restserver/src/main/scala/sharry/restserver/CookieData.scala index 1d875e5f..681f225d 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/CookieData.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/CookieData.scala @@ -1,9 +1,9 @@ package sharry.restserver -import sharry.backend.auth._ -import sharry.common._ +import sharry.backend.auth.* +import sharry.common.* -import org.http4s._ +import org.http4s.* import org.typelevel.ci.CIString case class CookieData(auth: AuthToken) { diff --git a/modules/restserver/src/main/scala/sharry/restserver/Main.scala b/modules/restserver/src/main/scala/sharry/restserver/Main.scala index d551136c..67a594f6 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/Main.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/Main.scala @@ -3,14 +3,14 @@ package sharry.restserver import java.nio.file.Path import java.nio.file.{Files, Paths} -import cats.effect._ +import cats.effect.* -import sharry.common._ +import sharry.common.* import sharry.logging.impl.ScribeConfigure import sharry.restserver.config.ConfigFile object Main extends IOApp { - private[this] val logger = sharry.logging.getLogger[IO] + private val logger = sharry.logging.getLogger[IO] val connectEC = ThreadFactories.fixed[IO](5, ThreadFactories.ofName("sharry-dbconnect")) @@ -60,7 +60,7 @@ object Main extends IOApp { } } - cfg = ConfigFile.loadConfig + cfg <- ConfigFile.loadConfig _ <- ScribeConfigure.configure[IO](cfg.logging) diff --git a/modules/restserver/src/main/scala/sharry/restserver/RestAppImpl.scala b/modules/restserver/src/main/scala/sharry/restserver/RestAppImpl.scala index c8863e69..df16ed67 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/RestAppImpl.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/RestAppImpl.scala @@ -2,8 +2,8 @@ package sharry.restserver import scala.concurrent.ExecutionContext -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import fs2.io.file.Files import sharry.backend.BackendApp diff --git a/modules/restserver/src/main/scala/sharry/restserver/RestServer.scala b/modules/restserver/src/main/scala/sharry/restserver/RestServer.scala index a17a044f..83d909db 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/RestServer.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/RestServer.scala @@ -1,8 +1,8 @@ package sharry.restserver import cats.data.{Kleisli, OptionT} -import cats.effect._ -import cats.syntax.all._ +import cats.effect.* +import cats.syntax.all.* import fs2.io.file.Files import fs2.io.net.Network import fs2.{Pure, Stream} @@ -12,24 +12,24 @@ import sharry.common.LenientUri import sharry.logging.Logger import sharry.restserver.config.Config import sharry.restserver.http4s.EnvMiddleware -import sharry.restserver.routes._ -import sharry.restserver.webapp._ +import sharry.restserver.routes.* +import sharry.restserver.webapp.* -import org.http4s._ +import org.http4s.* import org.http4s.client.Client import org.http4s.dsl.Http4sDsl import org.http4s.ember.client.EmberClientBuilder import org.http4s.ember.server.EmberServerBuilder import org.http4s.headers.{Location, `Content-Length`, `Content-Type`} import org.http4s.server.Router -import org.http4s.server.middleware.{Logger => Http4sLogger} +import org.http4s.server.middleware.Logger as Http4sLogger object RestServer { def stream[F[_]: Async: Files: Network]( cfg: Config, pools: Pools ): Stream[F, Nothing] = { - implicit val logger = sharry.logging.getLogger[F] + implicit val logger: Logger[F] = sharry.logging.getLogger[F] val server = httpApp(cfg, pools).flatMap(httpServer(cfg, _)) Stream diff --git a/modules/restserver/src/main/scala/sharry/restserver/config/Config.scala b/modules/restserver/src/main/scala/sharry/restserver/config/Config.scala index 8a481627..8f2d5492 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/config/Config.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/config/Config.scala @@ -1,10 +1,10 @@ package sharry.restserver.config import cats.data.{Validated, ValidatedNec} -import cats.syntax.all._ +import cats.syntax.all.* -import sharry.backend.config.{Config => BackendConfig} -import sharry.common._ +import sharry.backend.config.Config as BackendConfig +import sharry.common.* import sharry.logging.LogConfig import com.comcast.ip4s.{Host, Port} diff --git a/modules/restserver/src/main/scala/sharry/restserver/config/ConfigDecoders.scala b/modules/restserver/src/main/scala/sharry/restserver/config/ConfigDecoders.scala new file mode 100644 index 00000000..3c9e19a0 --- /dev/null +++ b/modules/restserver/src/main/scala/sharry/restserver/config/ConfigDecoders.scala @@ -0,0 +1,154 @@ +package sharry.restserver.config + +import scala.jdk.CollectionConverters.* + +import cats.Show +import cats.syntax.all.* +import fs2.io.file.Path + +import sharry.common.* +import sharry.logging.Level +import sharry.logging.LogConfig +import sharry.store.FileStoreType + +import ciris.* +import com.comcast.ip4s.{Host, Port} +import com.typesafe.config.ConfigValue as TCValue +import emil.javamail.syntax.* +import emil.{MailAddress, SSLType} +import org.http4s.Uri +import scodec.bits.ByteVector +import yamusca.data.Template + +private[config] trait ConfigDecoders: + extension [A, B](self: ConfigDecoder[A, B]) + def emap[C](typeName: String)(f: B => Either[String, C])(using Show[B]) = + self.mapEither((key, b) => + f(b).left.map(err => ConfigError.decode(typeName, key, b)) + ) + + extension [A](self: ConfigValue[Effect, List[A]]) + def listflatMap[B](f: A => ConfigValue[Effect, B]): ConfigValue[Effect, List[B]] = + self.flatMap(ids => + ids.foldLeft(ConfigValue.loaded(ConfigKey(""), List.empty[B])) { (cv, id) => + cv.flatMap(l => f(id).map(_ :: l)) + } + ) + + given ConfigDecoder[TCValue, String] = + ConfigDecoder[TCValue].map(_.atKey("a").getString("a")) + + given ConfigDecoder[TCValue, Double] = + ConfigDecoder[TCValue].map(_.atKey("a").getDouble("a")) + + given ConfigDecoder[TCValue, Long] = + ConfigDecoder[TCValue].map(_.atKey("a").getLong("a")) + + given [A](using ConfigDecoder[TCValue, A]): ConfigDecoder[TCValue, List[A]] = + ConfigDecoder[TCValue].mapEither { (cfgKey, cv) => + val inner = cv.atKey("a").getList("a") + inner.asScala.toList.traverse(e => ConfigDecoder[TCValue, A].decode(cfgKey, e)) + } + + given [K, A](using + ConfigDecoder[String, K], + ConfigDecoder[TCValue, A] + ): ConfigDecoder[TCValue, Map[K, A]] = + ConfigDecoder[TCValue].mapEither { (cfgKey, cv) => + val inner = cv.atKey("a").getConfig("a") + inner.root.keySet.asScala.toList + .traverse { key => + val value = inner.getValue(s"\"$key\"") + ConfigDecoder[String, K] + .decode(cfgKey, key) + .flatMap(k => + ConfigDecoder[TCValue, A].decode(cfgKey, value).map(v => k -> v) + ) + } + .map(_.toMap) + } + + given [A](using ConfigDecoder[String, A]): ConfigDecoder[String, List[A]] = + ConfigDecoder[String].mapEither { (ckey, str) => + str + .split(',') + .toList + .map(_.trim) + .filter(_.nonEmpty) + .traverse( + ConfigDecoder[String, A].decode(ckey, _) + ) + } + + given [A, B](using ConfigDecoder[A, B]): ConfigDecoder[List[A], List[B]] = + ConfigDecoder.instance { (ckey, lista) => + lista.traverse(ConfigDecoder[A, B].decode(ckey, _)) + } + + given [A](using ConfigDecoder[String, A]): ConfigDecoder[TCValue, A] = + ConfigDecoder[TCValue, String].as[A] + + given ConfigDecoder[String, Duration] = + ConfigDecoder[String].emap("Duration")(Duration.fromString) + + given ConfigDecoder[String, LenientUri] = + ConfigDecoder[String].emap("LenientUri")(LenientUri.parse) + + given ConfigDecoder[String, ByteVector] = + ConfigDecoder[String].emap("ByteVector") { str => + if (str.startsWith("hex:")) + ByteVector.fromHex(str.drop(4)).toRight(s"Invalid hex value: $str") + else if (str.startsWith("b64:")) + ByteVector.fromBase64(str.drop(4)).toRight(s"Invalid Base64 string: $str") + else ByteVector.encodeUtf8(str).left.map(_.getMessage()) + } + + given ConfigDecoder[String, Ident] = + ConfigDecoder[String].emap("Ident")(Ident.fromString) + + given ConfigDecoder[String, Password] = + ConfigDecoder[String].map(Password.apply) + + given ConfigDecoder[String, Uri] = + ConfigDecoder[String].mapOption("Uri")(Uri.fromString(_).toOption) + + given ConfigDecoder[String, Host] = + ConfigDecoder[String].mapOption("Host")(Host.fromString) + + given ConfigDecoder[String, Port] = + ConfigDecoder[String].mapOption("Port")(Port.fromString) + + given ConfigDecoder[String, ByteSize] = + ConfigDecoder[String].emap("ByteSize")(ByteSize.parse) + + given ConfigDecoder[String, Level] = + ConfigDecoder[String].emap("Level")(Level.fromString) + + given ConfigDecoder[String, LogConfig.Format] = + ConfigDecoder[String].emap("LogFormat")(LogConfig.Format.fromString) + + given ConfigDecoder[String, FileStoreType] = + ConfigDecoder[String].emap("FileStoreType")(FileStoreType.fromString) + + given ConfigDecoder[String, Path] = + ConfigDecoder[String].map(Path(_)) + + given ConfigDecoder[String, SignupMode] = + ConfigDecoder[String].emap("SignupMode")(SignupMode.fromString) + + given ConfigDecoder[String, SSLType] = + ConfigDecoder[String].emap("SSLType")(SSLType.fromString) + + given ConfigDecoder[String, MailAddress] = + ConfigDecoder[String].emap("MailAddress")(MailAddress.parse) + + given ConfigDecoder[String, Option[MailAddress]] = + ConfigDecoder[String].mapEither { (key, s) => + if (s.isEmpty) Right(None) + else ConfigDecoder[String, MailAddress].decode(key, s).map(Some(_)) + } + + given ConfigDecoder[String, Template] = + ConfigDecoder[String].emap("Template")(str => + yamusca.parser.parse(str).left.map(_._2) + ) diff --git a/modules/restserver/src/main/scala/sharry/restserver/config/ConfigFile.scala b/modules/restserver/src/main/scala/sharry/restserver/config/ConfigFile.scala index 76cb15cd..7b74bdee 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/config/ConfigFile.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/config/ConfigFile.scala @@ -1,66 +1,10 @@ package sharry.restserver.config -import sharry.common.config.Implicits._ -import sharry.logging.{Level, LogConfig} -import sharry.store.{FileStoreConfig, FileStoreType} - -import emil.MailAddress -import emil.SSLType -import emil.javamail.syntax._ -import pureconfig._ -import pureconfig.generic.auto._ -import pureconfig.generic.{CoproductHint, FieldCoproductHint} -import yamusca.imports.{Template, mustache} +import cats.effect.* object ConfigFile { - import Implicits._ - - def loadConfig: Config = - ConfigSource.default.at("sharry.restserver").loadOrThrow[Config].validOrThrow - - object Implicits { - implicit val mailAddressReader: ConfigReader[Option[MailAddress]] = - ConfigReader[String].emap( - reason(s => - if (s.trim.isEmpty) Right(None) else MailAddress.parse(s).map(m => Some(m)) - ) - ) - - implicit val mailSslTypeReader: ConfigReader[SSLType] = - ConfigReader[String].emap( - reason(s => - s.toLowerCase match { - case "none" => Right(SSLType.NoEncryption) - case "starttls" => Right(SSLType.StartTLS) - case "ssl" => Right(SSLType.SSL) - case _ => Left(s"Invalid ssl type '$s'. Use one of none, ssl or starttls.") - } - ) - ) - - implicit val templateReader: ConfigReader[Template] = - ConfigReader[String].emap( - reason(s => - mustache.parse(s).left.map(err => s"Error parsing template at ${err._1.pos}") - ) - ) - - implicit val logFormatReader: ConfigReader[LogConfig.Format] = - ConfigReader[String].emap(reason(LogConfig.Format.fromString)) - - implicit val logLevelReader: ConfigReader[Level] = - ConfigReader[String].emap(reason(Level.fromString)) - - implicit val fileStoreTypeReader: ConfigReader[FileStoreType] = - ConfigReader[String].emap(reason(FileStoreType.fromString)) + def loadConfig: IO[Config] = + ConfigValues.fullConfig.load[IO] - // the value "s-3" looks strange, this is to allow to write "s3" in the config - implicit val fileStoreCoproductHint: CoproductHint[FileStoreConfig] = - new FieldCoproductHint[FileStoreConfig]("type") { - override def fieldValue(name: String) = - if (name.equalsIgnoreCase("S3")) "s3" - else super.fieldValue(name) - } - } } diff --git a/modules/restserver/src/main/scala/sharry/restserver/config/ConfigValues.scala b/modules/restserver/src/main/scala/sharry/restserver/config/ConfigValues.scala new file mode 100644 index 00000000..2e08f1c0 --- /dev/null +++ b/modules/restserver/src/main/scala/sharry/restserver/config/ConfigValues.scala @@ -0,0 +1,421 @@ +package sharry.restserver.config + +import scala.jdk.CollectionConverters.* + +import cats.syntax.all.* +import fs2.io.file.Path + +import sharry.backend.auth.AuthConfig +import sharry.backend.config.{Config as BackendConfig, CopyFilesConfig, FilesConfig} +import sharry.backend.job.CleanupConfig +import sharry.backend.mail.MailConfig +import sharry.backend.share.ShareConfig +import sharry.backend.signup.SignupConfig +import sharry.common.* +import sharry.logging.Level +import sharry.logging.LogConfig +import sharry.store.ComputeChecksumConfig +import sharry.store.DomainCheckConfig +import sharry.store.FileStoreConfig +import sharry.store.FileStoreType +import sharry.store.JdbcConfig + +import ciris.* +import com.comcast.ip4s.{Host, Port} +import emil.MailAddress +import emil.SSLType +import scodec.bits.ByteVector +import yamusca.data.Template + +object ConfigValues extends ConfigDecoders: + private val hocon = Hocon.at("sharry.restserver") + private def senv(envName: String) = env(s"SHARRY_${envName}") + private def key(hoconPath: String, envName: String) = + senv(envName).or(hocon(hoconPath).as[String]) + + private def keyMap[A, B](hoconPath: String, envName: String)(using + ConfigDecoder[String, A], + ConfigDecoder[String, B] + ) = { + val envMap = senv(s"${envName}_NAMES") + .as[List[String]] + .listflatMap { k => + val value = senv(s"${envName}_$k").as[B] + val ckey = ConfigKey(s"${envName} key: $k") + val kk = ConfigDecoder[String, A] + .decode(Some(ckey), k) + .fold(ConfigValue.failed, ConfigValue.loaded(ckey, _)) + + value.flatMap(v => kk.map(_ -> v)) + } + .map(_.toMap) + + envMap.or(hocon(hoconPath).as[Map[A, B]]) + } + + private def keyList[A](hoconPath: String, envName: String)(using + ConfigDecoder[String, A] + ) = + senv(envName).as[List[A]].or(hocon(hoconPath).as[List[A]]) + + private def mapKeys[A](hoconPath: String, envName: String)(using + ConfigDecoder[String, A] + ) = { + val hoconKeys = + hocon(hoconPath) + .map(_.atKey("a").getConfig("a").root.keySet.asScala.toList) + .as[List[A]] + val envKeys = senv(envName).as[List[A]] + envKeys.or(hoconKeys) + } + + val baseUrl = key("base-url", "BASE_URL").as[LenientUri] + + val bind = { + val address = key("bind.address", "BIND_ADDRESS").as[Host] + val port = key("bind.port", "BIND_PORT").as[Port] + (address, port).mapN(Config.Bind.apply) + } + + val fileDownload = { + val chunkSize = + key("file-download.download-chunk-size", "FILE_DOWNLOAD_CHUNK_SIZE").as[ByteSize] + chunkSize.map(Config.FileDownload.apply) + } + + val logConfig = { + val minLevel = key("logging.minimum-level", "LOGGING_MINIMUM_LEVEL").as[Level] + val fmt = key("logging.format", "LOGGING_FORMAT").as[LogConfig.Format] + val extraLevel = keyMap[String, Level]("logging.levels", "LOGGING_LEVELS") + (minLevel, fmt, extraLevel).mapN(LogConfig.apply) + } + + val aliasMemberEnabled = key("alias-member-enabled", "ALIAS_MEMBER_ENABLED").as[Boolean] + + val webapp = { + val name = key("webapp.app-name", "WEBAPP_NAME") + val icon = key("webapp.app-icon", "WEBAPP_ICON") + val iconDark = key("webapp.app-icon-dark", "WEBAPP_ICON_DARK") + val logo = key("webapp.app-logo", "WEBAPP_LOGO") + val logoDark = key("webapp.app-logo-dark", "WEBAPP_LOGO_DARK") + val footer = key("webapp.app-footer", "WEBAPP_FOOTER") + val footerVisible = + key("webapp.app-footer-visible", "WEBAPP_FOOTER_VISIBLE").as[Boolean] + val chunkSize = key("webapp.chunk-size", "WEBAPP_CHUNK_SIZE").as[ByteSize] + val retryDelays = keyList[Duration]("webapp.retry-delays", "WEBAPP_RETRY_DELAYS") + val welcomeMsg = key("webapp.welcome-message", "WEBAPP_WELCOME_MESSAGE") + val defaultLang = key("webapp.default-language", "WEBAPP_DEFAULT_LANGUAGE") + val authRenewal = key("webapp.auth-renewal", "WEBAPP_AUTH_RENEWAL").as[Duration] + val initialPage = key("webapp.initial-page", "WEBAPP_INITIAL_PAGE") + val defaultValidity = + key("webapp.default-validity", "WEBAPP_DEFAULT_VALIDITY").as[Duration] + val initialTheme = key("webapp.initial-theme", "WEBAPP_INITIAL_THEME") + val oauthRedirect = + key("webapp.oauth-auto-redirect", "WEBAPP_OAUTH_AUTO_REDIRECT").as[Boolean] + val customHead = key("webapp.custom-head", "WEBAPP_CUSTOM_HEAD") + ( + name, + icon, + iconDark, + logo, + logoDark, + footer, + footerVisible, + chunkSize, + retryDelays, + welcomeMsg, + defaultLang, + authRenewal, + initialPage, + defaultValidity, + initialTheme, + oauthRedirect, + customHead + ).mapN(Config.Webapp.apply) + } + + val authFixed: ConfigValue[Effect, AuthConfig.Fixed] = { + def k(p: String, e: String) = + key(s"backend.auth.fixed.$p", s"BACKEND_AUTH_FIXED_$e") + + val enabled = k("enabled", "ENABLED").as[Boolean] + val user = k("user", "USER").as[Ident] + val pass = k("password", "PASSWORD").as[Password].redacted + val order = k("order", "ORDER").as[Int] + (enabled, user, pass, order).mapN(AuthConfig.Fixed.apply) + } + + val authHttp = { + def k(p: String, e: String) = + key(s"backend.auth.http.$p", s"BACKEND_AUTH_HTTP_$e") + + val enabled = k("enabled", "ENABLED").as[Boolean] + val url = k("url", "URL").as[LenientUri] + val method = k("method", "METHOD") + val body = k("body", "BODY") + val contentType = k("content-type", "CONTENT_TYPE") + val order = k("order", "ORDER").as[Int] + (enabled, url, method, body, contentType, order).mapN(AuthConfig.Http.apply) + } + + val authHttpBasic = { + def k(p: String, e: String) = + key(s"backend.auth.http-basic.$p", s"BACKEND_AUTH_HTTP_BASIC_$e") + + val enabled = k("enabled", "ENABLED").as[Boolean] + val url = k("url", "URL").as[LenientUri] + val method = k("method", "METHOD") + val order = k("order", "ORDER").as[Int] + (enabled, url, method, order).mapN(AuthConfig.HttpBasic.apply) + } + + val authCommand = { + def k(p: String, e: String) = + key(s"backend.auth.command.$p", s"BACKEND_AUTH_COMMAND_$e") + + val enabled = k("enabled", "ENABLED").as[Boolean] + val program = + keyList[String]("backend.auth.command.program", "BACKEND_AUTH_COMMAND_PROGRAM") + val success = k("success", "SUCCESS").as[Int] + val order = k("order", "ORDER").as[Int] + (enabled, program, success, order).mapN(AuthConfig.Command.apply) + } + + val authInternal = { + def k(p: String, e: String) = + key(s"backend.auth.internal.$p", s"BACKEND_AUTH_INTERNAL_$e") + + val enabled = k("enabled", "ENABLED").as[Boolean] + val order = k("order", "ORDER").as[Int] + (enabled, order).mapN(AuthConfig.Internal.apply) + } + + val authProxy = { + def k(p: String, e: String) = + key(s"backend.auth.proxy.$p", s"BACKEND_AUTH_INTERNAL_$e") + + val enabled = k("enabled", "ENABLED").as[Boolean] + val userHeader = k("user-header", "USER_HEADER") + val emailHeader = k("email-header", "EMAIL_HEADER").option + (enabled, userHeader, emailHeader).mapN(AuthConfig.Proxy.apply) + } + + def authOAuth(id: Ident) = { + def k(p: String, e: String) = + key( + s"backend.auth.oauth.${id.id}.$p", + s"BACKEND_AUTH_OAUTH_${id.id.toUpperCase()}_$e" + ) + val idkey = ConfigKey(s"oauth id key: ${id.id}") + val enabled = k("enabled", "ENABLED").as[Boolean] + val name = k("name", "NAME") + val icon = k("icon", "ICON").option + val scope = k("scope", "SCOPE") + val authorizeUrl = k("authorize-url", "AUTHORIZE_URL").as[LenientUri] + val tokenUrl = k("token-url", "TOKEN_URL").as[LenientUri] + val userUrl = k("user-url", "USER_URL").as[LenientUri] + val userIdkey = k("user-id-key", "USER_ID_KEY") + val userEmailKey = k("user-email-key", "USER_EMAIL_KEY").option + val clientId = k("client-id", "CLIENT_ID") + val clientSecret = k("client-secret", "CLIENT_SECRET") + ( + ConfigValue.loaded(idkey, id), + enabled, + name, + authorizeUrl, + tokenUrl, + userUrl, + userIdkey, + userEmailKey, + scope, + clientId, + clientSecret, + icon + ).mapN(AuthConfig.OAuth.apply) + } + + val authOAuthSeq = + mapKeys[Ident]("backend.auth.oauth", "BACKEND_AUTH_OAUTH_IDS").listflatMap(authOAuth) + + val auth = { + def k(p: String, e: String) = + key(s"backend.auth.$p", s"BACKEND_AUTH_$e") + val serverSecret = k("server-secret", "SERVER_SECRET").as[ByteVector] + val sessionValid = k("session-valid", "SESSION_VALID").as[Duration] + ( + serverSecret, + sessionValid, + authFixed, + authHttp, + authHttpBasic, + authCommand, + authProxy, + authInternal, + authOAuthSeq + ).mapN(AuthConfig.apply) + } + + val jdbc = { + val url = key("backend.jdbc.url", "BACKEND_JDBC_URL").as[LenientUri] + val user = key("backend.jdbc.user", "BACKEND_JDBC_USER") + val pass = key("backend.jdbc.password", "BACKEND_JDBC_PASSWORD").redacted + (url, user, pass).mapN(JdbcConfig.apply) + } + + def fileStoreConfig(id: String) = { + def k(p: String, e: String) = + key(s"backend.files.stores.$id.$p", s"BACKEND_FILES_STORES_${id.toUpperCase}_$e") + + val enabled = k("enabled", "ENABLED").as[Boolean] + k("type", "TYPE").as[FileStoreType].flatMap { + case FileStoreType.DefaultDatabase => + enabled.map(FileStoreConfig.DefaultDatabase.apply) + + case FileStoreType.FileSystem => + val dir = k("directory", "DIRECTORY").as[Path] + val cleanDirs = k("clean-empty-dirs", "CLEAN_EMPTY_DIRS").as[Boolean] + (enabled, dir, cleanDirs).mapN(FileStoreConfig.FileSystem.apply) + + case FileStoreType.S3 => + val endpoint = k("endpoint", "ENDPOINT") + val accessKey = k("access-key", "ACCESS_KEY") + val secretKey = k("secret-key", "SECRET_KEY") + val bucket = k("bucket", "BUCKET") + (enabled, endpoint, accessKey, secretKey, bucket).mapN(FileStoreConfig.S3.apply) + } + } + + val copyFiles = { + def k(p: String, e: String) = + key(s"backend.files.copy-files.$p", s"BACKEND_FILES_COPY_FILES_$e") + + val enabled = k("enable", "ENABLE").as[Boolean] + val source = k("source", "SOURCE").as[Ident] + val target = k("target", "TARGET").as[Ident] + val parallel = k("parallel", "PARALLEL").as[Int] + (enabled, source, target, parallel).mapN(CopyFilesConfig.apply) + } + + val files = { + val defaultStore = + key("backend.files.default-store", "BACKEND_FILES_DEFAULT_STORE").as[Ident] + val stores = mapKeys[Ident]("backend.files.stores", "BACKEND_FILES_STORES_IDS") + .listflatMap(id => fileStoreConfig(id.id).map(id -> _)) + .map(_.toMap) + (defaultStore, stores, copyFiles).mapN(FilesConfig.apply) + } + + val computeChecksum = { + def k(p: String, e: String) = + key(s"backend.compute-checksum.$p", s"BACKEND_COMPUTE_CHECKSUM_$e") + + val enable = k("enable", "ENABLE").as[Boolean] + val capacity = k("capacity", "CAPACITY").as[Int] + val parallel = k("parallel", "PARALLEL").as[Int] + val useDefault = k("use-default", "USE_DEFAULT").as[Boolean] + (enable, capacity, parallel, useDefault).mapN(ComputeChecksumConfig.apply) + } + + val signup = { + def k(p: String, e: String) = + key(s"backend.signup.$p", s"BACKEND_SIGNUP_$e") + + val mode = k("mode", "MODE").as[SignupMode] + val inviteTime = k("invite-time", "INVITE_TIME").as[Duration] + val invitePass = k("invite-password", "INVITE_PASSWORD").as[Password] + (mode, inviteTime, invitePass).mapN(SignupConfig.apply) + } + + def domainCheck(id: String) = { + def k(p: String, e: String) = + key( + s"backend.share.database-domain-checks.$id.$p", + s"BACKEND_SHARE_DATABASE_DOMAIN_CHECKS_${id.toUpperCase}.$e" + ) + + val enabled = k("enabled", "ENABLED").as[Boolean] + val nativeM = k("native", "NATIVE") + val message = k("message", "MESSAGE") + (enabled, nativeM, message).mapN(DomainCheckConfig.apply) + } + + val share = { + def k(p: String, e: String) = + key(s"backend.share.$p", s"BACKEND_SHARE_$e") + + val chunkSize = k("chunk-size", "CHUNK_SIZE").as[ByteSize] + val maxSize = k("max-size", "MAX_SIZE").as[ByteSize] + val maxValid = k("max-validity", "MAX_VALIDITY").as[Duration] + val domainChecks = mapKeys[String]( + "backend.share.database-domain-checks", + "BACKEND_SHARE_DATABASE_DOMAIN_CHECKS_IDS" + ) + .listflatMap(domainCheck) + (chunkSize, maxSize, maxValid, domainChecks).mapN(ShareConfig.apply) + } + + val cleanup = { + def k(p: String, e: String) = + key(s"backend.cleanup.$p", s"BACKEND_CLEANUP_$e") + + val enabled = k("enabled", "ENABLED").as[Boolean] + val interval = k("interval", "INTERVAL").as[Duration] + val invalidAge = k("invalid-age", "INVALID_AGE").as[Duration] + (enabled, interval, invalidAge).mapN(CleanupConfig.apply) + } + + val mailSmtp = { + def k(p: String, e: String) = + key(s"backend.mail.smtp.$p", s"BACKEND_MAIL_SMTP_$e") + + val host = k("host", "HOST") + val port = k("port", "PORT").as[Int] + val user = k("user", "USER") + val pass = k("password", "PASSWORD").as[Password].redacted + val sslType = k("ssl-type", "SSL_TYPE").as[SSLType] + val checkCerts = + k("check-certificates", "CHECK_CERTIFICATES").as[Boolean].default(true) + val timeout = k("timeout", "TIMEOUT").as[Duration] + val defaultFrom = k("default-from", "DEFAULT_FROM").as[Option[MailAddress]] + val listId = k("list-id", "LIST_ID") + (host, port, user, pass, sslType, checkCerts, timeout, defaultFrom, listId).mapN( + MailConfig.Smtp.apply + ) + } + + def mailTemplate(id: String) = { + def k(p: String, e: String) = + key( + s"backend.mail.templates.$id.$p", + s"BACKEND_MAIL_TEMPLATES_${id.toUpperCase}_$e" + ) + + val subject = k("subject", "SUBJECT").as[Template] + val body = k("body", "BODY").as[Template] + (subject, body).mapN(MailConfig.MailTpl.apply) + } + + val mail = { + def k(p: String, e: String) = + key(s"backend.mail.$p", s"BACKEND_MAIL_$e") + + val enabled = k("enabled", "ENABLED").as[Boolean] + val downloadTpl = mailTemplate("download") + val aliasTpl = mailTemplate("alias") + val uploadTpl = mailTemplate("upload-notify") + val templates = (downloadTpl, aliasTpl, uploadTpl).mapN(MailConfig.Templates.apply) + (enabled, mailSmtp, templates).mapN(MailConfig.apply) + } + + val backendConfig = + (jdbc, signup, auth, share, cleanup, mail, files, computeChecksum).mapN( + BackendConfig.apply + ) + + val fullConfig = + (baseUrl, aliasMemberEnabled, bind, fileDownload, logConfig, webapp, backendConfig) + .mapN( + Config.apply + ) + +end ConfigValues diff --git a/modules/restserver/src/main/scala/sharry/restserver/config/Hocon.scala b/modules/restserver/src/main/scala/sharry/restserver/config/Hocon.scala new file mode 100644 index 00000000..b65b3f88 --- /dev/null +++ b/modules/restserver/src/main/scala/sharry/restserver/config/Hocon.scala @@ -0,0 +1,24 @@ +package sharry.restserver.config + +import ciris.* +import com.typesafe.config.ConfigException +import com.typesafe.config.ConfigFactory +import com.typesafe.config.{Config, ConfigValue as TCValue} + +private[config] object Hocon: + final class HoconAt(config: Config, path: String): + def apply(name: String): ConfigValue[Effect, TCValue] = + val key = s"$path.$name" + val ckey = ConfigKey(key) + try + val value = config.getValue(key) + ConfigValue.loaded(ckey, value) + catch + case _: ConfigException.Missing => ConfigValue.missing(ckey) + case ex => ConfigValue.failed(ConfigError(ex.getMessage)) + + def at(config: Config)(path: String): HoconAt = + HoconAt(config.resolve(), path) + + def at(path: String): HoconAt = + at(ConfigFactory.load())(path) diff --git a/modules/restserver/src/main/scala/sharry/restserver/http4s/ClientRequestInfo.scala b/modules/restserver/src/main/scala/sharry/restserver/http4s/ClientRequestInfo.scala index e04310a2..b225f6bd 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/http4s/ClientRequestInfo.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/http4s/ClientRequestInfo.scala @@ -1,14 +1,14 @@ package sharry.restserver.http4s import cats.data.NonEmptyList -import cats.implicits._ +import cats.implicits.* -import sharry.common._ +import sharry.common.* import sharry.restserver.config.Config import com.comcast.ip4s.Port -import org.http4s._ -import org.http4s.headers._ +import org.http4s.* +import org.http4s.headers.* import org.typelevel.ci.CIString /** Obtain information about the client by inspecting the request. */ diff --git a/modules/restserver/src/main/scala/sharry/restserver/http4s/EnvMiddleware.scala b/modules/restserver/src/main/scala/sharry/restserver/http4s/EnvMiddleware.scala index 7cf8c48d..d2b23bfc 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/http4s/EnvMiddleware.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/http4s/EnvMiddleware.scala @@ -2,9 +2,9 @@ package sharry.restserver.http4s import cats.Functor -import sharry.common._ +import sharry.common.* -import org.http4s._ +import org.http4s.* object EnvMiddleware { diff --git a/modules/restserver/src/main/scala/sharry/restserver/http4s/NoCacheMiddleware.scala b/modules/restserver/src/main/scala/sharry/restserver/http4s/NoCacheMiddleware.scala index a3e827d5..f91a0264 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/http4s/NoCacheMiddleware.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/http4s/NoCacheMiddleware.scala @@ -4,10 +4,10 @@ import cats.Functor import cats.data.Kleisli import cats.data.NonEmptyList -import sharry.common._ +import sharry.common.* -import org.http4s._ -import org.http4s.headers._ +import org.http4s.* +import org.http4s.headers.* object NoCacheMiddleware { private val noCacheHeader = diff --git a/modules/restserver/src/main/scala/sharry/restserver/oauth/CodeFlow.scala b/modules/restserver/src/main/scala/sharry/restserver/oauth/CodeFlow.scala index 60ed3c55..e7cd368a 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/oauth/CodeFlow.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/oauth/CodeFlow.scala @@ -1,17 +1,17 @@ package sharry.restserver.oauth import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.auth.AuthConfig import sharry.common.Ident import sharry.logging.Logger import io.circe.Json -import org.http4s.Method._ -import org.http4s._ -import org.http4s.circe.CirceEntityCodec._ +import org.http4s.* +import org.http4s.Method.* +import org.http4s.circe.CirceEntityCodec.* import org.http4s.client.Client import org.http4s.client.dsl.Http4sClientDsl import org.http4s.client.middleware.RequestLogger @@ -131,13 +131,13 @@ object CodeFlow { logHeaders = true, logBody = true, logAction = Some((msg: String) => logger.trace(msg)) - ) _ + ) val lres = ResponseLogger( logHeaders = true, logBody = true, logAction = Some((msg: String) => logger.trace(msg)) - ) _ + ) lreq.andThen(lres)(c) } diff --git a/modules/restserver/src/main/scala/sharry/restserver/oauth/StateParam.scala b/modules/restserver/src/main/scala/sharry/restserver/oauth/StateParam.scala index dad4531c..ff568fc4 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/oauth/StateParam.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/oauth/StateParam.scala @@ -1,7 +1,7 @@ package sharry.restserver.oauth -import cats.effect._ -import cats.syntax.all._ +import cats.effect.* +import cats.syntax.all.* import sharry.common.util.{Random, SignUtil} diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/AccountRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/AccountRoutes.scala index 02c77147..f8922712 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/AccountRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/AccountRoutes.scala @@ -1,18 +1,18 @@ package sharry.restserver.routes import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.BackendApp import sharry.backend.account.{AccountItem, NewAccount} -import sharry.common._ -import sharry.restapi.model._ +import sharry.common.* +import sharry.restapi.model.* import sharry.store.records.ModAccount import org.http4s.HttpRoutes -import org.http4s.circe.CirceEntityDecoder._ -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.circe.CirceEntityDecoder.* +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl object AccountRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/AliasMemberRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/AliasMemberRoutes.scala index 8c4e0cb0..10c8a778 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/AliasMemberRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/AliasMemberRoutes.scala @@ -1,15 +1,15 @@ package sharry.restserver.routes -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.BackendApp import sharry.backend.account.AccountItem import sharry.backend.auth.AuthToken -import sharry.restapi.model._ +import sharry.restapi.model.* import org.http4s.HttpRoutes -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl object AliasMemberRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/AliasRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/AliasRoutes.scala index 178f0551..db2b1735 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/AliasRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/AliasRoutes.scala @@ -1,19 +1,19 @@ package sharry.restserver.routes import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.BackendApp import sharry.backend.alias.OAlias import sharry.backend.auth.AuthToken -import sharry.common._ -import sharry.restapi.model._ +import sharry.common.* +import sharry.restapi.model.* import sharry.store.records.RAlias import org.http4s.HttpRoutes -import org.http4s.circe.CirceEntityDecoder._ -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.circe.CirceEntityDecoder.* +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl object AliasRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/Authenticate.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/Authenticate.scala index 3f8fbca6..2376cae5 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/Authenticate.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/Authenticate.scala @@ -1,16 +1,16 @@ package sharry.restserver.routes -import cats.data._ -import cats.effect._ -import cats.implicits._ +import cats.data.* +import cats.effect.* +import cats.implicits.* -import sharry.backend.auth._ -import sharry.restserver._ +import sharry.backend.auth.* +import sharry.restserver.* -import org.http4s._ -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.* +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl -import org.http4s.server._ +import org.http4s.server.* import org.typelevel.ci.CIString object Authenticate { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/ByteResponse.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/ByteResponse.scala index cd68a3cf..3f3d74f8 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/ByteResponse.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/ByteResponse.scala @@ -2,18 +2,18 @@ package sharry.restserver.routes import cats.data.OptionT import cats.effect.Sync -import cats.implicits._ +import cats.implicits.* import fs2.Stream import sharry.backend.BackendApp -import sharry.backend.share._ -import sharry.common._ +import sharry.backend.share.* +import sharry.common.* import sharry.store.records.RFileMeta import binny.ByteRange -import org.http4s._ +import org.http4s.* import org.http4s.dsl.Http4sDsl -import org.http4s.headers._ +import org.http4s.headers.* import org.typelevel.ci.CIString object ByteResponse { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/Conv.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/Conv.scala index c0e2d5a6..8a84d98b 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/Conv.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/Conv.scala @@ -1,7 +1,7 @@ package sharry.restserver.routes import cats.data.NonEmptyList -import cats.implicits._ +import cats.implicits.* import cats.{ApplicativeError, MonadError} import sharry.backend.share.UploadResult diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/InfoRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/InfoRoutes.scala index fcc717f9..ca9062a0 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/InfoRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/InfoRoutes.scala @@ -1,13 +1,13 @@ package sharry.restserver.routes -import cats.effect._ +import cats.effect.* -import sharry.restapi.model._ +import sharry.restapi.model.* import sharry.restserver.BuildInfo import sharry.restserver.config.Config import org.http4s.HttpRoutes -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl object InfoRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/LoginRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/LoginRoutes.scala index b99857a3..b6f92fba 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/LoginRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/LoginRoutes.scala @@ -1,22 +1,22 @@ package sharry.restserver.routes import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.BackendApp import sharry.backend.account.NewAccount -import sharry.backend.auth._ -import sharry.common._ -import sharry.restapi.model._ -import sharry.restserver._ +import sharry.backend.auth.* +import sharry.common.* +import sharry.restapi.model.* +import sharry.restserver.* import sharry.restserver.config.Config import sharry.restserver.http4s.ClientRequestInfo import sharry.restserver.oauth.{CodeFlow, StateParam} -import org.http4s._ -import org.http4s.circe.CirceEntityDecoder._ -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.* +import org.http4s.circe.CirceEntityDecoder.* +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.client.Client import org.http4s.dsl.Http4sDsl import org.http4s.headers.Location diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/MailRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/MailRoutes.scala index 3c52736c..3dea0923 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/MailRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/MailRoutes.scala @@ -2,13 +2,13 @@ package sharry.restserver.routes import cats.data.EitherT import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.BackendApp import sharry.backend.auth.AuthToken import sharry.backend.mail.{MailData, MailSendResult} -import sharry.common._ +import sharry.common.* import sharry.restapi.model.BasicResult import sharry.restapi.model.MailTemplate import sharry.restapi.model.SimpleMail @@ -16,11 +16,11 @@ import sharry.restserver.config.Config import sharry.restserver.http4s.ClientRequestInfo import emil.MailAddress -import emil.javamail.syntax._ +import emil.javamail.syntax.* import org.http4s.HttpRoutes import org.http4s.Request -import org.http4s.circe.CirceEntityDecoder._ -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.circe.CirceEntityDecoder.* +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl object MailRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/NotifyRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/NotifyRoutes.scala index 7b3e17e5..e7ff55c1 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/NotifyRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/NotifyRoutes.scala @@ -1,18 +1,18 @@ package sharry.restserver.routes -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.BackendApp import sharry.backend.auth.AuthToken import sharry.backend.mail.NotifyResult -import sharry.common._ +import sharry.common.* import sharry.restapi.model.BasicResult import sharry.restserver.config.Config import sharry.restserver.http4s.ClientRequestInfo import org.http4s.HttpRoutes -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl object NotifyRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/OpenShareRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/OpenShareRoutes.scala index d2e89442..44cd6b32 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/OpenShareRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/OpenShareRoutes.scala @@ -1,14 +1,14 @@ package sharry.restserver.routes -import cats.effect._ +import cats.effect.* import sharry.backend.BackendApp -import sharry.backend.share._ -import sharry.common._ +import sharry.backend.share.* +import sharry.common.* import sharry.restserver.config.Config import sharry.restserver.routes.headers.SharryPassword -import org.http4s._ +import org.http4s.* import org.http4s.dsl.Http4sDsl object OpenShareRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/RegisterRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/RegisterRoutes.scala index 395151fd..3cf08d9f 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/RegisterRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/RegisterRoutes.scala @@ -1,17 +1,17 @@ package sharry.restserver.routes -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.BackendApp import sharry.backend.signup.OSignup.RegisterData import sharry.backend.signup.{NewInviteResult, SignupResult} -import sharry.restapi.model._ +import sharry.restapi.model.* import sharry.restserver.config.Config import org.http4s.HttpRoutes -import org.http4s.circe.CirceEntityDecoder._ -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.circe.CirceEntityDecoder.* +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl object RegisterRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/SettingRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/SettingRoutes.scala index 40f10d1e..bebb11bb 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/SettingRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/SettingRoutes.scala @@ -1,16 +1,16 @@ package sharry.restserver.routes -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.BackendApp import sharry.backend.auth.AuthToken import sharry.common.AccountSource -import sharry.restapi.model._ +import sharry.restapi.model.* import org.http4s.HttpRoutes -import org.http4s.circe.CirceEntityDecoder._ -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.circe.CirceEntityDecoder.* +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl object SettingRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/ShareDetailResponse.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/ShareDetailResponse.scala index 823e7381..eb213377 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/ShareDetailResponse.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/ShareDetailResponse.scala @@ -1,20 +1,20 @@ package sharry.restserver.routes import cats.data.OptionT -import cats.effect._ -import cats.syntax.all._ +import cats.effect.* +import cats.syntax.all.* import sharry.backend.BackendApp -import sharry.backend.share._ -import sharry.common._ -import sharry.restapi.model.{ShareDetail => ShareDetailDto, _} +import sharry.backend.share.* +import sharry.common.* +import sharry.restapi.model.{ShareDetail as ShareDetailDto, *} import sharry.restserver.config.Config import sharry.restserver.http4s.ClientRequestInfo -import org.http4s._ -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.* +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl -import org.http4s.headers._ +import org.http4s.headers.* object ShareDetailResponse { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/ShareRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/ShareRoutes.scala index 77769344..8ad1dda1 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/ShareRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/ShareRoutes.scala @@ -1,21 +1,21 @@ package sharry.restserver.routes import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.BackendApp import sharry.backend.auth.AuthToken -import sharry.backend.share._ -import sharry.common._ -import sharry.restapi.model._ +import sharry.backend.share.* +import sharry.common.* +import sharry.restapi.model.* import sharry.restserver.config.Config import sharry.restserver.routes.headers.SharryPassword import sharry.store.AddResult -import org.http4s._ -import org.http4s.circe.CirceEntityDecoder._ -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.* +import org.http4s.circe.CirceEntityDecoder.* +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl object ShareRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/ShareUploadRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/ShareUploadRoutes.scala index 4a9255ac..01c46397 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/ShareUploadRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/ShareUploadRoutes.scala @@ -1,16 +1,16 @@ package sharry.restserver.routes import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import fs2.Stream import sharry.backend.BackendApp import sharry.backend.auth.AuthToken import sharry.backend.share.{File, ShareData} -import sharry.common._ -import sharry.common.syntax.all._ -import sharry.restapi.model._ +import sharry.common.* +import sharry.common.syntax.all.* +import sharry.restapi.model.* import sharry.restserver.config.Config import sharry.restserver.http4s.ClientRequestInfo import sharry.restserver.routes.tus.TusRoutes @@ -18,8 +18,8 @@ import sharry.restserver.routes.tus.TusRoutes import org.http4s.HttpRoutes import org.http4s.Request import org.http4s.Uri -import org.http4s.circe.CirceEntityDecoder._ -import org.http4s.circe.CirceEntityEncoder._ +import org.http4s.circe.CirceEntityDecoder.* +import org.http4s.circe.CirceEntityEncoder.* import org.http4s.dsl.Http4sDsl import org.http4s.headers.{`Content-Length`, `Content-Type`} import org.http4s.multipart.Multipart diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/tus/SharryFileLength.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/tus/SharryFileLength.scala index e27408df..08f4ddd4 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/tus/SharryFileLength.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/tus/SharryFileLength.scala @@ -2,7 +2,7 @@ package sharry.restserver.routes.tus import sharry.common.ByteSize -import org.http4s._ +import org.http4s.* import org.typelevel.ci.CIString object SharryFileLength { diff --git a/modules/restserver/src/main/scala/sharry/restserver/routes/tus/TusRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/routes/tus/TusRoutes.scala index f98d16d8..17700ad2 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/routes/tus/TusRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/routes/tus/TusRoutes.scala @@ -1,18 +1,18 @@ package sharry.restserver.routes.tus import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import sharry.backend.BackendApp import sharry.backend.auth.AuthToken import sharry.backend.share.{FileInfo, UploadResult} -import sharry.common._ +import sharry.common.* import sharry.restserver.config.Config -import org.http4s._ +import org.http4s.* import org.http4s.dsl.Http4sDsl -import org.http4s.headers._ +import org.http4s.headers.* import org.typelevel.ci.CIString object TusRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/webapp/TemplateRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/webapp/TemplateRoutes.scala index 39a78839..bda42a82 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/webapp/TemplateRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/webapp/TemplateRoutes.scala @@ -3,9 +3,9 @@ package sharry.restserver.webapp import java.net.URL import java.util.concurrent.atomic.AtomicReference -import cats.effect._ -import cats.implicits._ -import fs2._ +import cats.effect.* +import cats.implicits.* +import fs2.* import fs2.io.file.{Files, Path} import sharry.logging.Logger @@ -13,16 +13,16 @@ import sharry.restapi.model.AppConfig import sharry.restserver.BuildInfo import sharry.restserver.config.Config import sharry.restserver.routes.InfoRoutes -import sharry.restserver.webapp.YamuscaConverter._ +import sharry.restserver.webapp.YamuscaConverter.* -import _root_.io.circe.syntax._ +import _root_.io.circe.syntax.* +import org.http4s.* import org.http4s.HttpRoutes -import org.http4s._ import org.http4s.dsl.Http4sDsl -import org.http4s.headers._ -import yamusca.derive._ -import yamusca.implicits._ -import yamusca.imports._ +import org.http4s.headers.* +import yamusca.derive.* +import yamusca.implicits.* +import yamusca.imports.* object TemplateRoutes { @@ -36,7 +36,7 @@ object TemplateRoutes { } def apply[F[_]: Async: Files](cfg: Config): InnerRoutes[F] = { - implicit val logger = sharry.logging.getLogger[F] + implicit val logger: Logger[F] = sharry.logging.getLogger[F] val indexTemplate = memo( loadResource("/index.html").flatMap(loadTemplate(_)) ) diff --git a/modules/restserver/src/main/scala/sharry/restserver/webapp/WebjarRoutes.scala b/modules/restserver/src/main/scala/sharry/restserver/webapp/WebjarRoutes.scala index 3d710b7b..e561f995 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/webapp/WebjarRoutes.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/webapp/WebjarRoutes.scala @@ -1,9 +1,9 @@ package sharry.restserver.webapp -import cats.effect._ +import cats.effect.* import org.http4s.HttpRoutes -import org.http4s.server.staticcontent._ +import org.http4s.server.staticcontent.* object WebjarRoutes { diff --git a/modules/restserver/src/main/scala/sharry/restserver/webapp/YamuscaConverter.scala b/modules/restserver/src/main/scala/sharry/restserver/webapp/YamuscaConverter.scala index 1c17773d..9e6fea34 100644 --- a/modules/restserver/src/main/scala/sharry/restserver/webapp/YamuscaConverter.scala +++ b/modules/restserver/src/main/scala/sharry/restserver/webapp/YamuscaConverter.scala @@ -4,9 +4,9 @@ import sharry.backend.mustache.YamuscaCommon import sharry.restapi.model.AppConfig import sharry.restapi.model.OAuthItem -import yamusca.derive._ -import yamusca.implicits._ -import yamusca.imports._ +import yamusca.derive.* +import yamusca.implicits.* +import yamusca.imports.* object YamuscaConverter extends YamuscaCommon { diff --git a/modules/restserver/src/test/scala/sharry/restserver/oauth/StateParamTest.scala b/modules/restserver/src/test/scala/sharry/restserver/oauth/StateParamTest.scala index d5c864fe..ade8aa3f 100644 --- a/modules/restserver/src/test/scala/sharry/restserver/oauth/StateParamTest.scala +++ b/modules/restserver/src/test/scala/sharry/restserver/oauth/StateParamTest.scala @@ -1,8 +1,8 @@ package sharry.restserver.oauth -import cats.effect._ +import cats.effect.* -import munit._ +import munit.* import scodec.bits.ByteVector class StateParamTest extends CatsEffectSuite { diff --git a/modules/store/src/main/scala/sharry/store/AddResult.scala b/modules/store/src/main/scala/sharry/store/AddResult.scala index c54b92b1..7e5d417b 100644 --- a/modules/store/src/main/scala/sharry/store/AddResult.scala +++ b/modules/store/src/main/scala/sharry/store/AddResult.scala @@ -1,6 +1,6 @@ package sharry.store -import sharry.store.AddResult._ +import sharry.store.AddResult.* sealed trait AddResult { def toEither: Either[Throwable, Unit] @@ -15,10 +15,10 @@ sealed trait AddResult { object AddResult { def fromUpdateExpectChange(errMsg: String)(e: Either[Throwable, Int]): AddResult = - e.fold(Failure, n => if (n > 0) Success else Failure(new Exception(errMsg))) + e.fold(Failure.apply, n => if (n > 0) Success else Failure(new Exception(errMsg))) def fromEither[B](e: Either[Throwable, B]): AddResult = - e.fold(Failure, _ => Success) + e.fold(Failure.apply, _ => Success) case object Success extends AddResult { def toEither = Right(()) diff --git a/modules/store/src/main/scala/sharry/store/ComputeChecksum.scala b/modules/store/src/main/scala/sharry/store/ComputeChecksum.scala index 05cbb9b1..f251423b 100644 --- a/modules/store/src/main/scala/sharry/store/ComputeChecksum.scala +++ b/modules/store/src/main/scala/sharry/store/ComputeChecksum.scala @@ -1,14 +1,14 @@ package sharry.store -import cats.effect._ +import cats.effect.* import cats.effect.std.Queue -import cats.syntax.all._ +import cats.syntax.all.* import fs2.{Pipe, Stream} import sharry.common.{ByteSize, Ident, Timestamp} import sharry.store.records.RFileMeta -import binny._ +import binny.* import binny.util.Stopwatch trait ComputeChecksum[F[_]] { @@ -27,7 +27,7 @@ object ComputeChecksum { for { queue <- Queue.bounded[F, Entry](config.capacity) } yield new ComputeChecksum[F] { - private[this] val logger = sharry.logging.getLogger[F] + private val logger = sharry.logging.getLogger[F] def submit(id: BinaryId, hint: Hint): F[Unit] = if (config.enable) queue.offer(Entry(id, hint)) diff --git a/modules/store/src/main/scala/sharry/store/FileStore.scala b/modules/store/src/main/scala/sharry/store/FileStore.scala index 95cfb6bc..cc8ca1db 100644 --- a/modules/store/src/main/scala/sharry/store/FileStore.scala +++ b/modules/store/src/main/scala/sharry/store/FileStore.scala @@ -3,17 +3,17 @@ package sharry.store import javax.sql.DataSource import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* import fs2.Chunk import fs2.io.file.Files -import sharry.common._ +import sharry.common.* import sharry.store.doobie.AttributeStore import sharry.store.records.RFileMeta -import _root_.doobie._ -import binny._ +import _root_.doobie.* +import binny.* trait FileStore[F[_]] { @@ -47,7 +47,7 @@ object FileStore { computeChecksumConfig: ComputeChecksumConfig, config: FileStoreConfig ): F[FileStore[F]] = { - val create = FileStoreConfig.createBinaryStore[F](ds, chunkSize) _ + val create = FileStoreConfig.createBinaryStore[F](ds, chunkSize) val as = AttributeStore(xa) for { bs <- create(config) diff --git a/modules/store/src/main/scala/sharry/store/FileStoreConfig.scala b/modules/store/src/main/scala/sharry/store/FileStoreConfig.scala index b9226676..f0a5aee1 100644 --- a/modules/store/src/main/scala/sharry/store/FileStoreConfig.scala +++ b/modules/store/src/main/scala/sharry/store/FileStoreConfig.scala @@ -3,7 +3,7 @@ package sharry.store import javax.sql.DataSource import cats.effect.Async -import cats.syntax.all._ +import cats.syntax.all.* import fs2.io.file.{Files, Path} import binny.ChunkedBinaryStore diff --git a/modules/store/src/main/scala/sharry/store/FileStoreType.scala b/modules/store/src/main/scala/sharry/store/FileStoreType.scala index 9976e4b9..e9204acb 100644 --- a/modules/store/src/main/scala/sharry/store/FileStoreType.scala +++ b/modules/store/src/main/scala/sharry/store/FileStoreType.scala @@ -17,8 +17,9 @@ object FileStoreType { NonEmptyList.of(DefaultDatabase, S3, FileSystem) def fromString(str: String): Either[String, FileStoreType] = + val sn = str.replaceAll("[-_]", "") // allow kebab- and snake-case all - .find(_.name.equalsIgnoreCase(str)) + .find(e => e.name.equalsIgnoreCase(sn) || e.name.equalsIgnoreCase(str)) .toRight(s"Invalid file store type: $str") def unsafeFromString(str: String): FileStoreType = diff --git a/modules/store/src/main/scala/sharry/store/Store.scala b/modules/store/src/main/scala/sharry/store/Store.scala index 69beb8be..bd34cbb9 100644 --- a/modules/store/src/main/scala/sharry/store/Store.scala +++ b/modules/store/src/main/scala/sharry/store/Store.scala @@ -2,14 +2,14 @@ package sharry.store import scala.concurrent.ExecutionContext -import cats.effect._ -import fs2._ +import cats.effect.* +import fs2.* import fs2.io.file.Files import sharry.common.ByteSize import sharry.store.doobie.StoreImpl -import _root_.doobie._ +import _root_.doobie.* import _root_.doobie.hikari.HikariTransactor import _root_.doobie.util.log.{LogEvent, Success} import com.zaxxer.hikari.HikariDataSource diff --git a/modules/store/src/main/scala/sharry/store/doobie/AttributeStore.scala b/modules/store/src/main/scala/sharry/store/doobie/AttributeStore.scala index c8e653f3..d72a0457 100644 --- a/modules/store/src/main/scala/sharry/store/doobie/AttributeStore.scala +++ b/modules/store/src/main/scala/sharry/store/doobie/AttributeStore.scala @@ -1,15 +1,15 @@ package sharry.store.doobie import cats.data.OptionT -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* -import sharry.common._ +import sharry.common.* import sharry.store.records.RFileMeta -import binny._ -import doobie._ -import doobie.implicits._ +import binny.* +import doobie.* +import doobie.implicits.* import scodec.bits.ByteVector final private[store] class AttributeStore[F[_]: Sync](xa: Transactor[F]) { diff --git a/modules/store/src/main/scala/sharry/store/doobie/Column.scala b/modules/store/src/main/scala/sharry/store/doobie/Column.scala index 1abecc66..c1444d84 100644 --- a/modules/store/src/main/scala/sharry/store/doobie/Column.scala +++ b/modules/store/src/main/scala/sharry/store/doobie/Column.scala @@ -2,8 +2,8 @@ package sharry.store.doobie import sharry.common.CIIdent -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* case class Column(name: String, ns: String = "", alias: String = "") { diff --git a/modules/store/src/main/scala/sharry/store/doobie/DoobieMeta.scala b/modules/store/src/main/scala/sharry/store/doobie/DoobieMeta.scala index 10aded2c..9a568164 100644 --- a/modules/store/src/main/scala/sharry/store/doobie/DoobieMeta.scala +++ b/modules/store/src/main/scala/sharry/store/doobie/DoobieMeta.scala @@ -3,11 +3,11 @@ package sharry.store.doobie import java.time.format.DateTimeFormatter import java.time.{Instant, LocalDate} -import sharry.common._ -import sharry.common.syntax.all._ +import sharry.common.* +import sharry.common.syntax.all.* -import doobie._ -import doobie.implicits.legacy.instant._ +import doobie.* +import doobie.implicits.legacy.instant.* import io.circe.{Decoder, Encoder} import scodec.bits.ByteVector diff --git a/modules/store/src/main/scala/sharry/store/doobie/Sql.scala b/modules/store/src/main/scala/sharry/store/doobie/Sql.scala index d449655f..dffac223 100644 --- a/modules/store/src/main/scala/sharry/store/doobie/Sql.scala +++ b/modules/store/src/main/scala/sharry/store/doobie/Sql.scala @@ -2,8 +2,8 @@ package sharry.store.doobie import sharry.common.Timestamp -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* object Sql { diff --git a/modules/store/src/main/scala/sharry/store/doobie/StoreImpl.scala b/modules/store/src/main/scala/sharry/store/doobie/StoreImpl.scala index 78f93838..bbd3842a 100644 --- a/modules/store/src/main/scala/sharry/store/doobie/StoreImpl.scala +++ b/modules/store/src/main/scala/sharry/store/doobie/StoreImpl.scala @@ -1,13 +1,13 @@ package sharry.store.doobie -import cats.effect._ -import cats.implicits._ +import cats.effect.* +import cats.implicits.* -import sharry.store._ +import sharry.store.* import sharry.store.migrate.FlywayMigrate -import _root_.doobie._ -import _root_.doobie.implicits._ +import _root_.doobie.* +import _root_.doobie.implicits.* final class StoreImpl[F[_]: Async](jdbc: JdbcConfig, fs: FileStore[F], xa: Transactor[F]) extends Store[F] { diff --git a/modules/store/src/main/scala/sharry/store/migrate/FlywayMigrate.scala b/modules/store/src/main/scala/sharry/store/migrate/FlywayMigrate.scala index c35fd586..99e73afd 100644 --- a/modules/store/src/main/scala/sharry/store/migrate/FlywayMigrate.scala +++ b/modules/store/src/main/scala/sharry/store/migrate/FlywayMigrate.scala @@ -8,7 +8,7 @@ import org.flywaydb.core.Flyway import org.flywaydb.core.api.output.MigrateResult object FlywayMigrate { - private[this] val logger = sharry.logging.unsafeLogger("FlywayMigrate") + private val logger = sharry.logging.unsafeLogger("FlywayMigrate") def run[F[_]: Sync](jdbc: JdbcConfig): F[MigrateResult] = Sync[F].delay { @@ -25,7 +25,7 @@ object FlywayMigrate { .configure() .cleanDisabled(true) .dataSource(jdbc.url.asString, jdbc.user, jdbc.password) - .locations(locations: _*) + .locations(locations*) .baselineOnMigrate(true) .baselineVersion("0") .load() @@ -37,7 +37,7 @@ object FlywayMigrate { .configure() .dataSource(jdbc.url.asString, jdbc.user, jdbc.password) .baselineOnMigrate(true) - .locations(locations: _*) + .locations(locations*) .load() } diff --git a/modules/store/src/main/scala/sharry/store/records/ModAccount.scala b/modules/store/src/main/scala/sharry/store/records/ModAccount.scala index fcc4daf2..4bfba75b 100644 --- a/modules/store/src/main/scala/sharry/store/records/ModAccount.scala +++ b/modules/store/src/main/scala/sharry/store/records/ModAccount.scala @@ -1,6 +1,6 @@ package sharry.store.records -import sharry.common._ +import sharry.common.* case class ModAccount( state: AccountState, diff --git a/modules/store/src/main/scala/sharry/store/records/RAccount.scala b/modules/store/src/main/scala/sharry/store/records/RAccount.scala index 163b8136..a1ccae46 100644 --- a/modules/store/src/main/scala/sharry/store/records/RAccount.scala +++ b/modules/store/src/main/scala/sharry/store/records/RAccount.scala @@ -1,14 +1,14 @@ package sharry.store.records -import cats.implicits._ +import cats.implicits.* import fs2.Stream -import sharry.common._ -import sharry.store.doobie.DoobieMeta._ -import sharry.store.doobie._ +import sharry.common.* +import sharry.store.doobie.* +import sharry.store.doobie.DoobieMeta.* -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* case class RAccount( id: Ident, diff --git a/modules/store/src/main/scala/sharry/store/records/RAlias.scala b/modules/store/src/main/scala/sharry/store/records/RAlias.scala index 47ffa6a2..34a452f9 100644 --- a/modules/store/src/main/scala/sharry/store/records/RAlias.scala +++ b/modules/store/src/main/scala/sharry/store/records/RAlias.scala @@ -1,15 +1,15 @@ package sharry.store.records import cats.effect.Sync -import cats.implicits._ +import cats.implicits.* import fs2.Stream -import sharry.common._ -import sharry.store.doobie.DoobieMeta._ -import sharry.store.doobie._ +import sharry.common.* +import sharry.store.doobie.* +import sharry.store.doobie.DoobieMeta.* -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* case class RAlias( id: Ident, diff --git a/modules/store/src/main/scala/sharry/store/records/RAliasMember.scala b/modules/store/src/main/scala/sharry/store/records/RAliasMember.scala index 04d069cb..fd0c51ea 100644 --- a/modules/store/src/main/scala/sharry/store/records/RAliasMember.scala +++ b/modules/store/src/main/scala/sharry/store/records/RAliasMember.scala @@ -1,14 +1,14 @@ package sharry.store.records import cats.effect.Sync -import cats.implicits._ +import cats.implicits.* -import sharry.common._ -import sharry.store.doobie.DoobieMeta._ -import sharry.store.doobie._ +import sharry.common.* +import sharry.store.doobie.* +import sharry.store.doobie.DoobieMeta.* -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* case class RAliasMember( id: Ident, diff --git a/modules/store/src/main/scala/sharry/store/records/RFileMeta.scala b/modules/store/src/main/scala/sharry/store/records/RFileMeta.scala index c4416d86..bb7d5df1 100644 --- a/modules/store/src/main/scala/sharry/store/records/RFileMeta.scala +++ b/modules/store/src/main/scala/sharry/store/records/RFileMeta.scala @@ -1,13 +1,13 @@ package sharry.store.records -import cats.implicits._ +import cats.implicits.* -import sharry.common._ -import sharry.store.doobie.DoobieMeta._ -import sharry.store.doobie._ +import sharry.common.* +import sharry.store.doobie.* +import sharry.store.doobie.DoobieMeta.* -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* import scodec.bits.ByteVector case class RFileMeta( diff --git a/modules/store/src/main/scala/sharry/store/records/RInvitation.scala b/modules/store/src/main/scala/sharry/store/records/RInvitation.scala index 4783a3bc..c34dc316 100644 --- a/modules/store/src/main/scala/sharry/store/records/RInvitation.scala +++ b/modules/store/src/main/scala/sharry/store/records/RInvitation.scala @@ -1,14 +1,14 @@ package sharry.store.records import cats.effect.Sync -import cats.implicits._ +import cats.implicits.* -import sharry.common._ -import sharry.store.doobie.DoobieMeta._ -import sharry.store.doobie._ +import sharry.common.* +import sharry.store.doobie.* +import sharry.store.doobie.DoobieMeta.* -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* case class RInvitation(id: Ident, created: Timestamp) {} diff --git a/modules/store/src/main/scala/sharry/store/records/RPublishShare.scala b/modules/store/src/main/scala/sharry/store/records/RPublishShare.scala index 09fc6d9c..3b3d841d 100644 --- a/modules/store/src/main/scala/sharry/store/records/RPublishShare.scala +++ b/modules/store/src/main/scala/sharry/store/records/RPublishShare.scala @@ -2,12 +2,12 @@ package sharry.store.records import cats.data.OptionT -import sharry.common._ -import sharry.store.doobie.DoobieMeta._ -import sharry.store.doobie._ +import sharry.common.* +import sharry.store.doobie.* +import sharry.store.doobie.DoobieMeta.* -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* case class RPublishShare( id: Ident, diff --git a/modules/store/src/main/scala/sharry/store/records/RShare.scala b/modules/store/src/main/scala/sharry/store/records/RShare.scala index ca078e64..ed9a12c2 100644 --- a/modules/store/src/main/scala/sharry/store/records/RShare.scala +++ b/modules/store/src/main/scala/sharry/store/records/RShare.scala @@ -1,11 +1,11 @@ package sharry.store.records -import sharry.common._ -import sharry.store.doobie.DoobieMeta._ -import sharry.store.doobie._ +import sharry.common.* +import sharry.store.doobie.* +import sharry.store.doobie.DoobieMeta.* -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* case class RShare( id: Ident, diff --git a/modules/store/src/main/scala/sharry/store/records/RShareFile.scala b/modules/store/src/main/scala/sharry/store/records/RShareFile.scala index c7e73880..783964dc 100644 --- a/modules/store/src/main/scala/sharry/store/records/RShareFile.scala +++ b/modules/store/src/main/scala/sharry/store/records/RShareFile.scala @@ -1,11 +1,11 @@ package sharry.store.records -import sharry.common._ -import sharry.store.doobie.DoobieMeta._ -import sharry.store.doobie._ +import sharry.common.* +import sharry.store.doobie.* +import sharry.store.doobie.DoobieMeta.* -import doobie._ -import doobie.implicits._ +import doobie.* +import doobie.implicits.* case class RShareFile( id: Ident, diff --git a/modules/store/src/test/scala/sharry/store/PermanentErrorTest.scala b/modules/store/src/test/scala/sharry/store/PermanentErrorTest.scala index 428e6eaa..226aa428 100644 --- a/modules/store/src/test/scala/sharry/store/PermanentErrorTest.scala +++ b/modules/store/src/test/scala/sharry/store/PermanentErrorTest.scala @@ -1,6 +1,6 @@ package sharry.store -import munit._ +import munit.* class PermanentErrorTest extends FunSuite { val nativePart = "value for domain safe_bytea violates check constraint" diff --git a/modules/store/src/test/scala/sharry/store/StoreFixture.scala b/modules/store/src/test/scala/sharry/store/StoreFixture.scala index f0b8d2ea..70968b52 100644 --- a/modules/store/src/test/scala/sharry/store/StoreFixture.scala +++ b/modules/store/src/test/scala/sharry/store/StoreFixture.scala @@ -4,14 +4,14 @@ import java.nio.file.Paths import scala.util.Random -import cats.effect._ +import cats.effect.* import cats.effect.unsafe.implicits.global import fs2.io.file.Files -import sharry.common._ -import sharry.store.doobie._ +import sharry.common.* +import sharry.store.doobie.* -import _root_.doobie._ +import _root_.doobie.* import org.h2.jdbcx.JdbcConnectionPool import scodec.bits.ByteVector @@ -22,7 +22,7 @@ trait StoreFixture { } object StoreFixture { - private[this] val logger = sharry.logging.unsafeLogger("StoreFixture") + private val logger = sharry.logging.unsafeLogger("StoreFixture") def makeStore[F[_]: Async: Files]: Resource[F, Store[F]] = { def dataSource(jdbc: JdbcConfig): Resource[F, JdbcConnectionPool] = { diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 56e21265..335a5857 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -6,6 +6,7 @@ object Dependencies { val BetterMonadicForVersion = "0.3.1" val BinnyVersion = "0.11.0" val CirceVersion = "0.14.7" + val CirisVersion = "3.6.0" val ClipboardJsVersion = "2.0.11" val DoobieVersion = "1.0.0-RC5" val EmilVersion = "0.17.0" @@ -19,17 +20,26 @@ object Dependencies { val MUnitVersion = "1.0.0" val MUnitCatsEffectVersion = "2.0.0" val PostgresVersion = "42.7.3" - val PureConfigVersion = "0.17.7" val ScribeVersion = "3.15.0" val SourcecodeVersion = "0.4.2" val SwaggerVersion = "5.17.14" val TikaVersion = "2.9.2" val TusClientVersion = "1.8.0-1" + val TypesafeConfigVersion = "1.4.3" val YamuscaVersion = "0.10.0" + val ciris = Seq( + "is.cir" %% "ciris" % CirisVersion + ) + val typesafeConfig = Seq( + "com.typesafe" % "config" % TypesafeConfigVersion + ) + val scribe = Seq( "com.outr" %% "scribe" % ScribeVersion, - "com.outr" %% "scribe-slf4j2" % ScribeVersion + "com.outr" %% "scribe-slf4j2" % ScribeVersion, + "com.outr" %% "scribe-cats" % ScribeVersion, + "com.outr" %% "scribe-json-circe" % ScribeVersion ) val sourcecode = Seq( @@ -66,12 +76,6 @@ object Dependencies { "io.circe" %% "circe-parser" % CirceVersion ) - // https://github.com/melrief/pureconfig - // MPL 2.0 - val pureconfig = Seq( - "com.github.pureconfig" %% "pureconfig" % PureConfigVersion - ) - // https://github.com/h2database/h2database // MPL 2.0 or EPL 1.0 val h2 = Seq(