diff --git a/obp-api/pom.xml b/obp-api/pom.xml
index 0a1501d849..c11d235330 100644
--- a/obp-api/pom.xml
+++ b/obp-api/pom.xml
@@ -23,6 +23,52 @@
src/main/resources/web.xml
+
+ http4s-jar
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 3.6.0
+
+ false
+ ${project.artifactId}-http4s
+
+
+ bootstrap.http4s.Http4sServer
+
+
+
+ jar-with-dependencies
+
+
+
+ /
+ true
+ runtime
+
+
+
+
+ ${project.build.outputDirectory}
+ /
+
+
+
+
+
+ http4s-fat-jar
+ package
+
+ single
+
+
+
+
+
+
+
@@ -84,6 +130,16 @@
bcpg-jdk15on
1.70
+
+ org.http4s
+ http4s-ember-server_${scala.version}
+ ${http4s.version}
+
+
+ org.http4s
+ http4s-dsl_${scala.version}
+ ${http4s.version}
+
org.bouncycastle
bcpkix-jdk15on
@@ -345,7 +401,7 @@
org.clapper
classutil_${scala.version}
- 1.4.0
+ 1.5.1
com.github.grumlimited
@@ -602,6 +658,20 @@
net.alchim31.maven
scala-maven-plugin
+ 4.8.1
+
+ true
+
+ -Xms4G
+ -Xmx12G
+ -XX:MaxMetaspaceSize=4G
+ -XX:+UseG1GC
+
+
+ -deprecation
+ -feature
+
+
org.apache.maven.plugins
@@ -609,6 +679,8 @@
3.4.0
${webXmlPath}
+ true
+ classes
diff --git a/obp-api/src/main/scala/bootstrap/http4s/Http4sBoot.scala b/obp-api/src/main/scala/bootstrap/http4s/Http4sBoot.scala
new file mode 100644
index 0000000000..0a867ec4a6
--- /dev/null
+++ b/obp-api/src/main/scala/bootstrap/http4s/Http4sBoot.scala
@@ -0,0 +1,346 @@
+/**
+Open Bank Project - API
+Copyright (C) 2011-2019, TESOBE GmbH.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+Email: contact@tesobe.com
+TESOBE GmbH.
+Osloer Strasse 16/17
+Berlin 13359, Germany
+
+This product includes software developed at
+TESOBE (http://www.tesobe.com/)
+
+ */
+package bootstrap.http4s
+
+import bootstrap.liftweb.ToSchemify
+import code.api.Constant._
+import code.api.util.ApiRole.CanCreateEntitlementAtAnyBank
+import code.api.util.ErrorMessages.MandatoryPropertyIsNotSet
+import code.api.util._
+import code.api.util.migration.Migration
+import code.api.util.migration.Migration.DbFunction
+import code.entitlement.Entitlement
+import code.model.dataAccess._
+import code.scheduler._
+import code.users._
+import code.util.Helper.MdcLoggable
+import code.views.Views
+import com.openbankproject.commons.util.Functions.Implicits._
+import net.liftweb.common.Box.tryo
+import net.liftweb.common._
+import net.liftweb.db.{DB, DBLogEntry}
+import net.liftweb.mapper.{DefaultConnectionIdentifier => _, _}
+import net.liftweb.util._
+
+import java.io.{File, FileInputStream}
+import java.util.TimeZone
+
+
+
+
+/**
+ * Http4s Boot class for initializing OBP-API core components
+ * This class handles database initialization, migrations, and system setup
+ * without Lift Web framework dependencies
+ */
+class Http4sBoot extends MdcLoggable {
+
+ /**
+ * For the project scope, most early initiate logic should in this method.
+ */
+ override protected def initiate(): Unit = {
+ val resourceDir = System.getProperty("props.resource.dir") ?: System.getenv("props.resource.dir")
+ val propsPath = tryo{Box.legacyNullTest(resourceDir)}.toList.flatten
+
+ val propsDir = for {
+ propsPath <- propsPath
+ } yield {
+ Props.toTry.map {
+ f => {
+ val name = propsPath + f() + "props"
+ name -> { () => tryo{new FileInputStream(new File(name))} }
+ }
+ }
+ }
+
+ Props.whereToLook = () => {
+ propsDir.flatten
+ }
+
+ if (Props.mode == Props.RunModes.Development) logger.info("OBP-API Props all fields : \n" + Props.props.mkString("\n"))
+ logger.info("external props folder: " + propsPath)
+ TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
+ logger.info("Current Project TimeZone: " + TimeZone.getDefault)
+
+
+ // set dynamic_code_sandbox_enable to System.properties, so com.openbankproject.commons.ExecutionContext can read this value
+ APIUtil.getPropsValue("dynamic_code_sandbox_enable")
+ .foreach(it => System.setProperty("dynamic_code_sandbox_enable", it))
+ }
+
+
+
+ def boot: Unit = {
+ implicit val formats = CustomJsonFormats.formats
+
+ logger.info("Http4sBoot says: Hello from the Open Bank Project API. This is Http4sBoot.scala for Http4s runner. The gitCommit is : " + APIUtil.gitCommit)
+
+ logger.debug("Boot says:Using database driver: " + APIUtil.driver)
+
+ DB.defineConnectionManager(net.liftweb.util.DefaultConnectionIdentifier, APIUtil.vendor)
+
+ /**
+ * Function that determines if foreign key constraints are
+ * created by Schemifier for the specified connection.
+ *
+ * Note: The chosen driver must also support foreign keys for
+ * creation to happen
+ *
+ * In case of PostgreSQL it works
+ */
+ MapperRules.createForeignKeys_? = (_) => APIUtil.getPropsAsBoolValue("mapper_rules.create_foreign_keys", false)
+
+ schemifyAll()
+
+ logger.info("Mapper database info: " + Migration.DbFunction.mapperDatabaseInfo)
+
+ DbFunction.tableExists(ResourceUser) match {
+ case true => // DB already exist
+ // Migration Scripts are used to update the model of OBP-API DB to a latest version.
+ // Please note that migration scripts are executed before Lift Mapper Schemifier
+ Migration.database.executeScripts(startedBeforeSchemifier = true)
+ logger.info("The Mapper database already exits. The scripts are executed BEFORE Lift Mapper Schemifier.")
+ case false => // DB is still not created. The scripts will be executed after Lift Mapper Schemifier
+ logger.info("The Mapper database is still not created. The scripts are going to be executed AFTER Lift Mapper Schemifier.")
+ }
+
+ // Migration Scripts are used to update the model of OBP-API DB to a latest version.
+
+ // Please note that migration scripts are executed after Lift Mapper Schemifier
+ Migration.database.executeScripts(startedBeforeSchemifier = false)
+
+ if (APIUtil.getPropsAsBoolValue("create_system_views_at_boot", true)) {
+ // Create system views
+ val owner = Views.views.vend.getOrCreateSystemView(SYSTEM_OWNER_VIEW_ID).isDefined
+ val auditor = Views.views.vend.getOrCreateSystemView(SYSTEM_AUDITOR_VIEW_ID).isDefined
+ val accountant = Views.views.vend.getOrCreateSystemView(SYSTEM_ACCOUNTANT_VIEW_ID).isDefined
+ val standard = Views.views.vend.getOrCreateSystemView(SYSTEM_STANDARD_VIEW_ID).isDefined
+ val stageOne = Views.views.vend.getOrCreateSystemView(SYSTEM_STAGE_ONE_VIEW_ID).isDefined
+ val manageCustomViews = Views.views.vend.getOrCreateSystemView(SYSTEM_MANAGE_CUSTOM_VIEWS_VIEW_ID).isDefined
+ // Only create Firehose view if they are enabled at instance.
+ val accountFirehose = if (ApiPropsWithAlias.allowAccountFirehose)
+ Views.views.vend.getOrCreateSystemView(SYSTEM_FIREHOSE_VIEW_ID).isDefined
+ else Empty.isDefined
+
+ APIUtil.getPropsValue("additional_system_views") match {
+ case Full(value) =>
+ val additionalSystemViewsFromProps = value.split(",").map(_.trim).toList
+ val additionalSystemViews = List(
+ SYSTEM_READ_ACCOUNTS_BASIC_VIEW_ID,
+ SYSTEM_READ_ACCOUNTS_DETAIL_VIEW_ID,
+ SYSTEM_READ_BALANCES_VIEW_ID,
+ SYSTEM_READ_TRANSACTIONS_BASIC_VIEW_ID,
+ SYSTEM_READ_TRANSACTIONS_DEBITS_VIEW_ID,
+ SYSTEM_READ_TRANSACTIONS_DETAIL_VIEW_ID,
+ SYSTEM_READ_ACCOUNTS_BERLIN_GROUP_VIEW_ID,
+ SYSTEM_READ_BALANCES_BERLIN_GROUP_VIEW_ID,
+ SYSTEM_READ_TRANSACTIONS_BERLIN_GROUP_VIEW_ID,
+ SYSTEM_INITIATE_PAYMENTS_BERLIN_GROUP_VIEW_ID
+ )
+ for {
+ systemView <- additionalSystemViewsFromProps
+ if additionalSystemViews.exists(_ == systemView)
+ } {
+ Views.views.vend.getOrCreateSystemView(systemView)
+ }
+ case _ => // Do nothing
+ }
+
+ }
+
+ ApiWarnings.logWarningsRegardingProperties()
+ ApiWarnings.customViewNamesCheck()
+ ApiWarnings.systemViewNamesCheck()
+
+ //see the notes for this method:
+ createDefaultBankAndDefaultAccountsIfNotExisting()
+
+ createBootstrapSuperUser()
+
+ if (APIUtil.getPropsAsBoolValue("logging.database.queries.enable", false)) {
+ DB.addLogFunc
+ {
+ case (log, duration) =>
+ {
+ logger.debug("Total query time : %d ms".format(duration))
+ log.allEntries.foreach
+ {
+ case DBLogEntry(stmt, duration) =>
+ logger.debug("The query : %s in %d ms".format(stmt, duration))
+ }
+ }
+ }
+ }
+
+ // start RabbitMq Adapter(using mapped connector as mockded CBS)
+ if (APIUtil.getPropsAsBoolValue("rabbitmq.adapter.enabled", false)) {
+ code.bankconnectors.rabbitmq.Adapter.startRabbitMqAdapter.main(Array(""))
+ }
+
+ // ensure our relational database's tables are created/fit the schema
+ val connector = code.api.Constant.CONNECTOR.openOrThrowException(s"$MandatoryPropertyIsNotSet. The missing prop is `connector` ")
+
+ logger.info(s"ApiPathZero (the bit before version) is $ApiPathZero")
+ logger.debug(s"If you can read this, logging level is debug")
+
+ // API Metrics (logs of API calls)
+ // If set to true we will write each URL with params to a datastore / log file
+ if (APIUtil.getPropsAsBoolValue("write_metrics", false)) {
+ logger.info("writeMetrics is true. We will write API metrics")
+ } else {
+ logger.info("writeMetrics is false. We will NOT write API metrics")
+ }
+
+ // API Metrics (logs of Connector calls)
+ // If set to true we will write each URL with params to a datastore / log file
+ if (APIUtil.getPropsAsBoolValue("write_connector_metrics", false)) {
+ logger.info("writeConnectorMetrics is true. We will write connector metrics")
+ } else {
+ logger.info("writeConnectorMetrics is false. We will NOT write connector metrics")
+ }
+
+
+ logger.info (s"props_identifier is : ${APIUtil.getPropsValue("props_identifier", "NONE-SET")}")
+
+ val locale = I18NUtil.getDefaultLocale()
+ logger.info("Default Project Locale is :" + locale)
+
+ }
+
+ def schemifyAll() = {
+ Schemifier.schemify(true, Schemifier.infoF _, ToSchemify.models: _*)
+ }
+
+
+ /**
+ * there will be a default bank and two default accounts in obp mapped mode.
+ * These bank and accounts will be used for the payments.
+ * when we create transaction request over counterparty and if the counterparty do not link to an existing obp account
+ * then we will use the default accounts (incoming and outgoing) to keep the money.
+ */
+ private def createDefaultBankAndDefaultAccountsIfNotExisting() ={
+ val defaultBankId= APIUtil.defaultBankId
+ val incomingAccountId= INCOMING_SETTLEMENT_ACCOUNT_ID
+ val outgoingAccountId= OUTGOING_SETTLEMENT_ACCOUNT_ID
+
+ MappedBank.find(By(MappedBank.permalink, defaultBankId)) match {
+ case Full(b) =>
+ logger.debug(s"Bank(${defaultBankId}) is found.")
+ case _ =>
+ MappedBank.create
+ .permalink(defaultBankId)
+ .fullBankName("OBP_DEFAULT_BANK")
+ .shortBankName("OBP")
+ .national_identifier("OBP")
+ .mBankRoutingScheme("OBP")
+ .mBankRoutingAddress("obp1")
+ .logoURL("")
+ .websiteURL("")
+ .saveMe()
+ logger.debug(s"creating Bank(${defaultBankId})")
+ }
+
+ MappedBankAccount.find(By(MappedBankAccount.bank, defaultBankId), By(MappedBankAccount.theAccountId, incomingAccountId)) match {
+ case Full(b) =>
+ logger.debug(s"BankAccount(${defaultBankId}, $incomingAccountId) is found.")
+ case _ =>
+ MappedBankAccount.create
+ .bank(defaultBankId)
+ .theAccountId(incomingAccountId)
+ .accountCurrency("EUR")
+ .saveMe()
+ logger.debug(s"creating BankAccount(${defaultBankId}, $incomingAccountId).")
+ }
+
+ MappedBankAccount.find(By(MappedBankAccount.bank, defaultBankId), By(MappedBankAccount.theAccountId, outgoingAccountId)) match {
+ case Full(b) =>
+ logger.debug(s"BankAccount(${defaultBankId}, $outgoingAccountId) is found.")
+ case _ =>
+ MappedBankAccount.create
+ .bank(defaultBankId)
+ .theAccountId(outgoingAccountId)
+ .accountCurrency("EUR")
+ .saveMe()
+ logger.debug(s"creating BankAccount(${defaultBankId}, $outgoingAccountId).")
+ }
+ }
+
+
+ /**
+ * Bootstrap Super User
+ * Given the following credentials, OBP will create a user *if it does not exist already*.
+ * This user's password will be valid for a limited amount of time.
+ * This user will be granted ONLY CanCreateEntitlementAtAnyBank
+ * This feature can also be used in a "Break Glass scenario"
+ */
+ private def createBootstrapSuperUser() ={
+
+ val superAdminUsername = APIUtil.getPropsValue("super_admin_username","")
+ val superAdminInitalPassword = APIUtil.getPropsValue("super_admin_inital_password","")
+ val superAdminEmail = APIUtil.getPropsValue("super_admin_email","")
+
+ val isPropsNotSetProperly = superAdminUsername==""||superAdminInitalPassword ==""||superAdminEmail==""
+
+ //This is the logic to check if an AuthUser exists for the `create sandbox` endpoint, AfterApiAuth, OpenIdConnect ,,,
+ val existingAuthUser = AuthUser.find(By(AuthUser.username, superAdminUsername))
+
+ if(isPropsNotSetProperly) {
+ //Nothing happens, props is not set
+ }else if(existingAuthUser.isDefined) {
+ logger.error(s"createBootstrapSuperUser- Errors: Existing AuthUser with username ${superAdminUsername} detected in data import where no ResourceUser was found")
+ } else {
+ val authUser = AuthUser.create
+ .email(superAdminEmail)
+ .firstName(superAdminUsername)
+ .lastName(superAdminUsername)
+ .username(superAdminUsername)
+ .password(superAdminInitalPassword)
+ .passwordShouldBeChanged(true)
+ .validated(true)
+
+ val validationErrors = authUser.validate
+
+ if(!validationErrors.isEmpty)
+ logger.error(s"createBootstrapSuperUser- Errors: ${validationErrors.map(_.msg)}")
+ else {
+ Full(authUser.save()) //this will create/update the resourceUser.
+
+ val userBox = Users.users.vend.getUserByProviderAndUsername(authUser.getProvider(), authUser.username.get)
+
+ val resultBox = userBox.map(user => Entitlement.entitlement.vend.addEntitlement("", user.userId, CanCreateEntitlementAtAnyBank.toString))
+
+ if(resultBox.isEmpty){
+ logger.error(s"createBootstrapSuperUser- Errors: ${resultBox}")
+ }
+ }
+
+ }
+
+ }
+
+
+}
diff --git a/obp-api/src/main/scala/bootstrap/http4s/Http4sServer.scala b/obp-api/src/main/scala/bootstrap/http4s/Http4sServer.scala
new file mode 100644
index 0000000000..8a8b3366ff
--- /dev/null
+++ b/obp-api/src/main/scala/bootstrap/http4s/Http4sServer.scala
@@ -0,0 +1,35 @@
+package bootstrap.http4s
+
+import cats.data.{Kleisli, OptionT}
+import cats.effect._
+import code.api.util.APIUtil
+import com.comcast.ip4s._
+import org.http4s._
+import org.http4s.ember.server._
+import org.http4s.implicits._
+
+import scala.language.higherKinds
+object Http4sServer extends IOApp {
+
+ val services: Kleisli[({type λ[β$0$] = OptionT[IO, β$0$]})#λ, Request[IO], Response[IO]] =
+ code.api.v7_0_0.Http4s700.wrappedRoutesV700Services
+
+ val httpApp: Kleisli[IO, Request[IO], Response[IO]] = (services).orNotFound
+
+ //Start OBP relevant objects, and settings
+ new bootstrap.http4s.Http4sBoot().boot
+
+ val port = APIUtil.getPropsAsIntValue("http4s.port",8181)
+ val host = APIUtil.getPropsValue("http4s.host","127.0.0.1")
+
+
+ override def run(args: List[String]): IO[ExitCode] = EmberServerBuilder
+ .default[IO]
+ .withHost(Host.fromString(host).get)
+ .withPort(Port.fromInt(port).get)
+ .withHttpApp(httpApp)
+ .build
+ .use(_ => IO.never)
+ .as(ExitCode.Success)
+}
+
diff --git a/obp-api/src/main/scala/code/api/OAuth2.scala b/obp-api/src/main/scala/code/api/OAuth2.scala
index d12934d8a0..00800f99f0 100644
--- a/obp-api/src/main/scala/code/api/OAuth2.scala
+++ b/obp-api/src/main/scala/code/api/OAuth2.scala
@@ -50,7 +50,7 @@ import sh.ory.hydra.model.OAuth2TokenIntrospection
import java.net.URI
import scala.concurrent.Future
-import scala.jdk.CollectionConverters.mapAsJavaMapConverter
+import scala.collection.JavaConverters._
/**
* This object provides the API calls necessary to third party applications
diff --git a/obp-api/src/main/scala/code/api/util/APIUtil.scala b/obp-api/src/main/scala/code/api/util/APIUtil.scala
index 2a3c96e128..d6fb5dbb4f 100644
--- a/obp-api/src/main/scala/code/api/util/APIUtil.scala
+++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala
@@ -2679,8 +2679,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{
}
def getDisabledVersions() : List[String] = {
- val defaultDisabledVersions = "OBPv1.2.1,OBPv1.3.0,OBPv1.4.0,OBPv2.0.0,OBPv2.1.0,OBPv2.2.0,OBPv3.0.0,OBPv3.1.0,OBPv4.0.0,OBPv5.0.0"
- val disabledVersions = APIUtil.getPropsValue("api_disabled_versions").getOrElse(defaultDisabledVersions).replace("[", "").replace("]", "").split(",").toList.filter(_.nonEmpty)
+ val disabledVersions = APIUtil.getPropsValue("api_disabled_versions").getOrElse("").replace("[", "").replace("]", "").split(",").toList.filter(_.nonEmpty)
if (disabledVersions.nonEmpty) {
logger.info(s"Disabled API versions: ${disabledVersions.mkString(", ")}")
}
diff --git a/obp-api/src/main/scala/code/api/util/CertificateVerifier.scala b/obp-api/src/main/scala/code/api/util/CertificateVerifier.scala
index 4cc0a408fc..66743d4832 100644
--- a/obp-api/src/main/scala/code/api/util/CertificateVerifier.scala
+++ b/obp-api/src/main/scala/code/api/util/CertificateVerifier.scala
@@ -8,7 +8,7 @@ import java.security.cert._
import java.util.{Base64, Collections}
import javax.net.ssl.TrustManagerFactory
import scala.io.Source
-import scala.jdk.CollectionConverters._
+import scala.collection.JavaConverters._
import scala.util.{Failure, Success, Try}
object CertificateVerifier extends MdcLoggable {
@@ -69,8 +69,8 @@ object CertificateVerifier extends MdcLoggable {
trustManagerFactory.init(trustStore)
// Get trusted CAs from the trust store
- val trustAnchors = trustStore.aliases().asScala
- .filter(trustStore.isCertificateEntry)
+ val trustAnchors = enumerationAsScalaIterator(trustStore.aliases())
+ .filter(trustStore.isCertificateEntry(_))
.map(alias => trustStore.getCertificate(alias).asInstanceOf[X509Certificate])
.map(cert => new TrustAnchor(cert, null))
.toSet
diff --git a/obp-api/src/main/scala/code/api/util/JwsUtil.scala b/obp-api/src/main/scala/code/api/util/JwsUtil.scala
index fb49658cc7..57df7733c7 100644
--- a/obp-api/src/main/scala/code/api/util/JwsUtil.scala
+++ b/obp-api/src/main/scala/code/api/util/JwsUtil.scala
@@ -17,7 +17,7 @@ import java.time.format.DateTimeFormatter
import java.time.{Duration, ZoneOffset, ZonedDateTime}
import java.util
import scala.collection.immutable.{HashMap, List}
-import scala.jdk.CollectionConverters.seqAsJavaListConverter
+import scala.collection.JavaConverters._
object JwsUtil extends MdcLoggable {
diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala
index d85f3d265e..83b9c45e36 100644
--- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala
+++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala
@@ -5,16 +5,10 @@ import code.DynamicEndpoint.DynamicEndpointSwagger
import code.accountattribute.AccountAttributeX
import code.api.Constant._
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
-import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{
- jsonDynamicResourceDoc,
- _
-}
-import code.api.dynamic.endpoint.helper.practise.{
- DynamicEndpointCodeGenerator,
- PractiseEndpoint
-}
+import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{jsonDynamicResourceDoc, _}
+import code.api.dynamic.endpoint.helper.practise.{DynamicEndpointCodeGenerator, PractiseEndpoint}
import code.api.dynamic.endpoint.helper.{CompiledObjects, DynamicEndpointHelper}
-import code.api.dynamic.entity.helper.{DynamicEntityHelper, DynamicEntityInfo}
+import code.api.dynamic.entity.helper.DynamicEntityInfo
import code.api.util.APIUtil.{fullBoxOrException, _}
import code.api.util.ApiRole._
import code.api.util.ApiTag._
@@ -31,20 +25,11 @@ import code.api.util.migration.Migration
import code.api.util.newstyle.AttributeDefinition._
import code.api.util.newstyle.Consumer._
import code.api.util.newstyle.UserCustomerLinkNewStyle.getUserCustomerLinks
-import code.api.util.newstyle.{
- BalanceNewStyle,
- UserCustomerLinkNewStyle,
- ViewNewStyle
-}
+import code.api.util.newstyle.{BalanceNewStyle, UserCustomerLinkNewStyle, ViewNewStyle}
import code.api.v1_2_1.{JSONFactory, PostTransactionTagJSON}
import code.api.v1_4_0.JSONFactory1_4_0
import code.api.v2_0_0.OBPAPI2_0_0.Implementations2_0_0
-import code.api.v2_0_0.{
- CreateEntitlementJSON,
- CreateUserCustomerLinkJson,
- EntitlementJSONs,
- JSONFactory200
-}
+import code.api.v2_0_0.{CreateEntitlementJSON, CreateUserCustomerLinkJson, EntitlementJSONs, JSONFactory200}
import code.api.v2_1_0._
import code.api.v3_0_0.{CreateScopeJson, JSONFactory300}
import code.api.v3_1_0._
@@ -54,15 +39,10 @@ import code.apicollection.MappedApiCollectionsProvider
import code.apicollectionendpoint.MappedApiCollectionEndpointsProvider
import code.authtypevalidation.JsonAuthTypeValidation
import code.bankconnectors.LocalMappedConnectorInternal._
-import code.bankconnectors.{
- Connector,
- DynamicConnector,
- InternalConnector,
- LocalMappedConnectorInternal
-}
+import code.bankconnectors.{Connector, DynamicConnector, InternalConnector, LocalMappedConnectorInternal}
import code.connectormethod.{JsonConnectorMethod, JsonConnectorMethodMethodBody}
import code.consent.{ConsentStatus, Consents}
-import code.dynamicEntity.{DynamicEntityCommons, ReferenceType}
+import code.dynamicEntity.DynamicEntityCommons
import code.dynamicMessageDoc.JsonDynamicMessageDoc
import code.dynamicResourceDoc.JsonDynamicResourceDoc
import code.endpointMapping.EndpointMappingCommons
@@ -82,10 +62,7 @@ import code.util.Helper.{MdcLoggable, ObpS, SILENCE_IS_GOLDEN, booleanToFuture}
import code.util.{Helper, JsonSchemaUtil}
import code.validation.JsonValidation
import code.views.Views
-import code.webhook.{
- BankAccountNotificationWebhookTrait,
- SystemAccountNotificationWebhookTrait
-}
+import code.webhook.{BankAccountNotificationWebhookTrait, SystemAccountNotificationWebhookTrait}
import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue
import com.github.dwickern.macros.NameOf.nameOf
import com.networknt.schema.ValidationMessage
@@ -110,10 +87,10 @@ import java.net.URLEncoder
import java.text.SimpleDateFormat
import java.util
import java.util.{Calendar, Date}
+import scala.collection.JavaConverters._
import scala.collection.immutable.{List, Nil}
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.Future
-import scala.jdk.CollectionConverters.collectionAsScalaIterableConverter
trait APIMethods400 extends MdcLoggable {
self: RestHelper =>
@@ -11796,10 +11773,10 @@ trait APIMethods400 extends MdcLoggable {
Future {
val versions: List[ScannedApiVersion] =
ApiVersion.allScannedApiVersion.asScala.toList.filter { version =>
- version.urlPrefix.trim.nonEmpty
+ version.urlPrefix.trim.nonEmpty && APIUtil.versionIsAllowed(version)
}
(
- ListResult("scanned_api_versions", versions),
+ ListResult("scanned_api_versions", versions),
HttpCode.`200`(cc.callContext)
)
}
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 bb32e82aac..c592809a1e 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
@@ -65,7 +65,7 @@ import scala.collection.immutable.{List, Nil}
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.Future
import scala.concurrent.duration._
-import scala.jdk.CollectionConverters._
+import scala.collection.JavaConverters._
import scala.util.Random
@@ -3486,7 +3486,7 @@ trait APIMethods600 {
|
|""",
EmptyBody,
- WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("web-ui-props-id"), "database"),
+ WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("web-ui-props-id"), Some("config")),
List(
WebUiPropsNotFoundByName,
UnknownError
@@ -3509,11 +3509,11 @@ trait APIMethods600 {
explicitProp match {
case Some(prop) =>
// Found in database
- Future.successful(WebUiPropsCommons(prop.name, prop.value, prop.webUiPropsId, source = "database"))
+ Future.successful(WebUiPropsCommons(prop.name, prop.value, prop.webUiPropsId, source = Some("database")))
case None if isActived =>
// Not in database, check implicit props if active=true
val implicitWebUiProps = getWebUIPropsPairs.map(webUIPropsPairs =>
- WebUiPropsCommons(webUIPropsPairs._1, webUIPropsPairs._2, webUiPropsId = None, source = "config")
+ WebUiPropsCommons(webUIPropsPairs._1, webUIPropsPairs._2, webUiPropsId = Some("default"), source = Some("config"))
)
val implicitProp = implicitWebUiProps.find(_.name == webUiPropName)
implicitProp match {
@@ -3584,7 +3584,7 @@ trait APIMethods600 {
EmptyBody,
ListResult(
"webui_props",
- (List(WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("web-ui-props-id"), "database")))
+ (List(WebUiPropsCommons("webui_api_explorer_url", "https://apiexplorer.openbankproject.com", Some("web-ui-props-id"), Some("database"))))
)
,
List(
@@ -3608,8 +3608,8 @@ trait APIMethods600 {
}
}
explicitWebUiProps <- Future{ MappedWebUiPropsProvider.getAll() }
- explicitWebUiPropsWithSource = explicitWebUiProps.map(prop => WebUiPropsCommons(prop.name, prop.value, prop.webUiPropsId, source = "database"))
- implicitWebUiProps = getWebUIPropsPairs.map(webUIPropsPairs=>WebUiPropsCommons(webUIPropsPairs._1, webUIPropsPairs._2, webUiPropsId = None, source = "config"))
+ explicitWebUiPropsWithSource = explicitWebUiProps.map(prop => WebUiPropsCommons(prop.name, prop.value, prop.webUiPropsId, source = Some("database")))
+ implicitWebUiProps = getWebUIPropsPairs.map(webUIPropsPairs=>WebUiPropsCommons(webUIPropsPairs._1, webUIPropsPairs._2, webUiPropsId = Some("default"), source = Some("config")))
result = what match {
case "database" =>
// Return only database props
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
new file mode 100644
index 0000000000..877b91b72d
--- /dev/null
+++ b/obp-api/src/main/scala/code/api/v7_0_0/Http4s700.scala
@@ -0,0 +1,72 @@
+package code.api.v7_0_0
+
+import cats.data.{Kleisli, OptionT}
+import cats.effect._
+import cats.implicits._
+import code.api.util.{APIUtil, CustomJsonFormats}
+import code.api.v4_0_0.JSONFactory400
+import code.bankconnectors.Connector
+import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
+import net.liftweb.json.Formats
+import net.liftweb.json.JsonAST.prettyRender
+import net.liftweb.json.Extraction
+import org.http4s._
+import org.http4s.dsl.io._
+import org.typelevel.vault.Key
+
+import scala.concurrent.Future
+import scala.language.{higherKinds, implicitConversions}
+
+object Http4s700 {
+
+ type HttpF[A] = OptionT[IO, A]
+
+ implicit val formats: Formats = CustomJsonFormats.formats
+ implicit def convertAnyToJsonString(any: Any): String = prettyRender(Extraction.decompose(any))
+
+ val apiVersion: ScannedApiVersion = ApiVersion.v7_0_0
+ val apiVersionString: String = apiVersion.toString
+
+ case class CallContext(userId: String, requestId: String)
+ import cats.effect.unsafe.implicits.global
+ val callContextKey: Key[CallContext] = Key.newKey[IO, CallContext].unsafeRunSync()
+
+ object CallContextMiddleware {
+
+ def withCallContext(routes: HttpRoutes[IO]): HttpRoutes[IO] =
+ Kleisli[HttpF, Request[IO], Response[IO]] { req: Request[IO] =>
+ val callContext = CallContext(userId = "example-user", requestId = java.util.UUID.randomUUID().toString)
+ val updatedAttributes = req.attributes.insert(callContextKey, callContext)
+ val updatedReq = req.withAttributes(updatedAttributes)
+ routes(updatedReq)
+ }
+ }
+
+ val v700Services: HttpRoutes[IO] = HttpRoutes.of[IO] {
+ case req @ GET -> Root / "obp" / `apiVersionString` / "root" =>
+ import com.openbankproject.commons.ExecutionContext.Implicits.global
+ val callContext = req.attributes.lookup(callContextKey).get.asInstanceOf[CallContext]
+ Ok(IO.fromFuture(IO(
+ for {
+ _ <- Future() // Just start async call
+ } yield {
+ convertAnyToJsonString(
+ JSONFactory700.getApiInfoJSON(apiVersion, s"Hello, ${callContext.userId}! Your request ID is ${callContext.requestId}.")
+ )
+ }
+ )))
+
+ case req @ GET -> Root / "obp" / `apiVersionString` / "banks" =>
+ import com.openbankproject.commons.ExecutionContext.Implicits.global
+ Ok(IO.fromFuture(IO(
+ for {
+ (banks, callContext) <- code.api.util.NewStyle.function.getBanks(None)
+ } yield {
+ convertAnyToJsonString(JSONFactory400.createBanksJson(banks))
+ }
+ )))
+ }
+
+ val wrappedRoutesV700Services: HttpRoutes[IO] = CallContextMiddleware.withCallContext(v700Services)
+}
+
diff --git a/obp-api/src/main/scala/code/api/v7_0_0/JSONFactory7.0.0.scala b/obp-api/src/main/scala/code/api/v7_0_0/JSONFactory7.0.0.scala
new file mode 100644
index 0000000000..a675842e65
--- /dev/null
+++ b/obp-api/src/main/scala/code/api/v7_0_0/JSONFactory7.0.0.scala
@@ -0,0 +1,72 @@
+package code.api.v7_0_0
+
+import code.api.Constant
+import code.api.util.APIUtil
+import code.api.util.ErrorMessages.MandatoryPropertyIsNotSet
+import code.api.v4_0_0.{EnergySource400, HostedAt400, HostedBy400}
+import code.util.Helper.MdcLoggable
+import com.openbankproject.commons.util.ApiVersion
+import net.liftweb.util.Props
+
+object JSONFactory700 extends MdcLoggable {
+
+ // Get git commit from build info
+ lazy val gitCommit: String = {
+ val commit = try {
+ Props.get("git.commit.id", "unknown")
+ } catch {
+ case _: Throwable => "unknown"
+ }
+ commit
+ }
+
+ case class APIInfoJsonV700(
+ version: String,
+ version_status: String,
+ git_commit: String,
+ stage: String,
+ connector: String,
+ hostname: String,
+ local_identity_provider: String,
+ hosted_by: HostedBy400,
+ hosted_at: HostedAt400,
+ energy_source: EnergySource400,
+ resource_docs_requires_role: Boolean,
+ message: String
+ )
+
+ def getApiInfoJSON(apiVersion: ApiVersion, message: String): APIInfoJsonV700 = {
+ val organisation = APIUtil.getPropsValue("hosted_by.organisation", "TESOBE")
+ val email = APIUtil.getPropsValue("hosted_by.email", "contact@tesobe.com")
+ val phone = APIUtil.getPropsValue("hosted_by.phone", "+49 (0)30 8145 3994")
+ val organisationWebsite = APIUtil.getPropsValue("organisation_website", "https://www.tesobe.com")
+ val hostedBy = new HostedBy400(organisation, email, phone, organisationWebsite)
+
+ val organisationHostedAt = APIUtil.getPropsValue("hosted_at.organisation", "")
+ val organisationWebsiteHostedAt = APIUtil.getPropsValue("hosted_at.organisation_website", "")
+ val hostedAt = HostedAt400(organisationHostedAt, organisationWebsiteHostedAt)
+
+ val organisationEnergySource = APIUtil.getPropsValue("energy_source.organisation", "")
+ val organisationWebsiteEnergySource = APIUtil.getPropsValue("energy_source.organisation_website", "")
+ val energySource = EnergySource400(organisationEnergySource, organisationWebsiteEnergySource)
+
+ val connector = code.api.Constant.CONNECTOR.openOrThrowException(s"$MandatoryPropertyIsNotSet. The missing prop is `connector` ")
+ val resourceDocsRequiresRole = APIUtil.getPropsAsBoolValue("resource_docs_requires_role", false)
+
+ APIInfoJsonV700(
+ version = apiVersion.vDottedApiVersion,
+ version_status = "BLEEDING_EDGE",
+ git_commit = gitCommit,
+ connector = connector,
+ hostname = Constant.HostName,
+ stage = System.getProperty("run.mode"),
+ local_identity_provider = Constant.localIdentityProvider,
+ hosted_by = hostedBy,
+ hosted_at = hostedAt,
+ energy_source = energySource,
+ resource_docs_requires_role = resourceDocsRequiresRole,
+ message = message
+ )
+ }
+}
+
diff --git a/obp-api/src/main/scala/code/bankconnectors/generator/ConnectorBuilderUtil.scala b/obp-api/src/main/scala/code/bankconnectors/generator/ConnectorBuilderUtil.scala
index 95d94df174..5a1438be1f 100644
--- a/obp-api/src/main/scala/code/bankconnectors/generator/ConnectorBuilderUtil.scala
+++ b/obp-api/src/main/scala/code/bankconnectors/generator/ConnectorBuilderUtil.scala
@@ -10,7 +10,7 @@ import org.apache.commons.lang3.StringUtils.uncapitalize
import java.io.File
import java.net.URL
import java.util.Date
-import scala.jdk.CollectionConverters.enumerationAsScalaIteratorConverter
+import scala.collection.JavaConverters._
import scala.language.postfixOps
import scala.reflect.runtime.universe._
import scala.reflect.runtime.{universe => ru}
diff --git a/obp-api/src/main/scala/code/snippet/ConsentScreen.scala b/obp-api/src/main/scala/code/snippet/ConsentScreen.scala
index 1871517b45..b4be08fecc 100644
--- a/obp-api/src/main/scala/code/snippet/ConsentScreen.scala
+++ b/obp-api/src/main/scala/code/snippet/ConsentScreen.scala
@@ -45,7 +45,7 @@ import net.liftweb.util.Helpers._
import sh.ory.hydra.api.AdminApi
import sh.ory.hydra.model.{AcceptConsentRequest, RejectRequest}
-import scala.jdk.CollectionConverters.seqAsJavaListConverter
+import scala.collection.JavaConverters._
import scala.xml.NodeSeq
diff --git a/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala b/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala
index b79da7d558..daddd1a293 100644
--- a/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala
+++ b/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala
@@ -43,7 +43,7 @@ import org.apache.commons.lang3.StringUtils
import org.codehaus.jackson.map.ObjectMapper
import scala.collection.immutable.{List, ListMap}
-import scala.jdk.CollectionConverters.seqAsJavaListConverter
+import scala.collection.JavaConverters._
import scala.xml.{Text, Unparsed}
class ConsumerRegistration extends MdcLoggable {
diff --git a/obp-api/src/main/scala/code/util/ClassScanUtils.scala b/obp-api/src/main/scala/code/util/ClassScanUtils.scala
index 22c070656f..a57f10f063 100644
--- a/obp-api/src/main/scala/code/util/ClassScanUtils.scala
+++ b/obp-api/src/main/scala/code/util/ClassScanUtils.scala
@@ -35,7 +35,15 @@ object ClassScanUtils {
*/
def getSubTypeObjects[T:TypeTag]: List[T] = {
val clazz = ReflectUtils.typeTagToClass[T]
- finder.getClasses().filter(_.implements(clazz.getName)).map(_.name).map(companion[T](_)).toList
+ val classes = try {
+ finder.getClasses().toList
+ } catch {
+ case _: UnsupportedOperationException =>
+ // ASM version is too old for some class files (e.g. requires ASM7). In that case,
+ // skip scanned APIs instead of failing the whole application.
+ Seq.empty
+ }
+ classes.filter(_.implements(clazz.getName)).map(_.name).map(companion[T](_)).toList
}
/**
@@ -43,14 +51,22 @@ object ClassScanUtils {
* @param predict check whether include this type in the result
* @return all fit type names
*/
- def findTypes(predict: ClassInfo => Boolean): List[String] = finder.getClasses()
- .filter(predict)
- .map(it => {
- val name = it.name
- if(name.endsWith("$")) name.substring(0, name.length - 1)
- else name
- }) //some companion type name ends with $, it added by scalac, should remove from class name
- .toList
+ def findTypes(predict: ClassInfo => Boolean): List[String] = {
+ val classes = try {
+ finder.getClasses().toList
+ } catch {
+ case _: UnsupportedOperationException =>
+ Seq.empty
+ }
+ classes
+ .filter(predict)
+ .map(it => {
+ val name = it.name
+ if(name.endsWith("$")) name.substring(0, name.length - 1)
+ else name
+ }) //some companion type name ends with $, it added by scalac, should remove from class name
+ .toList
+ }
/**
* get given class exists jar Files
@@ -71,7 +87,13 @@ object ClassScanUtils {
*/
def getMappers(packageName:String = ""): Seq[ClassInfo] = {
val mapperInterface = "net.liftweb.mapper.LongKeyedMapper"
- val infos = finder.getClasses().filter(it => it.interfaces.contains(mapperInterface))
+ val classes = try {
+ finder.getClasses().toList
+ } catch {
+ case _: UnsupportedOperationException =>
+ Seq.empty
+ }
+ val infos = classes.filter(it => it.interfaces.contains(mapperInterface))
if(StringUtils.isNoneBlank()) {
infos.filter(classInfo => classInfo.name.startsWith(packageName))
} else {
diff --git a/obp-api/src/main/scala/code/util/HydraUtil.scala b/obp-api/src/main/scala/code/util/HydraUtil.scala
index 1fdf5f6fbb..a6b1627ed1 100644
--- a/obp-api/src/main/scala/code/util/HydraUtil.scala
+++ b/obp-api/src/main/scala/code/util/HydraUtil.scala
@@ -15,7 +15,7 @@ import sh.ory.hydra.model.OAuth2Client
import sh.ory.hydra.{ApiClient, Configuration}
import scala.collection.immutable.List
-import scala.jdk.CollectionConverters.{mapAsJavaMapConverter, seqAsJavaListConverter}
+import scala.collection.JavaConverters._
object HydraUtil extends MdcLoggable{
diff --git a/obp-api/src/main/scala/code/webuiprops/MappedWebUiPropsProvider.scala b/obp-api/src/main/scala/code/webuiprops/MappedWebUiPropsProvider.scala
index eb7115ee9d..85e77cb5d9 100644
--- a/obp-api/src/main/scala/code/webuiprops/MappedWebUiPropsProvider.scala
+++ b/obp-api/src/main/scala/code/webuiprops/MappedWebUiPropsProvider.scala
@@ -77,6 +77,7 @@ class WebUiProps extends WebUiPropsT with LongKeyedMapper[WebUiProps] with IdPK
override def webUiPropsId: Option[String] = Option(WebUiPropsId.get)
override def name: String = Name.get
override def value: String = Value.get
+ override def source: Option[String] = Some("database")
}
object WebUiProps extends WebUiProps with LongKeyedMetaMapper[WebUiProps] {
diff --git a/obp-api/src/main/scala/code/webuiprops/WebUiProps.scala b/obp-api/src/main/scala/code/webuiprops/WebUiProps.scala
index 409be6f4e2..cd1763017f 100644
--- a/obp-api/src/main/scala/code/webuiprops/WebUiProps.scala
+++ b/obp-api/src/main/scala/code/webuiprops/WebUiProps.scala
@@ -9,12 +9,13 @@ trait WebUiPropsT {
def webUiPropsId: Option[String]
def name: String
def value: String
+ def source: Option[String]
}
case class WebUiPropsCommons(name: String,
value: String,
webUiPropsId: Option[String] = None,
- source: String = "database") extends WebUiPropsT with JsonFieldReName
+ source: Option[String] = None) extends WebUiPropsT with JsonFieldReName
object WebUiPropsCommons extends Converter[WebUiPropsT, WebUiPropsCommons]
diff --git a/obp-api/src/test/resources/frozen_type_meta_data b/obp-api/src/test/resources/frozen_type_meta_data
index 79531b8932..0ddfe92ded 100644
Binary files a/obp-api/src/test/resources/frozen_type_meta_data and b/obp-api/src/test/resources/frozen_type_meta_data differ
diff --git a/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala b/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala
index dadf79cdd3..a87c0e36f0 100644
--- a/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala
+++ b/obp-api/src/test/scala/code/api/v4_0_0/GetScannedApiVersionsTest.scala
@@ -25,6 +25,7 @@ TESOBE (http://www.tesobe.com/)
*/
package code.api.v4_0_0
+import code.api.util.APIUtil
import code.api.util.ApiRole._
import code.api.v4_0_0.APIMethods400.Implementations4_0_0
import code.entitlement.Entitlement
@@ -33,7 +34,7 @@ import com.openbankproject.commons.model.ListResult
import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
import org.scalatest.Tag
-import scala.jdk.CollectionConverters.collectionAsScalaIterableConverter
+import scala.collection.JavaConverters._
class GetScannedApiVersionsTest extends V400ServerSetup {
/**
@@ -46,8 +47,63 @@ class GetScannedApiVersionsTest extends V400ServerSetup {
object VersionOfApi extends Tag(ApiVersion.v4_0_0.toString)
object ApiEndpoint extends Tag(nameOf(Implementations4_0_0.getScannedApiVersions))
+ feature("test props-api_disabled_versions, Get all scanned API versions should works") {
+ scenario("We get all the scanned API versions with disabled versions filtered out", ApiEndpoint, VersionOfApi) {
+ // api_disabled_versions=[OBPv3.0.0,BGv1.3]
+ setPropsValues("api_disabled_versions"-> "[OBPv3.0.0,BGv1.3]")
+ Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateSystemLevelDynamicEntity.toString)
+ When("We make a request v4.0.0")
+ val request = (v4_0_0_Request / "api" / "versions").GET
+
+ val response = makeGetRequest(request)
+ Then("We should get a 200")
+ response.code should equal(200)
+
+ val listResult = response.body.extract[ListResult[List[ScannedApiVersion]]]
+ val responseApiVersions = listResult.results
+ val scannedApiVersions = ApiVersion.allScannedApiVersion.asScala.toList.filter { version =>
+ version.urlPrefix.trim.nonEmpty && APIUtil.versionIsAllowed(version)
+ }
+
+ responseApiVersions should equal(scannedApiVersions)
+
+ // Verify that disabled versions are not included
+ responseApiVersions.exists(_.fullyQualifiedVersion == "OBPv3.0.0") should equal(false)
+ responseApiVersions.exists(_.fullyQualifiedVersion == "BGv1.3") should equal(false)
+
+ }
+ }
+
+ feature("test props-api_enabled_versions, Get all scanned API versions should works") {
+ scenario("We get all the scanned API versions with disabled versions filtered out", ApiEndpoint, VersionOfApi) {
+ // api_enabled_versions=[OBPv2.2.0,OBPv3.0.0,UKv2.0]
+ setPropsValues("api_enabled_versions"-> "[OBPv2.2.0,OBPv3.0.0,UKv2.0]")
+ Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateSystemLevelDynamicEntity.toString)
+ When("We make a request v4.0.0")
+ val request = (v4_0_0_Request / "api" / "versions").GET
+
+ val response = makeGetRequest(request)
+ Then("We should get a 200")
+ response.code should equal(200)
+
+ val listResult = response.body.extract[ListResult[List[ScannedApiVersion]]]
+ val responseApiVersions = listResult.results
+ val scannedApiVersions = ApiVersion.allScannedApiVersion.asScala.toList.filter { version =>
+ version.urlPrefix.trim.nonEmpty && APIUtil.versionIsAllowed(version)
+ }
+
+ responseApiVersions should equal(scannedApiVersions)
+ // Verify that disabled versions are not included
+ responseApiVersions.exists(_.fullyQualifiedVersion == "OBPv2.2.0") should equal(true)
+ responseApiVersions.exists(_.fullyQualifiedVersion == "OBPv3.0.0") should equal(true)
+ responseApiVersions.exists(_.fullyQualifiedVersion == "UKv2.0") should equal(true)
+
+ }
+ }
+
feature("Get all scanned API versions should works") {
+
scenario("We get all the scanned API versions", ApiEndpoint, VersionOfApi) {
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanCreateSystemLevelDynamicEntity.toString)
When("We make a request v4.0.0")
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 0a5617d18a..6173ec700c 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
@@ -23,6 +23,7 @@ object ApiShortVersions extends Enumeration {
val `v5.0.0` = Value("v5.0.0")
val `v5.1.0` = Value("v5.1.0")
val `v6.0.0` = Value("v6.0.0")
+ val `v7.0.0` = Value("v7.0.0")
val `dynamic-endpoint` = Value("dynamic-endpoint")
val `dynamic-entity` = Value("dynamic-entity")
}
@@ -114,6 +115,7 @@ object ApiVersion {
val v5_0_0 = ScannedApiVersion(urlPrefix,ApiStandards.obp.toString,ApiShortVersions.`v5.0.0`.toString)
val v5_1_0 = ScannedApiVersion(urlPrefix,ApiStandards.obp.toString,ApiShortVersions.`v5.1.0`.toString)
val v6_0_0 = ScannedApiVersion(urlPrefix,ApiStandards.obp.toString,ApiShortVersions.`v6.0.0`.toString)
+ val v7_0_0 = ScannedApiVersion(urlPrefix,ApiStandards.obp.toString,ApiShortVersions.`v7.0.0`.toString)
val `dynamic-endpoint` = ScannedApiVersion(urlPrefix,ApiStandards.obp.toString,ApiShortVersions.`dynamic-endpoint`.toString)
val `dynamic-entity` = ScannedApiVersion(urlPrefix,ApiStandards.obp.toString,ApiShortVersions.`dynamic-entity`.toString)
@@ -131,6 +133,7 @@ object ApiVersion {
v5_0_0 ::
v5_1_0 ::
v6_0_0 ::
+ v7_0_0 ::
`dynamic-endpoint` ::
`dynamic-entity`::
Nil
diff --git a/obp-http4s-runner/pom.xml b/obp-http4s-runner/pom.xml
new file mode 100644
index 0000000000..c1bf115359
--- /dev/null
+++ b/obp-http4s-runner/pom.xml
@@ -0,0 +1,71 @@
+
+ 4.0.0
+
+
+ com.tesobe
+ obp-parent
+ 1.10.1
+ ../pom.xml
+
+
+ obp-http4s-runner
+ jar
+ OBP Http4s Runner
+
+
+
+
+ com.tesobe
+ obp-api
+ ${project.version}
+ classes
+ jar
+
+
+
+ org.clapper
+ classutil_${scala.version}
+
+
+
+
+
+ org.clapper
+ classutil_${scala.version}
+ 1.5.1
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 3.6.0
+
+
+
+ bootstrap.http4s.Http4sServer
+
+
+
+ jar-with-dependencies
+
+ false
+ obp-http4s-runner
+
+
+
+ make-fat-jar
+ package
+
+ single
+
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 2d8cadc37d..da476faed2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,6 +15,7 @@
2.5.32
1.8.2
3.5.0
+ 0.23.30
9.4.50.v20221201
2016.11-RC6-SNAPSHOT
@@ -34,6 +35,7 @@
obp-commons
obp-api
+ obp-http4s-runner
@@ -126,7 +128,7 @@
net.alchim31.maven
scala-maven-plugin
- 4.3.1
+ 4.8.1
${scala.compiler}
${project.build.sourceEncoding}
@@ -143,6 +145,7 @@
-verbose
-deprecation
-->
+ -Ypartial-unification