From 017397f07e4fab186c5b270f784e2abb785ec363 Mon Sep 17 00:00:00 2001 From: Delegue Alexandre Date: Mon, 14 Oct 2024 14:48:46 +0200 Subject: [PATCH] Scala3 migration (#196) * Upgrade scala 3 --- docker-compose.yml | 28 ++++++-- .../app/configuration/Configuration.scala | 14 ++-- .../app/controllers/HomeController.scala | 8 +-- .../app/controllers/UserDataController.scala | 2 +- nio-provider/app/models/UserExtractTask.scala | 8 +-- nio-provider/app/models/events.scala | 4 +- nio-provider/app/service/NioService.scala | 3 +- nio-provider/app/utils/Results.scala | 2 +- nio-provider/build.sbt | 4 +- .../app/configuration/Configuration.scala | 59 +++++++++------- .../app/controllers/Auth0Controller.scala | 4 +- .../app/controllers/ConsentController.scala | 10 +-- .../controllers/ExtractionController.scala | 6 +- .../app/controllers/HomeController.scala | 17 +++-- .../NioAuthenticateController.scala | 7 +- .../OrganisationOfferController.scala | 28 ++++---- .../controllers/UserExtractController.scala | 2 +- .../app/db/DeletionTaskMongoDataStore.scala | 2 +- nio-server/app/db/MongoDataStore.scala | 8 ++- nio-server/app/db/MongoOpsDataStore.scala | 19 +++--- nio-server/app/libs/io.scala | 9 --- nio-server/app/models/Account.scala | 18 +++-- nio-server/app/models/ApiKey.scala | 10 +-- nio-server/app/models/ConsentFact.scala | 59 ++++++++-------- nio-server/app/models/DeletionTask.scala | 7 +- nio-server/app/models/NioAccount.scala | 10 +-- nio-server/app/models/Offer.scala | 8 +-- nio-server/app/models/Organisation.scala | 12 ++-- nio-server/app/models/Permission.scala | 20 +++--- nio-server/app/models/UserExtractTask.scala | 10 +-- nio-server/app/models/events.scala | 12 ++-- .../app/service/ConsentManagerService.scala | 2 +- nio-server/app/utils/S3Manager.scala | 4 +- nio-server/build.sbt | 4 +- .../controllers/ConsentControllerSpec.scala | 5 +- .../controllers/EventControllerSpec.scala | 4 +- .../ExtractionControllerSpec.scala | 2 +- .../OrganisationControllerSpec.scala | 7 +- .../UserExtractControllerSpec.scala | 11 +-- .../test/models/ModelValidationSpec.scala | 17 ++--- nio-server/test/models/OrganisationSpec.scala | 5 +- nio-server/test/utils/TestUtils.scala | 68 ++++++++++++------- project/Dependencies.scala | 13 ++-- 43 files changed, 300 insertions(+), 252 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index bba3ae6c..6c8cf37e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,10 @@ version: '2' services: - mongo: + nio_mongo: image: mongo:3.4.3 ports: - 27017:27017 - zookeeper: + nio_zookeeper: image: confluentinc/cp-zookeeper:5.2.3 ports: - 32182:32181 @@ -14,12 +14,12 @@ services: extra_hosts: - "moby:127.0.0.1" - "localhost: 127.0.0.1" - kafka: + nio_kafka: image: confluentinc/cp-kafka:5.2.3 ports: - 29092:29092 depends_on: - - zookeeper + - nio_zookeeper environment: KAFKA_BROKER_ID: 1 KAFKA_ZOOKEEPER_CONNECT: zookeeper:32181 @@ -30,10 +30,26 @@ services: extra_hosts: - "moby:127.0.0.1" - "localhost: 127.0.0.1" - s3server: + nio_s3server: image: scality/s3server ports: - 8000:8000 environment: - "SCALITY_ACCESS_KEY_ID=newAccessKey" - - "SCALITY_SECRET_ACCESS_KEY=newSecretKey" \ No newline at end of file + - "SCALITY_SECRET_ACCESS_KEY=newSecretKey" + nio_akhq: + image: tchiotludo/akhq + ports: + - 9005:8080 + environment: + AKHQ_CONFIGURATION: | + akhq: + connections: + docker-kafka-server: + properties: + bootstrap.servers: "nio_kafka:9092" + depends_on: + - nio_kafka + extra_hosts: + - "moby:127.0.0.1" + - "localhost: 127.0.0.1" \ No newline at end of file diff --git a/nio-provider/app/configuration/Configuration.scala b/nio-provider/app/configuration/Configuration.scala index d9afa7ec..762f8d97 100644 --- a/nio-provider/app/configuration/Configuration.scala +++ b/nio-provider/app/configuration/Configuration.scala @@ -1,18 +1,22 @@ package configuration import play.api.Configuration -import pureconfig._ +import pureconfig.* +import pureconfig.generic.derivation.default.* +import pureconfig.generic.semiauto.* import pureconfig.generic.ProductHint import scala.concurrent.duration.FiniteDuration object NioConfiguration { - import pureconfig.generic.auto._ - implicit def hint[T]: ProductHint[T] = - ProductHint[T](ConfigFieldMapping(CamelCase, CamelCase)) - def apply(config: Configuration): NioConfiguration = + implicit def hint[T]: ProductHint[T] = ProductHint[T](ConfigFieldMapping(CamelCase, CamelCase)) + + def apply(config: Configuration): NioConfiguration = { + given ConfigReader[NioConfiguration] = deriveReader + given ConfigWriter[NioConfiguration] = deriveWriter ConfigSource.fromConfig(config.underlying).at("nio").loadOrThrow[NioConfiguration] + } } case class NioConfiguration(websocketHost: String, filter: Otoroshi, kafka: KafkaConfig, nio: NioConfig) diff --git a/nio-provider/app/controllers/HomeController.scala b/nio-provider/app/controllers/HomeController.scala index 5c6de53b..37b7fcf3 100644 --- a/nio-provider/app/controllers/HomeController.scala +++ b/nio-provider/app/controllers/HomeController.scala @@ -4,7 +4,7 @@ import org.apache.pekko.actor.ActorSystem import auth.AuthActionWithEmail import configuration.Env import messaging.KafkaMessageBroker -import play.api.mvc.{AbstractController, ControllerComponents} +import play.api.mvc.{AbstractController, Action, AnyContent, ControllerComponents} import scala.concurrent.ExecutionContext @@ -16,13 +16,13 @@ class HomeController(val AuthAction: AuthActionWithEmail, implicit val ec: ExecutionContext) extends AbstractController(cc) { - def index() = AuthAction { implicit req => + def index(): Action[AnyContent] = AuthAction { implicit req => Ok(views.html.index(env, req.email, env.config.websocketHost)) } - def indexOther() = index() + def indexOther(): Action[AnyContent] = index() - def otherRoutes(route: String) = AuthAction { implicit req => + def otherRoutes(route: String): Action[AnyContent] = AuthAction { implicit req => Ok(views.html.index(env, req.email, env.config.websocketHost)) } diff --git a/nio-provider/app/controllers/UserDataController.scala b/nio-provider/app/controllers/UserDataController.scala index 6283757b..ab8250aa 100644 --- a/nio-provider/app/controllers/UserDataController.scala +++ b/nio-provider/app/controllers/UserDataController.scala @@ -35,7 +35,7 @@ class UserDataController( def uploadFile(tenant: String, orgKey: String, userId: String, name: String): Action[MultipartFormData[Files.TemporaryFile]] = AuthAction.async(parse.multipartFormData) { implicit req => NioLogger.info(s"upload file $name") - val src: Source[ByteString, _] = + val src: Source[ByteString, ?] = StreamConverters.fromInputStream { () => new FileInputStream(req.body.files.head.ref) } diff --git a/nio-provider/app/models/UserExtractTask.scala b/nio-provider/app/models/UserExtractTask.scala index 917a6a79..dc824176 100644 --- a/nio-provider/app/models/UserExtractTask.scala +++ b/nio-provider/app/models/UserExtractTask.scala @@ -39,10 +39,10 @@ object UserExtractTask { } and (__ \ "uploadStartedAt").readNullable[LocalDateTime] and (__ \ "endedAt").readNullable[LocalDateTime] - )(UserExtractTask.apply _) + )(UserExtractTask.apply) implicit val userExtractTaskWrites: Writes[UserExtractTask] = ( - (JsPath \ "_id").write[String] and + (JsPath \ "_id").write[String] and (JsPath \ "tenant").write[String] and (JsPath \ "orgKey").write[String] and (JsPath \ "userId").write[String] and @@ -50,7 +50,7 @@ object UserExtractTask { (JsPath \ "startedAt").write[LocalDateTime] and (JsPath \ "uploadStartedAt").writeNullable[LocalDateTime] and (JsPath \ "endedAt").writeNullable[LocalDateTime] - )(unlift(UserExtractTask.unapply)) + )(u => (u._id, u.tenant, u.orgKey, u.userId, u.email, u.startedAt, u.uploadStartedAt, u.endedAt)) implicit val userExtractTaskOWrites: OWrites[UserExtractTask] = ( (JsPath \ "_id").write[String] and @@ -61,7 +61,7 @@ object UserExtractTask { (JsPath \ "startedAt").write[LocalDateTime] and (JsPath \ "uploadStartedAt").writeNullable[LocalDateTime] and (JsPath \ "endedAt").writeNullable[LocalDateTime] - )(unlift(UserExtractTask.unapply)) + )(u => (u._id, u.tenant, u.orgKey, u.userId, u.email, u.startedAt, u.uploadStartedAt, u.endedAt)) implicit val format: Format[UserExtractTask] = Format(userExtractTaskReads, userExtractTaskWrites) diff --git a/nio-provider/app/models/events.scala b/nio-provider/app/models/events.scala index 6e4078a4..18e76ee9 100644 --- a/nio-provider/app/models/events.scala +++ b/nio-provider/app/models/events.scala @@ -7,11 +7,13 @@ import utils.DateUtils import scala.collection.Seq object EventType extends Enumeration { - type WeekDay = Value + type EventType = Value val UserExtractTaskAsked, UserExtractTaskCompleted, Unknown = Value def from(name: String): Value = values.find(_.toString.toLowerCase == name.toLowerCase()).getOrElse(Unknown) + + implicit val format: Format[EventType] = Json.formatEnum(this) } object NioEvent { diff --git a/nio-provider/app/service/NioService.scala b/nio-provider/app/service/NioService.scala index 705beac3..e5a37cb7 100644 --- a/nio-provider/app/service/NioService.scala +++ b/nio-provider/app/service/NioService.scala @@ -24,8 +24,9 @@ class NioService(env: Env, wSClient: WSClient)( orgKey: String, userId: String, name: String, - src: Source[ByteString, _], + src: Source[ByteString, ?], contentTypeHeader: Option[String]): Future[JsValue] = { + import play.api.libs.ws.bodyWritableOf_Multipart wSClient .url( s"${env.config.nio.url}/api/$tenant/organisations/$orgKey/users/$userId/_files/$name") diff --git a/nio-provider/app/utils/Results.scala b/nio-provider/app/utils/Results.scala index 191deb6d..b8a47f17 100644 --- a/nio-provider/app/utils/Results.scala +++ b/nio-provider/app/utils/Results.scala @@ -43,7 +43,7 @@ object Result { def fromJsError(jsError: Seq[(JsPath, Seq[JsonValidationError])]): AppErrors = { val fieldErrors = jsError.map { case (k, v) => - (k.toJsonString, v.map(err => ErrorMessage(err.message, err.args.map(_.toString): _*)).toList) + (k.toJsonString, v.map(err => ErrorMessage(err.message, err.args.map(_.toString)*)).toList) }.toMap AppErrors(fieldErrors = fieldErrors) } diff --git a/nio-provider/build.sbt b/nio-provider/build.sbt index 9201df0d..bc55859a 100644 --- a/nio-provider/build.sbt +++ b/nio-provider/build.sbt @@ -25,7 +25,9 @@ libraryDependencies ++= Seq( "org.apache.pekko" %% "pekko-connectors-kafka" % pekkoKafka, "de.svenkubiak" % "jBCrypt" % "0.4.1", // ISC/BSD "com.auth0" % "java-jwt" % javaJwt, // MIT license - "com.github.pureconfig" %% "pureconfig" % pureConfig, // Apache 2.0 +// "com.github.pureconfig" %% "pureconfig" % pureConfig, // Apache 2.0 + "com.github.pureconfig" %% "pureconfig-core" % pureConfig, // Apache 2.0 + "com.github.pureconfig" %% "pureconfig-generic-scala3" % pureConfig, // Apache 2.0 "org.scalactic" %% "scalactic" % scalaticVersion, // Apache 2.0 "org.webjars" % "swagger-ui" % "3.12.1", "org.typelevel" %% "cats-core" % catsVersion, // MIT diff --git a/nio-server/app/configuration/Configuration.scala b/nio-server/app/configuration/Configuration.scala index acc5e3eb..30c278c1 100644 --- a/nio-server/app/configuration/Configuration.scala +++ b/nio-server/app/configuration/Configuration.scala @@ -1,19 +1,13 @@ package configuration import play.api.Configuration -import pureconfig._ import pureconfig.generic.ProductHint -import pureconfig.generic.auto._ +import pureconfig.* +import pureconfig.generic.derivation.default.* +import pureconfig.generic.semiauto.* import scala.concurrent.duration.FiniteDuration -object NioConfiguration { - - implicit def hint[T]: ProductHint[T] = ProductHint[T](ConfigFieldMapping(CamelCase, CamelCase)) - - def apply(config: Configuration): NioConfiguration = - ConfigSource.fromConfig(config.underlying).at("nio").loadOrThrow[NioConfiguration] -} case class NioConfiguration( baseUrl: String, @@ -89,23 +83,9 @@ case class KafkaConfig( case class Location(location: Option[String]) -object TenantConfiguration { - implicit def hint[T]: ProductHint[T] = - ProductHint[T](ConfigFieldMapping(CamelCase, CamelCase)) - - def apply(config: Configuration): TenantConfiguration = - ConfigSource.fromConfig(config.underlying).at("tenant").loadOrThrow[TenantConfiguration] -} case class TenantConfiguration(admin: AdminConfig) -object HealthCheckConfiguration { - implicit def hint[T]: ProductHint[T] = - ProductHint[T](ConfigFieldMapping(CamelCase, CamelCase)) - - def apply(config: Configuration): HealthCheckConfiguration = - ConfigSource.fromConfig(config.underlying).at("healthcheck").loadOrThrow[HealthCheckConfiguration] -} case class HealthCheckConfiguration(secret: String, header: String) @@ -127,3 +107,36 @@ case class MailGunConfig(apiKey: String, endpoint: String, from: String) case class CatchUpEventsConfig(strategy: String, delay: FiniteDuration, interval: FiniteDuration) case class Db(batchSize: Int) + +object NioConfiguration { + + implicit def hint[T]: ProductHint[T] = ProductHint[T](ConfigFieldMapping(CamelCase, CamelCase)) + + def apply(config: Configuration): NioConfiguration = { + given ConfigReader[NioConfiguration] = deriveReader + given ConfigWriter[NioConfiguration] = deriveWriter + ConfigSource.fromConfig(config.underlying).at("nio").loadOrThrow[NioConfiguration] + } +} + + +object TenantConfiguration { + implicit def hint[T]: ProductHint[T] = ProductHint[T](ConfigFieldMapping(CamelCase, CamelCase)) + + def apply(config: Configuration): TenantConfiguration = { + given ConfigReader[TenantConfiguration] = deriveReader + given ConfigWriter[TenantConfiguration] = deriveWriter + ConfigSource.fromConfig(config.underlying).at("tenant").loadOrThrow[TenantConfiguration] + } +} + + +object HealthCheckConfiguration { + implicit def hint[T]: ProductHint[T] = ProductHint[T](ConfigFieldMapping(CamelCase, CamelCase)) + + def apply(config: Configuration): HealthCheckConfiguration = { + given ConfigReader[HealthCheckConfiguration] = deriveReader + given ConfigWriter[HealthCheckConfiguration] = deriveWriter + ConfigSource.fromConfig(config.underlying).at("healthcheck").loadOrThrow[HealthCheckConfiguration] + } +} \ No newline at end of file diff --git a/nio-server/app/controllers/Auth0Controller.scala b/nio-server/app/controllers/Auth0Controller.scala index ffa10c6d..5521af2d 100644 --- a/nio-server/app/controllers/Auth0Controller.scala +++ b/nio-server/app/controllers/Auth0Controller.scala @@ -91,7 +91,8 @@ class Auth0Controller(env: Env, wsClient: WSClient, cc: ControllerComponents)(im } } - private def getToken(code: String, sessionId: String): Future[Either[AppErrors, (String, String)]] = + private def getToken(code: String, sessionId: String): Future[Either[AppErrors, (String, String)]] = { + import play.api.libs.ws.writeableOf_JsValue wsClient .url(s"https://${auth0Config.domain}/oauth/token") .addHttpHeaders(HeaderNames.ACCEPT -> MimeTypes.JSON) @@ -118,6 +119,7 @@ class Auth0Controller(env: Env, wsClient: WSClient, cc: ControllerComponents)(im Left(AppErrors(Seq(ErrorMessage("tokens.not.send")))) } } + } private def getUser(accessToken: String): Future[JsValue] = wsClient diff --git a/nio-server/app/controllers/ConsentController.scala b/nio-server/app/controllers/ConsentController.scala index b3b59b80..ec02be26 100644 --- a/nio-server/app/controllers/ConsentController.scala +++ b/nio-server/app/controllers/ConsentController.scala @@ -273,7 +273,7 @@ class ConsentController( val newLineSplit: Flow[ByteString, ByteString, NotUsed] = Framing.delimiter(ByteString("\n"), 10000, allowTruncation = true) val toJson: Flow[ByteString, JsValue, NotUsed] = Flow[ByteString] via newLineSplit map (_.utf8String) filterNot (_.isEmpty) map (l => Json.parse(l)) - private def ndJson(implicit ec: ExecutionContext): BodyParser[Source[JsValue, _]] = BodyParser(_ => Accumulator.source[ByteString].map(s => Right(s.via(toJson)))(ec)) + private def ndJson(implicit ec: ExecutionContext): BodyParser[Source[JsValue, ?]] = BodyParser(_ => Accumulator.source[ByteString].map(s => Right(s.via(toJson)))(ec)) private object ImportError { implicit val format: OFormat[ImportError] = Json.format[ImportError] @@ -314,7 +314,7 @@ class ConsentController( } - def batchImport(tenant: String, orgKey: String): Action[Source[JsValue, _]] = AuthAction.async(ndJson) { implicit req => + def batchImport(tenant: String, orgKey: String): Action[Source[JsValue, ?]] = AuthAction.async(ndJson) { implicit req => val result: Future[JsValue] = req.body .map(json => ((json \ "userId").validate[String].getOrElse(""), json)) .via(sharding(10, Flow[(String, JsValue)].mapAsync(1) { case (_, json) => @@ -326,14 +326,14 @@ class ConsentController( } ) })) - .fold(ImportResult()){ (acc, elt) => acc combine elt } + .fold(ImportResult()){ (acc, elt) => acc.combine(elt) } .map { importResult => Json.toJson(importResult) } .runWith(Sink.head) result.map { json => Ok(json) } } - private def handleImportPatch(tenant: String, orgKey: String, req: SecuredAuthContext[Source[JsValue, _]], json: JsValue, userId: String, patchCommand: PartialConsentFact): Future[ImportResult] = { + private def handleImportPatch(tenant: String, orgKey: String, req: SecuredAuthContext[Source[JsValue, ?]], json: JsValue, userId: String, patchCommand: PartialConsentFact): Future[ImportResult] = { (for { _ <- if (patchCommand.userId.isDefined && !patchCommand.userId.contains(userId)) IO.error(ImportResult.error("error.userId.is.immutable", command = json)) else IO.succeed(patchCommand) @@ -370,7 +370,7 @@ class ConsentController( } yield result).merge } - private def handleImportUpdate(tenant: String, orgKey: String, req: SecuredAuthContext[Source[JsValue, _]], json: JsValue, userId: String, consentFact: ConsentFact): Future[ImportResult] = { + private def handleImportUpdate(tenant: String, orgKey: String, req: SecuredAuthContext[Source[JsValue, ?]], json: JsValue, userId: String, consentFact: ConsentFact): Future[ImportResult] = { if (consentFact.userId != userId) { NioLogger.error(s"error.userId.is.immutable : userId in path $userId // userId on body ${consentFact.userId}") diff --git a/nio-server/app/controllers/ExtractionController.scala b/nio-server/app/controllers/ExtractionController.scala index 1c246a04..47bb99f8 100644 --- a/nio-server/app/controllers/ExtractionController.scala +++ b/nio-server/app/controllers/ExtractionController.scala @@ -45,7 +45,7 @@ class ExtractionController( implicit val mat: Materializer = Materializer(system) - val fileBodyParser: BodyParser[Source[ByteString, _]] = BodyParser { _ => + val fileBodyParser: BodyParser[Source[ByteString, ?]] = BodyParser { _ => Accumulator.source[ByteString].map(s => Right(s)) } implicit val readable: ReadableEntity[AppIds] = AppIds @@ -166,7 +166,7 @@ class ExtractionController( } private def upload(tenant: String, task: ExtractionTask, appId: String, name: String)(implicit - req: ReqWithExtractionTask[Source[ByteString, _]] + req: ReqWithExtractionTask[Source[ByteString, ?]] ): Future[String] = req.body .via( @@ -184,7 +184,7 @@ class ExtractionController( } private def oldUpload(tenant: String, task: ExtractionTask, appId: String, name: String)(implicit - req: ReqWithExtractionTask[Source[ByteString, _]] + req: ReqWithExtractionTask[Source[ByteString, ?]] ): Future[String] = { val uploadKey = s"$tenant/${task.orgKey}/${task.userId}/${task._id}/$appId/$name" diff --git a/nio-server/app/controllers/HomeController.scala b/nio-server/app/controllers/HomeController.scala index 27d45142..fd4e65c3 100644 --- a/nio-server/app/controllers/HomeController.scala +++ b/nio-server/app/controllers/HomeController.scala @@ -1,16 +1,15 @@ package controllers import java.nio.file.Files - import org.apache.pekko.actor.ActorSystem import org.apache.pekko.http.scaladsl.util.FastFuture import auth.AuthContextWithEmail import configuration.Env import controllers.ErrorManager.ErrorManagerResult import db.TenantMongoDataStore -import play.api.mvc.{ActionBuilder, AnyContent, ControllerComponents} +import play.api.mvc.{Action, ActionBuilder, AnyContent, ControllerComponents} -import scala.jdk.CollectionConverters._ +import scala.jdk.CollectionConverters.* import scala.concurrent.ExecutionContext class HomeController( @@ -54,7 +53,7 @@ class HomeController( .replace("$CLIENT_ID", env.config.filter.otoroshi.headerGatewayHeaderClientId) .replace("$CLIENT_SECRET", env.config.filter.otoroshi.headerGatewayHeaderClientSecret) - def index(tenant: String) = AuthAction.async { implicit req => + def index(tenant: String): Action[AnyContent] = AuthAction.async { implicit req => req.authInfo match { case Some(authInfo) if authInfo.isAdmin => tenantStore.findByKey(tenant).map { @@ -72,7 +71,7 @@ class HomeController( } } - def indexNoTenant = AuthAction { implicit req => + def indexNoTenant: Action[AnyContent] = AuthAction { implicit req => req.authInfo match { case Some(authInfo) if authInfo.isAdmin => Ok( @@ -86,13 +85,13 @@ class HomeController( } } - def login = AuthAction { _ => + def login: Action[AnyContent] = AuthAction { _ => Ok(views.html.indexLogin(env)) } - def indexOther(tenant: String) = index(tenant) + def indexOther(tenant: String): Action[AnyContent] = index(tenant) - def otherRoutes(tenant: String, route: String) = AuthAction.async { implicit req => + def otherRoutes(tenant: String, route: String): Action[AnyContent] = AuthAction.async { implicit req => req.authInfo match { case Some(authInfo) if authInfo.isAdmin => tenantStore.findByKey(tenant).map { @@ -110,7 +109,7 @@ class HomeController( } } - def swagger() = AuthAction { _ => + def swagger(): Action[AnyContent] = AuthAction { _ => Ok(swaggerContent).as("application/json") } } diff --git a/nio-server/app/controllers/NioAuthenticateController.scala b/nio-server/app/controllers/NioAuthenticateController.scala index 57814dd6..4b0ea837 100644 --- a/nio-server/app/controllers/NioAuthenticateController.scala +++ b/nio-server/app/controllers/NioAuthenticateController.scala @@ -7,8 +7,9 @@ import com.auth0.jwt.algorithms.Algorithm import configuration.{DefaultFilterConfig, Env} import controllers.ErrorManager.AppErrorManagerResult import db.NioAccountMongoDataStore +import libs.xmlorjson.XmlOrJson import models.{Auth, NioAccount} -import play.api.mvc.{ControllerComponents, Cookie} +import play.api.mvc.{Action, AnyContent, ControllerComponents, Cookie} import utils.Sha import scala.concurrent.ExecutionContext @@ -27,7 +28,7 @@ class NioAuthenticateController( lazy val cookieName: String = config.cookieClaim lazy val algorithm: Algorithm = Algorithm.HMAC512(config.sharedKey) - def login = Action(bodyParser).async { implicit req => + def login: Action[XmlOrJson] = Action(bodyParser).async { implicit req => req.body.read[Auth] match { case Left(e) => FastFuture.successful(e.forbidden()) @@ -55,7 +56,7 @@ class NioAuthenticateController( .sign(algorithm) } - def logout = Action { _ => + def logout: Action[AnyContent] = Action { _ => Redirect(s"${env.config.baseUrl}") .withCookies(Cookie(name = cookieName, value = "", maxAge = Some(0))) } diff --git a/nio-server/app/controllers/OrganisationOfferController.scala b/nio-server/app/controllers/OrganisationOfferController.scala index 5957c817..5d863143 100644 --- a/nio-server/app/controllers/OrganisationOfferController.scala +++ b/nio-server/app/controllers/OrganisationOfferController.scala @@ -12,15 +12,15 @@ import controllers.ErrorManager.{AppErrorManagerResult, ErrorManagerResult, Erro import db.OrganisationMongoDataStore import libs.xmlorjson.XmlOrJson import messaging.KafkaMessageBroker -import models._ +import models.* import java.time.{Clock, LocalDateTime} import utils.{DateUtils, NioLogger} import play.api.http.HttpEntity -import play.api.libs.json.Reads._ +import play.api.libs.json.Reads.* import play.api.libs.json.{JsValue, Json} import play.api.libs.streams.Accumulator -import play.api.mvc.{ActionBuilder, AnyContent, ControllerComponents} +import play.api.mvc.{Action, AnyContent, ActionBuilder, ControllerComponents} import reactivemongo.api.bson.BSONObjectID import service.{ConsentManagerService, OfferManagerService} @@ -43,7 +43,7 @@ class OrganisationOfferController( implicit val readable: ReadableEntity[Offer] = Offer implicit val materializer: Materializer = Materializer(actorSystem) - def findAll(tenant: String, orgKey: String) = + def findAll(tenant: String, orgKey: String): Action[AnyContent] = authAction.async { implicit req => NioLogger.info(s"get offers for $orgKey") offerManagerService @@ -84,7 +84,7 @@ class OrganisationOfferController( } - def add(tenant: String, orgKey: String) = + def add(tenant: String, orgKey: String): Action[XmlOrJson] = authAction.async(bodyParser) { implicit req => val addOffer: (String, String, SecuredAuthContext[XmlOrJson], Offer, Option[Offer]) => Future[Result] = (tenant, orgKey, req, offer, maybeOffer) => { @@ -114,7 +114,7 @@ class OrganisationOfferController( ) } - def update(tenant: String, orgKey: String, offerKey: String) = + def update(tenant: String, orgKey: String, offerKey: String): Action[XmlOrJson] = authAction.async(bodyParser) { implicit req => val updateOffer: (String, String, SecuredAuthContext[XmlOrJson], Offer, Option[Offer]) => Future[Result] = (tenant, orgKey, req, offer, maybeOffer) => { @@ -161,14 +161,14 @@ class OrganisationOfferController( case class OfferConsentWithGroup(groupKey: String, consentKey: String) case class UserIdAndInitDate(id: String, date: String) - def handleConsent( + private def handleConsent( tenant: String, orgKey: String, authInfo: AuthInfo, offerKey: String, setToFalse: Option[Seq[OfferConsentWithGroup]], - source: Source[UserIdAndInitDate, _] - ): Source[JsValue, _] = + source: Source[UserIdAndInitDate, ?] + ): Source[JsValue, ?] = source .mapAsync(env.config.db.batchSize) { value => consentController @@ -231,12 +231,12 @@ class OrganisationOfferController( val newLineSplit: Flow[ByteString, ByteString, NotUsed] = Framing.delimiter(ByteString("\n"), 10000, allowTruncation = true) - def jsonToIdAndDate: Flow[ByteString, UserIdAndInitDate, NotUsed] = + private def jsonToIdAndDate: Flow[ByteString, UserIdAndInitDate, NotUsed] = Flow[ByteString] via newLineSplit map (_.utf8String) filterNot (_.isEmpty) map (l => Json.parse(l)) map (value => UserIdAndInitDate((value \ "userId").as[String], (value \ "date").as[String]) ) - def csvToIdAndDate(drop: Long, separator: String): Flow[ByteString, UserIdAndInitDate, NotUsed] = + private def csvToIdAndDate(drop: Long, separator: String): Flow[ByteString, UserIdAndInitDate, NotUsed] = Flow[ByteString] .via(newLineSplit) .drop(drop) @@ -249,7 +249,7 @@ class OrganisationOfferController( List.empty } - val sourceBodyParser: BodyParser[Source[UserIdAndInitDate, _]] = + val sourceBodyParser: BodyParser[Source[UserIdAndInitDate, ?]] = BodyParser("Streaming BodyParser") { req => val drop = req.getQueryString("drop").map(_.toLong).getOrElse(0L) val separator = req.getQueryString("separator").getOrElse(";") @@ -262,14 +262,14 @@ class OrganisationOfferController( } } - def initializeOffer(tenant: String, orgKey: String, offerKey: String) = authAction(sourceBodyParser) { req => + def initializeOffer(tenant: String, orgKey: String, offerKey: String): Action[Source[UserIdAndInitDate, ?]] = authAction(sourceBodyParser) { req => NioLogger.info(s" Begin offer initialization for tenant $tenant organisation $orgKey and offer $offerKey") val setToFalse: Option[Seq[OfferConsentWithGroup]] = req.queryString .get("setToFalse") .map(strings => strings.map { string => val index = string.indexOf('.') - OfferConsentWithGroup.apply _ tupled (string.take(index), string.drop(index + 1)) + OfferConsentWithGroup(string.take(index), string.drop(index + 1)) } ) diff --git a/nio-server/app/controllers/UserExtractController.scala b/nio-server/app/controllers/UserExtractController.scala index 8149cb3a..965c2301 100644 --- a/nio-server/app/controllers/UserExtractController.scala +++ b/nio-server/app/controllers/UserExtractController.scala @@ -282,7 +282,7 @@ class UserExtractController( } - def streamFile: BodyParser[Source[ByteString, _]] = + def streamFile: BodyParser[Source[ByteString, ?]] = BodyParser { _ => Accumulator.source[ByteString].map(s => Right(s)) } diff --git a/nio-server/app/db/DeletionTaskMongoDataStore.scala b/nio-server/app/db/DeletionTaskMongoDataStore.scala index 6419ce29..50551733 100644 --- a/nio-server/app/db/DeletionTaskMongoDataStore.scala +++ b/nio-server/app/db/DeletionTaskMongoDataStore.scala @@ -10,7 +10,7 @@ import scala.collection.{immutable, Seq} class DeletionTaskMongoDataStore(val mongoApi: ReactiveMongoApi)(implicit val executionContext: ExecutionContext) extends MongoDataStore[DeletionTask] { - val format: OFormat[DeletionTask] = models.DeletionTask.deletionTaskFormats + val format: OFormat[DeletionTask] = models.DeletionTask.deletionTaskOFormats override def collectionName(tenant: String) = s"$tenant-deletionTasks" override def indices = Seq( diff --git a/nio-server/app/db/MongoDataStore.scala b/nio-server/app/db/MongoDataStore.scala index 76840353..fbf9974a 100644 --- a/nio-server/app/db/MongoDataStore.scala +++ b/nio-server/app/db/MongoDataStore.scala @@ -67,10 +67,12 @@ trait MongoDataStore[T] { function(col) } - def insertOne(tenant: String, objToInsert: T): Future[Boolean] = + def insertOne(tenant: String, objToInsert: T): Future[Boolean] = { + import reactivemongo.play.json.compat.json2bson.toDocumentWriter tenant.request[Boolean] { col => col.insertOne[T](objToInsert) } + } def updateOne(tenant: String, id: String, objToUpdate: T): Future[Boolean] = tenant.request[Boolean] { col => @@ -82,10 +84,12 @@ trait MongoDataStore[T] { col.updateOneByQuery(query, objToUpdate) } - def updateByQuery(tenant: String, query: JsObject, update: JsObject): Future[Boolean] = + def updateByQuery(tenant: String, query: JsObject, update: JsObject): Future[Boolean] = { + import reactivemongo.play.json.compat.json2bson.toDocumentWriter tenant.request[Boolean] { col => col.updateByQuery(query, update) } + } def findOneById(tenant: String, id: String): Future[Option[T]] = tenant.request[Option[T]] { col => diff --git a/nio-server/app/db/MongoOpsDataStore.scala b/nio-server/app/db/MongoOpsDataStore.scala index b3b1aeee..09a7028e 100644 --- a/nio-server/app/db/MongoOpsDataStore.scala +++ b/nio-server/app/db/MongoOpsDataStore.scala @@ -19,29 +19,30 @@ object MongoOpsDataStore { import reactivemongo.play.json.compat._ import reactivemongo.pekkostream._ - def insertOne[T](objToInsert: T)(implicit oformat: OFormat[T]): Future[Boolean] = { + def insertOne[T](objToInsert: T)(implicit oformat: OFormat[T], writer: BSONDocumentWriter[T]): Future[Boolean] = { import json2bson._ - implicit val writer = implicitly[BSONDocumentWriter[T]] coll.insert.one[T](objToInsert).map(_.writeErrors.isEmpty) } - def updateOne[T](id: String, objToUpdate: T)(implicit oformat: OFormat[T]): Future[Boolean] = + def updateOne[T](id: String, objToUpdate: T)(implicit oformat: OFormat[T]): Future[Boolean] = { + import reactivemongo.play.json.compat.json2bson.toDocumentWriter updateOne(Json.obj("_id" -> id), objToUpdate) + } - def updateOneByQuery[T](query: JsObject, objToUpdate: T)(implicit oformat: OFormat[T]): Future[Boolean] = + def updateOneByQuery[T](query: JsObject, objToUpdate: T)(implicit oformat: OFormat[T]): Future[Boolean] = { + import reactivemongo.play.json.compat.json2bson.toDocumentWriter updateOne(query, objToUpdate) + } - def updateByQuery[T](query: JsObject, update: JsObject)(implicit OFormat: OFormat[T]): Future[Boolean] = { + def updateByQuery[T](query: JsObject, update: JsObject)(implicit OFormat: OFormat[T], writer: BSONDocumentWriter[T]): Future[Boolean] = { import json2bson._ -// implicit val writer = implicitly[BSONDocumentWriter[T]] val builder = coll.update(ordered = false) val updates = builder.element(q = query, u = update, upsert = true, multi = false) updates.flatMap(d => builder.many(List(d))).map(_.writeErrors.isEmpty) } - def updateOne[T](query: JsObject, objToUpdate: T)(implicit oformat: OFormat[T]): Future[Boolean] = { + def updateOne[T](query: JsObject, objToUpdate: T)(implicit oformat: OFormat[T], writer: BSONDocumentWriter[T]): Future[Boolean] = { import json2bson._ - implicit val writer = implicitly[BSONDocumentWriter[T]] coll.update.one(query, objToUpdate).map(_.writeErrors.isEmpty) } @@ -75,6 +76,7 @@ object MongoOpsDataStore { )(implicit oformat: OFormat[T]): Future[(Seq[T], Long)] = { import json2bson._ import bson2json._ + import reactivemongo.play.json.compat.ExtendedJsonConverters.toDocument val search: Future[Seq[T]] = coll .find(query) .sort(sort) @@ -98,6 +100,7 @@ object MongoOpsDataStore { )(implicit oformat: OFormat[T]): Future[Seq[T]] = { import json2bson._ import bson2json._ + import reactivemongo.play.json.compat.ExtendedJsonConverters.toDocument coll .find(query) .sort(sort) diff --git a/nio-server/app/libs/io.scala b/nio-server/app/libs/io.scala index f5f43540..b08a2ec6 100644 --- a/nio-server/app/libs/io.scala +++ b/nio-server/app/libs/io.scala @@ -31,15 +31,6 @@ object io { }) } - def keep(predicate: A => Boolean, ifFalse: => E)(implicit ec: ExecutionContext): IO[E, A] = { - value.flatMap { a => - if (predicate(a)) { - EitherT.rightT[Future, E](a) - } else { - EitherT.leftT[Future, A](ifFalse) - } - } - } def keep(predicate: A => Boolean, ifFalse: A => E)(implicit ec: ExecutionContext): IO[E, A] = { value.flatMap { a => if (predicate(a)) { diff --git a/nio-server/app/models/Account.scala b/nio-server/app/models/Account.scala index 8646a94c..3554cc0c 100644 --- a/nio-server/app/models/Account.scala +++ b/nio-server/app/models/Account.scala @@ -8,7 +8,7 @@ import libs.xml.XmlUtil.XmlCleaner import libs.xml.implicits._ import libs.xml.syntax._ import java.time.{LocalDateTime, Clock} -import play.api.libs.functional.syntax.{unlift, _} +import play.api.libs.functional.syntax._ import play.api.libs.json.Reads._ import play.api.libs.json.{JsValue, _} import utils.DateUtils @@ -35,12 +35,12 @@ object OrganisationUser { implicit val read: Reads[OrganisationUser] = ( (__ \ "userId").read[String] and (__ \ "orgKey").read[String] - )(OrganisationUser.apply _) + )(OrganisationUser.apply) implicit val write: Writes[OrganisationUser] = ( (JsPath \ "userId").write[String] and (JsPath \ "orgKey").write[String] - )(unlift(OrganisationUser.unapply)) + )(o => (o.userId, o.orgKey)) implicit val format: Format[OrganisationUser] = Format(read, write) @@ -83,17 +83,15 @@ object Account extends ReadableEntity[Account] { implicit val read: Reads[Account] = ( (__ \ "accountId").read[String] and - (__ \ "lastUpdate") - .readWithDefault[LocalDateTime](LocalDateTime.now(Clock.systemUTC))(DateUtils.utcDateTimeReads) and + (__ \ "lastUpdate").readWithDefault[LocalDateTime](LocalDateTime.now(Clock.systemUTC))(DateUtils.utcDateTimeReads) and (__ \ "organisationsUsers").read[Seq[OrganisationUser]] - )(Account.apply _) + )(Account.apply) implicit val write: OWrites[Account] = ( (JsPath \ "accountId").write[String] and - (JsPath \ "lastUpdate") - .write[LocalDateTime](DateUtils.utcDateTimeWrites) and - (JsPath \ "organisationsUsers").write[Seq[OrganisationUser]] - )(unlift(Account.unapply)) + (JsPath \ "lastUpdate").write[LocalDateTime](DateUtils.utcDateTimeWrites) and + (JsPath \ "organisationsUsers").write[Seq[OrganisationUser]] + )(a => (a.accountId, a.lastUpdate, a.organisationsUsers)) implicit val format: Format[Account] = Format(read, write) implicit val oformat: OFormat[Account] = OFormat(read, write) diff --git a/nio-server/app/models/ApiKey.scala b/nio-server/app/models/ApiKey.scala index c27d4cae..ada61443 100644 --- a/nio-server/app/models/ApiKey.scala +++ b/nio-server/app/models/ApiKey.scala @@ -8,7 +8,7 @@ import libs.xml.XMLRead import libs.xml.XmlUtil.XmlCleaner import libs.xml.implicits._ import libs.xml.syntax._ -import play.api.libs.functional.syntax.{unlift, _} +import play.api.libs.functional.syntax._ import play.api.libs.json.Reads._ import play.api.libs.json.{JsValue, _} import reactivemongo.api.bson.BSONObjectID @@ -85,7 +85,7 @@ object ApiKey extends ReadableEntity[ApiKey] { (__ \ "clientId").read[String] and (__ \ "clientSecret").read[String] and (__ \ "offerRestrictionPatterns").readNullable[Seq[String]] - )(ApiKey.apply _) + )(ApiKey.apply) implicit val writeClean: Writes[ApiKey] = Writes { userAccount => Json.obj( @@ -97,18 +97,18 @@ object ApiKey extends ReadableEntity[ApiKey] { } implicit val write: Writes[ApiKey] = ( - (JsPath \ "_id").write[String] and + (JsPath \ "_id").write[String] and (JsPath \ "clientId").write[String] and (JsPath \ "clientSecret").write[String] and (JsPath \ "offerRestrictionPatterns").writeNullable[Seq[String]] - )(unlift(ApiKey.unapply)) + )(k => (k._id, k.clientId, k.clientSecret, k.offerRestrictionPatterns)) implicit val owrite: OWrites[ApiKey] = ( (JsPath \ "_id").write[String] and (JsPath \ "clientId").write[String] and (JsPath \ "clientSecret").write[String] and (JsPath \ "offerRestrictionPatterns").writeNullable[Seq[String]] - )(unlift(ApiKey.unapply)) + )(k => (k._id, k.clientId, k.clientSecret, k.offerRestrictionPatterns)) implicit val formats: Format[ApiKey] = Format(read, write) implicit val oformats: OFormat[ApiKey] = OFormat(read, owrite) diff --git a/nio-server/app/models/ConsentFact.scala b/nio-server/app/models/ConsentFact.scala index efece07e..2507ed37 100644 --- a/nio-server/app/models/ConsentFact.scala +++ b/nio-server/app/models/ConsentFact.scala @@ -1,23 +1,23 @@ package models -import cats.data.Validated._ -import cats.implicits._ +import cats.data.Validated.* +import cats.implicits.* import controllers.ReadableEntity import libs.xml.XMLRead import libs.xml.XmlUtil.XmlCleaner -import libs.xml.implicits._ -import libs.xml.syntax._ -import play.api.libs.functional.syntax.{unlift, _} -import play.api.libs.json.Reads._ -import play.api.libs.json._ +import libs.xml.implicits.* +import libs.xml.syntax.* +import play.api.libs.functional.syntax.* +import play.api.libs.json.Reads.* +import play.api.libs.json.* import reactivemongo.api.bson.BSONObjectID import utils.DateUtils import utils.Result.AppErrors -import utils.Result.AppErrors._ +import utils.Result.AppErrors.* import utils.json.JsResultOps import java.time.{Clock, LocalDateTime} -import scala.xml.{Elem, NodeSeq} +import scala.xml.{Elem, NodeBuffer, NodeSeq} import scala.collection.Seq case class Metadata(key: String, value: String) @@ -64,7 +64,7 @@ case class Consent(key: String, label: String, checked: Boolean, expiredAt: Opti {checked} - {expiredAt.map(l => {l.format(DateUtils.utcDateFormatter)})} + {expiredAt.map(l => {l.format(DateUtils.utcDateFormatter)}).getOrElse(new NodeBuffer())} .clean() } @@ -148,15 +148,15 @@ object ConsentOffer extends ReadableEntity[ConsentOffer] { (__ \ "version").read[Int] and (__ \ "lastUpdate").readWithDefault[LocalDateTime](LocalDateTime.now(Clock.systemUTC()))(DateUtils.utcDateTimeReads) and (__ \ "groups").read[Seq[ConsentGroup]] - )(ConsentOffer.apply _) + )(ConsentOffer.apply) implicit val offerWrites: Writes[ConsentOffer] = ( - (__ \ "key").write[String] and + (__ \ "key").write[String] and (__ \ "label").write[String] and (__ \ "version").write[Int] and (__ \ "lastUpdate").write[LocalDateTime](DateUtils.utcDateTimeWrites) and (__ \ "groups").write[Seq[ConsentGroup]] - )(unlift(ConsentOffer.unapply)) + )(o => (o.key, o.label, o.version, o.lastUpdate, o.groups)) implicit val offerOWrites: OWrites[ConsentOffer] = ( (__ \ "key").write[String] and @@ -164,7 +164,7 @@ object ConsentOffer extends ReadableEntity[ConsentOffer] { (__ \ "version").write[Int] and (__ \ "lastUpdate").write[LocalDateTime](DateUtils.utcDateTimeWrites) and (__ \ "groups").write[Seq[ConsentGroup]] - )(unlift(ConsentOffer.unapply)) + )(o => (o.key, o.label, o.version, o.lastUpdate, o.groups)) implicit val format: Format[ConsentOffer] = Format(offerReads, offerWrites) implicit val oformat: OFormat[ConsentOffer] = @@ -375,7 +375,7 @@ object PartialConsentFact extends ReadableEntity[PartialConsentFact] { override def fromXml(xml: Elem): Either[AppErrors, PartialConsentFact] = PartialConsentFact.partialConsentFactReadXml.read(xml).toEither - override def fromJson(json: JsValue): Either[AppErrors, PartialConsentFact] = PartialConsentFact.format.reads(json).toEither(AppErrors.fromJsError _ ) + override def fromJson(json: JsValue): Either[AppErrors, PartialConsentFact] = PartialConsentFact.format.reads(json).toEither(AppErrors.fromJsError) } // A user will have multiple consent facts @@ -439,14 +439,13 @@ case class ConsentFact( {orgKey.getOrElse("")} - { - if (metaData.isDefined) - metaData.map { md => - - {md.map(e => )} - - }.get - } + + {metaData.map { md => + + {md.map(e => )} + + }.getOrElse(new NodeBuffer()) + } .clean() case class KeyPermissionGroup(group: String, permission: String) @@ -542,7 +541,7 @@ object ConsentFact extends ReadableEntity[ConsentFact] { (__ \ "orgKey").readNullable[String] and (__ \ "metaData").readNullable[Map[String, String]] and (__ \ "sendToKafka").readNullable[Boolean] - )(ConsentFact.newWithoutIdAndLastUpdate _) + )(ConsentFact.newWithoutIdAndLastUpdate) private val consentFactReads: Reads[ConsentFact] = ( (__ \ "_id").read[String] and @@ -555,10 +554,10 @@ object ConsentFact extends ReadableEntity[ConsentFact] { (__ \ "lastUpdateSystem").read[LocalDateTime](DateUtils.utcDateTimeReads) and (__ \ "orgKey").readNullable[String] and (__ \ "metaData").readNullable[Map[String, String]] - )(ConsentFact.newWithoutKafkaFlag _) + )(ConsentFact.newWithoutKafkaFlag) private val consentFactWrites: Writes[ConsentFact] = ( - (JsPath \ "_id").write[String] and + (JsPath \ "_id").write[String] and (JsPath \ "userId").write[String] and (JsPath \ "doneBy").write[DoneBy](DoneBy.doneByFormats) and (JsPath \ "version").write[Int] and @@ -569,7 +568,7 @@ object ConsentFact extends ReadableEntity[ConsentFact] { (JsPath \ "orgKey").writeNullable[String] and (JsPath \ "metaData").writeNullable[Map[String, String]] and (JsPath \ "sendToKafka").writeNullable[Boolean] - )(unlift(ConsentFact.unapply)) + )(cf => (cf._id, cf.userId, cf.doneBy, cf.version, cf.groups, cf.offers, cf.lastUpdate, cf.lastUpdateSystem, cf.orgKey, cf.metaData, cf.sendToKafka)) private val consentFactWritesWithoutId: Writes[ConsentFact] = ( (JsPath \ "_id").writeNullable[String].contramap((_: String) => None) and @@ -583,7 +582,7 @@ object ConsentFact extends ReadableEntity[ConsentFact] { (JsPath \ "orgKey").writeNullable[String] and (JsPath \ "metaData").writeNullable[Map[String, String]] and (JsPath \ "sendToKafka").writeNullable[Boolean] - )(unlift(ConsentFact.unapply)) + )(cf => (cf._id, cf.userId, cf.doneBy, cf.version, cf.groups, cf.offers, cf.lastUpdate, cf.lastUpdateSystem, cf.orgKey, cf.metaData, cf.sendToKafka)) private val consentFactOWrites: OWrites[ConsentFact] = ( (JsPath \ "_id").write[String] and @@ -597,7 +596,7 @@ object ConsentFact extends ReadableEntity[ConsentFact] { (JsPath \ "orgKey").writeNullable[String] and (JsPath \ "metaData").writeNullable[Map[String, String]] and (JsPath \ "sendToKafka").writeNullable[Boolean] - )(unlift(ConsentFact.unapply)) + )(cf => (cf._id, cf.userId, cf.doneBy, cf.version, cf.groups, cf.offers, cf.lastUpdate, cf.lastUpdateSystem, cf.orgKey, cf.metaData, cf.sendToKafka)) val consentFactFormats: Format[ConsentFact] = Format(consentFactReads, consentFactWrites) implicit val consentFactOFormats: OFormat[ConsentFact] = OFormat(consentFactReads, consentFactOWrites) @@ -668,7 +667,7 @@ object ConsentFactCommand { object UpdateConsentFact { val format: OFormat[UpdateConsentFact] = OFormat[UpdateConsentFact]( ((__ \ "userId").read[String] and - (__ \ "command").read[ConsentFact](ConsentFact.consentFactReadsWithoutIdAndLastUpdate))(UpdateConsentFact.apply _), + (__ \ "command").read[ConsentFact](ConsentFact.consentFactReadsWithoutIdAndLastUpdate))(UpdateConsentFact.apply), Json.writes[UpdateConsentFact] ) } diff --git a/nio-server/app/models/DeletionTask.scala b/nio-server/app/models/DeletionTask.scala index 7d5c4f0d..a81e3119 100644 --- a/nio-server/app/models/DeletionTask.scala +++ b/nio-server/app/models/DeletionTask.scala @@ -19,6 +19,9 @@ object DeletionTaskStatus extends Enumeration { values.find(_.toString.toLowerCase == name.toLowerCase()).getOrElse(Unknown) implicit val deletionTaskStatusReads: Reads[DeletionTaskStatus] = (json: JsValue) => JsSuccess(DeletionTaskStatus.withName(json.as[String])) + implicit val deletionTaskStatusWrites: Writes[DeletionTaskStatus] = Writes { s => + JsString(s.toString) + } } case class AppDeletionState(appId: String, status: DeletionTaskStatus) { @@ -31,7 +34,7 @@ case class AppDeletionState(appId: String, status: DeletionTaskStatus) { .clean() } object AppDeletionState { - implicit val appDeletionStateFormats: OFormat[AppDeletionState] = Json.format[AppDeletionState] + implicit val appDeletionStateFormats: Format[AppDeletionState] = Json.format[AppDeletionState] } case class DeletionTaskInfoPerApp(orgKey: String, userId: String, appId: String, deletionTaskId: String) { @@ -88,7 +91,7 @@ case class DeletionTask( object DeletionTask { implicit val dateTimeFormats: Format[LocalDateTime] = DateUtils.utcDateTimeFormats - implicit val deletionTaskFormats: OFormat[DeletionTask] = Json.format[DeletionTask] + implicit val deletionTaskOFormats: OFormat[DeletionTask] = Json.format[DeletionTask] def newTask(orgKey: String, userId: String, appIds: Set[String]): DeletionTask = { val now = LocalDateTime.now(Clock.systemUTC) diff --git a/nio-server/app/models/NioAccount.scala b/nio-server/app/models/NioAccount.scala index c0fcf142..a0e4bac4 100644 --- a/nio-server/app/models/NioAccount.scala +++ b/nio-server/app/models/NioAccount.scala @@ -8,7 +8,7 @@ import libs.xml.XMLRead import libs.xml.XmlUtil.XmlCleaner import libs.xml.implicits._ import libs.xml.syntax._ -import play.api.libs.functional.syntax.{unlift, _} +import play.api.libs.functional.syntax._ import play.api.libs.json.Reads._ import play.api.libs.json.{JsValue, _} import reactivemongo.api.bson.BSONObjectID @@ -23,7 +23,7 @@ object NioAccountUpdate extends ReadableEntity[NioAccountUpdate] { implicit val read: Reads[NioAccountUpdate] = ( (__ \ "isAdmin").read[Boolean] and (__ \ "offerRestrictionPatterns").readNullable[Seq[String]] - )(NioAccountUpdate.apply _) + )(NioAccountUpdate.apply) implicit val readXml: XMLRead[NioAccountUpdate] = (node: NodeSeq, path: Option[String]) => @@ -98,7 +98,7 @@ object NioAccount extends ReadableEntity[NioAccount] { (__ \ "password").read[String] and (__ \ "isAdmin").read[Boolean] and (__ \ "offerRestrictionPatterns").readNullable[Seq[String]] - )(NioAccount.apply _) + )(NioAccount.apply) implicit val writeClean: Writes[NioAccount] = Writes { userAccount => Json.obj( @@ -115,7 +115,7 @@ object NioAccount extends ReadableEntity[NioAccount] { (JsPath \ "password").write[String] and (JsPath \ "isAdmin").write[Boolean] and (JsPath \ "offerRestrictionPatterns").writeNullable[Seq[String]] - )(unlift(NioAccount.unapply)) + )(a => (a._id, a.email, a.password, a.isAdmin, a.offerRestrictionPatterns)) implicit val owrite: OWrites[NioAccount] = ( (JsPath \ "_id").write[String] and @@ -123,7 +123,7 @@ object NioAccount extends ReadableEntity[NioAccount] { (JsPath \ "password").write[String] and (JsPath \ "isAdmin").write[Boolean] and (JsPath \ "offerRestrictionPatterns").writeNullable[Seq[String]] - )(unlift(NioAccount.unapply)) + )(a => (a._id, a.email, a.password, a.isAdmin, a.offerRestrictionPatterns)) implicit val formats: Format[NioAccount] = Format(read, write) implicit val oformats: OFormat[NioAccount] = OFormat(read, owrite) diff --git a/nio-server/app/models/Offer.scala b/nio-server/app/models/Offer.scala index b340a066..7ebd132e 100644 --- a/nio-server/app/models/Offer.scala +++ b/nio-server/app/models/Offer.scala @@ -6,7 +6,7 @@ import libs.xml.XMLRead import libs.xml.XmlUtil.XmlCleaner import libs.xml.implicits._ import libs.xml.syntax._ -import play.api.libs.functional.syntax.{unlift, _} +import play.api.libs.functional.syntax._ import play.api.libs.json.Reads._ import play.api.libs.json._ import utils.Result.{AppErrors, ErrorMessage, Result} @@ -41,21 +41,21 @@ object Offer extends ReadableEntity[Offer] { version.getOrElse(1) } and (__ \ "groups").read[Seq[PermissionGroup]] - )(Offer.apply _) + )(Offer.apply) implicit val offerWrites: Writes[Offer] = ( (__ \ "key").write[String] and (__ \ "label").write[String] and (__ \ "version").write[Int] and (__ \ "groups").write[Seq[PermissionGroup]] - )(unlift(Offer.unapply)) + )(o => (o.key, o.label, o.version, o.groups)) implicit val offerOWrites: OWrites[Offer] = ( (__ \ "key").write[String] and (__ \ "label").write[String] and (__ \ "version").write[Int] and (__ \ "groups").write[Seq[PermissionGroup]] - )(unlift(Offer.unapply)) + )(o => (o.key, o.label, o.version, o.groups)) implicit val format: Format[Offer] = Format(offerReads, offerWrites) implicit val oformat: OFormat[Offer] = OFormat(offerReads, offerOWrites) diff --git a/nio-server/app/models/Organisation.scala b/nio-server/app/models/Organisation.scala index e518e52b..6104b6c6 100644 --- a/nio-server/app/models/Organisation.scala +++ b/nio-server/app/models/Organisation.scala @@ -9,7 +9,7 @@ import libs.xml.XmlUtil.XmlCleaner import libs.xml.implicits._ import libs.xml.syntax._ import java.time.{LocalDateTime, Clock} -import play.api.libs.functional.syntax.{unlift, _} +import play.api.libs.functional.syntax._ import play.api.libs.json.Reads._ import play.api.libs.json._ import reactivemongo.api.bson.BSONObjectID @@ -208,17 +208,17 @@ object Organisation extends ReadableEntity[Organisation] { } and (__ \ "groups").read[Seq[PermissionGroup]] and (__ \ "offers").readNullable[Seq[Offer]] - )(Organisation.apply _) + )(Organisation.apply) implicit val organisationWrites: Writes[Organisation] = ( - (JsPath \ "_id").write[String] and + (JsPath \ "_id").write[String] and (JsPath \ "key").write[String] and (JsPath \ "label").write[String] and (JsPath \ "version").write[VersionInfo] and (JsPath \ "groups").write[Seq[PermissionGroup]] and (JsPath \ "offers").writeNullable[Seq[Offer]] - )(unlift(Organisation.unapply)) - + )(o => (o._id, o.key, o.label, o.version, o.groups, o.offers)) + implicit val organisationOWrites: OWrites[Organisation] = ( (JsPath \ "_id").write[String] and (JsPath \ "key").write[String] and @@ -226,7 +226,7 @@ object Organisation extends ReadableEntity[Organisation] { (JsPath \ "version").write[VersionInfo] and (JsPath \ "groups").write[Seq[PermissionGroup]] and (JsPath \ "offers").writeNullable[Seq[Offer]] - )(unlift(Organisation.unapply)) + )(o => (o._id, o.key, o.label, o.version, o.groups, o.offers)) implicit val formats: Format[Organisation] = Format(organisationReads, organisationWrites) diff --git a/nio-server/app/models/Permission.scala b/nio-server/app/models/Permission.scala index a40aa82e..6c74c7a5 100644 --- a/nio-server/app/models/Permission.scala +++ b/nio-server/app/models/Permission.scala @@ -1,21 +1,21 @@ package models import cats.data.Validated -import cats.data.Validated._ -import cats.implicits._ +import cats.data.Validated.* +import cats.implicits.* import libs.xml.XMLRead import libs.xml.XmlUtil.XmlCleaner -import libs.xml.implicits._ -import libs.xml.syntax._ -import play.api.libs.functional.syntax._ -import play.api.libs.json._ -import play.api.libs.json.Reads._ +import libs.xml.implicits.* +import libs.xml.syntax.* +import play.api.libs.functional.syntax.* +import play.api.libs.json.* +import play.api.libs.json.Reads.* import utils.Result.AppErrors import java.time.{Clock, LocalDateTime, ZoneId} import scala.concurrent.duration.{Duration, FiniteDuration} import scala.util.{Failure, Success, Try} -import scala.xml.{Elem, NodeSeq} +import scala.xml.{Elem, NodeBuffer, NodeSeq} sealed trait PermissionType { def print : String = this match { @@ -68,7 +68,7 @@ case class Permission(key: String, label: String, `type`: PermissionType = OptIn {key} {`type`.print} - {validityPeriod.map(p => p.toString())} + {validityPeriod.map(p => {p.toString}).getOrElse(new NodeBuffer())} .clean() } @@ -106,7 +106,7 @@ object Permission { (__ \ "label").read[String] and (__ \ "type").read[PermissionType].orElse(Reads.pure(OptIn)) and (__ \ "validityPeriod").readNullable[FiniteDuration] - )(Permission.apply _), + )(Permission.apply), Json.writes[Permission] ) diff --git a/nio-server/app/models/UserExtractTask.scala b/nio-server/app/models/UserExtractTask.scala index 671eca7f..b86aadcc 100644 --- a/nio-server/app/models/UserExtractTask.scala +++ b/nio-server/app/models/UserExtractTask.scala @@ -6,7 +6,7 @@ import libs.xml.XMLRead import libs.xml.XmlUtil.XmlCleaner import libs.xml.implicits._ import libs.xml.syntax._ -import play.api.libs.functional.syntax.{unlift, _} +import play.api.libs.functional.syntax._ import play.api.libs.json.Reads._ import play.api.libs.json.Writes._ import play.api.libs.json._ @@ -88,10 +88,10 @@ object UserExtractTask extends ReadableEntity[UserExtractTask] { } and (__ \ "uploadStartedAt").readNullable[LocalDateTime] and (__ \ "endedAt").readNullable[LocalDateTime] - )(UserExtractTask.apply _) + )(UserExtractTask.apply) implicit val userExtractTaskWrites: Writes[UserExtractTask] = ( - (JsPath \ "_id").write[String] and + (JsPath \ "_id").write[String] and (JsPath \ "tenant").write[String] and (JsPath \ "orgKey").write[String] and (JsPath \ "userId").write[String] and @@ -99,7 +99,7 @@ object UserExtractTask extends ReadableEntity[UserExtractTask] { (JsPath \ "startedAt").write[LocalDateTime] and (JsPath \ "uploadStartedAt").writeNullable[LocalDateTime] and (JsPath \ "endedAt").writeNullable[LocalDateTime] - )(unlift(UserExtractTask.unapply)) + )(ue => (ue._id, ue.tenant, ue.orgKey, ue.userId, ue.email, ue.startedAt, ue.uploadStartedAt, ue.endedAt)) implicit val userExtractTaskOWrites: OWrites[UserExtractTask] = ( (JsPath \ "_id").write[String] and @@ -110,7 +110,7 @@ object UserExtractTask extends ReadableEntity[UserExtractTask] { (JsPath \ "startedAt").write[LocalDateTime] and (JsPath \ "uploadStartedAt").writeNullable[LocalDateTime] and (JsPath \ "endedAt").writeNullable[LocalDateTime] - )(unlift(UserExtractTask.unapply)) + )(ue => (ue._id, ue.tenant, ue.orgKey, ue.userId, ue.email, ue.startedAt, ue.uploadStartedAt, ue.endedAt)) implicit val format: Format[UserExtractTask] = Format(userExtractTaskReads, userExtractTaskWrites) implicit val oformat: OFormat[UserExtractTask] = OFormat(userExtractTaskReads, userExtractTaskOWrites) diff --git a/nio-server/app/models/events.scala b/nio-server/app/models/events.scala index d9e1ecca..a8b21c3a 100644 --- a/nio-server/app/models/events.scala +++ b/nio-server/app/models/events.scala @@ -8,7 +8,7 @@ import utils.{DateUtils, IdGenerator} import scala.collection.Seq object EventType extends Enumeration { - type WeekDay = Value + type EventType = Value val TenantCreated, TenantDeleted, OrganisationCreated, OrganisationUpdated, OrganisationReleased, OrganisationDeleted, ConsentFactCreated, ConsentFactUpdated, AccountCreated, AccountUpdated, AccountDeleted, SecuredEvent, DeletionStarted, DeletionAppDone, DeletionFinished, ExtractionStarted, ExtractionAppFilesMetadataReceived, @@ -17,10 +17,12 @@ object EventType extends Enumeration { def from(name: String): Value = values.find(_.toString.toLowerCase == name.toLowerCase()).getOrElse(Unknown) + + implicit val format: Format[EventType] = Json.formatEnum(this) } object NioEvent { - val gen = IdGenerator(1024) + val gen: IdGenerator = IdGenerator(1024) def fromJson(json: JsValue): Option[NioEvent] = for { @@ -165,7 +167,7 @@ case class TenantCreated( def `type`: EventType.Value = EventType.TenantCreated - def asJson(): JsObject = + def asJson(): JsObject = { Json .obj( "type" -> `type`, @@ -177,6 +179,7 @@ case class TenantCreated( "payload" -> payload.asJson() ) .cleanMetadata() + } } case class TenantDeleted( @@ -191,7 +194,7 @@ case class TenantDeleted( def `type`: EventType.Value = EventType.TenantDeleted - def asJson(): JsObject = + def asJson(): JsObject = { Json .obj( "type" -> `type`, @@ -203,6 +206,7 @@ case class TenantDeleted( "payload" -> payload.asJson() ) .cleanMetadata() + } } case class OrganisationCreated( diff --git a/nio-server/app/service/ConsentManagerService.scala b/nio-server/app/service/ConsentManagerService.scala index a117f2bd..bc0431ca 100644 --- a/nio-server/app/service/ConsentManagerService.scala +++ b/nio-server/app/service/ConsentManagerService.scala @@ -330,7 +330,7 @@ class ConsentManagerService( NioLogger.error( s"error.version.higher.than.release : last version saved ${lastConsentFactStored.version} -> version specified ${consentFact.version}" ) - AppErrorWithStatus("error.version.higher.than.release") + _ => AppErrorWithStatus("error.version.higher.than.release") }) .flatMap { organisation => createOrReplace(tenant, author, metadata, organisation, consentFact, Option(lastConsentFactStored), command = command) diff --git a/nio-server/app/utils/S3Manager.scala b/nio-server/app/utils/S3Manager.scala index 45c0d0ab..50448cf0 100644 --- a/nio-server/app/utils/S3Manager.scala +++ b/nio-server/app/utils/S3Manager.scala @@ -33,7 +33,7 @@ trait FSUserExtractManager { userId: String, extractTaskId: String, name: String, - src: Source[ByteString, _] + src: Source[ByteString, ?] )(implicit s3ExecutionContext: S3ExecutionContext): Future[String] def getUploadedFile(tenant: String, orgKey: String, userId: String, extractTaskId: String, name: String)(implicit @@ -139,7 +139,7 @@ class S3Manager(env: Env, actorSystem: ActorSystem) extends FSManager with FSUse userId: String, extractTaskId: String, name: String, - src: Source[ByteString, _] + src: Source[ByteString, ?] )(implicit s3ExecutionContext: S3ExecutionContext): Future[String] = { val bucketName = s3Config.uploadBucketName diff --git a/nio-server/build.sbt b/nio-server/build.sbt index 9f53de79..1ccb2264 100644 --- a/nio-server/build.sbt +++ b/nio-server/build.sbt @@ -40,7 +40,9 @@ libraryDependencies ++= Seq( "org.apache.commons" % "commons-lang3" % "3.11", "de.svenkubiak" % "jBCrypt" % "0.4.1", // ISC/BSD "com.auth0" % "java-jwt" % javaJwt, // MIT license - "com.github.pureconfig" %% "pureconfig" % pureConfig, // Apache 2.0 +// "com.github.pureconfig" %% "pureconfig" % pureConfig, // Apache 2.0 + "com.github.pureconfig" %% "pureconfig-core" % pureConfig, // Apache 2.0 + "com.github.pureconfig" %% "pureconfig-generic-scala3" % pureConfig, // Apache 2.0 "org.scalactic" %% "scalactic" % scalaticVersion, // Apache 2.0 "org.webjars" % "swagger-ui" % "3.12.1", "org.typelevel" %% "cats-core" % catsVersion, // MIT diff --git a/nio-server/test/controllers/ConsentControllerSpec.scala b/nio-server/test/controllers/ConsentControllerSpec.scala index 3174d4e7..36aa31cc 100644 --- a/nio-server/test/controllers/ConsentControllerSpec.scala +++ b/nio-server/test/controllers/ConsentControllerSpec.scala @@ -3,7 +3,7 @@ package controllers import org.apache.pekko.japi.Option import models._ -import java.time.{Clock, LocalDateTime, ZoneId} +import java.time.{Clock, LocalDateTime} import utils.NioLogger import play.api.libs.json.{JsArray, JsObject, JsValue, Json} import play.api.libs.ws.WSResponse @@ -11,7 +11,6 @@ import utils.{DateUtils, TestUtils} import play.api.test.Helpers._ import java.time.format.DateTimeFormatter -import scala.concurrent.duration.DurationInt class ConsentControllerSpec extends TestUtils { @@ -506,7 +505,7 @@ class ConsentControllerSpec extends TestUtils { ) ) )) - ).map(Json.stringify _).mkString("", "\n", "\n") + ).map(Json.stringify).mkString("", "\n", "\n") val response = postText(s"/$tenant/organisations/$organisationKey/users/_batch", commands) println(response.body) diff --git a/nio-server/test/controllers/EventControllerSpec.scala b/nio-server/test/controllers/EventControllerSpec.scala index 5e1cabd1..5df93c8d 100644 --- a/nio-server/test/controllers/EventControllerSpec.scala +++ b/nio-server/test/controllers/EventControllerSpec.scala @@ -3,7 +3,7 @@ package controllers import java.util.concurrent.atomic.AtomicBoolean import org.apache.pekko.actor.ActorSystem -import org.apache.pekko.stream.{Materializer, ActorMaterializer} +import org.apache.pekko.stream.Materializer import play.api.libs.json.Json import play.api.libs.ws.WSResponse import play.api.test.Helpers._ @@ -42,7 +42,7 @@ class EventControllerSpec extends TestUtils { val isOk = new AtomicBoolean(false) ws.url(s"$apiPath/$tenant1/events") - .withHttpHeaders(jsonHeaders: _*) + .withHttpHeaders(jsonHeaders*) .withMethod("GET") .withRequestTimeout(Duration.Inf) .stream() diff --git a/nio-server/test/controllers/ExtractionControllerSpec.scala b/nio-server/test/controllers/ExtractionControllerSpec.scala index 1daa56a3..50836d6e 100644 --- a/nio-server/test/controllers/ExtractionControllerSpec.scala +++ b/nio-server/test/controllers/ExtractionControllerSpec.scala @@ -12,8 +12,8 @@ import java.util.concurrent.TimeUnit import org.apache.pekko.stream.scaladsl.FileIO import com.amazonaws.services.s3.AmazonS3 import play.api.libs.ws.SourceBody -import s3.{S3, S3Configuration} +import play.api.libs.ws.writeableOf_WsBody import scala.concurrent.Await import scala.concurrent.duration.Duration diff --git a/nio-server/test/controllers/OrganisationControllerSpec.scala b/nio-server/test/controllers/OrganisationControllerSpec.scala index 98bb6190..704e0f78 100644 --- a/nio-server/test/controllers/OrganisationControllerSpec.scala +++ b/nio-server/test/controllers/OrganisationControllerSpec.scala @@ -1,14 +1,13 @@ package controllers -import models._ +import models.* import java.time.{Clock, LocalDateTime} -import utils.{DateUtils, NioLogger, TestUtils} +import utils.{DateUtils, TestUtils} import play.api.libs.json.{JsArray, JsValue, Json} import play.api.libs.ws.WSResponse -import play.api.test.Helpers._ +import play.api.test.Helpers.* -import java.time.format.DateTimeFormatter import scala.concurrent.duration.DurationInt class OrganisationControllerSpec extends TestUtils { diff --git a/nio-server/test/controllers/UserExtractControllerSpec.scala b/nio-server/test/controllers/UserExtractControllerSpec.scala index 03cfeb20..c57ce040 100644 --- a/nio-server/test/controllers/UserExtractControllerSpec.scala +++ b/nio-server/test/controllers/UserExtractControllerSpec.scala @@ -5,25 +5,18 @@ import java.nio.charset.StandardCharsets import java.nio.file.Files import java.util.concurrent.TimeUnit -import org.apache.pekko.NotUsed -import org.apache.pekko.http.scaladsl.model.Multipart.BodyPart import org.apache.pekko.stream.scaladsl.{FileIO, Source} import models.{Organisation, Permission, PermissionGroup, UserExtract} -import org.apache.http.entity.ContentType -import org.apache.http.entity.mime.MultipartEntityBuilder import play.api.libs.json.{JsArray, JsValue} -import play.api.libs.ws.SourceBody -import utils.NioLogger import play.api.mvc.MultipartFormData -import play.api.mvc.MultipartFormData.{DataPart, FilePart} +import play.api.mvc.MultipartFormData.FilePart import play.api.test.Helpers._ -import play.mvc.BodyParser.MultipartFormData -import play.shaded.ahc.org.asynchttpclient.request.body.multipart.StringPart import play.shaded.ahc.org.asynchttpclient.request.body.multipart.part.StringMultipartPart import utils.TestUtils import scala.concurrent.Await import scala.concurrent.duration.Duration +import play.api.libs.ws.bodyWritableOf_Multipart class UserExtractControllerSpec extends TestUtils { diff --git a/nio-server/test/models/ModelValidationSpec.scala b/nio-server/test/models/ModelValidationSpec.scala index 5cf909fd..668383d1 100644 --- a/nio-server/test/models/ModelValidationSpec.scala +++ b/nio-server/test/models/ModelValidationSpec.scala @@ -1,13 +1,13 @@ package models -import java.time.{LocalDateTime, Clock} +import java.time.{Clock, LocalDateTime} import org.scalatest.matchers.must.Matchers import org.scalatest.wordspec.AnyWordSpecLike import play.api.libs.json.JsValue import utils.DateUtils import utils.Result.AppErrors -import scala.xml.Elem +import scala.xml.{Elem, NodeBuffer} class ModelValidationSpec extends AnyWordSpecLike with Matchers { @@ -72,9 +72,7 @@ class ModelValidationSpec extends AnyWordSpecLike with Matchers { "xml serialize/deserialize" in { val xml: Elem = consentFact.asXml() - val consentFactEither: Either[AppErrors, ConsentFact] = - ConsentFact.fromXml(xml) - + val consentFactEither: Either[AppErrors, ConsentFact] = ConsentFact.fromXml(xml) consentFactEither.isRight must be(true) val consentFactFromXml: ConsentFact = consentFactEither.toOption.get @@ -152,13 +150,11 @@ class ModelValidationSpec extends AnyWordSpecLike with Matchers { {consentFact.lastUpdate.format(DateUtils.utcDateFormatter)} {consentFact.orgKey.getOrElse("")} - { - if (consentFact.metaData.isDefined) - consentFact.metaData.map { md => + {consentFact.metaData.map { md => {md.map(e => )} - }.get + }.getOrElse(new NodeBuffer()) } @@ -194,8 +190,7 @@ class ModelValidationSpec extends AnyWordSpecLike with Matchers { consentFact.orgKey.get must be("orgKey") - consentFact.metaData.get.toSeq.head must be("key1", "value1") - consentFact.metaData.get.toSeq(1) must be("key2", "value2") + consentFact.metaData must be(Some(Map("key1" -> "value1", "key2" -> "value2"))) } } diff --git a/nio-server/test/models/OrganisationSpec.scala b/nio-server/test/models/OrganisationSpec.scala index 584809a6..5cd1caab 100644 --- a/nio-server/test/models/OrganisationSpec.scala +++ b/nio-server/test/models/OrganisationSpec.scala @@ -132,7 +132,7 @@ class OrganisationSpec extends PlaySpec with AnyWordSpecLike { ) val json = org.asJson() -println(Json.prettyPrint(json)) + println(Json.prettyPrint(json)) val fromJson = Organisation.fromJson(json) fromJson.map(_.key) mustBe Right(org.key) @@ -219,9 +219,10 @@ println(Json.prettyPrint(json)) ) val xml = org.asXml() - + println(xml) val fromXml = Organisation.fromXml(xml) + println(fromXml) fromXml.map(_.key) mustBe Right(org.key) } diff --git a/nio-server/test/utils/TestUtils.scala b/nio-server/test/utils/TestUtils.scala index 6add3c1a..a1e72d24 100644 --- a/nio-server/test/utils/TestUtils.scala +++ b/nio-server/test/utils/TestUtils.scala @@ -5,22 +5,19 @@ import java.util.UUID import java.util.concurrent.TimeUnit import java.{lang, util} import org.apache.pekko.actor.ActorSystem -import org.apache.pekko.http.scaladsl.model.HttpEntity import org.apache.pekko.kafka.scaladsl.Consumer import org.apache.pekko.kafka.{ConsumerSettings, Subscriptions} -import org.apache.pekko.stream.{ActorMaterializer, Materializer} +import org.apache.pekko.stream.Materializer import org.apache.pekko.stream.scaladsl.Sink import com.amazonaws.services.s3.model.PutObjectResult import com.typesafe.config.{Config, ConfigFactory} import filters.AuthInfoMock -import loader.NioLoader import models.Tenant import org.apache.kafka.clients.consumer.ConsumerConfig import org.apache.kafka.common.TopicPartition import org.apache.kafka.common.serialization.{ByteArrayDeserializer, StringDeserializer} import org.scalatest._ import org.scalatest.matchers.must -import org.scalatest.time.SpanSugar.convertIntToGrainOfTime import org.scalatest.wordspec.AnyWordSpecLike import org.scalatestplus.play.{BaseOneServerPerSuite, FakeApplicationFactory, PlaySpec} import play.api.inject.DefaultApplicationLifecycle @@ -28,7 +25,6 @@ import play.api.libs.json.{JsValue, Json} import play.api.libs.ws.{BodyWritable, WSClient, WSResponse} import play.api.test.Helpers._ import play.api.{Application, ApplicationLoader, Configuration, Environment} -import play.core.DefaultWebCommands import play.modules.reactivemongo.ReactiveMongoApi import reactivemongo.api.bson.collection.BSONCollection import service.ConsentManagerService @@ -36,6 +32,7 @@ import service.ConsentManagerService import scala.concurrent.duration._ import scala.concurrent.{Await, ExecutionContext, Future} import scala.xml.Elem +import play.api.libs.ws.DefaultBodyWritables._ class MockS3Manager extends FSManager { override def addFile(key: String, content: String)(implicit @@ -56,8 +53,8 @@ trait TestUtils with BeforeAndAfterEach with BeforeAndAfterAll { - protected implicit val actorSystem = ActorSystem("test") - protected implicit val materializer = Materializer(actorSystem) + protected implicit val actorSystem: ActorSystem = ActorSystem("test") + protected implicit val materializer: Materializer = Materializer(actorSystem) def kafkaPort: Int = 9092 def mongoPort: Int = 27018 @@ -131,7 +128,6 @@ trait TestUtils val reactiveMongoApi: ReactiveMongoApi = nioComponents.reactiveMongoApi import play.api.libs.json._ - import reactivemongo.api.bson._ import reactivemongo.play.json.compat._ def delete(query: JsObject)(coll: BSONCollection): Future[Boolean] = { @@ -250,23 +246,23 @@ trait TestUtils val futureResponse = httpVerb match { case GET => ws.url(s"$suffix$path") - .withHttpHeaders(headers: _*) + .withHttpHeaders(headers*) .get() case DELETE => ws.url(s"$suffix$path") - .withHttpHeaders(headers: _*) + .withHttpHeaders(headers*) .delete() case POST => ws.url(s"$suffix$path") - .withHttpHeaders(headers: _*) + .withHttpHeaders(headers*) .post(body) case PUT => ws.url(s"$suffix$path") - .withHttpHeaders(headers: _*) + .withHttpHeaders(headers*) .put(body) case PATCH => ws.url(s"$suffix$path") - .withHttpHeaders(headers: _*) + .withHttpHeaders(headers*) .patch(body) case _ => Future.failed(new IllegalArgumentException(s"Unknown http verb: $httpVerb")) @@ -274,42 +270,58 @@ trait TestUtils Await.result[WSResponse](futureResponse, Duration(10, TimeUnit.SECONDS)) } - def postJson(path: String, body: JsValue, headers: Seq[(String, String)] = jsonHeaders) = + def postJson(path: String, body: JsValue, headers: Seq[(String, String)] = jsonHeaders): WSResponse = { + import play.api.libs.ws.writeableOf_JsValue callByType[JsValue](path = path, httpVerb = POST, body = body, headers = headers) + } - def postText(path: String, body: String, headers: Seq[(String, String)] = jsonHeaders) = + def postText(path: String, body: String, headers: Seq[(String, String)] = jsonHeaders): WSResponse = callByType[String](path = path, httpVerb = POST, body = body, headers = headers) - def postBinaryFile(path: String, body: File, api: Boolean = true, headers: Seq[(String, String)] = jsonHeaders) = { + def postBinaryFile(path: String, body: File, api: Boolean = true, headers: Seq[(String, String)] = jsonHeaders): WSResponse = { val suffix = if (api) apiPath else serverHost val futureResponse = ws .url(s"$suffix$path") - .withHttpHeaders(headers: _*) + .withHttpHeaders(headers*) .post(body) Await.result[WSResponse](futureResponse, Duration(10, TimeUnit.SECONDS)) } - def getJson(path: String, headers: Seq[(String, String)] = jsonHeaders) = + def getJson(path: String, headers: Seq[(String, String)] = jsonHeaders): WSResponse = { + import play.api.libs.ws.writeableOf_JsValue callByType[JsValue](path = path, httpVerb = GET, headers = headers) + } - def putJson(path: String, body: JsValue, headers: Seq[(String, String)] = jsonHeaders) = + def putJson(path: String, body: JsValue, headers: Seq[(String, String)] = jsonHeaders): WSResponse = { + import play.api.libs.ws.writeableOf_JsValue callByType[JsValue](path = path, httpVerb = PUT, body = body, headers = headers) + } - def patchJson(path: String, body: JsValue, headers: Seq[(String, String)] = jsonHeaders) = + def patchJson(path: String, body: JsValue, headers: Seq[(String, String)] = jsonHeaders): WSResponse = { + import play.api.libs.ws.writeableOf_JsValue callByType[JsValue](path = path, httpVerb = PATCH, body = body, headers = headers) + } - def delete(path: String, headers: Seq[(String, String)] = jsonHeaders) = + def delete(path: String, headers: Seq[(String, String)] = jsonHeaders): WSResponse = { + import play.api.libs.ws.writeableOf_JsValue callByType[JsValue](path = path, httpVerb = DELETE, headers = headers) + } - def postXml(path: String, body: Elem, headers: Seq[(String, String)] = xmlHeaders) = + def postXml(path: String, body: Elem, headers: Seq[(String, String)] = xmlHeaders): WSResponse = { + import play.api.libs.ws.writeableOf_NodeSeq callByType[Elem](path = path, httpVerb = POST, body = body, headers = headers) + } - def getXml(path: String, headers: Seq[(String, String)] = xmlHeaders) = + def getXml(path: String, headers: Seq[(String, String)] = xmlHeaders): WSResponse = { + import play.api.libs.ws.writeableOf_NodeSeq callByType[Elem](path = path, httpVerb = GET, headers = headers) + } - def putXml(path: String, body: Elem, headers: Seq[(String, String)] = xmlHeaders) = + def putXml(path: String, body: Elem, headers: Seq[(String, String)] = xmlHeaders): WSResponse = { + import play.api.libs.ws.writeableOf_NodeSeq callByType[Elem](path = path, httpVerb = PUT, body = body, headers = headers) + } protected def callJson( path: String, @@ -320,8 +332,10 @@ trait TestUtils ACCEPT -> JSON, CONTENT_TYPE -> JSON ) - ): WSResponse = + ): WSResponse = { + import play.api.libs.ws.writeableOf_JsValue callByType[JsValue](path, httpVerb, body, api, headers) + } protected def callXml( path: String, @@ -332,6 +346,8 @@ trait TestUtils ACCEPT -> XML, CONTENT_TYPE -> XML ) - ): WSResponse = + ): WSResponse = { + import play.api.libs.ws.writeableOf_NodeSeq callByType[Elem](path, httpVerb, body, api, headers) + } } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 21c79150..a7b573be 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -1,16 +1,17 @@ object Dependencies { - val _scalaVersion = "2.13.15" + val _scalaVersion = "3.4.3" +// val _scalaVersion = "2.13.15" val reactiveMongoVersion = "1.1.0" val pekko = "1.1.1" val pekkoKafka = "1.1.0" - val pureConfig = "0.14.0" - val scalaticVersion = "3.2.0" - val catsVersion = "2.2.0" - val macwireVersion = "2.3.7" + val pekkoS3Version = "1.0.2" + val pureConfig = "0.17.7" + val scalaticVersion = "3.2.19" + val catsVersion = "2.12.0" + val macwireVersion = "2.6.2" val metricsVersion = "4.0.2" - val pekkoS3Version = "1.0.2" val scalatestPlay = "7.0.1" val javaJwt = "3.11.0" }