diff --git a/src/main/resources/props/sample.props.template b/src/main/resources/props/sample.props.template index 0dc8f6b0..dc8260e6 100644 --- a/src/main/resources/props/sample.props.template +++ b/src/main/resources/props/sample.props.template @@ -149,11 +149,17 @@ dev.port=8082 # need to set it manually here. #api_manager_url= -# API explorer menu structure (temporary layout - for first workshops) -webui_index_dynamic_1_link_url=/?tags=Dynamic-Endpoint -webui_index_dynamic_1_link_text=Third Party -webui_index_dynamic_2_link_url=/?tags=Dynamic-Endpoint -webui_index_dynamic_2_link_text=Third Party 2 +# API explorer menu structure, the value should be validate json format. +#webui_index_dynamic_url_text_pairs=[\ +# {\ +# "url": "/?api-collection-id=feb47896-6a18-4a96-b8e9-ed6db05dbd401",\ +# "text": "Third Party 1"\ +# },\ +# {\ +# "url": "/?api-collection-id=feb47896-6a18-4a96-b8e9-ed6db05dbd401",\ +# "text": "Third Party 2"\ +# }\ +# ] # Sngle Sign On diff --git a/src/main/scala/code/lib/ObpAPI.scala b/src/main/scala/code/lib/ObpAPI.scala index a4e1c6ba..f3b22199 100644 --- a/src/main/scala/code/lib/ObpAPI.scala +++ b/src/main/scala/code/lib/ObpAPI.scala @@ -1,11 +1,12 @@ package code.lib +import code.lib.ObpAPI.UnknownErrorMessage import java.io._ import java.text.SimpleDateFormat import java.util.{Date, UUID} import code.lib.ObpJson._ import code.util.Helper -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, covertWebpageIdToObpOperationId} import code.util.cache.Caching import net.liftweb.common.{Box, Failure, Full, _} import net.liftweb.http.{RequestVar, S, SessionVar} @@ -21,6 +22,7 @@ import scala.concurrent.duration._ import scala.language.postfixOps import java.util.UUID.randomUUID import net.liftweb.common._ +import net.liftweb.json case class Header(key: String, value: String) @@ -39,6 +41,41 @@ object ObpAPI extends Loggable { val defaultProvider = Helper.getPropsValue("defaultAuthProvider").getOrElse("") val userNotFoundError = "user (\\S+) at provider (\\S+) not found".r + + final val AccountUrlPath = "/accounts/" + final val ApiCollectionId = "api-collection-id" + final val CacheModifier = "cache-modifier" + final val ContentEqualStatic = "content=static" + final val ContentEqualDynamic = "content=dynamic" + final val UnknownErrorMessage = "Unknown Error!" + final val OBPVersionV400 = "OBPv4.0.0" + final val UKVersionV31 = "UKv3.1" + final val UKVersionV20 = "UKv2.0" + final val BGVersionV13 = "BGv1.3" + final val PAPIVersionV2111 = "PAPIv2.1.1.1" + final val BGVersionV133 = "BGv1.3.3" + final val VersionV133 = "v1.3.3" + final val DisplayEqualNone = "display: none" + final val ResourceStyleCss = ".resource [style]" + final val ResourceErrorStyleCss = ".resource-error [style]" + final val DisplayEqualBlock = "display: block" + final val ContentBoxHeadline = ".content-box__headline *" + final val RolesBoxId = "@roles_box [id]" + final val RolesBoxStyle = "@roles_box [style]" + final val RoleItemClassCss = ".role_item" + final val RolesRoleNameCss = "@roles__role_name" + final val RoleStatusNameCss = "@roles__status" + final val RolesBankIdInput = "@roles__bank_id_input" + final val RolesRoleInput = "@roles__role_input" + final val RolesEntitlementRequestId = "@roles__entitlement_request_response [id]" + final val RolesRequestEntitlementButton = "@roles__request_entitlement_button" + final val PleaseLoginToRequestThisRole = " - Please login to request this Role" + final val YouHaveThisRole = s" - You have this Role." + final val ContactOBPTeam = s" - You have requested this Role. Please contact Open Bank Project team to grant your this role." + final val YouCanRequestThisRole = s" - You can request this Role." + final val RolesEntitlementRequestButtonBox = "@roles__entitlement_request_button_box [style]" + final val EndPointAnchorHref = ".end-point-anchor [href]" + final val ContentBoxHeadlineId = ".content-box__headline [id]" /** * The request vars ensure that for one page load, the same API call isn't @@ -83,7 +120,7 @@ object ObpAPI extends Loggable { fromDate.map(f => Header("obp_from_date", dateFormat.format(f))).toList ::: toDate.map(t => Header("obp_to_date", dateFormat.format(t))).toList ::: sortDirection.map(s => Header("obp_sort_direction", s.value)).toList ::: Nil - ObpGet(s"$obpPrefix/v3.0.0/banks/" + urlEncode(bankId) + "/accounts/" + urlEncode(accountId) + "/" + urlEncode(viewId) + + ObpGet(s"$obpPrefix/v3.0.0/banks/" + urlEncode(bankId) + AccountUrlPath + urlEncode(accountId) + "/" + urlEncode(viewId) + "/transactions", headers).flatMap(x => x.extractOpt[TransactionsJsonV300]) } @@ -94,19 +131,19 @@ object ObpAPI extends Loggable { def publicAccounts(bankId : String) : Box[BarebonesAccountsJson] = { - ObpGet(s"$obpPrefix/v3.1.0/banks/" + urlEncode(bankId) + "/accounts/public").flatMap(_.extractOpt[BarebonesAccountsJson]) + ObpGet(s"$obpPrefix/v3.1.0/banks/" + urlEncode(bankId) + AccountUrlPath + "public").flatMap(_.extractOpt[BarebonesAccountsJson]) } def publicAccounts : Box[BarebonesAccountsJson] = { - ObpGet(s"$obpPrefix/v3.1.0/accounts/public").flatMap(_.extractOpt[BarebonesAccountsJson]) + ObpGet(s"$obpPrefix/v3.1.0${AccountUrlPath}public").flatMap(_.extractOpt[BarebonesAccountsJson]) } def privateAccounts(bankId : String) : Box[BarebonesAccountsJson] = { - ObpGet(s"$obpPrefix/v3.1.0/banks/" + urlEncode(bankId) + "/accounts/private").flatMap(_.extractOpt[BarebonesAccountsJson]) + ObpGet(s"$obpPrefix/v3.1.0/banks/" + urlEncode(bankId) + AccountUrlPath + "private").flatMap(_.extractOpt[BarebonesAccountsJson]) } def privateAccounts : Box[BarebonesAccountsJson] = { - ObpGet(s"$obpPrefix/v1.2.1/accounts/private").flatMap(_.extractOpt[BarebonesAccountsJson]) + ObpGet(s"$obpPrefix/v1.2.1${AccountUrlPath}private").flatMap(_.extractOpt[BarebonesAccountsJson]) } @deprecated("This method will mix public and private, not clear for Apps.","2018-02-18") @@ -116,20 +153,20 @@ object ObpAPI extends Loggable { // Similar to getViews below def getViewsForBankAccount(bankId: String, accountId: String) = { - ObpGet(s"$obpPrefix/v3.1.0/banks/" + bankId + "/accounts/" + accountId + "/views").flatMap(_.extractOpt[ViewsJson]) + ObpGet(s"$obpPrefix/v3.1.0/banks/" + bankId + AccountUrlPath + accountId + "/views").flatMap(_.extractOpt[ViewsJson]) } def getAccount(bankId: String, accountId: String, viewId: String) : Box[AccountJson] = { - ObpGet(s"$obpPrefix/v3.1.0/banks/" + urlEncode(bankId) + "/accounts/" + urlEncode(accountId) + "/" + urlEncode(viewId) + "/account").flatMap(x => x.extractOpt[AccountJson]) + ObpGet(s"$obpPrefix/v3.1.0/banks/" + urlEncode(bankId) + AccountUrlPath + urlEncode(accountId) + "/" + urlEncode(viewId) + "/account").flatMap(x => x.extractOpt[AccountJson]) } def getCounterparties(bankId: String, accountId: String, viewId: String): Box[DirectOtherAccountsJson] = { - val counterparties = ObpGet(s"$obpPrefix/v3.1.0/banks/" + urlEncode(bankId) + "/accounts/" + urlEncode(accountId) + "/" + urlEncode(viewId) + "/other_accounts").flatMap(x => x.extractOpt[DirectOtherAccountsJson]) + val counterparties = ObpGet(s"$obpPrefix/v3.1.0/banks/" + urlEncode(bankId) + AccountUrlPath + urlEncode(accountId) + "/" + urlEncode(viewId) + "/other_accounts").flatMap(x => x.extractOpt[DirectOtherAccountsJson]) counterparties } def getExplictCounterparties(bankId: String, accountId: String, viewId: String): Box[ExplictCounterpartiesJson] = { - ObpGet(s"$obpPrefix/v2.2.0/banks/" + urlEncode(bankId) + "/accounts/" + urlEncode(accountId) + "/" + urlEncode(viewId) + "/counterparties").flatMap(x => x.extractOpt[ExplictCounterpartiesJson]) + ObpGet(s"$obpPrefix/v2.2.0/banks/" + urlEncode(bankId) + AccountUrlPath + urlEncode(accountId) + "/" + urlEncode(viewId) + "/counterparties").flatMap(x => x.extractOpt[ExplictCounterpartiesJson]) } def getEntitlementsV300 : Box[EntitlementsJson] = { @@ -226,44 +263,55 @@ object ObpAPI extends Loggable { ObpPost(s"$obpPrefix/v4.0.0/my/api-collections", Extraction.decompose(postSelectionEndpointJson)) } - def createMyApiCollectionEndpoint (apiCollectionName: String, operationId: String) = { - val postSelectionEndpointJson = PostSelectionEndpointJson400(operationId) + def createMyApiCollectionEndpoint (apiCollectionName: String, webPageOperationId: String) = { + val obpOperationId = covertWebpageIdToObpOperationId(webPageOperationId) + val postSelectionEndpointJson = PostSelectionEndpointJson400(obpOperationId) ObpPost(s"$obpPrefix/v4.0.0/my/api-collections/$apiCollectionName/api-collection-endpoints", Extraction.decompose(postSelectionEndpointJson)) } - def deleteMyApiCollectionEndpoint (apiCollectionName: String, operationId: String) = { - ObpDelete(s"$obpPrefix/v4.0.0/my/api-collections/$apiCollectionName/api-collection-endpoints/$operationId") + def deleteMyApiCollectionEndpoint (apiCollectionName: String, webPageOperationId: String) = { + val obpOperationId = covertWebpageIdToObpOperationId(webPageOperationId) + ObpDelete(s"$obpPrefix/v4.0.0/my/api-collections/$apiCollectionName/api-collection-endpoints/$obpOperationId") } - //NOTE: there is no parameters for the method, the cache is not working well. need to fix later -// private val sharableApiCollectionsTTL: FiniteDuration = Helper.getPropsAsIntValue("sharable_api_collections.cache.ttl.seconds", 0) seconds - def sharableApiCollections: Box[List[(String, String)]] = { -// var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString) -// CacheKeyFromArguments.buildCacheKey { -// Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(sharableApiCollectionsTTL) { - val apiCollectionsResponse = ObpGet(s"$obpPrefix/v4.0.0/api-collections/featured").flatMap(_.extractOpt[ApiCollectionsJson400]) - apiCollectionsResponse.map(_.api_collections.map(apiCollection => (apiCollection.api_collection_name, apiCollection.api_collection_id))) -// } -// } - } + @deprecated("16-11-2021","this is the Legacy props, now we introduce `webui_index_dynamic_url_text_pairs` ") + def getApiCollectionsFromPropsLegacy: List[(String, String)] = { + val webuiIndexDynamic1LinkUrl = Helper.getPropsValue("webui_index_dynamic_1_link_url", "") + val webuiIndexDynamic1LinkText = Helper.getPropsValue("webui_index_dynamic_1_link_text", "") - val webuiIndexDynamic1LinkUrl = Helper.getPropsValue("webui_index_dynamic_1_link_url", "") - val webuiIndexDynamic1LinkText = Helper.getPropsValue("webui_index_dynamic_1_link_text", "") - - val webuiIndexDynamic2LinkUrl = Helper.getPropsValue("webui_index_dynamic_2_link_url", "") - val webuiIndexDynamic2LinkText = Helper.getPropsValue("webui_index_dynamic_2_link_text", "") + val webuiIndexDynamic2LinkUrl = Helper.getPropsValue("webui_index_dynamic_2_link_url", "") + val webuiIndexDynamic2LinkText = Helper.getPropsValue("webui_index_dynamic_2_link_text", "") + + if (webuiIndexDynamic1LinkUrl.nonEmpty && webuiIndexDynamic1LinkText.nonEmpty && webuiIndexDynamic2LinkText.nonEmpty && webuiIndexDynamic2LinkUrl.nonEmpty){ + List( + (webuiIndexDynamic1LinkText,webuiIndexDynamic1LinkUrl), (webuiIndexDynamic2LinkText,webuiIndexDynamic2LinkUrl) + ) + } else if (webuiIndexDynamic1LinkUrl.nonEmpty && webuiIndexDynamic1LinkText.nonEmpty ) + List( + (webuiIndexDynamic1LinkText,webuiIndexDynamic1LinkUrl) + ) + else + Nil + } + + val dynamicUrlTextPairsJson: List[DynamicUrlTextPairsJson] = { + def extractor(str: String) = try { + val dynamicUrlTextPairs = json.parse(str).extract[List[DynamicUrlTextPairsJson]] + //The props value can be parse to JNothing. + if(str.nonEmpty && dynamicUrlTextPairs == Nil) + throw new RuntimeException(s"props [webui_index_dynamic_url_text_pairs] parse -> extract to Nil! it should be the valid class($DynamicUrlTextPairsJson) json format, current value is $str .") + else + dynamicUrlTextPairs + } catch { + case e: Throwable => // error handling, found wrong props value as early as possible. + this.logger.error(s"props [webui_index_dynamic_url_text_pairs] value is invalid, it should be the class($DynamicUrlTextPairsJson) json format, current value is $str ." ); + throw e; + } + Helper.getPropsValue("webui_index_dynamic_url_text_pairs").map(extractor).getOrElse(Nil) + } def getApiCollectionsFromProps: Box[List[(String, String)]] = { - if (webuiIndexDynamic1LinkUrl.nonEmpty && webuiIndexDynamic1LinkText.nonEmpty && webuiIndexDynamic2LinkText.nonEmpty && webuiIndexDynamic2LinkUrl.nonEmpty){ - Full(List( - (webuiIndexDynamic1LinkText,webuiIndexDynamic1LinkUrl), (webuiIndexDynamic2LinkText,webuiIndexDynamic2LinkUrl) - )) - } else if (webuiIndexDynamic1LinkText.nonEmpty && webuiIndexDynamic1LinkText.nonEmpty ) - Full(List( - (webuiIndexDynamic1LinkText,webuiIndexDynamic1LinkUrl) - )) - else - Full(Nil) + Full(getApiCollectionsFromPropsLegacy ++ dynamicUrlTextPairsJson.map(dynamicUrlTextPair => List((dynamicUrlTextPair.text, dynamicUrlTextPair.url))).flatten) } /** @@ -275,17 +323,18 @@ object ObpAPI extends Loggable { // Returns both system and dynamic resource docs: def getAllResourceDocsJson(apiVersion : String): Box[List[ResourceDocJson]] = { - val apiCollectionIdParam = List("api-collection-id") + val apiCollectionIdParam = List(ApiCollectionId) .map(paramName => (paramName, S.param(paramName))) .collect{ - case (paramName, Full(paramValue)) if(paramValue.trim.size > 0) => s"$paramName=$paramValue" + case (paramName, Full(paramValue)) if(paramValue.trim.size > 0 + ) => s"$paramName=$paramValue" } .mkString("?", "&", "") //Note: ?content=static&content=dynamic // if there are two content parameters there, only the first one is valid for the api call. // so requestParams have the high priority - val requestParams = List("tags", "language", "functions", "content", "cache-modifier") + val requestParams = List("tags", "language", "functions", "content", CacheModifier) .map(paramName => (paramName, S.param(paramName))) .collect{ case (paramName, Full(paramValue)) if(paramValue.trim.size > 0) => s"$paramName=$paramValue" @@ -302,11 +351,11 @@ object ObpAPI extends Loggable { lazy val dynamicResourcesDocs = getDynamicResourceDocs(apiVersion,requestParams, canReadResourceDocRole, OAuthClient.loggedIn) //If the api-collection-id in the URL, it will ignore all other parameters, so here we first check it: - if(apiCollectionIdParam.contains("api-collection-id=")) { + if(apiCollectionIdParam.contains(ApiCollectionId + "=")) { getResourceDocsByApiCollectionId(apiVersion, apiCollectionIdParam) - }else if(requestParams.contains("content=static")) { + }else if(requestParams.contains(ContentEqualStatic)) { staticResourcesDocs - } else if (requestParams.contains("content=dynamic")){ + } else if (requestParams.contains(ContentEqualDynamic)){ dynamicResourcesDocs } else{ for{ @@ -321,7 +370,7 @@ object ObpAPI extends Loggable { // Returns all bank level dynamic resources def getStaticAndAllBankLevelDynamicResourceDocs(apiVersion : String) = { - val apiCollectionIdParam = List("api-collection-id") + val apiCollectionIdParam = List(ApiCollectionId) .map(paramName => (paramName, S.param(paramName))) .collect{ case (paramName, Full(paramValue)) if(paramValue.trim.size > 0) => s"$paramName=$paramValue" @@ -331,7 +380,7 @@ object ObpAPI extends Loggable { //Note: ?content=static&content=dynamic // if there are two content parameters there, only the first one is valid for the api call. // so requestParams have the high priority - val requestParams = List("tags", "language", "functions", "cache-modifier") + val requestParams = List("tags", "language", "functions", CacheModifier) .map(paramName => (paramName, S.param(paramName))) .collect{ case (paramName, Full(paramValue)) if(paramValue.trim.size > 0) => s"$paramName=$paramValue" @@ -351,11 +400,11 @@ object ObpAPI extends Loggable { bankId => getBankLevelDynamicResourceDocs(apiVersion,bankId,requestParams)).flatten.flatten) //If the api-collection-id in the URL, it will ignore all other parameters, so here we first check it: - if(apiCollectionIdParam.contains("api-collection-id=")) { + if(apiCollectionIdParam.contains(ApiCollectionId + "=")) { getResourceDocsByApiCollectionId(apiVersion, apiCollectionIdParam) - }else if(requestParams.contains("content=static")) { + }else if(requestParams.contains(ContentEqualStatic)) { staticResourcesDocs - } else if (requestParams.contains("content=dynamic")){ + } else if (requestParams.contains(ContentEqualDynamic)){ dynamicResourcesDocs } else{ for{ @@ -369,7 +418,7 @@ object ObpAPI extends Loggable { // Returns only the bank level resource docs def getOneBankLevelResourceDocsJson(apiVersion : String, bankId:String) = { - val apiCollectionIdParam = List("api-collection-id") + val apiCollectionIdParam = List(ApiCollectionId) .map(paramName => (paramName, S.param(paramName))) .collect{ case (paramName, Full(paramValue)) if(paramValue.trim.size > 0) => s"$paramName=$paramValue" @@ -379,7 +428,7 @@ object ObpAPI extends Loggable { //Note: ?content=static&content=dynamic // if there are two content parameters there, only the first one is valid for the api call. // so requestParams have the high priority - val requestParams = List("tags", "language", "functions", "content", "cache-modifier") + val requestParams = List("tags", "language", "functions", "content", CacheModifier) .map(paramName => (paramName, S.param(paramName))) .collect{ case (paramName, Full(paramValue)) if(paramValue.trim.size > 0) => s"$paramName=$paramValue" @@ -396,7 +445,7 @@ object ObpAPI extends Loggable { var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString) CacheKeyFromArguments.buildCacheKey { Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(getStaticResourceDocsJsonTTL) { - val requestParamsRemovedContent = requestParams.replace("content=static","") + val requestParamsRemovedContent = requestParams.replace(ContentEqualStatic,"") getResourceDocs(apiVersion, requestParamsRemovedContent, "static") } } @@ -409,7 +458,7 @@ object ObpAPI extends Loggable { var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString) CacheKeyFromArguments.buildCacheKey { Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(getDynamicResourceDocsJsonTTL) { - val requestParamsRemovedContent = requestParams.replace("content=dynamic","") + val requestParamsRemovedContent = requestParams.replace(ContentEqualDynamic,"") getResourceDocs(apiVersion, requestParamsRemovedContent, "dynamic") } } @@ -439,7 +488,7 @@ object ObpAPI extends Loggable { def getBankLevelDynamicResourceDocsJValueResponse(apiVersion : String, bankId:String, requestParams: String) = { logger.debug("getBankLevelResourceDocsJValueResponse says Hello") - val result = ObpGet(s"$obpPrefix/v4.0.0/banks/$bankId/resource-docs/$apiVersion/obp$requestParams&cache-modifier=${UUID.randomUUID().toString}") + val result = ObpGet(s"$obpPrefix/v4.0.0/banks/$bankId/resource-docs/$apiVersion/obp$requestParams&$CacheModifier=${UUID.randomUUID().toString}") logger.debug("getBankLevelResourceDocsJValueResponse says result is: " + result) result } @@ -448,7 +497,7 @@ object ObpAPI extends Loggable { ObpGet(s"$obpPrefix/v4.0.0/resource-docs/$apiVersion/obp$requestParams").map(extractResourceDocsJson).map(_.resource_docs) def getApiCollectionByIdJValueResponse(apiVersion : String) = { - val apiCollectionIdParam = List("api-collection-id") + val apiCollectionIdParam = List(ApiCollectionId) .map(paramName => (paramName, S.param(paramName))) .collect{ case (paramName, Full(paramValue)) if(paramValue.trim.size > 0) => s"$paramName=$paramValue" @@ -605,7 +654,7 @@ object ObpPut { OBPRequest(apiPath, Some(json), "PUT", Nil) match { case Full((status, result, _)) => APIUtils.getAPIResponseBody(status, result) case Failure(msg, exception, chain) => Failure(msg) - case _ => Failure("Unknown Error!") + case _ =>Failure(UnknownErrorMessage) } } } @@ -622,7 +671,7 @@ object ObpPost { OBPRequest(apiPath, Some(json), "POST", Nil) match { case Full((status, result, _)) => APIUtils.getAPIResponseBody(status, result) case Failure(msg, exception, chain) => Failure(msg) - case _ => Failure("Unknown Error!") + case _ => Failure(UnknownErrorMessage) } } } @@ -657,16 +706,16 @@ object ObpDeleteBoolean { object ObpDelete { def apply(apiPath: String): Box[JValue] = { OBPRequest(apiPath, None, "DELETE", Nil) match { - case Full((status, result, _)) => Full(APIUtils.apiResponseWorked(status, result)) + case Full((status, result, _)) => APIUtils.getAPIResponseBody(status, result) case Failure(msg, exception, chain) => Failure(msg) - case _ => Failure("Unknown Error!") + case _ => Failure(UnknownErrorMessage) } } } object ObpDeleteWithHeader { def apply(apiPath: String, headers : List[Header] = Nil): (Box[JValue], List[String]) = { OBPRequest(apiPath, None, "DELETE", headers) match { - case Full(value) => (APIUtils.deleteApiResponse(value._1, value._2), value._3) + case Full(value) => (APIUtils.getAPIResponseBody(value._1, value._2), value._3) } } } @@ -682,7 +731,7 @@ object ObpGet { OBPRequest(apiPath, None, "GET", headers) match { case Full((status, result, _)) => APIUtils.getAPIResponseBody(status, result) case Failure(msg, exception, chain) => Failure(msg) - case _ => Failure("Unknown Error!") + case _ => Failure(UnknownErrorMessage) } } } @@ -696,7 +745,7 @@ object ObpHead { OBPRequest(apiPath, None, "HEAD", headers) match { case Full((status, result, _)) => APIUtils.getAPIResponseBody(status, result) case Failure(msg, exception, chain) => Failure(msg) - case _ => Failure("Unknown Error!") + case _ => Failure(UnknownErrorMessage) } } } @@ -1232,6 +1281,7 @@ object ObpJson { ) case class ResourceDocsJson (resource_docs : List[ResourceDocJson]) + case class DynamicUrlTextPairsJson (url:String, text:String) /////////////////////////////////////////// diff --git a/src/main/scala/code/snippet/ApiExplorer.scala b/src/main/scala/code/snippet/ApiExplorer.scala index 3ec4b094..16638454 100644 --- a/src/main/scala/code/snippet/ApiExplorer.scala +++ b/src/main/scala/code/snippet/ApiExplorer.scala @@ -1,10 +1,10 @@ package code.snippet -import code.lib.ObpAPI.{getAuthenticationTypeValidations, getJsonSchemaValidations, getMySpaces, obpPrefix} +import code.lib.ObpAPI._ import code.lib.ObpJson._ import code.lib.{ObpAPI, ObpGet, _} import code.util.Helper -import code.util.Helper.MdcLoggable +import code.util.Helper.{MdcLoggable, covertObpOperationIdToWebpageId} import net.liftweb.json import net.liftweb.util.{CssSel, Html5} import java.net.URL @@ -180,7 +180,7 @@ WIP to add comments on resource docs. This code copied from Sofit. logger.info(s"nativeParam is $nativeParam") - def apiCollectionIdParam = S.param("api-collection-id") + def apiCollectionIdParam = S.param(ApiCollectionId) logger.info(s"apiCollectionIdParam is $apiCollectionIdParam") @@ -343,7 +343,7 @@ WIP to add comments on resource docs. This code copied from Sofit. val defaultVersion: String = Helper.getPropsValue("default.version") match { case Full(v) => v - case _ => "OBPv4.0.0" + case _ => OBPVersionV400 } // Get the requested version from the url parameter and default if none @@ -352,9 +352,10 @@ WIP to add comments on resource docs. This code copied from Sofit. // Possible OBP Versions - val obpVersionsSupported = List("OBPv3.1.0", "OBPv4.0.0") + val obpVersionsSupported = List("OBPv3.1.0", OBPVersionV400) - val otherVersionsSupported = List("BGv1.3", "UKv3.1") + + val otherVersionsSupported = List(BGVersionV13, UKVersionV31) // This is basically all versions supported val allSupportedVersionsInDropdownMenu = List( @@ -366,11 +367,11 @@ WIP to add comments on resource docs. This code copied from Sofit. "OBPv2.2.0", "OBPv3.0.0", "OBPv3.1.0", - "OBPv4.0.0", - "UKv3.1", + OBPVersionV400, + UKVersionV31, "BGv1.3", "STETv1.4", - "PAPIv2.1.1.1", + PAPIVersionV2111, "AUv1.0.0", "0.6v1", "MXOFv1.0.0", @@ -590,7 +591,10 @@ WIP to add comments on resource docs. This code copied from Sofit. var errorResponseBodies = List("") var isFavourites = "false" - var favouritesOperationId = "" + //Note: OperationIdFromWebpage = OBPv4_0_0-getBanks + //But operationIdForOBP => OBPv4.0.0-getBanks (Javascript do not support '.' there.) + //We must do the converting properly for this two ids. + var favouritesOperationIdFromWebpage = "" var favouritesApiCollectionId = "" @@ -665,20 +669,18 @@ WIP to add comments on resource docs. This code copied from Sofit. val allResources = for { r <- allResourcesList } yield ResourceDocPlus( - //in OBP-API, before it returned v3_1_0, but now, only return v3.1.0 - //But this field will be used in JavaScript, so need clean the field. - id = r.operation_id.replace(".","_").replaceAll(" ","_"), + id = covertObpOperationIdToWebpageId(r.operation_id), operationId = r.operation_id, verb = r.request_verb, url = modifiedRequestUrl( r.specified_url, // We used to use the request_url - but we want to use the specified url i.e. the later version. apiVersion - .replaceAll("UKv2.0", "v2.0") - .replaceAll("UKv3.1", "v3.1") - .replaceAll("BGv1.3.3", "v1.3.3") + .replaceAll(UKVersionV20, "v2.0") + .replaceAll(UKVersionV31, "v3.1") + .replaceAll(BGVersionV133, VersionV133) .replaceAll("BGv1", "v1") - .replaceAll("BGv1.3", "v1.3") - .replaceAll("PAPIv2.1.1.1", "v2.1.1.1") + .replaceAll(BGVersionV13, "v1.3") + .replaceAll(PAPIVersionV2111, "v2.1.1.1") .replaceAll("OBPv", ""), presetBankId, presetAccountId @@ -773,8 +775,8 @@ WIP to add comments on resource docs. This code copied from Sofit. //this can be empty list, if there is no operationIds there. - val getOperationIdsByApiCollectionId = ObpAPI.getApiCollectionEndpointsById(apiCollectionId).map(_.api_collection_endpoints.map(_.operation_id)).openOr(List()) - val getMyOperationIds = ObpAPI.getApiCollectionEndpoints("Favourites").map(_.api_collection_endpoints.map(_.operation_id)).openOr(List()) + def webpageOperationIds = ObpAPI.getApiCollectionEndpointsById(apiCollectionId).map(_.api_collection_endpoints.map(_.operation_id)).openOr(List()).map(covertObpOperationIdToWebpageId) + def myWebpageOperationIds = ObpAPI.getApiCollectionEndpoints("Favourites").map(_.api_collection_endpoints.map(_.operation_id)).openOr(List()).map(covertObpOperationIdToWebpageId) // Group resources by the first tag val unsortedGroupedResources: Map[String, List[ResourceDocPlus]] = resources.groupBy(_.tags.headOr("ToTag")) @@ -963,20 +965,20 @@ WIP to add comments on resource docs. This code copied from Sofit. s"$requestUrl" } logger.info(s"urlWithVersion is: " + urlWithVersion - .replaceAll("UKv2.0", "v2.0") - .replaceAll("UKv3.1", "v3.1") - .replaceAll("BGv1.3.3", "v1.3.3") + .replaceAll(UKVersionV20, "v2.0") + .replaceAll(UKVersionV31, "v3.1") + .replaceAll(BGVersionV133, VersionV133) .replaceAll("BGv1", "v1") - .replaceAll("BGv1.3", "v1.3") + .replaceAll(BGVersionV13, "v1.3") .replaceAll("(? (i .replace("b1", "API Builder") - .replace("BGv1.3.3", "Berlin Group 1.3.3") - .replace("BGv1.3", "Berlin Group 1.3") + .replace(BGVersionV133, "Berlin Group 1.3.3") + .replace(BGVersionV13, "Berlin Group 1.3") .replace("BGv1", "Berlin Group") - .replace("UKv2.0", "UK 2.0") - .replace("UKv3.1", "UK 3.1") + .replace(UKVersionV20, "UK 2.0") + .replace(UKVersionV31, "UK 3.1") .replace("STETv1.4", "STET 1.4") - .replace("PAPIv2.1.1.1", "Polish API 2.1.1.1") + .replace(PAPIVersionV2111, "Polish API 2.1.1.1") .replace("AUv1.0.0", "AU CDR v1.0.0"), s"${CurrentReq.value.uri}?version=${i}&list-all-banks=${listAllBanks}")) @@ -1083,12 +1094,15 @@ WIP to add comments on resource docs. This code copied from Sofit. featuredBankIds.contains(b.id.get) // Add a flag to say if this bank is featured. ) + // Banks where a user has accounts + My Spaces + Featured Banks. + val userCanShowBankIds= (myBankIds++featuredBankIds.map(BankId(_))++ getMySpaces.map(_.bank_ids.map(BankId(_))).getOrElse(List.empty[BankId])).toSet + val banksForUser = if (listAllBanks) // Url param says show all. banks else - if(!myBankIds.isEmpty) // User has accounts so show those banks - banks.filter(b => myBankIds.contains(BankId(b.id))) + if(!userCanShowBankIds.isEmpty) // User has accounts so show those banks + banks.filter(b => userCanShowBankIds.contains(BankId(b.id))) else // If we have a featured list of banks show those, else all. banks.filter(b => b.isFeatured || featuredBankIds.length == 0) @@ -1309,7 +1323,7 @@ WIP to add comments on resource docs. This code copied from Sofit. * we need to skip the case: &api-collection-id=& */ def isCollectionOfResourceDocs_? = { - S.param("api-collection-id").isDefined && S.param("api-collection-id").getOrElse("").nonEmpty + S.param(ApiCollectionId).isDefined && S.param(ApiCollectionId).getOrElse("").nonEmpty } val glossaryItems = getGlossaryItemsJson.map(_.glossary_items).getOrElse(List()) @@ -1415,7 +1429,14 @@ WIP to add comments on resource docs. This code copied from Sofit. "@api_glossary_item_link * " #>{ val description = glossaryItems.find(_.title == i._1.replaceAll("-"," ")).map(_.description.markdown).getOrElse("") if (description.length > 100) - description.substring(0,100).trim() +" ..." + "More..." + else + "" //If there is no description, we will show empty here. + } & + "@api_glossary_item_text * " #>{ + val description = glossaryItems.find(_.title == i._1.replaceAll("-"," ")).map(_.description.markdown).getOrElse("") + if (description.length > 100) + description.substring(0,100).trim() else "" //If there is no description, we will show empty here. } & @@ -1483,51 +1504,51 @@ WIP to add comments on resource docs. This code copied from Sofit. // This creates the list of resources in the DOM { if(allResourcesBox.isInstanceOf[Failure]) { - ".resource [style]" #> s"display: none" & - ".resource-error [style]" #> s"display: block" & - ".content-box__headline *" #> { + ResourceStyleCss #> s"${DisplayEqualNone}" & + ResourceErrorStyleCss #> s"${DisplayEqualBlock}" & + ContentBoxHeadline #> { allResourcesBox.asInstanceOf[Failure].msg }& { if(allResourcesBox.asInstanceOf[Failure].msg.contains("CanReadResourceDoc")){ //required roles and related user information - "@roles_box [id]" #> s"roles_box_canReadResourceDocRoleInfo" & - "@roles_box [style]" #> {s"display: block"} & + RolesBoxId #> s"roles_box_canReadResourceDocRoleInfo" & + RolesBoxStyle #> {s"${DisplayEqualBlock}"} & // We generate mulutiple .role_items from roleInfos (including the form defined in index.html) - ".role_item" #> canReadResourceDocRoleInfo.map { r => - "@roles__status" #> {if (! isLoggedIn) - s" - Please login to request this Role" + RoleItemClassCss #> canReadResourceDocRoleInfo.map { r => + RoleStatusNameCss #> {if (! isLoggedIn) + PleaseLoginToRequestThisRole else if (r.userHasEntitlement) - s" - You have this Role." + YouHaveThisRole else if (r.userHasEntitlementRequest) - s" - You have requested this Role. Please contact Open Bank Project team to grant your this role." + ContactOBPTeam else - s" - You can request this Role."} & - "@roles__role_name" #> s"${r.role}" & + YouCanRequestThisRole} & + RolesRoleNameCss #> s"${r.role}" & // ajaxSubmit will submit the form. // The value of rolesBankId is given to bank_id_input field and the value of bank_id_input entered by user is given back to rolesBankId - "@roles__bank_id_input" #> SHtml.text({if (r.requiresBankId) rolesBankId else ""}, rolesBankId = _, if (r.requiresBankId) "type" -> "text" else "type" -> "hidden") & - "@roles__role_input" #> SHtml.text(s"${r.role}", entitlementRequestRoleName = _, "type" -> "hidden" ) & + RolesBankIdInput #> SHtml.text({if (r.requiresBankId) rolesBankId else ""}, rolesBankId = _, if (r.requiresBankId) "type" -> "text" else "type" -> "hidden") & + RolesRoleInput #> SHtml.text(s"${r.role}", entitlementRequestRoleName = _, "type" -> "hidden" ) & "@roles__resource_id_input" #> text("canReadResourceDocRoleInfo", s => RolesResourceId = s, "type" -> "hidden", "id" -> s"roles__resource_id_input_${canReadResourceDocRoleInfo}") & - "@roles__request_entitlement_button" #> Helper.ajaxSubmit("Request", disabledBtn, processEntitlementRequest) & - "@roles__entitlement_request_response [id]" #> s"roles__entitlement_request_response_${canReadResourceDocRoleInfo}_${r.role}" & - "@roles__entitlement_request_button_box [style]" #> { if (! isLoggedIn || r.userHasEntitlement || r.userHasEntitlementRequest) - s"display: none" + RolesRequestEntitlementButton #> Helper.ajaxSubmit("Request", disabledBtn, processEntitlementRequest) & + RolesEntitlementRequestId #> s"roles__entitlement_request_response_${canReadResourceDocRoleInfo}_${r.role}" & + RolesEntitlementRequestButtonBox #> { if (! isLoggedIn || r.userHasEntitlement || r.userHasEntitlementRequest) + s"${DisplayEqualNone}" else - s"display: block" + s"${DisplayEqualBlock}" } } } else{ - "@roles_box [style]" #> s"display: none" + RolesBoxStyle #> s"${DisplayEqualNone}" } } }else if(allResourcesBox.isEmpty || allResourcesBox.openOr(Nil).length ==0){ - ".resource [style]" #> s"display: none" & - ".resource-error [style]" #> s"display: block" & - ".content-box__headline *" #> { + ResourceStyleCss #> s"${DisplayEqualNone}" & + ResourceErrorStyleCss #> s"${DisplayEqualBlock}" & + ContentBoxHeadline #> { "Sorry, we could not return any Resource Docs." }& - ".content-box__info-box [style]" #> s"display: none" + ".content-box__info-box [style]" #> s"${DisplayEqualNone}" } else { //The default tag is the first tag of the resource, if it is empty, we use the API Tag. @@ -1542,9 +1563,9 @@ WIP to add comments on resource docs. This code copied from Sofit. resourcesShowedInPage }).map { i => // append the anchor to the current url. Maybe need to set the catalogue to all etc else another user might not find if the link is sent to them. - ".end-point-anchor [href]" #> s"#${i.id}" & - ".content-box__headline *" #> i.summary & - ".content-box__headline [id]" #> i.id & // id for the anchor to find + EndPointAnchorHref #> s"#${i.id}" & + ContentBoxHeadline #> i.summary & + ContentBoxHeadlineId #> i.id & // id for the anchor to find // Replace attribute named overview_text with the value (whole div/span element is replaced leaving just the text) "@description *" #> i.description & "@special_instructions *" #> i.specialInstructions & @@ -1607,34 +1628,34 @@ WIP to add comments on resource docs. This code copied from Sofit. ".connector_method_item_link *" #> i } & //required roles and related user information - "@roles_box [id]" #> s"roles_box_${i.id}" & - "@roles_box [style]" #> { if (i.roleInfos.isEmpty) - s"display: none" + RolesBoxId #> s"roles_box_${i.id}" & + RolesBoxStyle #> { if (i.roleInfos.isEmpty) + s"${DisplayEqualNone}" else - s"display: block" + s"${DisplayEqualBlock}" } & // We generate multiple .role_items from roleInfos (including the form defined in index.html) - ".role_item" #> i.roleInfos.map { r => - "@roles__status" #> {if (! isLoggedIn) - s" - Please login to request this Role" + RoleItemClassCss #> i.roleInfos.map { r => + RoleStatusNameCss #> {if (! isLoggedIn) + PleaseLoginToRequestThisRole else if (r.userHasEntitlement) - s" - You have this Role." + YouHaveThisRole else if (r.userHasEntitlementRequest) - s" - You have requested this Role. Please contact Open Bank Project team to grant your this role." + ContactOBPTeam else - s" - You can request this Role."} & - "@roles__role_name" #> s"${r.role}" & + YouCanRequestThisRole} & + RolesRoleNameCss #> s"${r.role}" & // ajaxSubmit will submit the form. // The value of rolesBankId is given to bank_id_input field and the value of bank_id_input entered by user is given back to rolesBankId - "@roles__bank_id_input" #> SHtml.text({if (r.requiresBankId) rolesBankId else ""}, rolesBankId = _, if (r.requiresBankId) "type" -> "text" else "type" -> "hidden") & - "@roles__role_input" #> SHtml.text(s"${r.role}", entitlementRequestRoleName = _, "type" -> "hidden" ) & + RolesBankIdInput #> SHtml.text({if (r.requiresBankId) rolesBankId else ""}, rolesBankId = _, if (r.requiresBankId) "type" -> "text" else "type" -> "hidden") & + RolesRoleInput #> SHtml.text(s"${r.role}", entitlementRequestRoleName = _, "type" -> "hidden" ) & "@roles__resource_id_input" #> text(i.id.toString, s => RolesResourceId = s, "type" -> "hidden", "id" -> s"roles__resource_id_input_${i.id}_${r.role}") & - "@roles__request_entitlement_button" #> Helper.ajaxSubmit("Request", disabledBtn, processEntitlementRequest) & - "@roles__entitlement_request_response [id]" #> s"roles__entitlement_request_response_${i.id}_${r.role}" & - "@roles__entitlement_request_button_box [style]" #> { if (! isLoggedIn || r.userHasEntitlement || r.userHasEntitlementRequest) - s"display: none" + RolesRequestEntitlementButton #> Helper.ajaxSubmit("Request", disabledBtn, processEntitlementRequest) & + RolesEntitlementRequestId #> s"roles__entitlement_request_response_${i.id}_${r.role}" & + RolesEntitlementRequestButtonBox #> { if (! isLoggedIn || r.userHasEntitlement || r.userHasEntitlementRequest) + s"${DisplayEqualNone}" else - s"display: block" + s"${DisplayEqualBlock}" } } & // @@ -1644,11 +1665,11 @@ WIP to add comments on resource docs. This code copied from Sofit. "@success_response_body [id]" #> s"success_response_body_${i.id}" & // The button. First argument is the text of the button (GET, POST etc). Second argument is function to call. Arguments to the func could be sent in third argument "@call_button" #> Helper.ajaxSubmit(i.verb, disabledBtn, process) & - ".favourites_operatino_id" #> text(i.id.toString, s => favouritesOperationId = s, "type" -> "hidden","class" -> "favourites_operatino_id") & + ".favourites_operation_id" #> text(i.id.toString, s => favouritesOperationIdFromWebpage = s, "type" -> "hidden","class" -> "favourites_operation_id") & ".favourites_api_collection_id" #> text(apiCollectionId, s => favouritesApiCollectionId = s, "type" -> "hidden","class" -> "favourites_api_collection_id") & ".favourites_button" #> Helper.ajaxSubmit("★", disabledBtn, processFavourites, "id" -> s"favourites_button_${i.id.toString}", - if(apiCollectionIdParam.isDefined && getOperationIdsByApiCollectionId.nonEmpty) {"style" -> "color:#53C4EF"} - else if(getMyOperationIds.contains(i.id.toString)) {"style" -> "color:#53C4EF"} + if(apiCollectionIdParam.isDefined && webpageOperationIds.nonEmpty) {"style" -> "color:#53C4EF"} + else if(myWebpageOperationIds.contains(i.id.toString)) {"style" -> "color:#53C4EF"} else {"style" -> "color:#767676"} ) & ".favourites_error_message [id]" #> s"favourites_error_message_${i.id}" & @@ -1675,7 +1696,6 @@ WIP to add comments on resource docs. This code copied from Sofit. logger.debug("before showResources:") def resourceDocsRequiresRole = ObpAPI.getRoot.flatMap(_.extractOpt[APIInfoJson400].map(_.resource_docs_requires_role)).openOr(false) - // Get a list of resource docs from the API server // This will throw an exception if resource_docs key is not populated // Convert the json representation to ResourceDoc (pretty much a one to one mapping) @@ -1691,9 +1711,9 @@ WIP to add comments on resource docs. This code copied from Sofit. val glossaryItems = getGlossaryItemsJson.map(_.glossary_items).getOrElse(List()) if(glossaryItems.length==0) { - ".resource [style]" #> s"display: none" & - ".resource-error [style]" #> s"display: block" & - ".content-box__headline *" #> { + ResourceStyleCss #> s"${DisplayEqualNone}" & + ResourceErrorStyleCss #> s"${DisplayEqualBlock}" & + ContentBoxHeadline #> { if(!isLoggedIn)//If no resources, first check the login, "Sorry, we could not return any Glossary Items. Note: OBP-20001: User not logged in." else if(isLoggedIn && canReadGlossaryRole.isEmpty) //Then check the missing role @@ -1703,33 +1723,33 @@ WIP to add comments on resource docs. This code copied from Sofit. }&{ if(isLoggedIn && canReadGlossaryRole.isEmpty){ //required roles and related user information - "@roles_box [id]" #> s"roles_box_CanReadGlossaryRoleInfo" & - "@roles_box [style]" #> {s"display: block"} & + RolesBoxId #> s"roles_box_CanReadGlossaryRoleInfo" & + RolesBoxStyle #> {s"${DisplayEqualBlock}"} & // We generate multiple .role_items from roleInfos (including the form defined in index.html) - ".role_item" #> canReadGlossaryRoleInfo.map { r => - "@roles__status" #> {if (! isLoggedIn) - s" - Please login to request this Role" + RoleItemClassCss #> canReadGlossaryRoleInfo.map { r => + RoleStatusNameCss #> {if (! isLoggedIn) + PleaseLoginToRequestThisRole else if (r.userHasEntitlement) - s" - You have this Role." + YouHaveThisRole else if (r.userHasEntitlementRequest) s" - You have requested this Role. Please contact the administrators to grant you this role." else - s" - You can request this Role."} & - "@roles__role_name" #> s"${r.role}" & + YouCanRequestThisRole} & + RolesRoleNameCss #> s"${r.role}" & // ajaxSubmit will submit the form. // The value of rolesBankId is given to bank_id_input field and the value of bank_id_input entered by user is given back to rolesBankId - "@roles__bank_id_input" #> SHtml.text({if (r.requiresBankId) rolesBankId else ""}, rolesBankId = _, if (r.requiresBankId) "type" -> "text" else "type" -> "hidden") & - "@roles__role_input" #> SHtml.text(s"${r.role}", entitlementRequestRoleName = _, "type" -> "hidden" ) & - "@roles__request_entitlement_button" #> Helper.ajaxSubmit("Request", disabledBtn, processEntitlementRequest) & - "@roles__entitlement_request_response [id]" #> s"roles__entitlement_request_response_${canReadGlossaryRoleInfo}_${r.role}" & - "@roles__entitlement_request_button_box [style]" #> { if (! isLoggedIn || r.userHasEntitlement || r.userHasEntitlementRequest) - s"display: none" + RolesBankIdInput #> SHtml.text({if (r.requiresBankId) rolesBankId else ""}, rolesBankId = _, if (r.requiresBankId) "type" -> "text" else "type" -> "hidden") & + RolesRoleInput #> SHtml.text(s"${r.role}", entitlementRequestRoleName = _, "type" -> "hidden" ) & + RolesRequestEntitlementButton #> Helper.ajaxSubmit("Request", disabledBtn, processEntitlementRequest) & + RolesEntitlementRequestId #> s"roles__entitlement_request_response_${canReadGlossaryRoleInfo}_${r.role}" & + RolesEntitlementRequestButtonBox #> { if (! isLoggedIn || r.userHasEntitlement || r.userHasEntitlementRequest) + s"${DisplayEqualNone}" else - s"display: block" + s"${DisplayEqualBlock}" } } }else{ - "@roles_box [style]" #> s"display: none" + RolesBoxStyle #> s"${DisplayEqualNone}" } } }else{ @@ -1738,9 +1758,9 @@ WIP to add comments on resource docs. This code copied from Sofit. val tag = i.title.replaceAll(" ", "-") val operationId = allResourcesList.find(_.tags.head == tag).map(_.operation_id).getOrElse("") // append the anchor to the current url. Maybe need to set the catalogue to all etc else another user might not find if the link is sent to them. - ".end-point-anchor [href]" #> s"#${urlEncode(i.title.replaceAll(" ", "-"))}" & - ".content-box__headline *" #> i.title & - ".content-box__headline [id]" #> i.title.replaceAll(" ", "-") & // id for the anchor to find + EndPointAnchorHref #> s"#${urlEncode(i.title.replaceAll(" ", "-"))}" & + ContentBoxHeadline #> i.title & + ContentBoxHeadlineId #> i.title.replaceAll(" ", "-") & // id for the anchor to find //i.title must be a proper tag, and will prepare the URL for it ... ".glossary_item_apis [href]" #> { s"./?operation_id=${operationId.replace(".","_").replaceAll(" ","_")}#group-${tag}" @@ -1783,9 +1803,9 @@ WIP to add comments on resource docs. This code copied from Sofit. } } & ".message-doc" #> messageDocs.map { i => - ".end-point-anchor [href]" #> s"#${urlEncode(i.process.replaceAll(" ", "-"))}" & - ".content-box__headline *" #> i.process & - ".content-box__headline [id]" #> i.process.replaceAll(" ", "-") & // id for the anchor to find + EndPointAnchorHref #> s"#${urlEncode(i.process.replaceAll(" ", "-"))}" & + ContentBoxHeadline #> i.process & + ContentBoxHeadlineId #> i.process.replaceAll(" ", "-") & // id for the anchor to find ".outbound-topic *" #> stringToNodeSeq(i.outbound_topic.getOrElse("")) & ".inbound-topic *" #> stringToNodeSeq(i.inbound_topic.getOrElse("")) & ".outbound-message *" #> stringToNodeSeq(Helper.renderJson(i.example_outbound_message)) & diff --git a/src/main/scala/code/snippet/Login.scala b/src/main/scala/code/snippet/Login.scala index 8e539d6a..19c3d838 100644 --- a/src/main/scala/code/snippet/Login.scala +++ b/src/main/scala/code/snippet/Login.scala @@ -46,8 +46,9 @@ class Login { ObpAPI.currentUser.map { u => u.provider.toLowerCase() match { - case provider if provider.contains("google") => u.email - case provider if provider.contains("yahoo") => u.email + case provider if provider.contains("google") && !u.email.isEmpty => u.email + case provider if provider.contains("yahoo") && !u.email.isEmpty => u.email + case provider if provider.contains("microsoft") && !u.email.isEmpty => u.email case _ => u.username } } diff --git a/src/main/scala/code/util/Helper.scala b/src/main/scala/code/util/Helper.scala index 5b25dd66..fdf74c86 100644 --- a/src/main/scala/code/util/Helper.scala +++ b/src/main/scala/code/util/Helper.scala @@ -156,4 +156,22 @@ Returns a string which can be used for the title of the account case JNothing => "" case v => pretty(render(v)) } + + //in OBP-API, before it returned v3_1_0, but now, only return v3.1.0 + //But this field will be used in JavaScript/Webpage html id attribute, so need clean the field. + //To use any of the meta-characters (such as !"#$%&'()*+,./:;<=>?@[\]^`{|}~) as a literal part of a name, + //it must be escaped with with two backslashes: \\. For example, an element with id="foo.bar", + //can use the selector $("#foo\\.bar"). + //So in Leftweb: + // eg: SetHtml(s"OBPv4.0.0_getBank", Text("Wrong OperationId")) --> not working + // eg: SetHtml(s"OBPv4_0_0_getBank", Text("Wrong OperationId")) --> working, + def covertObpOperationIdToWebpageId(operation_id: String) = { + operation_id.replace(".", "_").replaceAll(" ", "_") + } + + + def covertWebpageIdToObpOperationId(web_page_operation_id: String) = { + web_page_operation_id.replace("_", ".") + } + } diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html index 9c689343..b81818a1 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -59,7 +59,9 @@ API group