diff --git a/obp-api/src/main/resources/props/sample.props.template b/obp-api/src/main/resources/props/sample.props.template index fbba340c8..5328d33f0 100644 --- a/obp-api/src/main/resources/props/sample.props.template +++ b/obp-api/src/main/resources/props/sample.props.template @@ -411,7 +411,9 @@ webui_dummy_customer_logins = Customer Logins\ \ Please ask a member of the Open Bank Project team for more logins if you require. You can use this [application](https://sofit.openbankproject.com) which also uses OAuth to browse your transaction data (use the above username/password).\ - +# when developer register the consumer successfully, it will show this message to developer on the webpage or email. +webui_register_consumer_success_message_webpage = Thanks for registering your consumer with the Open Bank API! Here is your developer information. Please save it in a secure location. +webui_register_consumer_success_message_email = Thank you for registering to use the Open Bank Project API. ## End of webui_ section ######## 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 cc648fac5..f4df70d43 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 @@ -512,7 +512,7 @@ object SwaggerDefinitionsJSON { ) val userJSONV121 = UserJSONV121( id = "5995d6a2-01b3-423c-a173-5481df49bdaf", - provider = "OBP", + provider = providerValueExample.value, display_name = "OBP" ) @@ -1569,8 +1569,8 @@ object SwaggerDefinitionsJSON { val userJsonV200 = UserJsonV200( user_id = ExampleValue.userIdExample.value, email = ExampleValue.emailExample.value, - provider_id = "OBP", - provider = "OBP", + provider_id = providerIdValueExample.value, + provider = providerValueExample.value, username = "robert.x.0.gh", entitlements = entitlementJSONs ) @@ -1690,7 +1690,7 @@ object SwaggerDefinitionsJSON { ) val createMeetingJson = CreateMeetingJson( - provider_id = "String", + provider_id = providerIdValueExample.value, purpose_id = "String" ) @@ -1707,7 +1707,7 @@ object SwaggerDefinitionsJSON { val meetingJson = MeetingJson( meeting_id = "String", - provider_id = "String", + provider_id = providerIdValueExample.value, purpose_id = "String", bank_id = bankIdExample.value, present = meetingPresentJSON, @@ -1852,9 +1852,9 @@ object SwaggerDefinitionsJSON { val resourceUserJSON = ResourceUserJSON( user_id = ExampleValue.userIdExample.value, email = ExampleValue.emailExample.value, - provider_id = "obp", - provider = "obp", - username = "TESOBE" + provider_id = providerIdValueExample.value, + provider = providerValueExample.value, + username = usernameExample.value ) val availableRoleJSON = AvailableRoleJSON( @@ -1919,7 +1919,7 @@ object SwaggerDefinitionsJSON { val userJSONV210 = UserJSONV210( id = "123", - provider = "OBP", + provider = providerValueExample.value, username = "OBP" ) @@ -3184,7 +3184,7 @@ object SwaggerDefinitionsJSON { ) val createMeetingJsonV310 = CreateMeetingJsonV310( - provider_id = "String, eg: tokbox", + provider_id = providerIdValueExample.value, purpose_id = "String, eg: onboarding", date = DateWithMsExampleObject, creator = contactDetailsJson, @@ -3193,7 +3193,7 @@ object SwaggerDefinitionsJSON { val meetingJsonV310 = MeetingJsonV310( meeting_id = "UUID-String", - provider_id = "String, eg: tokbox", + provider_id = providerIdValueExample.value, purpose_id = "String, eg: onboarding", bank_id = bankIdExample.value, present = meetingPresentJSON, 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 129eab585..93f8de58c 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -2472,15 +2472,16 @@ Returns a string showed to the developer //eg: List(("webui_get_started_text","Get started building your application using this sandbox now"), // ("webui_post_consumer_registration_more_info_text"," Please tell us more your Application and / or Startup using this link")) def getWebUIPropsPairs: List[(String, String)] = { + val filepath = this.getClass.getResource("/props/sample.props.template").getPath + val bufferedSource: BufferedSource = scala.io.Source.fromFile(filepath) - val bufferedSource = scala.io.Source.fromFile("obp-api/src/main/resources/props/sample.props.template") val proPairs: List[(String, String)] = for{ line <- bufferedSource.getLines.toList if(line.startsWith("webui_")) webuiProps = line.toString.split("=", 2) } yield { - val webuiProsKey = webuiProps(0) - val webuiProsValue = if (webuiProps.length > 1) webuiProps(1) else "" - (webuiProsKey, webuiProsValue) + val webuiPropsKey = webuiProps(0).trim //Remove the whitespace + val webuiPropsValue = if (webuiProps.length > 1) webuiProps(1).trim else "" + (webuiPropsKey, webuiPropsValue) } bufferedSource.close() proPairs diff --git a/obp-api/src/main/scala/code/api/util/ExampleValue.scala b/obp-api/src/main/scala/code/api/util/ExampleValue.scala index 9b7959490..41c004543 100644 --- a/obp-api/src/main/scala/code/api/util/ExampleValue.scala +++ b/obp-api/src/main/scala/code/api/util/ExampleValue.scala @@ -208,7 +208,12 @@ object ExampleValue { val cardAttributeValueExample = ConnectorField("2012-04-23", s"The card attribute values") glossaryItems += makeGlossaryItem("Adapter.card_attribute_value", cardAttributeValueExample) - + + val providerValueExample = ConnectorField("http://127.0.0.1:8080", s"The provider for current user.") + glossaryItems += makeGlossaryItem("Adapter.provider", providerValueExample) + + val providerIdValueExample = ConnectorField("Chris", s"The provider id of the current user. ") + glossaryItems += makeGlossaryItem("Adapter.provider_id", providerIdValueExample) val cbsErrorCodeExample = ConnectorField("500-OFFLINE", "An error code returned by the CBS") diff --git a/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala b/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala index facdcd1ba..03fd0bbeb 100644 --- a/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala +++ b/obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala @@ -20,7 +20,7 @@ import code.api.v2_2_0.{CreateAccountJSONV220, JSONFactory220} import code.api.v3_0_0.JSONFactory300 import code.api.v3_0_0.JSONFactory300.createAdapterInfoJson import code.api.v3_1_0.JSONFactory310._ -import code.bankconnectors.Connector +import code.bankconnectors.{Connector, LocalMappedConnector} import code.bankconnectors.rest.RestConnector_vMar2019 import code.consent.{ConsentStatus, Consents} import code.consumer.Consumers @@ -28,7 +28,7 @@ import code.context.{UserAuthContextUpdateProvider, UserAuthContextUpdateStatus} import code.entitlement.Entitlement import code.kafka.KafkaHelper import code.loginattempts.LoginAttempt -import code.methodrouting.{MethodRoutingCommons, MethodRoutingParam} +import code.methodrouting.{MethodRoutingCommons, MethodRoutingParam, MethodRoutingT} import code.metrics.APIMetrics import code.model._ import code.model.dataAccess.{AuthUser, BankAccountCreation} @@ -42,6 +42,7 @@ import com.github.dwickern.macros.NameOf.nameOf import com.nexmo.client.NexmoClient import com.nexmo.client.sms.messages.TextMessage import com.openbankproject.commons.model.{CreditLimit, _} +import com.openbankproject.commons.util.ReflectUtils import net.liftweb.common.{Box, Empty, Full} import net.liftweb.http.S import net.liftweb.http.provider.HTTPParam @@ -3907,15 +3908,20 @@ trait APIMethods310 { "Get MethodRoutings", s"""Get the all MethodRoutings. | - |optional request parameters: + |Query url parameters: | - |* method_name: filter with method_name, url example: /management/method_routings?method_name=getBank + |* method_name: filter with method_name + |* active: if active = true, it will show all the webui_ props. Even if they are set yet, we will retrun all the default webui_ props + | + |eg: + |${getObpApiRoot}/v3.1.0/management/method_routings?active=true + |${getObpApiRoot}/v3.1.0/management/method_routings?method_name=getBank | |""", emptyObjectJson, ListResult( "method_routings", - (List(MethodRoutingCommons("getBanks", "rest_vMar2019", false, Some("some_bank_.*"), Some(List(MethodRoutingParam("url", "http://mydomain.com/xxx"))), Some("method-routing-id")))) + (List(MethodRoutingCommons("getBanks", "rest_vMar2019", false, Some("some_bank_.*"), List(MethodRoutingParam("url", "http://mydomain.com/xxx")), Some("method-routing-id")))) ) , List( @@ -3937,12 +3943,42 @@ trait APIMethods310 { _ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetMethodRoutings, callContext) methodRoutings <- NewStyle.function.getMethodRoutingsByMethdName(req.param("method_name")) } yield { - val listCommons: List[MethodRoutingCommons] = methodRoutings - (ListResult("method_routings", listCommons), HttpCode.`200`(callContext)) + val listCommons: List[MethodRoutingCommons] = req.param("active") match { + case Full("true") => methodRoutings ++ getDefaultMethodRountings(methodRoutings ) + case _ => methodRoutings + } + (ListResult("method_routings", listCommons.map(_.toJson)), HttpCode.`200`(callContext)) } } } + /** + * get all methodRountings exception saved in DB + * @param methodRoutingsInDB saved in DB methodRouting#methodName + * @return all default methodRounting#methodName, those just in mapped connector + */ + private def getDefaultMethodRountings(methodRoutingsInDB: List[MethodRoutingT]) = { + val methodRountingNamesInDB = methodRoutingsInDB.map(_.methodName).toSet + + val methodRegex = """method \S+(? methodRegex.matcher(it.toString).matches()) + .filter(_.asMethod.isPublic) + .map(_.asMethod) + .filter(it => !methodRountingNamesInDB.contains(it.name.toString) && it.overrides.size > 0) + .map(it => MethodRoutingCommons( + methodName = it.name.toString, + connectorName = "mapped", + isBankIdExactMatch = false, + bankIdPattern = Some("*"), + parameters= List.empty[MethodRoutingParam], + methodRoutingId = Some(""), + )) + .toList + } + resourceDocs += ResourceDoc( createMethodRouting, implementedInApiVersion, @@ -3967,9 +4003,9 @@ trait APIMethods310 { | |* if bank_id_pattern is regex, special characters need to do escape, for example: bank_id_pattern = "some\\-id_pattern_\\d+" |""", - MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"), Some(List(MethodRoutingParam("url", "http://mydomain.com/xxx")))), + MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"), List(MethodRoutingParam("url", "http://mydomain.com/xxx"))), MethodRoutingCommons("getBank", "rest_vMar2019", false, Some("some_bankId_.*"), - Some(List(MethodRoutingParam("url", "http://mydomain.com/xxx"))), + List(MethodRoutingParam("url", "http://mydomain.com/xxx")), Some("this-method-routing-Id") ), List( @@ -4002,7 +4038,7 @@ trait APIMethods310 { Full(methodRouting) <- NewStyle.function.createOrUpdateMethodRouting(postedData) } yield { val commonsData: MethodRoutingCommons = methodRouting - (commonsData, HttpCode.`201`(callContext)) + (commonsData.toJson, HttpCode.`201`(callContext)) } } } @@ -4031,8 +4067,8 @@ trait APIMethods310 { | |* if bank_id_pattern is regex, special characters need to do escape, for example: bank_id_pattern = "some\\-id_pattern_\\d+" |""", - MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"), Some(List(MethodRoutingParam("url", "http://mydomain.com/xxx")))), - MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"),Some(List(MethodRoutingParam("url", "http://mydomain.com/xxx"))), Some("this-method-routing-Id")), + MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"), List(MethodRoutingParam("url", "http://mydomain.com/xxx"))), + MethodRoutingCommons("getBank", "rest_vMar2019", true, Some("some_bankId"), List(MethodRoutingParam("url", "http://mydomain.com/xxx")), Some("this-method-routing-Id")), List( UserNotLoggedIn, UserHasMissingRoles, @@ -4068,7 +4104,7 @@ trait APIMethods310 { Full(methodRouting) <- NewStyle.function.createOrUpdateMethodRouting(putData) } yield { val commonsData: MethodRoutingCommons = methodRouting - (commonsData, HttpCode.`200`(callContext)) + (commonsData.toJson, HttpCode.`200`(callContext)) } } } @@ -5289,8 +5325,14 @@ trait APIMethods310 { | |Get the all WebUiProps key values, those props key with "webui_" can be stored in DB, this endpoint get all from DB. | - |You can use the url query parameter: *active*. It must be a boolean string. and If active == true, it will show - |combination of explicit (inserted) + implicit (default) method_routings. + |url query parameter: + |active: It must be a boolean string. and If active = true, it will show + | combination of explicit (inserted) + implicit (default) method_routings. + | + |eg: + |${getObpApiRoot}/v3.1.0/management/webui_props + |${getObpApiRoot}/v3.1.0/management/webui_props?active=true + | |""", emptyObjectJson, ListResult( @@ -5323,7 +5365,10 @@ trait APIMethods310 { explicitWebUiProps <- Future{ MappedWebUiPropsProvider.getAll() } implicitWebUiPropsRemovedDuplicated = if(isActived){ val implicitWebUiProps = getWebUIPropsPairs.map(webUIPropsPairs=>WebUiPropsCommons(webUIPropsPairs._1, webUIPropsPairs._2, webUiPropsId= Some("default"))) - explicitWebUiProps.map(abck =>implicitWebUiProps.filterNot(_.name==abck.name)).flatten + if(explicitWebUiProps.nonEmpty) + //remove the depulicated fields in the webui fileds. + explicitWebUiProps.map(webUiProp =>implicitWebUiProps.filterNot(_.name==webUiProp.name)).flatten + else implicitWebUiProps } else { List.empty[WebUiPropsCommons] } diff --git a/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala b/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala index e8e180986..85c4ee382 100644 --- a/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala +++ b/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala @@ -238,7 +238,7 @@ messageDocs += MessageDoc( var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString) CacheKeyFromArguments.buildCacheKey { Caching.memoizeWithProvider(Some(cacheKey.toString()))(banksTTL second){ - val url = getUrl("getBankAccountsBalances" , ("bankIdAccountIds", bankIdAccountIds)) + val url = getUrl(callContext,"getBankAccountsBalances" , ("bankIdAccountIds", bankIdAccountIds)) sendGetRequest[InBoundGetBankAccountsBalances](url, callContext) .map { boxedResult => boxedResult match { @@ -293,16 +293,24 @@ messageDocs += MessageDoc( //TODO please modify this baseUrl to your remote api server base url of this connector private[this] val baseUrl = "http://localhost:8080/restConnector" - private[this] def getUrl(methodName: String, variables: (String, Any)*): String = { + private[this] def getUrl(callContext: Option[CallContext], methodName: String, variables: (String, Any)*): String = { // rest connector can have url value in the parameters, key is url + + //Temporary solution: + val basicUserAuthContext: List[BasicUserAuthContext] = callContext.map(_.toOutboundAdapterCallContext.outboundAdapterAuthInfo.map(_.userAuthContext)).flatten.flatten.getOrElse(List.empty[BasicUserAuthContext]) + val bankId = basicUserAuthContext.find(_.key=="bank-id").map(_.value) + val accountId = basicUserAuthContext.find(_.key=="account-id").map(_.value) + val parameterUrl = if (bankId.isDefined &&accountId.isDefined) s"/${bankId.get},${accountId.get}" else "" + + //http://127.0.0.1:8080/restConnector/getBankAccountsBalances/bankIdAccountIds val urlInMethodRouting = NewStyle.function.getMethodRoutings(Some(methodName)) - .flatMap(_.parameters).flatten + .flatMap(_.parameters) .find(_.key == "url") .map(_.value) - + // http://127.0.0.1:8080/restConnector/getBankAccountsBalances/bankIdAccountIds/dmo.02.de.de,60e65f3f-0743-41f5-9efd-3c6f0438aa42 if(urlInMethodRouting.isDefined) { - return urlInMethodRouting.get + return urlInMethodRouting.get + parameterUrl } // convert any type value to string, to fill in the url diff --git a/obp-api/src/main/scala/code/methodrouting/MappedMethodRoutingProvider.scala b/obp-api/src/main/scala/code/methodrouting/MappedMethodRoutingProvider.scala index 102846182..9b9654230 100644 --- a/obp-api/src/main/scala/code/methodrouting/MappedMethodRoutingProvider.scala +++ b/obp-api/src/main/scala/code/methodrouting/MappedMethodRoutingProvider.scala @@ -46,7 +46,7 @@ object MappedMethodRoutingProvider extends MethodRoutingProvider with CustomJson val isExactMatch = if(bankIdPattern.isDefined) methodRouting.isBankIdExactMatch else false val existsMethodRoutingParameters = methodRouting.parameters match { - case Some(parameters) if (parameters.nonEmpty) => parameters + case parameters if (parameters.nonEmpty) => parameters case _ => List.empty[MethodRoutingParam] } @@ -88,7 +88,7 @@ class MethodRouting extends MethodRoutingT with LongKeyedMapper[MethodRouting] w override def connectorName: String = ConnectorName.get //Here we store all the key-value paris in one big String filed in database. - override def parameters: Option[List[MethodRoutingParam]] = Option(json.parse(if (Parameters.get != null) Parameters.get else "[]").extract[List[MethodRoutingParam]]) + override def parameters: List[MethodRoutingParam] = json.parse(if (Parameters.get != null) Parameters.get else "[]").extract[List[MethodRoutingParam]] } object MethodRouting extends MethodRouting with LongKeyedMetaMapper[MethodRouting] { diff --git a/obp-api/src/main/scala/code/methodrouting/MethodRoutingProvider.scala b/obp-api/src/main/scala/code/methodrouting/MethodRoutingProvider.scala index c9dacef44..2b0ddc067 100644 --- a/obp-api/src/main/scala/code/methodrouting/MethodRoutingProvider.scala +++ b/obp-api/src/main/scala/code/methodrouting/MethodRoutingProvider.scala @@ -4,6 +4,7 @@ package code.methodrouting import com.openbankproject.commons.model.{Converter, JsonFieldReName, ProductCollection, ProductCollectionCommons} import net.liftweb.common.Box +import net.liftweb.json.JsonAST.{JArray, JBool, JField, JNull, JObject, JString} import net.liftweb.util.SimpleInjector object MethodRoutingProvider extends SimpleInjector { @@ -24,16 +25,33 @@ trait MethodRoutingT { */ def isBankIdExactMatch: Boolean def connectorName: String - def parameters: Option[List[MethodRoutingParam]] + def parameters: List[MethodRoutingParam] } case class MethodRoutingCommons(methodName: String, connectorName: String, isBankIdExactMatch: Boolean, bankIdPattern: Option[String], - parameters: Option[List[MethodRoutingParam]] = None, + parameters: List[MethodRoutingParam] = Nil, methodRoutingId: Option[String] = None, - ) extends MethodRoutingT with JsonFieldReName + ) extends MethodRoutingT with JsonFieldReName { + /** + * when serialized to json, the Option filed will be not shown, this method just generate a full fields json, include all None value fields + * @return JObject include all fields + */ + def toJson = { + val paramsJson: List[JObject] = this.parameters.map(param => JObject(List(JField("key", JString(param.key)), JField("value", JString(param.value))))) + + JObject(List( + JField("method_name", JString(this.methodName)), + JField("connector_name", JString(this.connectorName)), + JField("is_bank_id_exact_match", JBool(this.isBankIdExactMatch)), + JField("bank_id_pattern", this.bankIdPattern.map(JString(_)).getOrElse(JString("*"))), + JField("parameters", JArray(paramsJson)), + JField("method_routing_id", this.methodRoutingId.map(JString(_)).getOrElse(JNull)) + )) + } +} object MethodRoutingCommons extends Converter[MethodRoutingT, MethodRoutingCommons] diff --git a/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala b/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala index 23a7dca0d..507575355 100644 --- a/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala +++ b/obp-api/src/main/scala/code/snippet/ConsumerRegistration.scala @@ -89,7 +89,11 @@ class ConsumerRegistration extends MdcLoggable { val urlOAuthEndpoint = APIUtil.getPropsValue("hostname", "") + "/oauth/initiate" val urlDirectLoginEndpoint = APIUtil.getPropsValue("hostname", "") + "/my/logins/direct" val createDirectLoginToken = getWebUiPropsValue("webui_create_directlogin_token_url", "") + val registerConsumerSuccessMessageWebpage = getWebUiPropsValue( + "webui_register_consumer_success_message_webpage", + "Thanks for registering your consumer with the Open Bank API! Here is your developer information. Please save it in a secure location.") //thanks for registering, here's your key, etc. + "#register-consumer-success-message *" #> registerConsumerSuccessMessageWebpage & "#app-consumer_id *" #> consumer.id.get & "#app-name *" #> consumer.name.get & "#app-redirect-url *" #> consumer.redirectURL & @@ -228,14 +232,14 @@ class ConsumerRegistration extends MdcLoggable { val params = PlainMailBodyType(registrationMessage) :: List(To(registered.developerEmail.get)) - val subject1 : String = "Thank you for registering to use the Open Bank Project API." - val subject2 : String = if (sendSensitive) "This email contains your API keys." else "This email does NOT contain your API keys." - val subject : String = s"$subject1 $subject2" + val webuiRegisterConsumerSuccessMssageEmail : String = getWebUiPropsValue( + "webui_register_consumer_success_message_email", + "Thank you for registering to use the Open Bank Project API.") //this is an async call Mailer.sendMail( From(from), - Subject(subject1), + Subject(webuiRegisterConsumerSuccessMssageEmail), params :_* ) } diff --git a/obp-api/src/main/webapp/consumer-registration.html b/obp-api/src/main/webapp/consumer-registration.html index 4d97755a5..236cade8a 100644 --- a/obp-api/src/main/webapp/consumer-registration.html +++ b/obp-api/src/main/webapp/consumer-registration.html @@ -79,7 +79,7 @@ Berlin 13359, Germany
Thanks for registering your consumer with the Open Bank API! Here is your developer information. Please save it in a secure location.
+Thanks for registering your consumer with the Open Bank API! Here is your developer information. Please save it in a secure location.