diff --git a/build.sbt b/build.sbt index dd7b6b681d..add70f9eae 100644 --- a/build.sbt +++ b/build.sbt @@ -17,11 +17,18 @@ ThisBuild / semanticdbVersion := "4.13.9" // Fix dependency conflicts ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always +ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-java8-compat" % VersionScheme.Always lazy val liftVersion = "3.5.0" lazy val akkaVersion = "2.5.32" lazy val jettyVersion = "9.4.50.v20221201" lazy val avroVersion = "1.8.2" +lazy val pekkoVersion = "1.4.0" +lazy val pekkoHttpVersion = "1.3.0" +lazy val http4sVersion = "0.23.30" +lazy val catsEffectVersion = "3.5.7" +lazy val ip4sVersion = "3.7.0" +lazy val jakartaMailVersion = "2.0.1" lazy val commonSettings = Seq( resolvers ++= Seq( @@ -42,8 +49,8 @@ lazy val obpCommons = (project in file("obp-commons")) "net.liftweb" %% "lift-util" % liftVersion, "net.liftweb" %% "lift-mapper" % liftVersion, "org.scala-lang" % "scala-reflect" % "2.12.20", - "org.scalatest" %% "scalatest" % "3.2.15" % Test, - "org.scalactic" %% "scalactic" % "3.2.15", + "org.scalatest" %% "scalatest" % "3.0.9" % Test, + "org.scalactic" %% "scalactic" % "3.0.9", "net.liftweb" %% "lift-json" % liftVersion, "com.alibaba" % "transmittable-thread-local" % "2.11.5", "org.apache.commons" % "commons-lang3" % "3.12.0", @@ -95,6 +102,20 @@ lazy val obpApi = (project in file("obp-api")) "com.typesafe.akka" %% "akka-remote" % akkaVersion, "com.typesafe.akka" %% "akka-slf4j" % akkaVersion, "com.typesafe.akka" %% "akka-http-core" % "10.1.6", + + // Pekko (ActorSystem + Pekko HTTP used by OBP runtime components) + "org.apache.pekko" %% "pekko-actor" % pekkoVersion, + "org.apache.pekko" %% "pekko-remote" % pekkoVersion, + "org.apache.pekko" %% "pekko-slf4j" % pekkoVersion, + "org.apache.pekko" %% "pekko-stream" % pekkoVersion, + "org.apache.pekko" %% "pekko-http" % pekkoHttpVersion, + + // http4s (v7.0.0 experimental stack) + "org.typelevel" %% "cats-effect" % catsEffectVersion, + "com.comcast" %% "ip4s-core" % ip4sVersion, + "org.http4s" %% "http4s-core" % http4sVersion, + "org.http4s" %% "http4s-dsl" % http4sVersion, + "org.http4s" %% "http4s-ember-server" % http4sVersion, // Avro "com.sksamuel.avro4s" %% "avro4s-core" % avroVersion, @@ -164,6 +185,9 @@ lazy val obpApi = (project in file("obp-api")) // RabbitMQ "com.rabbitmq" % "amqp-client" % "5.22.0", "net.liftmodules" %% "amqp_3.1" % "1.5.0", + + // Blockchain (Ethereum raw transaction decoding) + "org.web3j" % "core" % "4.14.0", // Elasticsearch "org.elasticsearch" % "elasticsearch" % "8.14.0", @@ -175,6 +199,7 @@ lazy val obpApi = (project in file("obp-api")) // Utilities "cglib" % "cglib" % "3.3.0", "com.sun.activation" % "jakarta.activation" % "1.2.2", + "com.sun.mail" % "jakarta.mail" % jakartaMailVersion, "com.nulab-inc" % "zxcvbn" % "1.9.0", // Testing - temporarily disabled due to version incompatibility @@ -192,7 +217,7 @@ lazy val obpApi = (project in file("obp-api")) // Test dependencies "junit" % "junit" % "4.13.2" % Test, - "org.scalatest" %% "scalatest" % "3.2.15" % Test, + "org.scalatest" %% "scalatest" % "3.0.9" % Test, "org.seleniumhq.selenium" % "htmlunit-driver" % "2.36.0" % Test, "org.testcontainers" % "rabbitmq" % "1.20.3" % Test ) diff --git a/obp-api/src/main/scala/code/api/AUOpenBanking/v1_0_0/ApiCollector.scala b/obp-api/src/main/scala/code/api/AUOpenBanking/v1_0_0/ApiCollector.scala index d8fea1182f..12e75972be 100644 --- a/obp-api/src/main/scala/code/api/AUOpenBanking/v1_0_0/ApiCollector.scala +++ b/obp-api/src/main/scala/code/api/AUOpenBanking/v1_0_0/ApiCollector.scala @@ -35,7 +35,7 @@ import code.api.OBPRestHelper import code.api.util.APIUtil.{OBPEndpoint, ResourceDoc, getAllowedEndpoints} import code.api.util.ScannedApis import code.util.Helper.MdcLoggable -import com.openbankproject.commons.util.{ApiVersionStatus, ScannedApiVersion} +import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus} import scala.collection.mutable.ArrayBuffer @@ -47,7 +47,7 @@ This file defines which endpoints from all the versions are available in v1 */ object ApiCollector extends OBPRestHelper with MdcLoggable with ScannedApis { //please modify these three parameter if it is not correct. - override val apiVersion = ScannedApiVersion("cds-au", "AU", "v1.0.0") + override val apiVersion = ApiVersion.auOpenBankingV100 val versionStatus = ApiVersionStatus.DRAFT.toString private[this] val endpoints = diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala index ff5422cff8..5c0148ce2d 100644 --- a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala @@ -35,7 +35,7 @@ import code.api.OBPRestHelper import code.api.util.APIUtil.{OBPEndpoint, ResourceDoc, getAllowedEndpoints} import code.api.util.{ScannedApis} import code.util.Helper.MdcLoggable -import com.openbankproject.commons.util.{ApiVersionStatus, ScannedApiVersion} +import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus} import scala.collection.mutable.ArrayBuffer @@ -45,7 +45,7 @@ import scala.collection.mutable.ArrayBuffer This file defines which endpoints from all the versions are available in v1 */ object ApiCollector extends OBPRestHelper with MdcLoggable with ScannedApis { - override val apiVersion = ScannedApiVersion("BAHRAIN-OBF", "BAHRAIN-OBF", "v1.0.0") + override val apiVersion = ApiVersion.bahrainObfV100 val versionStatus = ApiVersionStatus.DRAFT.toString private[this] val endpoints = diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocs140.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocs140.scala index 1a5d8bebc0..bec0f2adeb 100644 --- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocs140.scala +++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocs140.scala @@ -149,6 +149,7 @@ object ResourceDocs300 extends OBPRestHelper with ResourceDocsAPIMethods with Md object ResourceDocs600 extends OBPRestHelper with ResourceDocsAPIMethods with MdcLoggable { val version: ApiVersion = ApiVersion.v6_0_0 val versionStatus = ApiVersionStatus.BLEEDING_EDGE.toString + override def includeTechnologyInResponse: Boolean = true val routes: Seq[OBPEndpoint] = List( ImplementationsResourceDocs.getResourceDocsObpV400, ImplementationsResourceDocs.getResourceDocsSwagger, @@ -206,7 +207,7 @@ object ResourceDocs300 extends OBPRestHelper with ResourceDocsAPIMethods with Md case _ if (apiCollectionIdParam.isDefined) => val operationIds = MappedApiCollectionEndpointsProvider.getApiCollectionEndpoints(apiCollectionIdParam.getOrElse("")).map(_.operationId).map(getObpFormatOperationId) val resourceDocs = ResourceDoc.getResourceDocs(operationIds) - val resourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(resourceDocs, isVersion4OrHigher, locale) + val resourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(resourceDocs, isVersion4OrHigher, locale, includeTechnology = includeTechnologyInResponse) resourceDocsJson.resource_docs case _ => contentParam match { @@ -247,4 +248,4 @@ object ResourceDocs300 extends OBPRestHelper with ResourceDocsAPIMethods with Md } } -} \ No newline at end of file +} diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala index b355e782ed..6488006040 100644 --- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala +++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/ResourceDocsAPIMethods.scala @@ -65,6 +65,8 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth // We add previous APIMethods so we have access to the Resource Docs self: OBPRestHelper => + def includeTechnologyInResponse: Boolean = false + val ImplementationsResourceDocs = new Object() { val localResourceDocs = ArrayBuffer[ResourceDoc]() @@ -346,7 +348,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth // Filter val rdFiltered = ResourceDocsAPIMethodsUtil.filterResourceDocs(resourceDocs, resourceDocTags, partialFunctionNames) // Format the data as json - JSONFactory1_4_0.createResourceDocsJson(rdFiltered, isVersion4OrHigher, locale) + JSONFactory1_4_0.createResourceDocsJson(rdFiltered, isVersion4OrHigher, locale, includeTechnology = includeTechnologyInResponse) } } @@ -500,7 +502,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth NewStyle.function.tryons(s"$UnknownError Can not prepare OBP resource docs.", 500, callContext) { val operationIds = MappedApiCollectionEndpointsProvider.getApiCollectionEndpoints(apiCollectionIdParam.getOrElse("")).map(_.operationId).map(getObpFormatOperationId) val resourceDocs = ResourceDoc.getResourceDocs(operationIds) - val resourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(resourceDocs, isVersion4OrHigher, locale) + val resourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(resourceDocs, isVersion4OrHigher, locale, includeTechnology = includeTechnologyInResponse) val resourceDocsJsonJValue = Full(resourceDocsJsonToJsonResponse(resourceDocsJson)) resourceDocsJsonJValue.map(successJsonResponse(_)) } @@ -709,7 +711,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth case _ if (apiCollectionIdParam.isDefined) => val operationIds = MappedApiCollectionEndpointsProvider.getApiCollectionEndpoints(apiCollectionIdParam.getOrElse("")).map(_.operationId).map(getObpFormatOperationId) val resourceDocs = ResourceDoc.getResourceDocs(operationIds) - val resourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(resourceDocs, isVersion4OrHigher, locale) + val resourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(resourceDocs, isVersion4OrHigher, locale, includeTechnology = includeTechnologyInResponse) resourceDocsJson.resource_docs case _ => contentParam match { @@ -903,7 +905,7 @@ trait ResourceDocsAPIMethods extends MdcLoggable with APIMethods220 with APIMeth case _ if (apiCollectionIdParam.isDefined) => val operationIds = MappedApiCollectionEndpointsProvider.getApiCollectionEndpoints(apiCollectionIdParam.getOrElse("")).map(_.operationId).map(getObpFormatOperationId) val resourceDocs = ResourceDoc.getResourceDocs(operationIds) - val resourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(resourceDocs, isVersion4OrHigher, locale) + val resourceDocsJson = JSONFactory1_4_0.createResourceDocsJson(resourceDocs, isVersion4OrHigher, locale, includeTechnology = includeTechnologyInResponse) resourceDocsJson.resource_docs case _ => contentParam match { @@ -1257,4 +1259,3 @@ so the caller must specify any required filtering by catalog explicitly. } - diff --git a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala index 6e22b45cca..5e454e8a23 100644 --- a/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala +++ b/obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala @@ -1796,7 +1796,8 @@ object SwaggerDefinitionsJSON { lazy val implementedByJson = ImplementedByJson( version = "1_4_0", - function = "getBranches" + function = "getBranches", + technology = None ) // Used to describe the OBP API calls for documentation and API discovery purposes lazy val canCreateCustomerSwagger = CanCreateCustomer() @@ -4018,7 +4019,7 @@ object SwaggerDefinitionsJSON { lazy val topApiJson = TopApiJson( count = 7076, Implemented_by_partial_function = "getBanks", - implemented_in_version = "v1.2.1" + implemented_in_version = ApiVersion.v1_2_1.toString ) lazy val topApisJson = TopApisJson(List(topApiJson)) @@ -4129,7 +4130,7 @@ object SwaggerDefinitionsJSON { lazy val callLimitPostJsonV600 = CallLimitPostJsonV600( from_date = DateWithDayExampleObject, to_date = DateWithDayExampleObject, - api_version = Some("v6.0.0"), + api_version = Some(ApiVersion.v6_0_0.toString), api_name = Some("getConsumerCallLimits"), bank_id = None, per_second_call_limit = "100", @@ -4144,7 +4145,7 @@ object SwaggerDefinitionsJSON { rate_limiting_id = "80e1e0b2-d8bf-4f85-a579-e69ef36e3305", from_date = DateWithDayExampleObject, to_date = DateWithDayExampleObject, - api_version = Some("v6.0.0"), + api_version = Some(ApiVersion.v6_0_0.toString), api_name = Some("getConsumerCallLimits"), bank_id = None, per_second_call_limit = "100", @@ -5128,7 +5129,7 @@ object SwaggerDefinitionsJSON { user_id = userIdExample.value, allowed_attempts =3, challenge_type = ChallengeType.OBP_TRANSACTION_REQUEST_CHALLENGE.toString, - link = "/obp/v4.0.0/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/TRANSACTION_REQUEST_TYPE/transaction-requests/TRANSACTION_REQUEST_ID/challenge" + link = s"/obp/${ApiVersion.v4_0_0}/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transaction-request-types/TRANSACTION_REQUEST_TYPE/transaction-requests/TRANSACTION_REQUEST_ID/challenge" ) lazy val transactionRequestWithChargeJSON400 = TransactionRequestWithChargeJSON400( id = "4050046c-63b3-4868-8a22-14b4181d33a6", diff --git a/obp-api/src/main/scala/code/api/constant/constant.scala b/obp-api/src/main/scala/code/api/constant/constant.scala index 9816ad4a29..0f7167cbe1 100644 --- a/obp-api/src/main/scala/code/api/constant/constant.scala +++ b/obp-api/src/main/scala/code/api/constant/constant.scala @@ -654,6 +654,11 @@ object Constant extends MdcLoggable { CAN_GRANT_ACCESS_TO_VIEWS, CAN_REVOKE_ACCESS_TO_VIEWS, ) + + + final val TECHNOLOGY_LIFTWEB = "liftweb" + final val TECHNOLOGY_HTTP4S = "http4s" + } diff --git a/obp-api/src/main/scala/code/api/util/http4s/ErrorResponseConverter.scala b/obp-api/src/main/scala/code/api/util/http4s/ErrorResponseConverter.scala index 856b0f1ee7..25c2d78291 100644 --- a/obp-api/src/main/scala/code/api/util/http4s/ErrorResponseConverter.scala +++ b/obp-api/src/main/scala/code/api/util/http4s/ErrorResponseConverter.scala @@ -1,10 +1,9 @@ package code.api.util.http4s import cats.effect._ -import code.api.APIFailureNewStyle import code.api.util.ErrorMessages._ import code.api.util.CallContext -import net.liftweb.common.{Failure => LiftFailure} +import net.liftweb.json.{JInt, JString, parseOpt} import net.liftweb.json.compactRender import net.liftweb.json.JsonDSL._ import org.http4s._ @@ -30,6 +29,8 @@ object ErrorResponseConverter { implicit val formats: Formats = CustomJsonFormats.formats private val jsonContentType: `Content-Type` = `Content-Type`(MediaType.application.json) + private val internalFieldsFailCode = "failCode" + private val internalFieldsFailMsg = "failMsg" /** * OBP standard error response format. @@ -51,39 +52,20 @@ object ErrorResponseConverter { * Convert any error to http4s Response[IO]. */ def toHttp4sResponse(error: Throwable, callContext: CallContext): IO[Response[IO]] = { - error match { - case e: APIFailureNewStyle => apiFailureToResponse(e, callContext) - case _ => unknownErrorToResponse(error, callContext) + parseApiFailureFromExceptionMessage(error).map { failure => + createErrorResponse(failure.code, failure.message, callContext) + }.getOrElse { + unknownErrorToResponse(error, callContext) } } - /** - * Convert APIFailureNewStyle to http4s Response. - * Uses failCode as HTTP status and failMsg as error message. - */ - def apiFailureToResponse(failure: APIFailureNewStyle, callContext: CallContext): IO[Response[IO]] = { - val errorJson = OBPErrorResponse(failure.failCode, failure.failMsg) - val status = org.http4s.Status.fromInt(failure.failCode).getOrElse(org.http4s.Status.BadRequest) - IO.pure( - Response[IO](status) - .withEntity(toJsonString(errorJson)) - .withContentType(jsonContentType) - .putHeaders(org.http4s.Header.Raw(CIString("Correlation-Id"), callContext.correlationId)) - ) - } - - /** - * Convert Lift Box Failure to http4s Response. - * Returns 400 Bad Request with failure message. - */ - def boxFailureToResponse(failure: LiftFailure, callContext: CallContext): IO[Response[IO]] = { - val errorJson = OBPErrorResponse(400, failure.msg) - IO.pure( - Response[IO](org.http4s.Status.BadRequest) - .withEntity(toJsonString(errorJson)) - .withContentType(jsonContentType) - .putHeaders(org.http4s.Header.Raw(CIString("Correlation-Id"), callContext.correlationId)) - ) + private def parseApiFailureFromExceptionMessage(error: Throwable): Option[OBPErrorResponse] = { + Option(error.getMessage).flatMap(parseOpt).flatMap { json => + (json \ internalFieldsFailCode, json \ internalFieldsFailMsg) match { + case (JInt(code), JString(message)) => Some(OBPErrorResponse(code.toInt, message)) + case _ => None + } + } } /** @@ -91,7 +73,7 @@ object ErrorResponseConverter { * Returns 500 Internal Server Error. */ def unknownErrorToResponse(e: Throwable, callContext: CallContext): IO[Response[IO]] = { - val errorJson = OBPErrorResponse(500, s"$UnknownError: ${e.getMessage}") + val errorJson = OBPErrorResponse(500, UnknownError) IO.pure( Response[IO](org.http4s.Status.InternalServerError) .withEntity(toJsonString(errorJson)) diff --git a/obp-api/src/main/scala/code/api/util/http4s/Http4sSupport.scala b/obp-api/src/main/scala/code/api/util/http4s/Http4sSupport.scala index f231ba002c..1f95980fcd 100644 --- a/obp-api/src/main/scala/code/api/util/http4s/Http4sSupport.scala +++ b/obp-api/src/main/scala/code/api/util/http4s/Http4sSupport.scala @@ -106,9 +106,14 @@ object Http4sRequestAttributes { def executeAndRespond[A](req: Request[IO])(f: CallContext => Future[A])(implicit formats: Formats): IO[Response[IO]] = { implicit val cc: CallContext = req.callContext for { - result <- IO.fromFuture(IO(f(cc))) - jsonString = prettyRender(Extraction.decompose(result)) - response <- Ok(jsonString) + attempted <- IO.fromFuture(IO(f(cc))).attempt + response <- attempted match { + case Right(result) => + val jsonString = prettyRender(Extraction.decompose(result)) + Ok(jsonString) + case Left(error) => + ErrorResponseConverter.toHttp4sResponse(error, cc) + } } yield response } diff --git a/obp-api/src/main/scala/code/api/util/http4s/ResourceDocMiddleware.scala b/obp-api/src/main/scala/code/api/util/http4s/ResourceDocMiddleware.scala index 78e946fb05..26fbaa18c1 100644 --- a/obp-api/src/main/scala/code/api/util/http4s/ResourceDocMiddleware.scala +++ b/obp-api/src/main/scala/code/api/util/http4s/ResourceDocMiddleware.scala @@ -10,6 +10,7 @@ import code.api.util.newstyle.ViewNewStyle import code.api.util.{APIUtil, ApiRole, CallContext, NewStyle} import code.util.Helper.MdcLoggable import com.openbankproject.commons.model._ +import com.openbankproject.commons.util.ApiShortVersions import com.github.dwickern.macros.NameOf.nameOf import net.liftweb.common.{Box, Empty, Full} import org.http4s._ @@ -86,7 +87,7 @@ object ResourceDocMiddleware extends MdcLoggable { def apply(resourceDocs: ArrayBuffer[ResourceDoc]): HttpRoutes[IO] => HttpRoutes[IO] = { routes => Kleisli[HttpF, Request[IO], Response[IO]] { req: Request[IO] => // Build initial CallContext from request - OptionT.liftF(Http4sCallContextBuilder.fromRequest(req, "v7.0.0")).flatMap { cc => + OptionT.liftF(Http4sCallContextBuilder.fromRequest(req, ApiShortVersions.`v7.0.0`.toString)).flatMap { cc => ResourceDocMatcher.findResourceDoc(req.method.name, req.uri.path, resourceDocs) match { case Some(resourceDoc) => val ccWithDoc = ResourceDocMatcher.attachToCallContext(cc, resourceDoc) diff --git a/obp-api/src/main/scala/code/api/v1_4_0/JSONFactory1_4_0.scala b/obp-api/src/main/scala/code/api/v1_4_0/JSONFactory1_4_0.scala index db6f7ee9f0..1608f3e98e 100644 --- a/obp-api/src/main/scala/code/api/v1_4_0/JSONFactory1_4_0.scala +++ b/obp-api/src/main/scala/code/api/v1_4_0/JSONFactory1_4_0.scala @@ -3,6 +3,7 @@ package code.api.v1_4_0 import code.api.Constant.{CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL, LOCALISED_RESOURCE_DOC_PREFIX} import code.api.berlin.group.v1_3.JvalueCaseClass import code.api.cache.Caching +import code.api.Constant import java.util.Date import code.api.util.APIUtil.{EmptyBody, PrimaryDataBody, ResourceDoc} import code.api.util.ApiTag.ResourceDocTag @@ -328,7 +329,8 @@ object JSONFactory1_4_0 extends MdcLoggable{ // Used to describe where an API call is implemented case class ImplementedByJson ( version : String, // Short hand for the version e.g. "1_4_0" means Implementations1_4_0 - function : String // The val / partial function that implements the call e.g. "getBranches" + function : String, // The val / partial function that implements the call e.g. "getBranches" + technology: Option[String] = None ) case class ResourceDocMeta( @@ -525,11 +527,12 @@ object JSONFactory1_4_0 extends MdcLoggable{ locale: Option[String],// this will be in the cacheKey resourceDocUpdatedTags: ResourceDoc, isVersion4OrHigher:Boolean,// this will be in the cacheKey + includeTechnology: Boolean, // this will be in the cacheKey urlParametersI18n:String , jsonRequestBodyFieldsI18n:String, jsonResponseBodyFieldsI18n:String ): ResourceDocJson = { - val cacheKey = LOCALISED_RESOURCE_DOC_PREFIX + s"operationId:${operationId}-locale:$locale- isVersion4OrHigher:$isVersion4OrHigher".intern() + val cacheKey = LOCALISED_RESOURCE_DOC_PREFIX + s"operationId:${operationId}-locale:$locale- isVersion4OrHigher:$isVersion4OrHigher- includeTechnology:$includeTechnology".intern() Caching.memoizeSyncWithImMemory(Some(cacheKey))(CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL.seconds) { val fieldsDescription = if (resourceDocUpdatedTags.tags.toString.contains("Dynamic-Entity") @@ -564,6 +567,13 @@ object JSONFactory1_4_0 extends MdcLoggable{ val summary = resourceDocUpdatedTags.summary.replaceFirst("""\.(\s*)$""", "$1") // remove the ending dot in summary val translatedSummary = I18NUtil.ResourceDocTranslation.translate(I18NResourceDocField.SUMMARY, resourceDocUpdatedTags.operationId, locale, summary) + val technology = + if (includeTechnology) { + Some(if (resourceDocUpdatedTags.http4sPartialFunction.isDefined) Constant.TECHNOLOGY_HTTP4S else Constant.TECHNOLOGY_LIFTWEB) + } else { + None + } + val resourceDoc = ResourceDocJson( operation_id = resourceDocUpdatedTags.operationId, request_verb = resourceDocUpdatedTags.requestVerb, @@ -575,7 +585,11 @@ object JSONFactory1_4_0 extends MdcLoggable{ example_request_body = resourceDocUpdatedTags.exampleRequestBody, success_response_body = resourceDocUpdatedTags.successResponseBody, error_response_bodies = resourceDocUpdatedTags.errorResponseBodies, - implemented_by = ImplementedByJson(resourceDocUpdatedTags.implementedInApiVersion.fullyQualifiedVersion, resourceDocUpdatedTags.partialFunctionName), // was resourceDocUpdatedTags.implementedInApiVersion.noV + implemented_by = ImplementedByJson( + version = resourceDocUpdatedTags.implementedInApiVersion.fullyQualifiedVersion, + function = resourceDocUpdatedTags.partialFunctionName, + technology = technology + ), // was resourceDocUpdatedTags.implementedInApiVersion.noV tags = resourceDocUpdatedTags.tags.map(i => i.tag), typed_request_body = createTypedBody(resourceDocUpdatedTags.exampleRequestBody), typed_success_response_body = createTypedBody(resourceDocUpdatedTags.successResponseBody), @@ -592,7 +606,7 @@ object JSONFactory1_4_0 extends MdcLoggable{ }} - def createLocalisedResourceDocJson(rd: ResourceDoc, isVersion4OrHigher:Boolean, locale: Option[String], urlParametersI18n:String ,jsonRequestBodyFieldsI18n:String, jsonResponseBodyFieldsI18n:String) : ResourceDocJson = { + def createLocalisedResourceDocJson(rd: ResourceDoc, isVersion4OrHigher:Boolean, locale: Option[String], includeTechnology: Boolean, urlParametersI18n:String ,jsonRequestBodyFieldsI18n:String, jsonResponseBodyFieldsI18n:String) : ResourceDocJson = { // We MUST recompute all resource doc values due to translation via Web UI props --> now need to wait $CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL seconds val userDefinedEndpointTags = getAllEndpointTagsBox(rd.operationId).map(endpointTag =>ResourceDocTag(endpointTag.tagName)) val resourceDocWithUserDefinedEndpointTags: ResourceDoc = rd.copy(tags = userDefinedEndpointTags++ rd.tags) @@ -602,6 +616,7 @@ object JSONFactory1_4_0 extends MdcLoggable{ locale: Option[String], resourceDocWithUserDefinedEndpointTags, isVersion4OrHigher: Boolean, + includeTechnology: Boolean, urlParametersI18n: String, jsonRequestBodyFieldsI18n: String, jsonResponseBodyFieldsI18n: String @@ -609,7 +624,7 @@ object JSONFactory1_4_0 extends MdcLoggable{ } - def createResourceDocsJson(resourceDocList: List[ResourceDoc], isVersion4OrHigher:Boolean, locale: Option[String]) : ResourceDocsJson = { + def createResourceDocsJson(resourceDocList: List[ResourceDoc], isVersion4OrHigher:Boolean, locale: Option[String], includeTechnology: Boolean = false) : ResourceDocsJson = { val urlParametersI18n = I18NUtil.ResourceDocTranslation.translate( I18NResourceDocField.URL_PARAMETERS, "resourceDocUrlParametersString_i180n", @@ -632,11 +647,11 @@ object JSONFactory1_4_0 extends MdcLoggable{ if(isVersion4OrHigher){ ResourceDocsJson( - resourceDocList.map(createLocalisedResourceDocJson(_,isVersion4OrHigher, locale, urlParametersI18n, jsonRequestBodyFields, jsonResponseBodyFields)), + resourceDocList.map(createLocalisedResourceDocJson(_,isVersion4OrHigher, locale, includeTechnology, urlParametersI18n, jsonRequestBodyFields, jsonResponseBodyFields)), meta=Some(ResourceDocMeta(new Date(), resourceDocList.length)) ) } else { - ResourceDocsJson(resourceDocList.map(createLocalisedResourceDocJson(_,false, locale, urlParametersI18n, jsonRequestBodyFields, jsonResponseBodyFields))) + ResourceDocsJson(resourceDocList.map(createLocalisedResourceDocJson(_,false, locale, includeTechnology, urlParametersI18n, jsonRequestBodyFields, jsonResponseBodyFields))) } } diff --git a/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala b/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala index 5ef812c7d4..721ebbca9a 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala @@ -1283,7 +1283,7 @@ object JSONFactory400 { ).mkString("") val otpViaApiPath = Constant.HostName + List( - "/obp/v4.0.0/banks/", + s"/obp/${ApiVersion.v4_0_0}/banks/", stringOrNull(tr.from.bank_id), "/accounts/", stringOrNull(tr.from.account_id), @@ -2072,4 +2072,3 @@ object JSONFactory400 { } } } - diff --git a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala index 1ffe22eefd..2e610543e5 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala @@ -1800,18 +1800,18 @@ trait APIMethods600 { ListResult( "scanned_api_versions", List( - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v1.2.1", fully_qualified_version = "OBPv1.2.1", is_active = true), - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v1.3.0", fully_qualified_version = "OBPv1.3.0", is_active = true), - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v1.4.0", fully_qualified_version = "OBPv1.4.0", is_active = true), - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v2.0.0", fully_qualified_version = "OBPv2.0.0", is_active = true), - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v2.1.0", fully_qualified_version = "OBPv2.1.0", is_active = true), - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v2.2.0", fully_qualified_version = "OBPv2.2.0", is_active = true), - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v3.0.0", fully_qualified_version = "OBPv3.0.0", is_active = true), - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v3.1.0", fully_qualified_version = "OBPv3.1.0", is_active = true), - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v4.0.0", fully_qualified_version = "OBPv4.0.0", is_active = true), - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v5.0.0", fully_qualified_version = "OBPv5.0.0", is_active = true), - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v5.1.0", fully_qualified_version = "OBPv5.1.0", is_active = true), - ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = "v6.0.0", fully_qualified_version = "OBPv6.0.0", is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v1_2_1.toString, fully_qualified_version = ApiVersion.v1_2_1.fullyQualifiedVersion, is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v1_3_0.toString, fully_qualified_version = ApiVersion.v1_3_0.fullyQualifiedVersion, is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v1_4_0.toString, fully_qualified_version = ApiVersion.v1_4_0.fullyQualifiedVersion, is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v2_0_0.toString, fully_qualified_version = ApiVersion.v2_0_0.fullyQualifiedVersion, is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v2_1_0.toString, fully_qualified_version = ApiVersion.v2_1_0.fullyQualifiedVersion, is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v2_2_0.toString, fully_qualified_version = ApiVersion.v2_2_0.fullyQualifiedVersion, is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v3_0_0.toString, fully_qualified_version = ApiVersion.v3_0_0.fullyQualifiedVersion, is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v3_1_0.toString, fully_qualified_version = ApiVersion.v3_1_0.fullyQualifiedVersion, is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v4_0_0.toString, fully_qualified_version = ApiVersion.v4_0_0.fullyQualifiedVersion, is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v5_0_0.toString, fully_qualified_version = ApiVersion.v5_0_0.fullyQualifiedVersion, is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v5_1_0.toString, fully_qualified_version = ApiVersion.v5_1_0.fullyQualifiedVersion, is_active = true), + ScannedApiVersionJsonV600(url_prefix = "obp", api_standard = "OBP", api_short_version = ApiVersion.v6_0_0.toString, fully_qualified_version = ApiVersion.v6_0_0.fullyQualifiedVersion, is_active = true), ScannedApiVersionJsonV600(url_prefix = "berlin-group", api_standard = "BG", api_short_version = "v1.3", fully_qualified_version = "BGv1.3", is_active = false) ) ), @@ -4289,7 +4289,7 @@ trait APIMethods600 { lazy val getWebUiProp: OBPEndpoint = { case "webui-props" :: webUiPropName :: Nil JsonGet req => { cc => implicit val ec = EndpointContext(Some(cc)) - logger.info(s"========== GET /obp/v6.0.0/webui-props/$webUiPropName (SINGLE PROP) called ==========") + logger.info(s"========== GET /obp/${ApiVersion.v6_0_0}/webui-props/$webUiPropName (SINGLE PROP) called ==========") val active = ObpS.param("active").getOrElse("false") for { invalidMsg <- Future(s"""$InvalidFilterParameterFormat `active` must be a boolean, but current `active` value is: ${active} """) @@ -4391,7 +4391,7 @@ trait APIMethods600 { case "webui-props":: Nil JsonGet req => { cc => implicit val ec = EndpointContext(Some(cc)) val what = ObpS.param("what").getOrElse("active") - logger.info(s"========== GET /obp/v6.0.0/webui-props (ALL PROPS) called with what=$what ==========") + logger.info(s"========== GET /obp/${ApiVersion.v6_0_0}/webui-props (ALL PROPS) called with what=$what ==========") for { callContext <- Future.successful(cc.callContext) _ <- NewStyle.function.tryons(s"""$InvalidFilterParameterFormat `what` must be one of: active, database, config. Current value: $what""", 400, callContext) { @@ -4417,11 +4417,11 @@ trait APIMethods600 { explicitWebUiPropsWithSource ++ configPropsNotInDatabase } } yield { - logger.info(s"========== GET /obp/v6.0.0/webui-props returning ${result.size} records ==========") + logger.info(s"========== GET /obp/${ApiVersion.v6_0_0}/webui-props returning ${result.size} records ==========") result.foreach { prop => logger.info(s" - name: ${prop.name}, value: ${prop.value}, webUiPropsId: ${prop.webUiPropsId}") } - logger.info(s"========== END GET /obp/v6.0.0/webui-props ==========") + logger.info(s"========== END GET /obp/${ApiVersion.v6_0_0}/webui-props ==========") (ListResult("webui_props", result), HttpCode.`200`(callContext)) } } @@ -6983,11 +6983,11 @@ trait APIMethods600 { schema = net.liftweb.json.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string"}, "language": {"type": "string"}}}""").asInstanceOf[net.liftweb.json.JsonAST.JObject], _links = Some(DynamicEntityLinksJsonV600( related = List( - RelatedLinkJsonV600("list", "/obp/v6.0.0/my/customer_preferences", "GET"), - RelatedLinkJsonV600("create", "/obp/v6.0.0/my/customer_preferences", "POST"), - RelatedLinkJsonV600("read", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "GET"), - RelatedLinkJsonV600("update", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "PUT"), - RelatedLinkJsonV600("delete", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "DELETE") + RelatedLinkJsonV600("list", s"/obp/${ApiVersion.v6_0_0}/my/customer_preferences", "GET"), + RelatedLinkJsonV600("create", s"/obp/${ApiVersion.v6_0_0}/my/customer_preferences", "POST"), + RelatedLinkJsonV600("read", s"/obp/${ApiVersion.v6_0_0}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "GET"), + RelatedLinkJsonV600("update", s"/obp/${ApiVersion.v6_0_0}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "PUT"), + RelatedLinkJsonV600("delete", s"/obp/${ApiVersion.v6_0_0}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "DELETE") ) )) ) @@ -7047,11 +7047,11 @@ trait APIMethods600 { schema = net.liftweb.json.parse("""{"description": "User preferences", "required": ["theme"], "properties": {"theme": {"type": "string"}, "language": {"type": "string"}}}""").asInstanceOf[net.liftweb.json.JsonAST.JObject], _links = Some(DynamicEntityLinksJsonV600( related = List( - RelatedLinkJsonV600("list", "/obp/v6.0.0/my/customer_preferences", "GET"), - RelatedLinkJsonV600("create", "/obp/v6.0.0/my/customer_preferences", "POST"), - RelatedLinkJsonV600("read", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "GET"), - RelatedLinkJsonV600("update", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "PUT"), - RelatedLinkJsonV600("delete", "/obp/v6.0.0/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "DELETE") + RelatedLinkJsonV600("list", s"/obp/${ApiVersion.v6_0_0}/my/customer_preferences", "GET"), + RelatedLinkJsonV600("create", s"/obp/${ApiVersion.v6_0_0}/my/customer_preferences", "POST"), + RelatedLinkJsonV600("read", s"/obp/${ApiVersion.v6_0_0}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "GET"), + RelatedLinkJsonV600("update", s"/obp/${ApiVersion.v6_0_0}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "PUT"), + RelatedLinkJsonV600("delete", s"/obp/${ApiVersion.v6_0_0}/my/customer_preferences/CUSTOMER_PREFERENCES_ID", "DELETE") ) )) ) diff --git a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala index 97ac5265d9..921adfe760 100644 --- a/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala +++ b/obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala @@ -38,6 +38,7 @@ import com.openbankproject.commons.model.{ CustomerAttribute, _ } +import com.openbankproject.commons.util.ApiVersion import net.liftweb.common.Box import java.util.Date @@ -1430,8 +1431,8 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable { val entityName = entity.entityName val idPlaceholder = StringHelpers.snakify(entityName + "Id").toUpperCase() val baseUrl = entity.bankId match { - case Some(bankId) => s"/obp/v6.0.0/banks/$bankId/my/$entityName" - case None => s"/obp/v6.0.0/my/$entityName" + case Some(bankId) => s"/obp/${ApiVersion.v6_0_0}/banks/$bankId/my/$entityName" + case None => s"/obp/${ApiVersion.v6_0_0}/my/$entityName" } val links = DynamicEntityLinksJsonV600( diff --git a/obp-api/src/main/scala/code/api/v7_0_0/Http4s700.scala b/obp-api/src/main/scala/code/api/v7_0_0/Http4s700.scala index 229c610276..6d28b18a18 100644 --- a/obp-api/src/main/scala/code/api/v7_0_0/Http4s700.scala +++ b/obp-api/src/main/scala/code/api/v7_0_0/Http4s700.scala @@ -9,7 +9,7 @@ import code.api.util.APIUtil.{EmptyBody, _} import code.api.util.ApiRole.canGetCardsForBank import code.api.util.ApiTag._ import code.api.util.ErrorMessages._ -import code.api.util.http4s.{Http4sRequestAttributes, ResourceDocMiddleware} +import code.api.util.http4s.{ErrorResponseConverter, Http4sRequestAttributes, ResourceDocMiddleware} import code.api.util.http4s.Http4sRequestAttributes.{RequestOps, EndpointHelpers} import code.api.util.{ApiVersionUtils, CallContext, CustomJsonFormats, NewStyle} import code.api.v1_3_0.JSONFactory1_3_0 @@ -26,6 +26,7 @@ import org.http4s.dsl.io._ import scala.collection.mutable.ArrayBuffer import scala.concurrent.Future import scala.language.{higherKinds, implicitConversions} +import code.util.Helper object Http4s700 { @@ -201,25 +202,39 @@ object Http4s700 { val getResourceDocsObpV700: HttpRoutes[IO] = HttpRoutes.of[IO] { case req @ GET -> `prefixPath` / "resource-docs" / requestedApiVersionString / "obp" => + implicit val cc: CallContext = req.callContext + val queryParams = req.uri.query.multiParams + val tags = queryParams + .get("tags") + .map(_.flatMap(_.split(",").toList).map(_.trim).filter(_.nonEmpty).map(ResourceDocTag(_)).toList) + val functions = queryParams + .get("functions") + .map(_.flatMap(_.split(",").toList).map(_.trim).filter(_.nonEmpty).toList) + val localeParam = queryParams + .get("locale") + .flatMap(_.headOption) + .orElse(queryParams.get("language").flatMap(_.headOption)) + .map(_.trim) + .filter(_.nonEmpty) + EndpointHelpers.executeAndRespond(req) { _ => - val queryParams = req.uri.query.multiParams - val tags = queryParams - .get("tags") - .map(_.flatMap(_.split(",").toList).map(_.trim).filter(_.nonEmpty).map(ResourceDocTag(_)).toList) - val functions = queryParams - .get("functions") - .map(_.flatMap(_.split(",").toList).map(_.trim).filter(_.nonEmpty).toList) - val localeParam = queryParams - .get("locale") - .flatMap(_.headOption) - .orElse(queryParams.get("language").flatMap(_.headOption)) - .map(_.trim) - .filter(_.nonEmpty) for { - requestedApiVersion <- Future(ApiVersionUtils.valueOf(requestedApiVersionString)) - resourceDocs = ResourceDocs140.ImplementationsResourceDocs.getResourceDocsList(requestedApiVersion).getOrElse(Nil) - filteredDocs = ResourceDocsAPIMethodsUtil.filterResourceDocs(resourceDocs, tags, functions) - } yield JSONFactory1_4_0.createResourceDocsJson(filteredDocs, isVersion4OrHigher = true, localeParam) + requestedApiVersion <- NewStyle.function.tryons( + failMsg = s"$InvalidApiVersionString Current value: $requestedApiVersionString", + failCode = 400, + callContext = Some(cc) + ) { + ApiVersionUtils.valueOf(requestedApiVersionString) + } + _ <- Helper.booleanToFuture( + failMsg = s"$InvalidApiVersionString This server supports only ${ApiVersion.v7_0_0}. Current value: $requestedApiVersionString", + failCode = 400, + cc = Some(cc) + ) { + requestedApiVersion == ApiVersion.v7_0_0 + } + http4sOnlyDocs = ResourceDocsAPIMethodsUtil.filterResourceDocs(resourceDocs.toList, tags, functions) + } yield JSONFactory1_4_0.createResourceDocsJson(http4sOnlyDocs, isVersion4OrHigher = true, localeParam, includeTechnology = true) } } diff --git a/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsTechnologyTest.scala b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsTechnologyTest.scala new file mode 100644 index 0000000000..bec8e32ecf --- /dev/null +++ b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsTechnologyTest.scala @@ -0,0 +1,49 @@ +package code.api.ResourceDocs1_4_0 + +import code.api.Constant +import code.setup.{PropsReset, ServerSetup} +import com.openbankproject.commons.util.ApiVersion +import net.liftweb.json.JsonAST.{JArray, JNothing, JNull, JString} + +class ResourceDocsTechnologyTest extends ServerSetup with PropsReset { + private val v600 = ApiVersion.v6_0_0.toString + private val v500 = ApiVersion.v5_0_0.toString + + feature("ResourceDocs implemented_by.technology") { + + scenario(s"$v600 resource-docs should include implemented_by.technology") { + setPropsValues("resource_docs_requires_role" -> "false") + + val request = (baseRequest / "obp" / v600 / "resource-docs" / v600 / "obp").GET + val response = makeGetRequest(request) + + response.code should equal(200) + (response.body \ "resource_docs") match { + case JArray(docs) => + val technology = docs.head \ "implemented_by" \ "technology" + technology should equal(JString(Constant.TECHNOLOGY_LIFTWEB)) + case _ => + fail("Expected resource_docs field to be an array") + } + } + + scenario(s"$v500 resource-docs should not include implemented_by.technology") { + setPropsValues("resource_docs_requires_role" -> "false") + + val request = (baseRequest / "obp" / v500 / "resource-docs" / v500 / "obp").GET + val response = makeGetRequest(request) + + response.code should equal(200) + (response.body \ "resource_docs") match { + case JArray(docs) => + val technology = docs.head \ "implemented_by" \ "technology" + technology match { + case JNothing | JNull => succeed + case _ => fail("Expected implemented_by.technology to be absent for v5.0.0 resource-docs") + } + case _ => + fail("Expected resource_docs field to be an array") + } + } + } +} diff --git a/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsTest.scala b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsTest.scala index 7b7bce74f9..8135580af2 100644 --- a/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsTest.scala +++ b/obp-api/src/test/scala/code/api/ResourceDocs1_4_0/ResourceDocsTest.scala @@ -1,5 +1,6 @@ package code.api.ResourceDocs1_4_0 +import code.api.Constant import code.api.ResourceDocs1_4_0.ResourceDocs140.ImplementationsResourceDocs import code.api.berlin.group.ConstantsBG import code.api.util.APIUtil.OAuth._ @@ -21,6 +22,31 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with object VersionOfApi extends Tag(ApiVersion.v1_4_0.toString) object ApiEndpoint1 extends Tag(nameOf(ImplementationsResourceDocs.getResourceDocsObp)) object ApiEndpoint2 extends Tag(nameOf(ImplementationsResourceDocs.getBankLevelDynamicResourceDocsObp)) + + private val v600 = ApiVersion.v6_0_0.toString + private val fq600 = ApiVersion.v6_0_0.fullyQualifiedVersion + private val v510 = ApiVersion.v5_1_0.toString + private val fq510 = ApiVersion.v5_1_0.fullyQualifiedVersion + private val v500 = ApiVersion.v5_0_0.toString + private val fq500 = ApiVersion.v5_0_0.fullyQualifiedVersion + private val v400 = ApiVersion.v4_0_0.toString + private val fq400 = ApiVersion.v4_0_0.fullyQualifiedVersion + private val v310 = ApiVersion.v3_1_0.toString + private val fq310 = ApiVersion.v3_1_0.fullyQualifiedVersion + private val v300 = ApiVersion.v3_0_0.toString + private val fq300 = ApiVersion.v3_0_0.fullyQualifiedVersion + private val v220 = ApiVersion.v2_2_0.toString + private val fq220 = ApiVersion.v2_2_0.fullyQualifiedVersion + private val v210 = ApiVersion.v2_1_0.toString + private val fq210 = ApiVersion.v2_1_0.fullyQualifiedVersion + private val v200 = ApiVersion.v2_0_0.toString + private val fq200 = ApiVersion.v2_0_0.fullyQualifiedVersion + private val v140 = ApiVersion.v1_4_0.toString + private val fq140 = ApiVersion.v1_4_0.fullyQualifiedVersion + private val v130 = ApiVersion.v1_3_0.toString + private val fq130 = ApiVersion.v1_3_0.fullyQualifiedVersion + private val v121 = ApiVersion.v1_2_1.toString + private val fq121 = ApiVersion.v1_2_1.fullyQualifiedVersion override def beforeEach() = { super.beforeEach() @@ -68,22 +94,23 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with def stringToNodeSeq(html : String) : NodeSeq = { val newHtmlString =scala.xml.XML.loadString("
" + html + "
").toString() //Note: `parse` method: We much enclose the div, otherwise only the first element is returned. - Html5.parse(newHtmlString).head + Html5.parse(newHtmlString).headOption.getOrElse(NodeSeq.Empty) } feature(s"test ${ApiEndpoint1.name} ") { - scenario(s"We will test ${ApiEndpoint1.name} Api -v6.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV6_0Request / "resource-docs" / "v6.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$v600", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV6_0Request / "resource-docs" / v600 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] responseGetObp.code should equal(200) + responseDocs.resource_docs.head.implemented_by.technology shouldBe Some(Constant.TECHNOLOGY_LIFTWEB) //This should not throw any exceptions responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -OBPv6.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV6_0Request / "resource-docs" / "OBPv6.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$fq600", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV6_0Request / "resource-docs" / fq600 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -91,63 +118,64 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with //This should not throw any exceptions responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v5.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV5_0Request / "resource-docs" / "v5.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$v500", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV5_0Request / "resource-docs" / v500 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] responseGetObp.code should equal(200) + responseDocs.resource_docs.head.implemented_by.technology shouldBe None //This should not throw any exceptions responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } scenario("Test OpenAPI endpoint with valid parameters", ApiEndpoint1, VersionOfApi) { - val requestGetOpenAPI = (ResourceDocsV6_0Request / "resource-docs" / "v6.0.0" / "openapi").GET < stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -OBPv5.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV5_0Request / "resource-docs" / "OBPv5.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$fq500", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV5_0Request / "resource-docs" / fq500 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -166,8 +194,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v4.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v4.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$v400", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / v400 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -176,8 +204,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -OBPv4.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "OBPv4.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$fq400", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / fq400 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -186,8 +214,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v3.1.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v3.1.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$v310", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / v310 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -197,8 +225,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -OBPv3.1.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "OBPv3.1.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$fq310", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / fq310 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -207,8 +235,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v3.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v3.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$v300", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / v300 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -217,8 +245,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -OBPv3.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "OBPv3.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$fq300", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / fq300 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -227,8 +255,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v2.2.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v2.2.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$v220", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / v220 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -237,8 +265,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -OBPv2.2.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "OBPv2.2.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$fq220", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / fq220 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -247,8 +275,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v2.1.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v2.1.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$v210", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / v210 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -257,8 +285,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -OBPv2.1.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "OBPv2.1.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$fq210", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / fq210 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -267,8 +295,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v2.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v2.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$v200", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / v200 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -277,8 +305,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -OBPv2.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "OBPv2.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$fq200", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / fq200 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -287,16 +315,16 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v1.4.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v1.4.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$v140", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / v140 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") responseGetObp.body.extract[ResourceDocsJson] responseGetObp.code should equal(200) } - scenario(s"We will test ${ApiEndpoint1.name} Api -OBPv1.4.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "OBPv1.4.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$fq140", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / fq140 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -305,8 +333,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v1.3.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v1.3.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$v130", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / v130 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -315,8 +343,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -OBPv1.3.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "OBPv1.3.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$fq130", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / fq130 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -325,8 +353,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v1.2.1", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v1.2.1" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$v121", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / v121 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -335,8 +363,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -OBPv1.2.1", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "OBPv1.2.1" / "obp").GET + scenario(s"We will test ${ApiEndpoint1.name} Api -$fq121", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / fq121 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -385,11 +413,11 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v4.0.0 - resource_docs_requires_role props", ApiEndpoint1, VersionOfApi) { + scenario(s"We will test ${ApiEndpoint1.name} Api -$v400 - resource_docs_requires_role props", ApiEndpoint1, VersionOfApi) { setPropsValues( "resource_docs_requires_role" -> "true", ) - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v4.0.0" / "obp").GET + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / v400 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -397,11 +425,11 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseGetObp.toString contains(AuthenticatedUserIsRequired) should be (true) } - scenario(s"We will test ${ApiEndpoint1.name} Api -v4.0.0 - resource_docs_requires_role props- login in user", ApiEndpoint1, VersionOfApi) { + scenario(s"We will test ${ApiEndpoint1.name} Api -$v400 - resource_docs_requires_role props- login in user", ApiEndpoint1, VersionOfApi) { setPropsValues( "resource_docs_requires_role" -> "true", ) - val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / "v4.0.0" / "obp").GET <@ (user1) + val requestGetObp = (ResourceDocsV4_0Request / "resource-docs" / v400 / "obp").GET <@ (user1) val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -413,8 +441,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with } feature(s"test ${ApiEndpoint2.name} ") { - scenario(s"We will test ${ApiEndpoint2.name} Api -v6.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v6.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$v600", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v600 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -422,8 +450,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with //This should not throw any exceptions responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -OBPv6.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "OBPv6.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$fq600", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / fq600 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -431,8 +459,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with //This should not throw any exceptions responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v5.0.0/v4.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v5.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$v500/$v400", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v500 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -441,8 +469,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v4.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v4.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$v400", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v400 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -451,8 +479,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -OBPv4.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "OBPv4.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$fq400", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / fq400 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -461,8 +489,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v3.1.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v3.1.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$v310", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v310 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -472,8 +500,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -OBPv3.1.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "OBPv3.1.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$fq310", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / fq310 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -482,8 +510,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v3.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v3.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$v300", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v300 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -492,8 +520,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -OBPv3.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "OBPv3.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$fq300", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / fq300 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -502,8 +530,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v2.2.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v2.2.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$v220", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v220 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -512,8 +540,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -OBPv2.2.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "OBPv2.2.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$fq220", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / fq220 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -522,8 +550,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v2.1.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v2.1.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$v210", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v210 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -532,8 +560,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -OBPv2.1.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "OBPv2.1.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$fq210", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / fq210 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -542,8 +570,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v2.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v2.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$v200", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v200 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -552,8 +580,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -OBPv2.0.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "OBPv2.0.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$fq200", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / fq200 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -562,16 +590,16 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v1.4.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v1.4.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$v140", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v140 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") responseGetObp.body.extract[ResourceDocsJson] responseGetObp.code should equal(200) } - scenario(s"We will test ${ApiEndpoint2.name} Api -OBPv1.4.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "OBPv1.4.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$fq140", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / fq140 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -580,8 +608,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v1.3.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v1.3.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$v130", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v130 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -590,8 +618,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -OBPv1.3.0", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "OBPv1.3.0" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$fq130", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / fq130 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -600,8 +628,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v1.2.1", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v1.2.1" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$v121", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v121 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -610,8 +638,8 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -OBPv1.2.1", ApiEndpoint1, VersionOfApi) { - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "OBPv1.2.1" / "obp").GET + scenario(s"We will test ${ApiEndpoint2.name} Api -$fq121", ApiEndpoint1, VersionOfApi) { + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / fq121 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -660,11 +688,11 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseDocs.resource_docs.map(responseDoc => stringToNodeSeq(responseDoc.description)) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v4.0.0 - resource_docs_requires_role props", ApiEndpoint1, VersionOfApi) { + scenario(s"We will test ${ApiEndpoint2.name} Api -$v400 - resource_docs_requires_role props", ApiEndpoint1, VersionOfApi) { setPropsValues( "resource_docs_requires_role" -> "true", ) - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v4.0.0" / "obp").GET + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v400 / "obp").GET val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] @@ -672,11 +700,11 @@ class ResourceDocsTest extends ResourceDocsV140ServerSetup with PropsReset with responseGetObp.toString contains(AuthenticatedUserIsRequired) should be (true) } - scenario(s"We will test ${ApiEndpoint2.name} Api -v4.0.0 - resource_docs_requires_role props- login in user", ApiEndpoint1, VersionOfApi) { + scenario(s"We will test ${ApiEndpoint2.name} Api -$v400 - resource_docs_requires_role props- login in user", ApiEndpoint1, VersionOfApi) { setPropsValues( "resource_docs_requires_role" -> "true", ) - val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / "v4.0.0" / "obp").GET <@ (user1) + val requestGetObp = (ResourceDocsV1_4Request /"banks"/ testBankId1.value/ "resource-docs" / v400 / "obp").GET <@ (user1) val responseGetObp = makeGetRequest(requestGetObp) And("We should get 200 and the response can be extract to case classes") val responseDocs = responseGetObp.body.extract[ResourceDocsJson] diff --git a/obp-api/src/test/scala/code/api/util/http4s/Http4sCallContextBuilderTest.scala b/obp-api/src/test/scala/code/api/util/http4s/Http4sCallContextBuilderTest.scala index d6d22baee5..8c504a126a 100644 --- a/obp-api/src/test/scala/code/api/util/http4s/Http4sCallContextBuilderTest.scala +++ b/obp-api/src/test/scala/code/api/util/http4s/Http4sCallContextBuilderTest.scala @@ -2,6 +2,7 @@ package code.api.util.http4s import cats.effect.IO import cats.effect.unsafe.implicits.global +import com.openbankproject.commons.util.ApiShortVersions import net.liftweb.common.{Empty, Full} import org.http4s._ import org.http4s.dsl.io._ @@ -23,49 +24,51 @@ import org.scalatest.{FeatureSpec, GivenWhenThen, Matchers, Tag} class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenWhenThen { object Http4sCallContextBuilderTag extends Tag("Http4sCallContextBuilder") + private val v700 = ApiShortVersions.`v7.0.0`.toString + private val base = s"/obp/$v700" feature("Http4sCallContextBuilder - URL extraction") { scenario("Extract URL with path only", Http4sCallContextBuilderTag) { - Given("A request with path /obp/v7.0.0/banks") + Given(s"A request with path $base/banks") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("URL should match the request URI") - callContext.url should equal("/obp/v7.0.0/banks") + callContext.url should equal(s"$base/banks") } scenario("Extract URL with query parameters", Http4sCallContextBuilderTag) { Given("A request with query parameters") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks?limit=10&offset=0") + uri = Uri.unsafeFromString(s"$base/banks?limit=10&offset=0") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("URL should include query parameters") - callContext.url should equal("/obp/v7.0.0/banks?limit=10&offset=0") + callContext.url should equal(s"$base/banks?limit=10&offset=0") } scenario("Extract URL with path parameters", Http4sCallContextBuilderTag) { Given("A request with path parameters") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks/gh.29.de/accounts/test1") + uri = Uri.unsafeFromString(s"$base/banks/gh.29.de/accounts/test1") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("URL should include path parameters") - callContext.url should equal("/obp/v7.0.0/banks/gh.29.de/accounts/test1") + callContext.url should equal(s"$base/banks/gh.29.de/accounts/test1") } } @@ -75,7 +78,7 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW Given("A request with multiple headers") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ).withHeaders( Header.Raw(org.typelevel.ci.CIString("Content-Type"), "application/json"), Header.Raw(org.typelevel.ci.CIString("Accept"), "application/json"), @@ -83,7 +86,7 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("Headers should be converted to HTTPParam list") callContext.requestHeaders should not be empty @@ -96,11 +99,11 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW Given("A request with no custom headers") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("Headers list should be empty or contain only default headers") // http4s may add default headers, so we just check it's a list @@ -115,11 +118,11 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW val jsonBody = """{"name": "Test Bank", "id": "test-bank-1"}""" val request = Request[IO]( method = Method.POST, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ).withEntity(jsonBody) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("Body should be extracted as Some(string)") callContext.httpBody should be(Some(jsonBody)) @@ -129,11 +132,11 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW Given("A GET request with no body") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("Body should be None") callContext.httpBody should be(None) @@ -144,11 +147,11 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW val jsonBody = """{"name": "Updated Bank"}""" val request = Request[IO]( method = Method.PUT, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks/test-bank-1") + uri = Uri.unsafeFromString(s"$base/banks/test-bank-1") ).withEntity(jsonBody) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("Body should be extracted") callContext.httpBody should be(Some(jsonBody)) @@ -162,13 +165,13 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW val requestId = "test-correlation-id-12345" val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ).withHeaders( Header.Raw(org.typelevel.ci.CIString("X-Request-ID"), requestId) ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("Correlation ID should match the header value") callContext.correlationId should equal(requestId) @@ -178,11 +181,11 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW Given("A request without X-Request-ID header") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("Correlation ID should be generated (UUID format)") callContext.correlationId should not be empty @@ -198,13 +201,13 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW val clientIp = "192.168.1.100" val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ).withHeaders( Header.Raw(org.typelevel.ci.CIString("X-Forwarded-For"), clientIp) ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("IP address should match the header value") callContext.ipAddress should equal(clientIp) @@ -215,13 +218,13 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW val forwardedFor = "192.168.1.100, 10.0.0.1, 172.16.0.1" val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ).withHeaders( Header.Raw(org.typelevel.ci.CIString("X-Forwarded-For"), forwardedFor) ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("IP address should be the first IP in the list") callContext.ipAddress should equal("192.168.1.100") @@ -231,11 +234,11 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW Given("A request without X-Forwarded-For or remote address") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("IP address should be empty string") callContext.ipAddress should equal("") @@ -249,13 +252,13 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW val token = "eyJhbGciOiJIUzI1NiJ9.eyIiOiIifQ.test" val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ).withHeaders( Header.Raw(org.typelevel.ci.CIString("DirectLogin"), s"token=$token") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("DirectLogin params should contain token") callContext.directLoginParams should contain key "token" @@ -267,13 +270,13 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW val token = "eyJhbGciOiJIUzI1NiJ9.eyIiOiIifQ.test" val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ).withHeaders( Header.Raw(org.typelevel.ci.CIString("Authorization"), s"DirectLogin token=$token") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("DirectLogin params should contain token") callContext.directLoginParams should contain key "token" @@ -287,13 +290,13 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW Given("A request with DirectLogin username and password") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ).withHeaders( Header.Raw(org.typelevel.ci.CIString("DirectLogin"), """username="testuser", password="testpass", consumer_key="key123"""") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("DirectLogin params should contain all parameters") callContext.directLoginParams should contain key "username" @@ -309,13 +312,13 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW val oauthHeader = """OAuth oauth_consumer_key="consumer123", oauth_token="token456", oauth_signature="sig789"""" val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ).withHeaders( Header.Raw(org.typelevel.ci.CIString("Authorization"), oauthHeader) ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("OAuth params should be extracted") callContext.oAuthParams should contain key "oauth_consumer_key" @@ -334,13 +337,13 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW val bearerToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature" val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ).withHeaders( Header.Raw(org.typelevel.ci.CIString("Authorization"), s"Bearer $bearerToken") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("Authorization header should be stored") callContext.authReqHeaderField should equal(Full(s"Bearer $bearerToken")) @@ -350,11 +353,11 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW Given("A request without Authorization header") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("Auth header field should be Empty") callContext.authReqHeaderField should equal(Empty) @@ -373,40 +376,40 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW Given("A POST request") val request = Request[IO]( method = Method.POST, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("Verb should be POST") callContext.verb should equal("POST") } scenario("Set implementedInVersion from parameter", Http4sCallContextBuilderTag) { - Given("A request with API version v7.0.0") + Given(s"A request with API version $v700") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ) When("Building CallContext with version parameter") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("implementedInVersion should match the parameter") - callContext.implementedInVersion should equal("v7.0.0") + callContext.implementedInVersion should equal(v700) } scenario("Set startTime to current date", Http4sCallContextBuilderTag) { Given("A request") val request = Request[IO]( method = Method.GET, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks") + uri = Uri.unsafeFromString(s"$base/banks") ) When("Building CallContext") val beforeTime = new java.util.Date() - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() val afterTime = new java.util.Date() Then("startTime should be set and within reasonable range") @@ -427,7 +430,7 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW val request = Request[IO]( method = Method.POST, - uri = Uri.unsafeFromString("/obp/v7.0.0/banks?limit=10") + uri = Uri.unsafeFromString(s"$base/banks?limit=10") ).withHeaders( Header.Raw(org.typelevel.ci.CIString("Content-Type"), "application/json"), Header.Raw(org.typelevel.ci.CIString("DirectLogin"), s"token=$token"), @@ -436,12 +439,12 @@ class Http4sCallContextBuilderTest extends FeatureSpec with Matchers with GivenW ).withEntity(jsonBody) When("Building CallContext") - val callContext = Http4sCallContextBuilder.fromRequest(request, "v7.0.0").unsafeRunSync() + val callContext = Http4sCallContextBuilder.fromRequest(request, v700).unsafeRunSync() Then("All fields should be populated correctly") - callContext.url should equal("/obp/v7.0.0/banks?limit=10") + callContext.url should equal(s"$base/banks?limit=10") callContext.verb should equal("POST") - callContext.implementedInVersion should equal("v7.0.0") + callContext.implementedInVersion should equal(v700) callContext.correlationId should equal(correlationId) callContext.ipAddress should equal(clientIp) callContext.httpBody should be(Some(jsonBody)) diff --git a/obp-api/src/test/scala/code/api/util/http4s/ResourceDocMatcherTest.scala b/obp-api/src/test/scala/code/api/util/http4s/ResourceDocMatcherTest.scala index a686295aa6..a2c7c52233 100644 --- a/obp-api/src/test/scala/code/api/util/http4s/ResourceDocMatcherTest.scala +++ b/obp-api/src/test/scala/code/api/util/http4s/ResourceDocMatcherTest.scala @@ -2,6 +2,7 @@ package code.api.util.http4s import code.api.util.APIUtil.ResourceDoc import code.api.util.ApiTag.ResourceDocTag +import com.openbankproject.commons.util.ApiShortVersions import com.openbankproject.commons.util.ApiVersion import net.liftweb.json.JsonAST.JObject import org.http4s._ @@ -25,6 +26,8 @@ import scala.collection.mutable.ArrayBuffer class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThen { object ResourceDocMatcherTag extends Tag("ResourceDocMatcher") + private val v700 = ApiShortVersions.`v7.0.0`.toString + private val base = s"/obp/$v700" // Helper to create minimal ResourceDoc for testing private def createResourceDoc( @@ -56,8 +59,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("GET", "/banks", "getBanks") ) - When("Matching a GET request to /obp/v7.0.0/banks") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks") + When(s"Matching a GET request to $base/banks") + val path = Uri.Path.unsafeFromString(s"$base/banks") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -71,8 +74,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("POST", "/banks", "createBank") ) - When("Matching a POST request to /obp/v7.0.0/banks") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks") + When(s"Matching a POST request to $base/banks") + val path = Uri.Path.unsafeFromString(s"$base/banks") val result = ResourceDocMatcher.findResourceDoc("POST", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -86,8 +89,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("GET", "/management/metrics", "getMetrics") ) - When("Matching a GET request to /obp/v7.0.0/management/metrics") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/management/metrics") + When(s"Matching a GET request to $base/management/metrics") + val path = Uri.Path.unsafeFromString(s"$base/management/metrics") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -101,8 +104,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("GET", "/banks", "getBanks") ) - When("Matching a POST request to /obp/v7.0.0/banks") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks") + When(s"Matching a POST request to $base/banks") + val path = Uri.Path.unsafeFromString(s"$base/banks") val result = ResourceDocMatcher.findResourceDoc("POST", path, resourceDocs) Then("Should return None") @@ -115,8 +118,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("GET", "/banks", "getBanks") ) - When("Matching a GET request to /obp/v7.0.0/accounts") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/accounts") + When(s"Matching a GET request to $base/accounts") + val path = Uri.Path.unsafeFromString(s"$base/accounts") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should return None") @@ -132,8 +135,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("GET", "/banks/BANK_ID", "getBank") ) - When("Matching a GET request to /obp/v7.0.0/banks/gh.29.de") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de") + When(s"Matching a GET request to $base/banks/gh.29.de") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -147,8 +150,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("GET", "/banks/BANK_ID/accounts", "getBankAccounts") ) - When("Matching a GET request to /obp/v7.0.0/banks/test-bank-1/accounts") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/test-bank-1/accounts") + When(s"Matching a GET request to $base/banks/test-bank-1/accounts") + val path = Uri.Path.unsafeFromString(s"$base/banks/test-bank-1/accounts") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -160,8 +163,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe Given("A matched ResourceDoc with BANK_ID") val resourceDoc = createResourceDoc("GET", "/banks/BANK_ID", "getBank") - When("Extracting path parameters from /obp/v7.0.0/banks/gh.29.de") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de") + When(s"Extracting path parameters from $base/banks/gh.29.de") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de") val params = ResourceDocMatcher.extractPathParams(path, resourceDoc) Then("Should extract BANK_ID value") @@ -178,8 +181,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("GET", "/banks/BANK_ID/accounts/ACCOUNT_ID", "getBankAccount") ) - When("Matching a GET request to /obp/v7.0.0/banks/gh.29.de/accounts/test1") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de/accounts/test1") + When(s"Matching a GET request to $base/banks/gh.29.de/accounts/test1") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de/accounts/test1") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -191,8 +194,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe Given("A matched ResourceDoc with BANK_ID and ACCOUNT_ID") val resourceDoc = createResourceDoc("GET", "/banks/BANK_ID/accounts/ACCOUNT_ID", "getBankAccount") - When("Extracting path parameters from /obp/v7.0.0/banks/gh.29.de/accounts/test1") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de/accounts/test1") + When(s"Extracting path parameters from $base/banks/gh.29.de/accounts/test1") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de/accounts/test1") val params = ResourceDocMatcher.extractPathParams(path, resourceDoc) Then("Should extract both BANK_ID and ACCOUNT_ID values") @@ -208,8 +211,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("GET", "/banks/BANK_ID/accounts/ACCOUNT_ID/transactions", "getTransactions") ) - When("Matching a GET request to /obp/v7.0.0/banks/test-bank/accounts/acc-123/transactions") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/test-bank/accounts/acc-123/transactions") + When(s"Matching a GET request to $base/banks/test-bank/accounts/acc-123/transactions") + val path = Uri.Path.unsafeFromString(s"$base/banks/test-bank/accounts/acc-123/transactions") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -226,8 +229,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("GET", "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions", "getTransactionsForView") ) - When("Matching a GET request to /obp/v7.0.0/banks/gh.29.de/accounts/test1/owner/transactions") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de/accounts/test1/owner/transactions") + When(s"Matching a GET request to $base/banks/gh.29.de/accounts/test1/owner/transactions") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de/accounts/test1/owner/transactions") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -239,8 +242,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe Given("A matched ResourceDoc with BANK_ID, ACCOUNT_ID and VIEW_ID") val resourceDoc = createResourceDoc("GET", "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/transactions", "getTransactionsForView") - When("Extracting path parameters from /obp/v7.0.0/banks/gh.29.de/accounts/test1/owner/transactions") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de/accounts/test1/owner/transactions") + When(s"Extracting path parameters from $base/banks/gh.29.de/accounts/test1/owner/transactions") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de/accounts/test1/owner/transactions") val params = ResourceDocMatcher.extractPathParams(path, resourceDoc) Then("Should extract all three parameter values") @@ -258,8 +261,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("GET", "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/account", "getAccountForView") ) - When("Matching a GET request to /obp/v7.0.0/banks/test-bank/accounts/acc-1/public/account") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/test-bank/accounts/acc-1/public/account") + When(s"Matching a GET request to $base/banks/test-bank/accounts/acc-1/public/account") + val path = Uri.Path.unsafeFromString(s"$base/banks/test-bank/accounts/acc-1/public/account") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -277,7 +280,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe ) When("Matching a GET request with counterparty ID") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de/accounts/test1/owner/counterparties/ff010868-ac7d-4f96-9fc5-70dd5757e891") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de/accounts/test1/owner/counterparties/ff010868-ac7d-4f96-9fc5-70dd5757e891") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -290,7 +293,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe val resourceDoc = createResourceDoc("GET", "/banks/BANK_ID/accounts/ACCOUNT_ID/VIEW_ID/counterparties/COUNTERPARTY_ID", "getCounterparty") When("Extracting path parameters") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de/accounts/test1/owner/counterparties/ff010868-ac7d-4f96-9fc5-70dd5757e891") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de/accounts/test1/owner/counterparties/ff010868-ac7d-4f96-9fc5-70dd5757e891") val params = ResourceDocMatcher.extractPathParams(path, resourceDoc) Then("Should extract all parameter values including COUNTERPARTY_ID") @@ -311,7 +314,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe ) When("Matching a DELETE request") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/management/counterparties/counterparty-123") + val path = Uri.Path.unsafeFromString(s"$base/management/counterparties/counterparty-123") val result = ResourceDocMatcher.findResourceDoc("DELETE", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -331,7 +334,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe ) When("Matching a request that doesn't match any ResourceDoc") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/accounts") + val path = Uri.Path.unsafeFromString(s"$base/accounts") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should return None") @@ -344,8 +347,8 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe createResourceDoc("GET", "/banks", "getBanks") ) - When("Matching a DELETE request to /obp/v7.0.0/banks") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks") + When(s"Matching a DELETE request to $base/banks") + val path = Uri.Path.unsafeFromString(s"$base/banks") val result = ResourceDocMatcher.findResourceDoc("DELETE", path, resourceDocs) Then("Should return None") @@ -359,7 +362,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe ) When("Matching a request with different segment count") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should return None") @@ -373,7 +376,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe ) When("Matching a request with different literal segment") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de/transactions") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de/transactions") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should return None") @@ -388,7 +391,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe val resourceDoc = createResourceDoc("GET", "/banks", "getBanks") When("Extracting path parameters") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks") + val path = Uri.Path.unsafeFromString(s"$base/banks") val params = ResourceDocMatcher.extractPathParams(path, resourceDoc) Then("Should return empty map") @@ -400,7 +403,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe val resourceDoc = createResourceDoc("GET", "/banks/BANK_ID", "getBank") When("Extracting path parameters with special characters") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de-test_bank") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de-test_bank") val params = ResourceDocMatcher.extractPathParams(path, resourceDoc) Then("Should extract the full value including special characters") @@ -413,7 +416,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe val resourceDoc = createResourceDoc("GET", "/banks/BANK_ID", "getBank") When("Extracting parameters from path with different segment count") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/accounts") + val path = Uri.Path.unsafeFromString(s"$base/accounts") val params = ResourceDocMatcher.extractPathParams(path, resourceDoc) Then("Should return empty map due to segment count mismatch") @@ -458,9 +461,9 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe val resourceDoc = createResourceDoc("GET", "/banks", "getBanks") val originalContext = code.api.util.CallContext( correlationId = "test-correlation-id", - url = "/obp/v7.0.0/banks", + url = s"$base/banks", verb = "GET", - implementedInVersion = "v7.0.0" + implementedInVersion = v700 ) When("Attaching ResourceDoc to CallContext") @@ -486,7 +489,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe ) When("Matching a specific request") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks/gh.29.de/accounts") + val path = Uri.Path.unsafeFromString(s"$base/banks/gh.29.de/accounts") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should select the most specific matching ResourceDoc") @@ -502,7 +505,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe ) When("Matching a request") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks") + val path = Uri.Path.unsafeFromString(s"$base/banks") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should return the first matching ResourceDoc") @@ -520,7 +523,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe ) When("Matching with lowercase get") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/banks") + val path = Uri.Path.unsafeFromString(s"$base/banks") val result = ResourceDocMatcher.findResourceDoc("get", path, resourceDocs) Then("Should find the matching ResourceDoc") @@ -535,7 +538,7 @@ class ResourceDocMatcherTest extends FeatureSpec with Matchers with GivenWhenThe ) When("Matching with different case /Banks") - val path = Uri.Path.unsafeFromString("/obp/v7.0.0/Banks") + val path = Uri.Path.unsafeFromString(s"$base/Banks") val result = ResourceDocMatcher.findResourceDoc("GET", path, resourceDocs) Then("Should not match (case-sensitive)") diff --git a/obp-api/src/test/scala/code/api/v1_4_0/JSONFactory1_4_0Test.scala b/obp-api/src/test/scala/code/api/v1_4_0/JSONFactory1_4_0Test.scala index c5be0d68c7..38304e9208 100644 --- a/obp-api/src/test/scala/code/api/v1_4_0/JSONFactory1_4_0Test.scala +++ b/obp-api/src/test/scala/code/api/v1_4_0/JSONFactory1_4_0Test.scala @@ -1,13 +1,13 @@ package code.api.v1_4_0 import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.usersJsonV400 - +import code.api.Constant import java.util.Date import code.api.util.APIUtil.ResourceDoc import code.api.util.{APIUtil, ExampleValue} +import code.api.util.CustomJsonFormats import code.api.v1_4_0.JSONFactory1_4_0.ResourceDocJson import code.api.v3_0_0.OBPAPI3_0_0 -import code.setup.DefaultUsers import net.liftweb.json.Extraction.decompose import net.liftweb.json._ import org.everit.json.schema.loader.SchemaLoader @@ -44,7 +44,8 @@ case class AllCases( jvalues: List[JValue]= List(APIUtil.defaultJValue) ) -class JSONFactory1_4_0Test extends V140ServerSetup with DefaultUsers { +class JSONFactory1_4_0Test extends code.setup.ServerSetup { + override implicit val formats: Formats = CustomJsonFormats.formats feature("Test JSONFactory1_4_0") { scenario("prepareDescription should work well, extract the parameters from URL") { @@ -116,7 +117,7 @@ class JSONFactory1_4_0Test extends V140ServerSetup with DefaultUsers { scenario("createResourceDocJson should work well, no exception is good enough") { val resourceDoc: ResourceDoc = OBPAPI3_0_0.allResourceDocs(5) val result: ResourceDocJson = JSONFactory1_4_0.createLocalisedResourceDocJson(resourceDoc,false, None, - urlParameters, "JSON request body fields:", "JSON response body fields:") + includeTechnology = false, urlParameters, "JSON request body fields:", "JSON response body fields:") } scenario("createResourceDocsJson should work well, no exception is good enough") { @@ -124,6 +125,21 @@ class JSONFactory1_4_0Test extends V140ServerSetup with DefaultUsers { val result = JSONFactory1_4_0.createResourceDocsJson(resourceDoc.toList, false, None) } + scenario("Technology field should be None unless includeTechnology=true") { + val liftDoc: ResourceDoc = OBPAPI3_0_0.allResourceDocs(0) + val json1 = JSONFactory1_4_0.createLocalisedResourceDocJson(liftDoc, false, None, includeTechnology = false, urlParameters, "JSON request body fields:", "JSON response body fields:") + json1.implemented_by.technology shouldBe None + + val json2 = JSONFactory1_4_0.createLocalisedResourceDocJson(liftDoc, false, None, includeTechnology = true, urlParameters, "JSON request body fields:", "JSON response body fields:") + json2.implemented_by.technology shouldBe Some(Constant.TECHNOLOGY_LIFTWEB) + } + + scenario("Technology field should be http4s when includeTechnology=true and doc is http4s") { + val http4sDoc: ResourceDoc = code.api.v7_0_0.Http4s700.resourceDocs.head + val json = JSONFactory1_4_0.createLocalisedResourceDocJson(http4sDoc, true, None, includeTechnology = true, urlParameters, "JSON request body fields:", "JSON response body fields:") + json.implemented_by.technology shouldBe Some(Constant.TECHNOLOGY_HTTP4S) + } + scenario("createTypedBody should work well, no exception is good enough") { val inputCaseClass = AllCases() val result = JSONFactory1_4_0.createTypedBody(inputCaseClass) diff --git a/obp-api/src/test/scala/code/api/v7_0_0/Http4s700RoutesTest.scala b/obp-api/src/test/scala/code/api/v7_0_0/Http4s700RoutesTest.scala index c43070d730..56cf330d57 100644 --- a/obp-api/src/test/scala/code/api/v7_0_0/Http4s700RoutesTest.scala +++ b/obp-api/src/test/scala/code/api/v7_0_0/Http4s700RoutesTest.scala @@ -1,9 +1,10 @@ package code.api.v7_0_0 +import code.api.Constant import cats.effect.IO import cats.effect.unsafe.implicits.global import code.api.util.ApiRole.{canGetCardsForBank, canReadResourceDoc} -import code.api.util.ErrorMessages.{AuthenticatedUserIsRequired, BankNotFound, UserHasMissingRoles} +import code.api.util.ErrorMessages.{AuthenticatedUserIsRequired, BankNotFound, InvalidApiVersionString, UserHasMissingRoles} import code.setup.ServerSetupWithTestData import net.liftweb.json.JValue import net.liftweb.json.JsonAST.{JArray, JField, JObject, JString} @@ -246,8 +247,68 @@ class Http4s700RoutesTest extends ServerSetupWithTestData { json match { case JObject(fields) => toFieldMap(fields).get("resource_docs") match { - case Some(JArray(_)) => - succeed + case Some(JArray(resourceDocs)) => + resourceDocs.exists { + case JObject(rdFields) => + toFieldMap(rdFields).get("implemented_by") match { + case Some(JObject(implFields)) => + toFieldMap(implFields).get("technology") match { + case Some(JString(value)) => value == Constant.TECHNOLOGY_HTTP4S + case _ => false + } + case _ => false + } + case _ => false + } shouldBe true + case _ => + fail("Expected resource_docs field to be an array") + } + case _ => + fail("Expected JSON object for resource-docs endpoint") + } + } + + scenario("Return only http4s technology endpoints", Http4s700RoutesTag) { + Given("GET /obp/v7.0.0/resource-docs/v7.0.0/obp request") + setPropsValues("resource_docs_requires_role" -> "false") + val request = Request[IO]( + method = Method.GET, + uri = Uri.unsafeFromString("/obp/v7.0.0/resource-docs/v7.0.0/obp") + ) + + When("Running through wrapped routes") + val (status, json) = runAndParseJson(request) + + Then("Response is 200 OK and includes no lift endpoints") + status shouldBe Status.Ok + json match { + case JObject(fields) => + toFieldMap(fields).get("resource_docs") match { + case Some(JArray(resourceDocs)) => + resourceDocs.exists { + case JObject(rdFields) => + toFieldMap(rdFields).get("implemented_by") match { + case Some(JObject(implFields)) => + toFieldMap(implFields).get("technology") match { + case Some(JString(value)) => value == Constant.TECHNOLOGY_HTTP4S + case _ => false + } + case _ => false + } + case _ => false + } shouldBe true + resourceDocs.exists { + case JObject(rdFields) => + toFieldMap(rdFields).get("implemented_by") match { + case Some(JObject(implFields)) => + toFieldMap(implFields).get("technology") match { + case Some(JString(value)) => value == Constant.TECHNOLOGY_LIFTWEB + case _ => false + } + case _ => false + } + case _ => false + } shouldBe false case _ => fail("Expected resource_docs field to be an array") } @@ -256,6 +317,33 @@ class Http4s700RoutesTest extends ServerSetupWithTestData { } } + scenario("Reject requesting non-v7 API version docs", Http4s700RoutesTag) { + Given("GET /obp/v7.0.0/resource-docs/v6.0.0/obp request") + setPropsValues("resource_docs_requires_role" -> "false") + val request = Request[IO]( + method = Method.GET, + uri = Uri.unsafeFromString("/obp/v7.0.0/resource-docs/v6.0.0/obp") + ) + + When("Running through wrapped routes") + val (status, json) = runAndParseJson(request) + + Then("Response is 400 Bad Request") + status.code shouldBe 400 + json match { + case JObject(fields) => + toFieldMap(fields).get("message") match { + case Some(JString(message)) => + message should include(InvalidApiVersionString) + message should include("v6.0.0") + case _ => + fail("Expected message field as JSON string for invalid-version response") + } + case _ => + fail("Expected JSON object for invalid-version response") + } + } + scenario("Reject unauthenticated access when resource docs role is required", Http4s700RoutesTag) { Given("GET /obp/v7.0.0/resource-docs/v7.0.0/obp request without auth headers and role required") setPropsValues("resource_docs_requires_role" -> "true") diff --git a/obp-api/src/test/scala/code/setup/DefaultUsers.scala b/obp-api/src/test/scala/code/setup/DefaultUsers.scala index 4f148ff39c..220e0f3567 100644 --- a/obp-api/src/test/scala/code/setup/DefaultUsers.scala +++ b/obp-api/src/test/scala/code/setup/DefaultUsers.scala @@ -106,28 +106,79 @@ trait DefaultUsers { // Create resource user, need provider val defaultProvider = Constant.HostName + private def getOrCreateResourceUser( + provider: String, + providerId: String, + createdByConsentId: Option[String], + name: String, + email: String, + userId: Option[String], + company: String + ): ResourceUser = { + UserX.findByProviderId(provider = provider, idGivenByProvider = providerId) + .map(_.asInstanceOf[ResourceUser]) + .getOrElse { + try { + UserX + .createResourceUser( + provider = provider, + providerId = Some(providerId), + createdByConsentId = createdByConsentId, + name = Some(name), + email = Some(email), + userId = userId, + company = Some(company) + ) + .openOrThrowException(attemptedToOpenAnEmptyBox) + } catch { + case e: Throwable => + UserX.findByProviderId(provider = provider, idGivenByProvider = providerId) + .map(_.asInstanceOf[ResourceUser]) + .getOrElse(throw e) + } + } + } + // create some resource user for test purposes - lazy val resourceUser1 = UserX.findByProviderId(provider = defaultProvider, idGivenByProvider= resourceUser1Name).map(_.asInstanceOf[ResourceUser]) - .getOrElse(UserX.createResourceUser(provider = defaultProvider, providerId= Some(resourceUser1Name), createdByConsentId= None, name= Some(resourceUser1Name), - email= Some("resourceUser1@123.com"), userId= userId1, company = Some("Tesobe GmbH")) - .openOrThrowException(attemptedToOpenAnEmptyBox) - ) + lazy val resourceUser1 = getOrCreateResourceUser( + provider = defaultProvider, + providerId = resourceUser1Name, + createdByConsentId = None, + name = resourceUser1Name, + email = "resourceUser1@123.com", + userId = userId1, + company = "Tesobe GmbH" + ) - lazy val resourceUser2 = UserX.findByProviderId(provider = defaultProvider, idGivenByProvider= resourceUser2Name).map(_.asInstanceOf[ResourceUser]) - .getOrElse(UserX.createResourceUser(provider = defaultProvider, providerId= Some(resourceUser2Name), createdByConsentId= None, - name= Some(resourceUser2Name),email= Some("resourceUser2@123.com"), userId= userId2, company = Some("Tesobe GmbH")) - .openOrThrowException(attemptedToOpenAnEmptyBox) - ) + lazy val resourceUser2 = getOrCreateResourceUser( + provider = defaultProvider, + providerId = resourceUser2Name, + createdByConsentId = None, + name = resourceUser2Name, + email = "resourceUser2@123.com", + userId = userId2, + company = "Tesobe GmbH" + ) - lazy val resourceUser3 = UserX.findByProviderId(provider = defaultProvider, idGivenByProvider= resourceUser3Name).map(_.asInstanceOf[ResourceUser]) - .getOrElse(UserX.createResourceUser(provider = defaultProvider, providerId= Some(resourceUser3Name), createdByConsentId= None, - name= Some(resourceUser3Name),email= Some("resourceUser3@123.com"), userId= userId3, company = Some("Tesobe GmbH")) - .openOrThrowException(attemptedToOpenAnEmptyBox)) + lazy val resourceUser3 = getOrCreateResourceUser( + provider = defaultProvider, + providerId = resourceUser3Name, + createdByConsentId = None, + name = resourceUser3Name, + email = "resourceUser3@123.com", + userId = userId3, + company = "Tesobe GmbH" + ) - lazy val resourceUser4 = UserX.findByProviderId(provider = defaultProvider, idGivenByProvider= resourceUser4Name).map(_.asInstanceOf[ResourceUser]) - .getOrElse(UserX.createResourceUser(provider = GatewayLogin.gateway, providerId = Some(resourceUser4Name), createdByConsentId= Some("simonr"), name= Some(resourceUser4Name), - email= Some("resourceUser4@123.com"), userId=userId4, company = Some("Tesobe GmbH")) - .openOrThrowException(attemptedToOpenAnEmptyBox)) + lazy val resourceUser4 = getOrCreateResourceUser( + provider = GatewayLogin.gateway, + providerId = resourceUser4Name, + createdByConsentId = Some("simonr"), + name = resourceUser4Name, + email = "resourceUser4@123.com", + userId = userId4, + company = "Tesobe GmbH" + ) // create the tokens in database, we only need token-key and token-secretAllCases lazy val testToken1 = Tokens.tokens.vend.createToken( diff --git a/obp-api/src/test/scala/code/setup/LocalMappedConnectorTestSetup.scala b/obp-api/src/test/scala/code/setup/LocalMappedConnectorTestSetup.scala index 8e0964c982..d88905d188 100644 --- a/obp-api/src/test/scala/code/setup/LocalMappedConnectorTestSetup.scala +++ b/obp-api/src/test/scala/code/setup/LocalMappedConnectorTestSetup.scala @@ -65,30 +65,56 @@ trait LocalMappedConnectorTestSetup extends TestConnectorSetupWithStandardPermis } override protected def createAccount(bankId: BankId, accountId : AccountId, currency : String) : BankAccount = { - BankAccountRouting.create - .BankId(bankId.value) - .AccountId(accountId.value) - .AccountRoutingScheme(AccountRoutingScheme.IBAN.toString) - .AccountRoutingAddress(iban4j.Iban.random().toString()) - .saveMe - BankAccountRouting.create - .BankId(bankId.value) - .AccountId(accountId.value) - .AccountRoutingScheme("AccountId") - .AccountRoutingAddress(accountId.value) - .saveMe - MappedBankAccount.create - .bank(bankId.value) - .theAccountId(accountId.value) - .accountCurrency(currency.toUpperCase) - .accountBalance(900000000) - .holder(randomString(4)) - .accountLastUpdate(now) - .accountName(randomString(4)) - .accountNumber(randomString(4)) - .accountLabel(randomString(4)) - .mBranchId(randomString(4)) - .saveMe + def getOrCreateRouting(scheme: String, address: String): Unit = { + val existing = BankAccountRouting.find( + By(BankAccountRouting.BankId, bankId.value), + By(BankAccountRouting.AccountId, accountId.value), + By(BankAccountRouting.AccountRoutingScheme, scheme) + ) + if (!existing.isDefined) { + try { + BankAccountRouting.create + .BankId(bankId.value) + .AccountId(accountId.value) + .AccountRoutingScheme(scheme) + .AccountRoutingAddress(address) + .saveMe + } catch { + case _: Throwable => + } + } + () + } + + getOrCreateRouting(AccountRoutingScheme.IBAN.toString, iban4j.Iban.random().toString()) + getOrCreateRouting("AccountId", accountId.value) + + val existingAccount = MappedBankAccount.find( + By(MappedBankAccount.bank, bankId.value), + By(MappedBankAccount.theAccountId, accountId.value) + ) + existingAccount.openOr { + try { + MappedBankAccount.create + .bank(bankId.value) + .theAccountId(accountId.value) + .accountCurrency(currency.toUpperCase) + .accountBalance(900000000) + .holder(randomString(4)) + .accountLastUpdate(now) + .accountName(randomString(4)) + .accountNumber(randomString(4)) + .accountLabel(randomString(4)) + .mBranchId(randomString(4)) + .saveMe + } catch { + case _: Throwable => + MappedBankAccount.find( + By(MappedBankAccount.bank, bankId.value), + By(MappedBankAccount.theAccountId, accountId.value) + ).openOrThrowException(attemptedToOpenAnEmptyBox) + } + } } override protected def updateAccountCurrency(bankId: BankId, accountId : AccountId, currency : String) : BankAccount = { diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/util/ApiVersion.scala b/obp-commons/src/main/scala/com/openbankproject/commons/util/ApiVersion.scala index 6173ec700c..e0fad93ce5 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/util/ApiVersion.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/util/ApiVersion.scala @@ -143,6 +143,8 @@ object ApiVersion { val berlinGroupV13 = ScannedApiVersion("berlin-group", "BG", "v1.3") val mxofV100 = ScannedApiVersion("mxof", "MXOF", "v1.0.0") val cnbv9 = ScannedApiVersion("CNBV9", "CNBV9", "v1.0.0") + val bahrainObfV100 = ScannedApiVersion("BAHRAIN-OBF", "BAHRAIN-OBF", "v1.0.0") + val auOpenBankingV100 = ScannedApiVersion("cds-au", "AU", "v1.0.0") /** * the ApiPathZero value must be got by obp-api project, so here is a workaround, let obp-api project modify this value