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 @@