From 5618f447850b8724f5701745bd24d0afaf3d1241 Mon Sep 17 00:00:00 2001 From: shuang Date: Tue, 28 Sep 2021 21:35:53 +0800 Subject: [PATCH 01/37] feature/dynamic_code_security: change macro repository from oldbig to OpenBankProject --- obp-api/pom.xml | 4 ++-- obp-commons/pom.xml | 2 +- pom.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/obp-api/pom.xml b/obp-api/pom.xml index 28695365f..fcf409b80 100644 --- a/obp-api/pom.xml +++ b/obp-api/pom.xml @@ -8,7 +8,7 @@ com.tesobe obp-parent ../pom.xml - 1.10.0 + 1.10.1 obp-api war @@ -479,7 +479,7 @@ - com.github.oldbig + com.github.OpenBankProject macmemo 0.6-OBP-SNAPSHOT diff --git a/obp-commons/pom.xml b/obp-commons/pom.xml index 9929785bb..5b77b1493 100644 --- a/obp-commons/pom.xml +++ b/obp-commons/pom.xml @@ -7,7 +7,7 @@ com.tesobe obp-parent ../pom.xml - 1.10.0 + 1.10.1 obp-commons jar diff --git a/pom.xml b/pom.xml index a2b5e94db..09db6c0de 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.tesobe obp-parent - 1.10.0 + 1.10.1 pom Open Bank Project API Parent 2011 From 7a1c41f61023e14fea60f10aff08e6d412bde55a Mon Sep 17 00:00:00 2001 From: hongwei Date: Sat, 16 Oct 2021 13:50:33 +0200 Subject: [PATCH 02/37] feature/OBPv400 added the bankLevel CURD DynamicMessageDoc --- .../SwaggerDefinitionsJSON.scala | 1 + .../main/scala/code/api/util/ApiRole.scala | 9 + .../main/scala/code/api/util/NewStyle.scala | 24 +-- .../scala/code/api/v4_0_0/APIMethods400.scala | 193 +++++++++++++++++- .../bankconnectors/DynamicConnector.scala | 10 +- .../dynamicMessageDoc/DynamicMessageDoc.scala | 2 + .../DynamicMessageDocProvider.scala | 13 +- .../MappedDynamicMessageDocProvider.scala | 62 ++++-- 8 files changed, 269 insertions(+), 45 deletions(-) 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 7fb68a87c..e9a8a12d4 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 @@ -4272,6 +4272,7 @@ object SwaggerDefinitionsJSON { ) val jsonDynamicMessageDoc = JsonDynamicMessageDoc( + bankId = Some(bankIdExample.value), dynamicMessageDocId = Some(dynamicMessageDocIdExample.value), process = processExample.value, messageFormat = messageFormatExample.value, diff --git a/obp-api/src/main/scala/code/api/util/ApiRole.scala b/obp-api/src/main/scala/code/api/util/ApiRole.scala index 1becd2472..34431f6ea 100644 --- a/obp-api/src/main/scala/code/api/util/ApiRole.scala +++ b/obp-api/src/main/scala/code/api/util/ApiRole.scala @@ -749,6 +749,9 @@ object ApiRole { case class CanCreateDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole lazy val canCreateDynamicMessageDoc = CanCreateDynamicMessageDoc() + + case class CanCreateBankLevelDynamicMessageDoc(requiresBankId: Boolean = true) extends ApiRole + lazy val canCreateBankLevelDynamicMessageDoc = CanCreateBankLevelDynamicMessageDoc() case class CanUpdateDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole lazy val canUpdateDynamicMessageDoc = CanUpdateDynamicMessageDoc() @@ -756,12 +759,18 @@ object ApiRole { case class CanGetDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole lazy val canGetDynamicMessageDoc = CanGetDynamicMessageDoc() + case class CanGetBankLevelDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole + lazy val canGetBankLevelDynamicMessageDoc = CanGetBankLevelDynamicMessageDoc() + case class CanGetAllDynamicMessageDocs(requiresBankId: Boolean = false) extends ApiRole lazy val canGetAllDynamicMessageDocs = CanGetAllDynamicMessageDocs() case class CanDeleteDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole lazy val canDeleteDynamicMessageDoc = CanDeleteDynamicMessageDoc() + case class CanDeleteBankLevelDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole + lazy val canDeleteBankLevelDynamicMessageDoc = CanDeleteBankLevelDynamicMessageDoc() + case class CanCreateEndpointMapping(requiresBankId: Boolean = false) extends ApiRole lazy val canCreateEndpointMapping = CanCreateEndpointMapping() diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index 72648d7fa..8b78ca0da 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -3294,41 +3294,41 @@ object NewStyle { (unboxFullOrFail(dynamicResourceDoc, callContext, s"$DynamicResourceDocDeleteError Current DYNAMIC_RESOURCE_DOC_ID(${dynamicResourceDocId})", 400), callContext) } - def createJsonDynamicMessageDoc(dynamicMessageDoc: JsonDynamicMessageDoc, callContext: Option[CallContext]): OBPReturnType[JsonDynamicMessageDoc] = + def createJsonDynamicMessageDoc(bankId: Option[String], dynamicMessageDoc: JsonDynamicMessageDoc, callContext: Option[CallContext]): OBPReturnType[JsonDynamicMessageDoc] = Future { - val newInternalConnector = DynamicMessageDocProvider.provider.vend.create(dynamicMessageDoc) + val newInternalConnector = DynamicMessageDocProvider.provider.vend.create(bankId, dynamicMessageDoc) val errorMsg = s"$UnknownError Can not create Dynamic Message Doc in the backend. " (unboxFullOrFail(newInternalConnector, callContext, errorMsg, 400), callContext) } - def updateJsonDynamicMessageDoc(entity: JsonDynamicMessageDoc, callContext: Option[CallContext]): OBPReturnType[JsonDynamicMessageDoc] = + def updateJsonDynamicMessageDoc(bankId: Option[String], entity: JsonDynamicMessageDoc, callContext: Option[CallContext]): OBPReturnType[JsonDynamicMessageDoc] = Future { - val updatedConnectorMethod = DynamicMessageDocProvider.provider.vend.update(entity: JsonDynamicMessageDoc) + val updatedConnectorMethod = DynamicMessageDocProvider.provider.vend.update(bankId: Option[String], entity: JsonDynamicMessageDoc) val errorMsg = s"$UnknownError Can not update Dynamic Message Doc in the backend. " (unboxFullOrFail(updatedConnectorMethod, callContext, errorMsg, 400), callContext) } - def isJsonDynamicMessageDocExists(process: String, callContext: Option[CallContext]): OBPReturnType[Boolean] = + def isJsonDynamicMessageDocExists(bankId: Option[String], process: String, callContext: Option[CallContext]): OBPReturnType[Boolean] = Future { - val result = DynamicMessageDocProvider.provider.vend.getByProcess(process) + val result = DynamicMessageDocProvider.provider.vend.getByProcess(bankId, process) (result.isDefined, callContext) } - def getJsonDynamicMessageDocs(callContext: Option[CallContext]): OBPReturnType[List[JsonDynamicMessageDoc]] = + def getJsonDynamicMessageDocs(bankId: Option[String], callContext: Option[CallContext]): OBPReturnType[List[JsonDynamicMessageDoc]] = Future { - val dynamicMessageDocs: List[JsonDynamicMessageDoc] = DynamicMessageDocProvider.provider.vend.getAll() + val dynamicMessageDocs: List[JsonDynamicMessageDoc] = DynamicMessageDocProvider.provider.vend.getAll(bankId) dynamicMessageDocs -> callContext } - def getJsonDynamicMessageDocById(dynamicMessageDocId: String, callContext: Option[CallContext]): OBPReturnType[JsonDynamicMessageDoc] = + def getJsonDynamicMessageDocById(bankId: Option[String], dynamicMessageDocId: String, callContext: Option[CallContext]): OBPReturnType[JsonDynamicMessageDoc] = Future { - val dynamicMessageDoc = DynamicMessageDocProvider.provider.vend.getById(dynamicMessageDocId) + val dynamicMessageDoc = DynamicMessageDocProvider.provider.vend.getById(bankId, dynamicMessageDocId) (unboxFullOrFail(dynamicMessageDoc, callContext, s"$DynamicMessageDocNotFound Current DYNAMIC_RESOURCE_DOC_ID(${dynamicMessageDocId})", 400), callContext) } - def deleteJsonDynamicMessageDocById(dynamicMessageDocId: String, callContext: Option[CallContext]): OBPReturnType[Boolean] = + def deleteJsonDynamicMessageDocById(bankId: Option[String], dynamicMessageDocId: String, callContext: Option[CallContext]): OBPReturnType[Boolean] = Future { - val dynamicMessageDoc = DynamicMessageDocProvider.provider.vend.deleteById(dynamicMessageDocId) + val dynamicMessageDoc = DynamicMessageDocProvider.provider.vend.deleteById(bankId, dynamicMessageDocId) (unboxFullOrFail(dynamicMessageDoc, callContext, s"$DynamicMessageDocDeleteError", 400), callContext) } diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index f28c9fe16..1389ba923 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -9258,7 +9258,7 @@ trait APIMethods400 { dynamicMessageDoc <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc", 400, cc.callContext) { json.extract[JsonDynamicMessageDoc] } - (dynamicMessageDocExisted, callContext) <- NewStyle.function.isJsonDynamicMessageDocExists(dynamicMessageDoc.process, cc.callContext) + (dynamicMessageDocExisted, callContext) <- NewStyle.function.isJsonDynamicMessageDocExists(None, dynamicMessageDoc.process, cc.callContext) _ <- Helper.booleanToFuture(failMsg = s"$DynamicMessageDocAlreadyExists The json body process(${dynamicMessageDoc.process}) already exists", cc=callContext) { (!dynamicMessageDocExisted) } @@ -9267,7 +9267,50 @@ trait APIMethods400 { _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=callContext) { connectorMethod.isDefined } - (dynamicMessageDoc, callContext) <- NewStyle.function.createJsonDynamicMessageDoc(dynamicMessageDoc, callContext) + (dynamicMessageDoc, callContext) <- NewStyle.function.createJsonDynamicMessageDoc(None, dynamicMessageDoc, callContext) + } yield { + (dynamicMessageDoc, HttpCode.`201`(callContext)) + } + } + } + + staticResourceDocs += ResourceDoc( + createBankLevelDynamicMessageDoc, + implementedInApiVersion, + nameOf(createBankLevelDynamicMessageDoc), + "POST", + "/management/banks/BANK_ID/dynamic-message-docs", + "Create Bank Level Dynamic Message Doc", + s"""Create a Bank Level Dynamic Message Doc. + |""", + jsonDynamicMessageDoc.copy(dynamicMessageDocId=None), + jsonDynamicMessageDoc, + List( + $UserNotLoggedIn, + UserHasMissingRoles, + InvalidJsonFormat, + UnknownError + ), + List(apiTagDynamicMessageDoc, apiTagNewStyle), + Some(List(canCreateBankLevelDynamicMessageDoc))) + + lazy val createBankLevelDynamicMessageDoc: OBPEndpoint = { + case "management" :: "banks" :: bankId ::"dynamic-message-docs" :: Nil JsonPost json -> _ => { + cc => + for { + dynamicMessageDoc <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc", 400, cc.callContext) { + json.extract[JsonDynamicMessageDoc] + } + (dynamicMessageDocExisted, callContext) <- NewStyle.function.isJsonDynamicMessageDocExists(Some(bankId), dynamicMessageDoc.process, cc.callContext) + _ <- Helper.booleanToFuture(failMsg = s"$DynamicMessageDocAlreadyExists The json body process(${dynamicMessageDoc.process}) already exists", cc=callContext) { + (!dynamicMessageDocExisted) + } + connectorMethod = DynamicConnector.createFunction(dynamicMessageDoc.process, dynamicMessageDoc.decodedMethodBody) + errorMsg = if(connectorMethod.isEmpty) s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" else "" + _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=callContext) { + connectorMethod.isDefined + } + (dynamicMessageDoc, callContext) <- NewStyle.function.createJsonDynamicMessageDoc(Some(bankId), dynamicMessageDoc, callContext) } yield { (dynamicMessageDoc, HttpCode.`201`(callContext)) } @@ -9306,8 +9349,8 @@ trait APIMethods400 { _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=cc.callContext) { connectorMethod.isDefined } - (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(dynamicMessageDocId, cc.callContext) - (dynamicMessageDoc, callContext) <- NewStyle.function.updateJsonDynamicMessageDoc(dynamicMessageDocBody.copy(dynamicMessageDocId=Some(dynamicMessageDocId)), callContext) + (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(None, dynamicMessageDocId, cc.callContext) + (dynamicMessageDoc, callContext) <- NewStyle.function.updateJsonDynamicMessageDoc(None, dynamicMessageDocBody.copy(dynamicMessageDocId=Some(dynamicMessageDocId)), callContext) } yield { (dynamicMessageDoc, HttpCode.`200`(callContext)) } @@ -9338,7 +9381,7 @@ trait APIMethods400 { case "management" :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonGet _ => { cc => for { - (dynamicMessageDoc, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(dynamicMessageDocId, cc.callContext) + (dynamicMessageDoc, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(None, dynamicMessageDocId, cc.callContext) } yield { (dynamicMessageDoc, HttpCode.`200`(callContext)) } @@ -9369,7 +9412,7 @@ trait APIMethods400 { case "management" :: "dynamic-message-docs" :: Nil JsonGet _ => { cc => for { - (dynamicMessageDocs, callContext) <- NewStyle.function.getJsonDynamicMessageDocs(cc.callContext) + (dynamicMessageDocs, callContext) <- NewStyle.function.getJsonDynamicMessageDocs(None, cc.callContext) } yield { (ListResult("dynamic-message-docs", dynamicMessageDocs), HttpCode.`200`(callContext)) } @@ -9400,8 +9443,142 @@ trait APIMethods400 { case "management" :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonDelete _ => { cc => for { - (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(dynamicMessageDocId, cc.callContext) - (dynamicResourceDoc, callContext) <- NewStyle.function.deleteJsonDynamicMessageDocById(dynamicMessageDocId, callContext) + (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(None, dynamicMessageDocId, cc.callContext) + (dynamicResourceDoc, callContext) <- NewStyle.function.deleteJsonDynamicMessageDocById(None, dynamicMessageDocId, callContext) + } yield { + (dynamicResourceDoc, HttpCode.`204`(callContext)) + } + } + } + + staticResourceDocs += ResourceDoc( + updateBankLevelDynamicMessageDoc, + implementedInApiVersion, + nameOf(updateBankLevelDynamicMessageDoc), + "PUT", + "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", + "Update Bank Level Dynamic Message Doc", + s"""Update a Bank Level Dynamic Message Doc. + |""", + jsonDynamicMessageDoc.copy(dynamicMessageDocId=None), + jsonDynamicMessageDoc, + List( + $UserNotLoggedIn, + UserHasMissingRoles, + InvalidJsonFormat, + UnknownError + ), + List(apiTagDynamicMessageDoc, apiTagNewStyle), + Some(List(canUpdateDynamicMessageDoc))) + + lazy val updateBankLevelDynamicMessageDoc: OBPEndpoint = { + case "management" :: "banks" :: bankId::"dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonPut json -> _ => { + cc => + for { + dynamicMessageDocBody <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $JsonDynamicMessageDoc", 400, cc.callContext) { + json.extract[JsonDynamicMessageDoc] + } + connectorMethod = DynamicConnector.createFunction(dynamicMessageDocBody.process, dynamicMessageDocBody.decodedMethodBody) + errorMsg = if(connectorMethod.isEmpty) s"$ConnectorMethodBodyCompileFail ${connectorMethod.asInstanceOf[Failure].msg}" else "" + _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=cc.callContext) { + connectorMethod.isDefined + } + (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(Some(bankId), dynamicMessageDocId, cc.callContext) + (dynamicMessageDoc, callContext) <- NewStyle.function.updateJsonDynamicMessageDoc(Some(bankId), dynamicMessageDocBody.copy(dynamicMessageDocId=Some(dynamicMessageDocId)), callContext) + } yield { + (dynamicMessageDoc, HttpCode.`200`(callContext)) + } + } + } + + staticResourceDocs += ResourceDoc( + getBankLevelDynamicMessageDoc, + implementedInApiVersion, + nameOf(getBankLevelDynamicMessageDoc), + "GET", + "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", + "Get Bank Level Dynamic Message Doc", + s"""Get a Bank Level Dynamic Message Doc by DYNAMIC_MESSAGE_DOC_ID. + | + |""", + EmptyBody, + jsonDynamicMessageDoc, + List( + $UserNotLoggedIn, + UserHasMissingRoles, + UnknownError + ), + List(apiTagDynamicMessageDoc, apiTagNewStyle), + Some(List(canGetBankLevelDynamicMessageDoc))) + + lazy val getBankLevelDynamicMessageDoc: OBPEndpoint = { + case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonGet _ => { + cc => + for { + (dynamicMessageDoc, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(None, dynamicMessageDocId, cc.callContext) + } yield { + (dynamicMessageDoc, HttpCode.`200`(callContext)) + } + } + } + + staticResourceDocs += ResourceDoc( + getAllBankLevelDynamicMessageDocs, + implementedInApiVersion, + nameOf(getAllBankLevelDynamicMessageDocs), + "GET", + "/management/banks/BANK_ID/dynamic-message-docs", + "Get all Bank Level Dynamic Message Docs", + s"""Get all Bank Level Dynamic Message Docs. + | + |""", + EmptyBody, + ListResult("dynamic-message-docs", jsonDynamicMessageDoc::Nil), + List( + $UserNotLoggedIn, + UserHasMissingRoles, + UnknownError + ), + List(apiTagDynamicMessageDoc, apiTagNewStyle), + Some(List(canGetAllDynamicMessageDocs))) + + lazy val getAllBankLevelDynamicMessageDocs: OBPEndpoint = { + case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: Nil JsonGet _ => { + cc => + for { + (dynamicMessageDocs, callContext) <- NewStyle.function.getJsonDynamicMessageDocs(Some(bankId), cc.callContext) + } yield { + (ListResult("dynamic-message-docs", dynamicMessageDocs), HttpCode.`200`(callContext)) + } + } + } + + staticResourceDocs += ResourceDoc( + deleteBankLevelDynamicMessageDoc, + implementedInApiVersion, + nameOf(deleteBankLevelDynamicMessageDoc), + "DELETE", + "/management/banks/BANK_ID/dynamic-message-docs/DYNAMIC_MESSAGE_DOC_ID", + "Delete Bank Level Dynamic Message Doc", + s"""Delete a Bank Level Dynamic Message Doc. + |""", + EmptyBody, + BooleanBody(true), + List( + $UserNotLoggedIn, + UserHasMissingRoles, + InvalidJsonFormat, + UnknownError + ), + List(apiTagDynamicMessageDoc, apiTagNewStyle), + Some(List(canDeleteBankLevelDynamicMessageDoc))) + + lazy val deleteBankLevelDynamicMessageDoc: OBPEndpoint = { + case "management" :: "banks" :: bankId :: "dynamic-message-docs" :: dynamicMessageDocId :: Nil JsonDelete _ => { + cc => + for { + (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(Some(bankId), dynamicMessageDocId, cc.callContext) + (dynamicResourceDoc, callContext) <- NewStyle.function.deleteJsonDynamicMessageDocById(Some(bankId), dynamicMessageDocId, callContext) } yield { (dynamicResourceDoc, HttpCode.`204`(callContext)) } diff --git a/obp-api/src/main/scala/code/bankconnectors/DynamicConnector.scala b/obp-api/src/main/scala/code/bankconnectors/DynamicConnector.scala index 49b3b33c1..e74ed01c4 100644 --- a/obp-api/src/main/scala/code/bankconnectors/DynamicConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/DynamicConnector.scala @@ -23,14 +23,14 @@ object DynamicConnector { def updateSingletonObject(key:String, value: Any) = singletonObjectMap.update(key, value) def removeSingletonObject(key:String) = singletonObjectMap.remove(key) - def invoke(process: String, args: Array[AnyRef], callContext: Option[CallContext]) = { + def invoke(bankId: Option[String], process: String, args: Array[AnyRef], callContext: Option[CallContext]) = { val function: Box[(Array[AnyRef], Option[CallContext]) => Future[Box[(AnyRef, Option[CallContext])]]] = - getFunction(process).asInstanceOf[Box[(Array[AnyRef], Option[CallContext]) => Future[Box[(AnyRef, Option[CallContext])]]]] + getFunction(bankId, process).asInstanceOf[Box[(Array[AnyRef], Option[CallContext]) => Future[Box[(AnyRef, Option[CallContext])]]]] function.map(f =>f(args: Array[AnyRef], callContext: Option[CallContext])).openOrThrowException(s"There is no process $process, it should not be called here") - } + } - private def getFunction(process: String) = { - DynamicMessageDocProvider.provider.vend.getByProcess(process) map { + private def getFunction(bankId: Option[String], process: String) = { + DynamicMessageDocProvider.provider.vend.getByProcess(bankId, process) map { case v :JsonDynamicMessageDoc => createFunction(process, v.decodedMethodBody).openOrThrowException(s"InternalConnector method compile fail") } diff --git a/obp-api/src/main/scala/code/dynamicMessageDoc/DynamicMessageDoc.scala b/obp-api/src/main/scala/code/dynamicMessageDoc/DynamicMessageDoc.scala index fb1c286c9..4efe66947 100644 --- a/obp-api/src/main/scala/code/dynamicMessageDoc/DynamicMessageDoc.scala +++ b/obp-api/src/main/scala/code/dynamicMessageDoc/DynamicMessageDoc.scala @@ -9,6 +9,7 @@ class DynamicMessageDoc extends LongKeyedMapper[DynamicMessageDoc] with IdPK { override def getSingleton = DynamicMessageDoc + object BankId extends MappedString(this, 255) object DynamicMessageDocId extends UUIDString(this) object Process extends MappedString(this, 255) object MessageFormat extends MappedString(this, 255) @@ -27,6 +28,7 @@ class DynamicMessageDoc extends LongKeyedMapper[DynamicMessageDoc] with IdPK { object DynamicMessageDoc extends DynamicMessageDoc with LongKeyedMetaMapper[DynamicMessageDoc] { override def dbIndexes: List[BaseIndex[DynamicMessageDoc]] = UniqueIndex(DynamicMessageDocId) :: UniqueIndex(Process) :: super.dbIndexes def getJsonDynamicMessageDoc(dynamicMessageDoc: DynamicMessageDoc) = JsonDynamicMessageDoc( + bankId = Some(dynamicMessageDoc.BankId.get), dynamicMessageDocId = Some(dynamicMessageDoc.DynamicMessageDocId.get), process = dynamicMessageDoc.Process.get, messageFormat = dynamicMessageDoc.MessageFormat.get, diff --git a/obp-api/src/main/scala/code/dynamicMessageDoc/DynamicMessageDocProvider.scala b/obp-api/src/main/scala/code/dynamicMessageDoc/DynamicMessageDocProvider.scala index 1685a1030..4b6fd2adf 100644 --- a/obp-api/src/main/scala/code/dynamicMessageDoc/DynamicMessageDocProvider.scala +++ b/obp-api/src/main/scala/code/dynamicMessageDoc/DynamicMessageDocProvider.scala @@ -16,6 +16,7 @@ object DynamicMessageDocProvider extends SimpleInjector { } case class JsonDynamicMessageDoc( + bankId: Option[String], dynamicMessageDocId: Option[String], process: String, messageFormat: String, @@ -34,12 +35,12 @@ case class JsonDynamicMessageDoc( trait DynamicMessageDocProvider { - def getById(dynamicMessageDocId: String): Box[JsonDynamicMessageDoc] - def getByProcess(process: String): Box[JsonDynamicMessageDoc] - def getAll(): List[JsonDynamicMessageDoc] + def getById(bankId: Option[String], dynamicMessageDocId: String): Box[JsonDynamicMessageDoc] + def getByProcess(bankId: Option[String], process: String): Box[JsonDynamicMessageDoc] + def getAll(bankId: Option[String]): List[JsonDynamicMessageDoc] - def create(entity: JsonDynamicMessageDoc): Box[JsonDynamicMessageDoc] - def update(entity: JsonDynamicMessageDoc): Box[JsonDynamicMessageDoc] - def deleteById(dynamicMessageDocId: String): Box[Boolean] + def create(bankId: Option[String], entity: JsonDynamicMessageDoc): Box[JsonDynamicMessageDoc] + def update(bankId: Option[String], entity: JsonDynamicMessageDoc): Box[JsonDynamicMessageDoc] + def deleteById(bankId: Option[String], dynamicMessageDocId: String): Box[Boolean] } \ No newline at end of file diff --git a/obp-api/src/main/scala/code/dynamicMessageDoc/MappedDynamicMessageDocProvider.scala b/obp-api/src/main/scala/code/dynamicMessageDoc/MappedDynamicMessageDocProvider.scala index 75201b499..f691ec793 100644 --- a/obp-api/src/main/scala/code/dynamicMessageDoc/MappedDynamicMessageDocProvider.scala +++ b/obp-api/src/main/scala/code/dynamicMessageDoc/MappedDynamicMessageDocProvider.scala @@ -7,6 +7,7 @@ import net.liftweb.common.{Box, Empty, Full} import net.liftweb.mapper._ import net.liftweb.util.Helpers.tryo import net.liftweb.util.Props + import java.util.UUID.randomUUID import code.util.Helper @@ -19,27 +20,43 @@ object MappedDynamicMessageDocProvider extends DynamicMessageDocProvider { else APIUtil.getPropsValue(s"dynamicMessageDoc.cache.ttl.seconds", "40").toInt } - override def getById(dynamicMessageDocId: String): Box[JsonDynamicMessageDoc] = - DynamicMessageDoc.find(By(DynamicMessageDoc.DynamicMessageDocId, dynamicMessageDocId)) - .map(DynamicMessageDoc.getJsonDynamicMessageDoc) + override def getById(bankId: Option[String], dynamicMessageDocId: String): Box[JsonDynamicMessageDoc] = + if(bankId.isEmpty) { + DynamicMessageDoc.find(By(DynamicMessageDoc.DynamicMessageDocId, dynamicMessageDocId)).map(DynamicMessageDoc.getJsonDynamicMessageDoc) + }else{ + DynamicMessageDoc.find( + By(DynamicMessageDoc.DynamicMessageDocId, dynamicMessageDocId), + By(DynamicMessageDoc.BankId, bankId.getOrElse("") + )).map(DynamicMessageDoc.getJsonDynamicMessageDoc) + } - override def getByProcess(process: String): Box[JsonDynamicMessageDoc] = - DynamicMessageDoc.find(By(DynamicMessageDoc.Process, process)) - .map(DynamicMessageDoc.getJsonDynamicMessageDoc) + override def getByProcess(bankId: Option[String], process: String): Box[JsonDynamicMessageDoc] = + if(bankId.isEmpty) { + DynamicMessageDoc.find(By(DynamicMessageDoc.Process, process)).map(DynamicMessageDoc.getJsonDynamicMessageDoc) + }else{ + DynamicMessageDoc.find( + By(DynamicMessageDoc.Process, process), + By(DynamicMessageDoc.BankId, bankId.getOrElse("") + )).map(DynamicMessageDoc.getJsonDynamicMessageDoc) + } - override def getAll(): List[JsonDynamicMessageDoc] = { + override def getAll(bankId: Option[String]): List[JsonDynamicMessageDoc] = { var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString) CacheKeyFromArguments.buildCacheKey { Caching.memoizeSyncWithProvider (Some(cacheKey.toString())) (getDynamicMessageDocTTL second) { - DynamicMessageDoc.findAll() - .map(DynamicMessageDoc.getJsonDynamicMessageDoc) + if(bankId.isEmpty){ + DynamicMessageDoc.findAll().map(DynamicMessageDoc.getJsonDynamicMessageDoc) + } else { + DynamicMessageDoc.findAll(By(DynamicMessageDoc.BankId, bankId.getOrElse(""))).map(DynamicMessageDoc.getJsonDynamicMessageDoc) + } }} } - override def create(entity: JsonDynamicMessageDoc): Box[JsonDynamicMessageDoc]= + override def create(bankId: Option[String], entity: JsonDynamicMessageDoc): Box[JsonDynamicMessageDoc]= { tryo { DynamicMessageDoc.create + .BankId(bankId.getOrElse(null)) .DynamicMessageDocId(APIUtil.generateUUID()) .Process(entity.process) .MessageFormat(entity.messageFormat) @@ -54,10 +71,20 @@ object MappedDynamicMessageDocProvider extends DynamicMessageDocProvider { .MethodBody(entity.methodBody) .saveMe() }.map(DynamicMessageDoc.getJsonDynamicMessageDoc) + } - override def update(entity: JsonDynamicMessageDoc): Box[JsonDynamicMessageDoc] = { - DynamicMessageDoc.find(By(DynamicMessageDoc.DynamicMessageDocId, entity.dynamicMessageDocId.getOrElse(""))) match { + override def update(bankId: Option[String], entity: JsonDynamicMessageDoc): Box[JsonDynamicMessageDoc] = { + val dynamicMessageDocBox = if(bankId.isDefined){ + DynamicMessageDoc.find( + By(DynamicMessageDoc.DynamicMessageDocId, entity.dynamicMessageDocId.getOrElse("")) + ) + } else { + DynamicMessageDoc.find( + By(DynamicMessageDoc.DynamicMessageDocId, entity.dynamicMessageDocId.getOrElse("")) + ) + } + dynamicMessageDocBox match { case Full(v) => tryo { v.DynamicMessageDocId(entity.dynamicMessageDocId.getOrElse("")) @@ -78,7 +105,14 @@ object MappedDynamicMessageDocProvider extends DynamicMessageDocProvider { } } - override def deleteById(id: String): Box[Boolean] = tryo { - DynamicMessageDoc.bulkDelete_!!(By(DynamicMessageDoc.DynamicMessageDocId, id)) + override def deleteById(bankId: Option[String], id: String): Box[Boolean] = tryo { + if(bankId.isEmpty) { + DynamicMessageDoc.bulkDelete_!!(By(DynamicMessageDoc.DynamicMessageDocId, id)) + }else{ + DynamicMessageDoc.bulkDelete_!!( + By(DynamicMessageDoc.BankId, bankId.getOrElse("")), + By(DynamicMessageDoc.DynamicMessageDocId, id) + ) + } } } \ No newline at end of file From 026b90afc3803658aaeb8c16f44194c0ed845a02 Mon Sep 17 00:00:00 2001 From: shuang Date: Mon, 18 Oct 2021 07:13:03 +0800 Subject: [PATCH 03/37] feature/dynamic_code_security: add sandbox support, bankId control not works now --- .../main/scala/code/api/OBPRestHelper.scala | 9 +- .../main/scala/code/api/util/APIUtil.scala | 35 +++-- .../code/api/util/CustomJsonFormats.scala | 1 + .../scala/code/api/util/DynamicUtil.scala | 91 +++++++++++- .../scala/code/api/util/ErrorMessages.scala | 4 + .../main/scala/code/api/util/NewStyle.scala | 93 ++++++++++-- .../scala/code/api/v4_0_0/APIMethods400.scala | 2 + .../dynamic/DynamicCompileEndpoint.scala | 33 +++-- .../api/v4_0_0/dynamic/DynamicEndpoints.scala | 135 ++++++++++++++++-- .../DynamicResourceDocsEndpointGroup.scala | 2 +- .../dynamic/practise/PractiseEndpoint.scala | 59 +++++--- .../commons/model/BankingModel.scala | 17 ++- .../commons/util/JsonSerializers.scala | 21 ++- 13 files changed, 424 insertions(+), 78 deletions(-) diff --git a/obp-api/src/main/scala/code/api/OBPRestHelper.scala b/obp-api/src/main/scala/code/api/OBPRestHelper.scala index 7357f890e..52e46485d 100644 --- a/obp-api/src/main/scala/code/api/OBPRestHelper.scala +++ b/obp-api/src/main/scala/code/api/OBPRestHelper.scala @@ -112,15 +112,18 @@ object ApiVersionHolder { * This is helpful if you want send back given error message and status code * @param jsonResponse */ -case class JsonResponseException(jsonResponse: JsonResponse) extends RuntimeException with NoStackTrace { +case class JsonResponseException(jsonResponse: JsonResponse) extends RuntimeException with NoStackTrace + +object JsonResponseException { /** * * @param errorMsg error message * @param errorCode response error code and status code * @param correlationId this value can be got from callContext */ - def this(errorMsg: String, errorCode: Int, correlationId: String) = - this(createErrorJsonResponse(errorMsg: String, errorCode: Int, correlationId: String)) + def apply(errorMsg: String, errorCode: Int, correlationId: String):JsonResponseException = { + JsonResponseException(createErrorJsonResponse(errorMsg: String, errorCode: Int, correlationId: String)) + } } trait OBPRestHelper extends RestHelper with MdcLoggable { 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 32ef1d00e..b617d8a84 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -44,7 +44,6 @@ import code.api.util.APIUtil.ResourceDoc.{findPathVariableNames, isPathVariable} import code.api.util.ApiRole.{canCreateProduct, canCreateProductAtAnyBank} import code.api.util.ApiTag.{ResourceDocTag, apiTagBank, apiTagNewStyle} import code.api.util.Glossary.GlossaryItem -import code.api.util.JwsUtil.getJwsHeaderValue import code.api.util.RateLimitingJson.CallLimit import code.api.v1_2.ErrorMessage import code.api.v2_0_0.CreateEntitlementJSON @@ -3736,6 +3735,22 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ pool } + /** + * according class name, method name and method's signature to get all dependent methods + */ + def getDependentMethods(className: String, methodName:String, signature: String): List[(String, String, String)] = { + val methods = ListBuffer[(String, String, String)]() + val method = cp.get(className).getMethod(methodName, signature) + method.instrument(new ExprEditor() { + @throws[CannotCompileException] + override def edit(m: MethodCall): Unit = { + val tuple = (m.getClassName, m.getMethodName, m.getSignature) + methods += tuple + } + }) + methods.toList + } + /** * get all dependent connector method names for an object * @param endpoint can be OBPEndpoint or other PartialFunction @@ -3743,21 +3758,13 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ */ def getDependentConnectorMethods(endpoint: PartialFunction[_, _]) = { val connectorTypeName = classOf[Connector].getName + def getObpTrace(className: String, methodName: String, signature: String, exclude: List[(String, String, String)] = Nil): List[(String, String, String)] = memo.memoize((className, methodName, signature)) { - val methods = ListBuffer[(String, String, String)]() - val method = cp.get(className).getMethod(methodName, signature) - method.instrument(new ExprEditor() { - @throws[CannotCompileException] - override def edit(m: MethodCall): Unit = { - val tuple = (m.getClassName, m.getMethodName, m.getSignature) - if (ReflectUtils.isObpClass(m.getClassName)) { - methods += tuple - } - } - }) + // List:: className->methodName->signature + val methods = getDependentMethods(className, methodName, signature) - val list = methods.distinct.toList.filterNot(exclude.contains) + val list = methods.distinct.filter(it => ReflectUtils.isObpClass(it._1)).filterNot(exclude.contains) list.collect { case x@(clazzName, _, _) if clazzName == connectorTypeName => x :: Nil case (clazzName, mName, mSignature) => @@ -3768,7 +3775,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ val endpointClassName = endpoint.getClass.getName // list of connector method name val connectorMethods: Array[String] = for { - method <- cp.get(endpoint.getClass.getName).getDeclaredMethods + method <- cp.get(endpointClassName).getDeclaredMethods (clazzName, methodName, _) <- getObpTrace(endpointClassName, method.getName, method.getSignature) if clazzName == connectorTypeName && !methodName.contains("$default$") } yield methodName diff --git a/obp-api/src/main/scala/code/api/util/CustomJsonFormats.scala b/obp-api/src/main/scala/code/api/util/CustomJsonFormats.scala index 1bf30a24f..356f534fe 100644 --- a/obp-api/src/main/scala/code/api/util/CustomJsonFormats.scala +++ b/obp-api/src/main/scala/code/api/util/CustomJsonFormats.scala @@ -23,6 +23,7 @@ object CustomJsonFormats { val formats: Formats = JsonSerializers.commonFormats + PrimaryDataBodySerializer + ToStringDeSerializer + TupleSerializer + val losslessFormats: Formats = net.liftweb.json.DefaultFormats.lossless ++ JsonSerializers.serializers val emptyHintFormats = DefaultFormats.withHints(ShortTypeHints(List())) ++ JsonSerializers.serializers diff --git a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala index a8888a2ad..2fb531225 100644 --- a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala +++ b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala @@ -1,16 +1,30 @@ package code.api.util +import code.api.JsonResponseException +import com.openbankproject.commons.util.Functions.Memo import com.openbankproject.commons.util.JsonUtils +import javassist.{ClassPool, LoaderClassPath} import net.liftweb.common.{Box, Failure, Full} -import net.liftweb.json.{JObject, JValue, prettyRender} +import net.liftweb.http.JsonResponse +import net.liftweb.json.{JValue, prettyRender} +import java.security.{AccessControlContext, AccessController, CodeSource, Permission, PermissionCollection, Permissions, Policy, PrivilegedAction, PrivilegedActionException, PrivilegedExceptionAction, ProtectionDomain} import java.util.concurrent.ConcurrentHashMap +import scala.collection.mutable.ListBuffer import scala.reflect.runtime.universe import scala.reflect.runtime.universe.runtimeMirror +import scala.runtime.NonLocalReturnControl import scala.tools.reflect.{ToolBox, ToolBoxError} object DynamicUtil { val toolBox: ToolBox[universe.type] = runtimeMirror(getClass.getClassLoader).mkToolBox() + private val memoClassPool = new Memo[ClassLoader, ClassPool] + + private def getClassPool(classLoader: ClassLoader) = memoClassPool.memoize(classLoader){ + val cp = ClassPool.getDefault + cp.appendClassPath(new LoaderClassPath(classLoader)) + cp + } // code -> dynamic method function // the same code should always be compiled once, so here cache them @@ -115,6 +129,81 @@ object DynamicUtil { } } + def getDynamicCodeDependentMethods(clazz: Class[_], predicate: String => Boolean = _ => true): List[(String, String, String)] = { + val className = clazz.getTypeName + val listBuffer = new ListBuffer[(String, String, String)]() + for { + method <- getClassPool(clazz.getClassLoader).get(className).getDeclaredMethods.toList + if predicate(method.getName) + ternary @ (typeName, methodName, signature) <- APIUtil.getDependentMethods(className, method.getName, method.getSignature) + } yield { + // if method is also dynamic compile code, extract it's dependent method + if(className.startsWith(typeName) && methodName.startsWith(clazz.getPackageName + "$")) { + listBuffer.appendAll(APIUtil.getDependentMethods(typeName, methodName, signature)) + } else { + listBuffer.append(ternary) + } + } + + listBuffer.distinct.toList + } + + trait Sandbox { + @throws[Exception] + def runInSandbox[R](action: => R): R + } + + object Sandbox { + // initialize SecurityManager if not initialized + if (System.getSecurityManager == null) { + Policy.setPolicy(new Policy() { + override def getPermissions(codeSource: CodeSource): PermissionCollection = { + for (element <- Thread.currentThread.getStackTrace) { + if ("sun.rmi.server.LoaderHandler" == element.getClassName && "loadClass" == element.getMethodName) + return new Permissions + } + super.getPermissions(codeSource) + } + + override def implies(domain: ProtectionDomain, permission: Permission) = true + }) + System.setSecurityManager(new SecurityManager) + } + + def createSandbox(permissionList: List[Permission]): Sandbox = { + val accessControlContext: AccessControlContext = { + val permissions = new Permissions() + permissionList.foreach(permissions.add) + val protectionDomain = new ProtectionDomain(null, permissions) + new AccessControlContext(Array(protectionDomain)) + } + + new Sandbox { + @throws[Exception] + def runInSandbox[R](action: => R): R = try { + val privilegedActionException: PrivilegedExceptionAction[R] = () => action + + AccessController.doPrivileged(privilegedActionException, accessControlContext) + } catch { + case pae: PrivilegedActionException => + throw pae.getException + + case e: NonLocalReturnControl[Full[JsonResponse]] if e.value.isInstanceOf[Full[JsonResponse]] => + throw JsonResponseException(e.value.orNull) + + case e: NonLocalReturnControl[JsonResponse] if e.value.isInstanceOf[JsonResponse] => + throw JsonResponseException(e.value) + + case e if e.getClass.getName == "net.liftweb.http.rest.ContinuationException" => + throw e + + case e: Throwable => + throw JsonResponseException(e.getMessage, 400, "") + } + } + } + } + /** * common import statements those are used by compiler */ diff --git a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala index aada7e286..affb59dfd 100644 --- a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala +++ b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala @@ -525,6 +525,10 @@ object ErrorMessages { val DynamicMessageDocNotFound = "OBP-40043: DynamicMessageDoc not found, please specify valid DYNAMIC_MESSAGE_DOC_ID. " val DynamicMessageDocDeleteError = "OBP-40044: DynamicMessageDoc can not be deleted. " val DynamicCodeCompileFail = "OBP-40045: The code to do compile is illegal scala code, compilation failed. " + + val DynamicResourceDocMethodDependency = "OBP-40046: DynamicResourceDoc method call forbidden methods. " + val DynamicResourceDocMethodPermission = "OBP-40047: DynamicResourceDoc method have no enough permissions. " + // Exceptions (OBP-50XXX) val UnknownError = "OBP-50000: Unknown Error." val FutureTimeoutException = "OBP-50001: Future Timeout Exception." diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index bc5838b3a..7eedcd6b9 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -1,6 +1,6 @@ package code.api.util -import java.io + import java.util.Date import java.util.UUID.randomUUID @@ -9,7 +9,7 @@ import code.DynamicEndpoint.{DynamicEndpointProvider, DynamicEndpointT} import code.api.APIFailureNewStyle import code.api.Constant.SYSTEM_READ_ACCOUNTS_BERLIN_GROUP_VIEW_ID import code.api.cache.Caching -import code.api.util.APIUtil.{EntitlementAndScopeStatus, JsonResponseExtractor, OBPReturnType, afterAuthenticateInterceptResult, canGrantAccessToViewCommon, canRevokeAccessToViewCommon, connectorEmptyResponse, createHttpParamsByUrlFuture, createQueriesByHttpParamsFuture, fullBoxOrException, generateUUID, unboxFull, unboxFullOrFail} +import code.api.util.APIUtil.{EntitlementAndScopeStatus, OBPReturnType, afterAuthenticateInterceptResult, canGrantAccessToViewCommon, canRevokeAccessToViewCommon, connectorEmptyResponse, createHttpParamsByUrlFuture, createQueriesByHttpParamsFuture, fullBoxOrException, generateUUID, unboxFull, unboxFullOrFail} import code.api.util.ApiRole.canCreateAnyTransactionRequest import code.api.util.ErrorMessages.{InsufficientAuthorisationToCreateTransactionRequest, _} import code.api.ResourceDocs1_4_0.ResourceDocs140.ImplementationsResourceDocs @@ -54,6 +54,7 @@ import net.liftweb.json.JsonDSL._ import net.liftweb.json.{JField, JInt, JNothing, JNull, JObject, JString, JValue, _} import net.liftweb.util.Helpers.tryo import org.apache.commons.lang3.StringUtils +import java.security.AccessControlException import scala.collection.immutable.List import scala.concurrent.Future @@ -63,7 +64,6 @@ import code.validation.{JsonSchemaValidationProvider, JsonValidation} import net.liftweb.http.JsonResponse import net.liftweb.util.Props import code.api.JsonResponseException -import code.api.v4_0_0.ProductFeeJsonV400 import code.api.v4_0_0.dynamic.{DynamicEndpointHelper, DynamicEntityInfo} import code.bankattribute.BankAttribute import code.connectormethod.{ConnectorMethodProvider, JsonConnectorMethod} @@ -71,9 +71,6 @@ import code.dynamicMessageDoc.{DynamicMessageDocProvider, JsonDynamicMessageDoc} import code.dynamicResourceDoc.{DynamicResourceDocProvider, JsonDynamicResourceDoc} import code.endpointMapping.{EndpointMappingProvider, EndpointMappingT} import code.endpointTag.EndpointTagT -import net.liftweb.json - -import scala.util.Success object NewStyle { lazy val endpoints: List[(String, String)] = List( @@ -191,6 +188,18 @@ object NewStyle { import com.openbankproject.commons.ExecutionContext.Implicits.global + private def validateBankId(bankId: Option[String], callContext: Option[CallContext]): Unit = { + bankId.foreach(validateBankId(_, callContext)) + } + + private def validateBankId(bankId: String, callContext: Option[CallContext]): Unit = try { + BankId.checkPermission(bankId) + } catch { + case e: AccessControlException => + val correlationId = callContext.map(_.correlationId).getOrElse("none") + throw JsonResponseException(s"$DynamicResourceDocMethodPermission No permission of operate bank $bankId", 400, correlationId) + } + def getBranch(bankId : BankId, branchId : BranchId, callContext: Option[CallContext]): OBPReturnType[BranchT] = { Connector.connector.vend.getBranch(bankId, branchId, callContext) map { x => fullBoxOrException(x ~> APIFailureNewStyle(BranchNotFoundByBranchId, 400, callContext.map(_.toLight))) @@ -292,13 +301,17 @@ object NewStyle { } def createBankLevelEndpointTag(bankId:String, operationId:String, tagName:String, callContext: Option[CallContext]): OBPReturnType[EndpointTagT] = { + validateBankId(bankId, callContext) + Connector.connector.vend.createBankLevelEndpointTag(bankId, operationId, tagName, callContext) map { i => (unboxFullOrFail(i._1, callContext, s"$CreateEndpointTagError", 400), i._2) } } def updateBankLevelEndpointTag(bankId:String, endpointTagId: String, operationId:String, tagName:String, callContext: Option[CallContext]): OBPReturnType[EndpointTagT] = { - Connector.connector.vend.updateBankLevelEndpointTag(bankId, endpointTagId, operationId, tagName, callContext) map { + validateBankId(bankId, callContext) + + Connector.connector.vend.updateBankLevelEndpointTag(bankId, endpointTagId, operationId, tagName, callContext) map { i => (unboxFullOrFail(i._1, callContext, s"$UpdateEndpointTagError", 400), i._2) } } @@ -310,6 +323,8 @@ object NewStyle { } def checkBankLevelEndpointTagExists(bankId: String, operationId: String, tagName:String, callContext: Option[CallContext]): OBPReturnType[Boolean] = { + validateBankId(bankId, callContext) + Connector.connector.vend.getBankLevelEndpointTag(bankId: String, operationId: String, tagName: String, callContext) map { i => (i._1.isDefined, i._2) } @@ -334,6 +349,8 @@ object NewStyle { } def getBankLevelEndpointTags(bankId:String, operationId : String, callContext: Option[CallContext]) : OBPReturnType[List[EndpointTagT]] = { + validateBankId(bankId, callContext) + Connector.connector.vend.getBankLevelEndpointTags(bankId, operationId, callContext) map { i => (unboxFullOrFail(i._1, callContext, s"$InvalidConnectorResponseForGetEndpointTags Current OPERATION_ID is $operationId", 404), i._2) } @@ -365,6 +382,8 @@ object NewStyle { bankRoutingAddress: String, callContext: Option[CallContext]): OBPReturnType[Bank] = { Future { + validateBankId(bankId, callContext) + Connector.connector.vend.createOrUpdateBank( bankId, fullBankName, @@ -930,7 +949,7 @@ object NewStyle { } def hasEntitlement(bankId: String, userId: String, role: ApiRole, callContext: Option[CallContext], errorMsg: String = ""): Future[Box[Unit]] = { - val errorInfo = + val errorInfo = if(StringUtils.isBlank(errorMsg)&& !bankId.isEmpty) UserHasMissingRoles + role.toString() + s" at Bank($bankId)" else if(StringUtils.isBlank(errorMsg)&& bankId.isEmpty) UserHasMissingRoles + role.toString() else errorMsg @@ -1891,6 +1910,8 @@ object NewStyle { def getProductCollectionItemsTree(collectionCode: String, bankId: String, callContext: Option[CallContext]): OBPReturnType[List[(ProductCollectionItem, Product, List[ProductAttribute])]] = { + validateBankId(bankId, callContext) + Connector.connector.vend.getProductCollectionItemsTree(collectionCode, bankId, callContext) map { i => { val data: Box[List[ProductCollectionItemsTree]] = i._1 @@ -2020,6 +2041,8 @@ object NewStyle { mSatisfied: Boolean, comments: String, callContext: Option[CallContext]): OBPReturnType[KycCheck] = { + validateBankId(bankId, callContext) + Connector.connector.vend.createOrUpdateKycCheck(bankId, customerId, id, customerNumber, date, how, staffUserId, mStaffName, mSatisfied, comments, callContext) .map { i => (unboxFullOrFail(i._1, callContext, s"$InvalidConnectorResponse Can not create or update KycCheck in the backend. ", 400), i._2) @@ -2036,6 +2059,8 @@ object NewStyle { issuePlace: String, expiryDate: Date, callContext: Option[CallContext]): OBPReturnType[KycDocument] = { + validateBankId(bankId, callContext) + Connector.connector.vend.createOrUpdateKycDocument( bankId, customerId, @@ -2062,6 +2087,8 @@ object NewStyle { relatesToKycDocumentId: String, relatesToKycCheckId: String, callContext: Option[CallContext]): OBPReturnType[KycMedia] = { + validateBankId(bankId, callContext) + Connector.connector.vend.createOrUpdateKycMedia( bankId, customerId, @@ -2084,6 +2111,8 @@ object NewStyle { ok: Boolean, date: Date, callContext: Option[CallContext]): OBPReturnType[KycStatus] = { + validateBankId(bankId, callContext) + Connector.connector.vend.createOrUpdateKycStatus( bankId, customerId, @@ -2287,7 +2316,9 @@ object NewStyle { posted: Option[CardPostedInfo], customerId: String, callContext: Option[CallContext] - ): OBPReturnType[PhysicalCard] = + ): OBPReturnType[PhysicalCard] = { + validateBankId(bankId, callContext) + Connector.connector.vend.createPhysicalCard( bankCardNumber: String, nameOnCard: String, @@ -2313,6 +2344,7 @@ object NewStyle { ) map { i => (unboxFullOrFail(i._1, callContext, s"$CreateCardError"), i._2) } + } def updatePhysicalCard( cardId: String, @@ -2337,7 +2369,9 @@ object NewStyle { posted: Option[CardPostedInfo], customerId: String, callContext: Option[CallContext] - ): OBPReturnType[PhysicalCardTrait] = + ): OBPReturnType[PhysicalCardTrait] = { + validateBankId(bankId, callContext) + Connector.connector.vend.updatePhysicalCard( cardId: String, bankCardNumber: String, @@ -2364,7 +2398,8 @@ object NewStyle { ) map { i => (unboxFullOrFail(i._1, callContext, s"$UpdateCardError"), i._2) } - + } + def getPhysicalCardsForBank(bank: Bank, user : User, queryParams: List[OBPQueryParam], callContext:Option[CallContext]) : OBPReturnType[List[PhysicalCard]] = Connector.connector.vend.getPhysicalCardsForBank(bank: Bank, user : User, queryParams: List[OBPQueryParam], callContext:Option[CallContext]) map { i => (unboxFullOrFail(i._1, callContext, CardNotFound), i._2) @@ -2572,18 +2607,24 @@ object NewStyle { } def createOrUpdateEndpointMapping(bankId: Option[String], endpointMapping: EndpointMappingT, callContext: Option[CallContext]) = Future { + validateBankId(bankId, callContext) + (EndpointMappingProvider.endpointMappingProvider.vend.createOrUpdate(bankId, endpointMapping), callContext) } map { i => (connectorEmptyResponse(i._1, callContext), i._2) } def deleteEndpointMapping(bankId: Option[String], endpointMappingId: String, callContext: Option[CallContext]) = Future { + validateBankId(bankId, callContext) + (EndpointMappingProvider.endpointMappingProvider.vend.delete(bankId, endpointMappingId), callContext) } map { i => (connectorEmptyResponse(i._1, callContext), i._2) } def getEndpointMappingById(bankId: Option[String], endpointMappingId : String, callContext: Option[CallContext]): OBPReturnType[EndpointMappingT] = { + validateBankId(bankId, callContext) + val endpointMappingBox: Box[EndpointMappingT] = EndpointMappingProvider.endpointMappingProvider.vend.getById(bankId, endpointMappingId) Future{ val endpointMapping = unboxFullOrFail(endpointMappingBox, callContext, s"$EndpointMappingNotFoundByEndpointMappingId Current ENDPOINT_MAPPING_ID is $endpointMappingId", 404) @@ -2592,6 +2633,8 @@ object NewStyle { } def getEndpointMappingByOperationId(bankId: Option[String], operationId : String, callContext: Option[CallContext]): OBPReturnType[EndpointMappingT] = { + validateBankId(bankId, callContext) + val endpointMappingBox: Box[EndpointMappingT] = EndpointMappingProvider.endpointMappingProvider.vend.getByOperationId(bankId, operationId) Future{ val endpointMapping = unboxFullOrFail(endpointMappingBox, callContext, s"$EndpointMappingNotFoundByOperationId Current OPERATION_ID is $operationId",404) @@ -2604,6 +2647,8 @@ object NewStyle { def getEndpointMappings(bankId: Option[String], callContext: Option[CallContext]): OBPReturnType[List[EndpointMappingT]] = { import scala.concurrent.duration._ + validateBankId(bankId, callContext) + var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString) CacheKeyFromArguments.buildCacheKey { Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(endpointMappingTTL second) { @@ -2663,6 +2708,8 @@ object NewStyle { * @return */ def deleteDynamicEntity(bankId: Option[String], dynamicEntityId: String): Future[Box[Boolean]] = Future { + validateBankId(bankId, None) + for { entity <- DynamicEntityProvider.connectorMethodProvider.vend.getById(bankId, dynamicEntityId) deleteEntityResult <- DynamicEntityProvider.connectorMethodProvider.vend.delete(entity) @@ -2680,6 +2727,8 @@ object NewStyle { } def getDynamicEntityById(bankId: Option[String], dynamicEntityId : String, callContext: Option[CallContext]): OBPReturnType[DynamicEntityT] = { + validateBankId(bankId, callContext) + val dynamicEntityBox: Box[DynamicEntityT] = DynamicEntityProvider.connectorMethodProvider.vend.getById(bankId, dynamicEntityId) val dynamicEntity = unboxFullOrFail(dynamicEntityBox, callContext, DynamicEntityNotFoundByDynamicEntityId, 404) Future{ @@ -2688,6 +2737,8 @@ object NewStyle { } def getDynamicEntityByEntityName(bankId: Option[String], entityName : String, callContext: Option[CallContext]): OBPReturnType[Box[DynamicEntityT]] = Future { + validateBankId(bankId, callContext) + val boxedDynamicEntity = DynamicEntityProvider.connectorMethodProvider.vend.getByEntityName(entityName) (boxedDynamicEntity, callContext) } @@ -2700,6 +2751,8 @@ object NewStyle { def getDynamicEntities(bankId: Option[String]): List[DynamicEntityT] = { import scala.concurrent.duration._ + validateBankId(bankId, None) + var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString) CacheKeyFromArguments.buildCacheKey { Caching.memoizeSyncWithProvider(Some(cacheKey.toString()))(dynamicEntityTTL second) { @@ -2754,6 +2807,8 @@ object NewStyle { queryParameters: Option[Map[String, List[String]]], callContext: Option[CallContext]): OBPReturnType[Box[JValue]] = { import DynamicEntityOperation._ + validateBankId(bankId, callContext) + val dynamicEntityBox = DynamicEntityProvider.connectorMethodProvider.vend.getByEntityName(entityName) // do validate, any validate process fail will return immediately if(dynamicEntityBox.isEmpty) { @@ -2836,6 +2891,8 @@ object NewStyle { dateStarts: Date, dateExpires: Option[Date], callContext: Option[CallContext]): OBPReturnType[DirectDebitTrait] = { + validateBankId(bankId, callContext) + Connector.connector.vend.createDirectDebit( bankId, accountId, @@ -2863,6 +2920,8 @@ object NewStyle { dateStarts: Date, dateExpires: Option[Date], callContext: Option[CallContext]): OBPReturnType[StandingOrderTrait] = { + validateBankId(bankId, callContext) + Connector.connector.vend.createStandingOrder( bankId, accountId, @@ -2909,18 +2968,24 @@ object NewStyle { } def createDynamicEndpoint(bankId:Option[String], userId: String, swaggerString: String, callContext: Option[CallContext]): OBPReturnType[DynamicEndpointT] = Future { + validateBankId(bankId, callContext) + (DynamicEndpointProvider.connectorMethodProvider.vend.create(bankId:Option[String], userId, swaggerString), callContext) } map { i => (connectorEmptyResponse(i._1, callContext), i._2) } def updateDynamicEndpointHost(bankId: Option[String], userId: String, swaggerString: String, callContext: Option[CallContext]): OBPReturnType[DynamicEndpointT] = Future { + validateBankId(bankId, callContext) + (DynamicEndpointProvider.connectorMethodProvider.vend.updateHost(bankId, userId, swaggerString), callContext) } map { i => (connectorEmptyResponse(i._1, callContext), i._2) } def getDynamicEndpoint(bankId: Option[String], dynamicEndpointId: String, callContext: Option[CallContext]): OBPReturnType[DynamicEndpointT] = { + validateBankId(bankId, callContext) + val dynamicEndpointBox: Box[DynamicEndpointT] = DynamicEndpointProvider.connectorMethodProvider.vend.get(bankId, dynamicEndpointId) val errorMessage = if(bankId.isEmpty) @@ -2934,6 +2999,8 @@ object NewStyle { } def getDynamicEndpoints(bankId: Option[String], callContext: Option[CallContext]): OBPReturnType[List[DynamicEndpointT]] = Future { + validateBankId(bankId, callContext) + (DynamicEndpointProvider.connectorMethodProvider.vend.getAll(bankId), callContext) } @@ -2947,6 +3014,8 @@ object NewStyle { * @return */ def deleteDynamicEndpoint(bankId: Option[String], dynamicEndpointId: String, callContext: Option[CallContext]): Future[Box[Boolean]] = { + validateBankId(bankId, callContext) + val dynamicEndpoint: OBPReturnType[DynamicEndpointT] = this.getDynamicEndpoint(bankId, dynamicEndpointId, callContext) for { (entity, _) <- dynamicEndpoint @@ -3325,6 +3394,8 @@ object NewStyle { } def validateUserAuthContextUpdateRequest(bankId: String, userId: String, key: String, value: String, scaMethod: String, callContext: Option[CallContext]): OBPReturnType[UserAuthContextUpdate] = { + validateBankId(bankId, callContext) + Connector.connector.vend.validateUserAuthContextUpdateRequest(bankId, userId, key, value, scaMethod, callContext) map { i => (connectorEmptyResponse(i._1, callContext), i._2) } diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 098faab33..00239d39a 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -8826,6 +8826,7 @@ trait APIMethods400 { } _ = try { CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) + .validateDependency() } catch { case e: Exception => val jsonResponse = createErrorJsonResponse(s"$DynamicCodeCompileFail ${e.getMessage}", 400, cc.correlationId) @@ -8890,6 +8891,7 @@ trait APIMethods400 { _ = try { CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) + .validateDependency() } catch { case e: Exception => val jsonResponse = createErrorJsonResponse(s"$DynamicCodeCompileFail ${e.getMessage}", 400, cc.correlationId) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicCompileEndpoint.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicCompileEndpoint.scala index f8e080abf..e21973b80 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicCompileEndpoint.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicCompileEndpoint.scala @@ -1,7 +1,7 @@ package code.api.v4_0_0.dynamic import code.api.util.APIUtil.{OBPEndpoint, OBPReturnType, futureToBoxedResponse, scalaFutureToLaFuture} -import code.api.util.{CallContext, CustomJsonFormats} +import code.api.util.{CallContext, CustomJsonFormats, DynamicUtil} import net.liftweb.common.Box import net.liftweb.http.{JsonResponse, Req} @@ -12,19 +12,34 @@ import net.liftweb.http.{JsonResponse, Req} trait DynamicCompileEndpoint { implicit val formats = CustomJsonFormats.formats - protected def process(callContext: CallContext, request: Req): Box[JsonResponse] + // * is any bankId + val boundBankId: String + + protected def process(callContext: CallContext, request: Req, pathParams: Map[String, String]): Box[JsonResponse] val endpoint: OBPEndpoint = new OBPEndpoint { override def isDefinedAt(x: Req): Boolean = true - override def apply(request: Req): CallContext => Box[JsonResponse] = process(_, request) + override def apply(request: Req): CallContext => Box[JsonResponse] = { cc => + val Some(pathParams) = cc.resourceDocument.map(_.getPathParams(request.path.partPath)) + + validateDependencies() + + CompiledObjects.sandbox(boundBankId).runInSandbox { + process(cc, request, pathParams) + } + + } } - protected implicit def scalaFutureToBoxedJsonResponse[T](scf: OBPReturnType[T])(implicit m: Manifest[T]): Box[JsonResponse] = { - futureToBoxedResponse(scalaFutureToLaFuture(scf)) - } - protected def getPathParams(callContext: CallContext, request: Req): Map[String, String] = { - val Some(resourceDoc) = callContext.resourceDocument - resourceDoc.getPathParams(request.path.partPath) + private def validateDependencies() = { + val dependencies = DynamicUtil.getDynamicCodeDependentMethods(this.getClass, "process" == ) + CompiledObjects.validateDependency(dependencies) } } + +object DynamicCompileEndpoint { + implicit def scalaFutureToBoxedJsonResponse[T](scf: OBPReturnType[T])(implicit m: Manifest[T]): Box[JsonResponse] = { + futureToBoxedResponse(scalaFutureToLaFuture(scf)) + } +} \ No newline at end of file diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala index 719b4d17f..2b698a5c1 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala @@ -1,17 +1,30 @@ package code.api.v4_0_0.dynamic -import code.api.util.APIUtil.{BooleanBody, DoubleBody, EmptyBody, LongBody, OBPEndpoint, PrimaryDataBody, ResourceDoc, StringBody} -import code.api.util.{CallContext, DynamicUtil} -import code.api.v4_0_0.dynamic.practise.{DynamicEndpointCodeGenerator, PractiseEndpointGroup} + +import code.api.JsonResponseException +import code.api.util.APIUtil.{BooleanBody, DoubleBody, EmptyBody, LongBody, OBPEndpoint, PrimaryDataBody, ResourceDoc, StringBody, createErrorJsonResponse} +import code.api.util.DynamicUtil.Sandbox +import code.api.util.{APIUtil, CallContext, DynamicUtil, ErrorMessages, NewStyle} +import code.api.util.NewStyle.HttpCode +import code.api.v4_0_0.JSONFactory400 +import code.api.v4_0_0.dynamic.practise.{DynamicEndpointCodeGenerator, PractiseEndpoint, PractiseEndpointGroup} +import com.openbankproject.commons.ExecutionContext +import com.openbankproject.commons.model.BankId +import com.openbankproject.commons.util.Functions.Memo +import com.openbankproject.commons.util.ReflectUtils import net.liftweb.common.{Box, Failure, Full} import net.liftweb.http.{JsonResponse, Req} import net.liftweb.json.{JNothing, JValue} import net.liftweb.json.JsonAST.{JBool, JDouble, JInt, JString} import org.apache.commons.lang3.StringUtils -import java.net.URLDecoder +import java.lang.reflect.ReflectPermission +import java.net.{NetPermission, URLDecoder} +import java.security.Permission +import java.util.PropertyPermission import scala.collection.immutable.List import scala.util.control.Breaks.{break, breakable} +import code.api.util.ErrorMessages.DynamicResourceDocMethodDependency object DynamicEndpoints { //TODO, better put all other dynamic endpoints into this list. eg: dynamicEntityEndpoints, dynamicSwaggerDocsEndpoints .... @@ -118,7 +131,7 @@ case class CompiledObjects(exampleRequestBody: Option[JValue], successResponseBo } val successResponse: Product = toCaseObject(successResponseBody) - val partialFunction: OBPEndpoint = { + private val partialFunction: OBPEndpoint = { //If the requestBody is PrimaryDataBody, return None. otherwise, return the exampleRequestBody:Option[JValue] // In side OBP resourceDoc, requestBody and successResponse must be Product type, @@ -141,26 +154,36 @@ case class CompiledObjects(exampleRequestBody: Option[JValue], successResponseBo val code = s""" - |import code.api.util.APIUtil.errorJsonResponse |import code.api.util.CallContext |import code.api.util.ErrorMessages.{InvalidJsonFormat, InvalidRequestPayload} |import code.api.util.NewStyle.HttpCode - |import code.api.v4_0_0.dynamic.DynamicCompileEndpoint + |import code.api.util.APIUtil.{OBPReturnType, futureToBoxedResponse, scalaFutureToLaFuture, errorJsonResponse} + | |import net.liftweb.common.{Box, EmptyBox, Full} |import net.liftweb.http.{JsonResponse, Req} |import net.liftweb.json.MappingException | |import scala.concurrent.Future + |import com.openbankproject.commons.ExecutionContext.Implicits.global + | + |implicit def scalaFutureToBoxedJsonResponse[T](scf: OBPReturnType[T])(implicit m: Manifest[T]): Box[JsonResponse] = { + | futureToBoxedResponse(scalaFutureToLaFuture(scf)) + |} + | + |implicit val formats = code.api.util.CustomJsonFormats.formats | |$requestBodyCaseClasses | |$responseBodyCaseClasses | - |(new DynamicCompileEndpoint { - | override protected def process(callContext: CallContext, request: Req): Box[JsonResponse] = { - | $decodedMethodBody - | } - |}).endpoint + |val endpoint: code.api.util.APIUtil.OBPEndpoint = { + | case request => { callContext => + | val Some(pathParams) = callContext.resourceDocument.map(_.getPathParams(request.path.partPath)) + | $decodedMethodBody + | } + |} + | + |endpoint | |""".stripMargin val endpointMethod = DynamicUtil.compileScalaCode[OBPEndpoint](code) @@ -173,6 +196,26 @@ case class CompiledObjects(exampleRequestBody: Option[JValue], successResponseBo } } + def validateDependency(): Unit = { + val dependentMethods: List[(String, String, String)] = DynamicUtil.getDynamicCodeDependentMethods(partialFunction.getClass) + CompiledObjects.validateDependency(dependentMethods); + } + + def sandboxEndpoint(bankId: Option[String]) : OBPEndpoint = { + val sandbox = CompiledObjects.sandbox(bankId.getOrElse("*")) + + new OBPEndpoint{ + override def isDefinedAt(req: Req): Boolean = partialFunction.isDefinedAt(req) + + // run dynamic code in sandbox + override def apply(req: Req): CallContext => Box[JsonResponse] = {cc => + val fn = partialFunction.apply(req) + + sandbox.runInSandbox(fn(cc)) + } + } + } + private def toCaseObject(jValue: Option[JValue]): Product = { if (jValue.isEmpty || jValue.exists(JNothing ==)) { EmptyBody @@ -188,4 +231,72 @@ case class CompiledObjects(exampleRequestBody: Option[JValue], successResponseBo } } +object CompiledObjects { + private val memoSandbox = new Memo[String, Sandbox] + // all Permissions put at here + private val permissions = List[Permission]( + new NetPermission("specifyStreamHandler"), + new ReflectPermission("suppressAccessChecks"), + new RuntimePermission("getenv.*"), + new PropertyPermission("cglib.useCache", "read"), + new PropertyPermission("net.sf.cglib.test.stressHashCodes", "read"), + new PropertyPermission("cglib.debugLocation", "read"), + new RuntimePermission("accessDeclaredMembers"), + new RuntimePermission("getClassLoader"), + ) + + // all allowed methods put at here, typeName -> methods + val allowedMethods: Map[String, Set[String]] = Map( + // companion objects methods + NewStyle.function.getClass.getTypeName -> "*", + CompiledObjects.getClass.getTypeName -> "sandbox", + HttpCode.getClass.getTypeName -> "200", + DynamicCompileEndpoint.getClass.getTypeName -> "getPathParams, scalaFutureToBoxedJsonResponse", + APIUtil.getClass.getTypeName -> "errorJsonResponse, errorJsonResponse$default$1, errorJsonResponse$default$2, errorJsonResponse$default$3, errorJsonResponse$default$4, scalaFutureToLaFuture, futureToBoxedResponse", + ErrorMessages.getClass.getTypeName -> "*", + ExecutionContext.Implicits.getClass.getTypeName -> "global", + JSONFactory400.getClass.getTypeName -> "createBanksJson", + + // class methods + classOf[Sandbox].getTypeName -> "runInSandbox", + classOf[CallContext].getTypeName -> "*", + classOf[ResourceDoc].getTypeName -> "getPathParams", + "scala.reflect.runtime.package$" -> "universe", + + // allow any method of PractiseEndpoint for test + PractiseEndpoint.getClass.getTypeName + "*" -> "*", + + ).mapValues(v => StringUtils.split(v, ',').map(_.trim).toSet) + + + def sandbox(bankId: String): Sandbox = memoSandbox.memoize(bankId){ + Sandbox.createSandbox(BankId.permission(bankId) :: permissions) + } + + /** + * validate dependencies, (className, methodName, signature) + */ + def validateDependency(dependentMethods: List[(String, String, String)]) = { + val notAllowedDependentMethods = dependentMethods collect { + case (typeName, method, _) + if (ReflectUtils.isObpClass(typeName) || typeName.startsWith("scala.reflect.runtime.") || typeName.startsWith("java.lang.reflect.")) && + !allowedMethods.get(typeName).exists(set => set.contains(method) || set.contains("*")) && + !allowedMethods.exists { it => + val (tpName, allowedMethods) = it + tpName.endsWith("*") && + typeName.startsWith(StringUtils.substringBeforeLast(tpName, "*")) && + (allowedMethods.contains(method) || allowedMethods.contains("*")) + } + => + s"$typeName.$method" + } + // change to JsonResponseException + if(notAllowedDependentMethods.nonEmpty) { + val illegalDependency = notAllowedDependentMethods.mkString("[", ", ", "]") + throw JsonResponseException(s"$DynamicResourceDocMethodDependency $illegalDependency", 400, "none") + } + } + +} + diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala index 58f661faf..7b9857cb9 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala @@ -37,7 +37,7 @@ object DynamicResourceDocsEndpointGroup extends EndpointGroup { private val toResourceDoc: JsonDynamicResourceDoc => ResourceDoc = { dynamicDoc => val compiledObjects = CompiledObjects(dynamicDoc.exampleRequestBody, dynamicDoc.successResponseBody, dynamicDoc.methodBody) ResourceDoc( - partialFunction = compiledObjects.partialFunction, //connectorMethodBody + partialFunction = compiledObjects.sandboxEndpoint(None), //connectorMethodBody, TODO add bankId implementedInApiVersion = apiVersion, partialFunctionName = dynamicDoc.partialFunctionName + "_" + (dynamicDoc.requestVerb + dynamicDoc.requestUrl).hashCode, requestVerb = dynamicDoc.requestVerb, diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala index f9331a067..3b625278e 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala @@ -1,35 +1,49 @@ package code.api.v4_0_0.dynamic.practise -import code.api.util.APIUtil.errorJsonResponse -import code.api.util.CallContext -import code.api.util.ErrorMessages.{InvalidJsonFormat, InvalidRequestPayload} -import code.api.util.NewStyle.HttpCode -import code.api.v4_0_0.dynamic.DynamicCompileEndpoint -import net.liftweb.common.{Box, EmptyBox, Full} -import net.liftweb.http.{JsonResponse, Req} -import net.liftweb.json.MappingException -import scala.concurrent.Future + +// any import statement here need be moved into the process method body /** * practise new endpoint at this object, don't commit you practise code to git */ -object PractiseEndpoint extends DynamicCompileEndpoint { - // all request case classes - case class RequestRootJsonClass(name: String, age: Long, hobby: Option[List[String]]) +object PractiseEndpoint extends code.api.v4_0_0.dynamic.DynamicCompileEndpoint { + // don't modify these import statement + import code.api.util.CallContext + import code.api.util.ErrorMessages.{InvalidJsonFormat, InvalidRequestPayload} + import code.api.util.NewStyle.HttpCode + import code.api.util.APIUtil.{OBPReturnType, futureToBoxedResponse, scalaFutureToLaFuture, errorJsonResponse} + import net.liftweb.common.{Box, EmptyBox, Full} + import net.liftweb.http.{JsonResponse, Req} + import net.liftweb.json.MappingException - // all response case classes - case class ResponseRootJsonClass(my_user_id: String, name: String, age: Long, hobby: Option[List[String]]) + import scala.concurrent.Future + import com.openbankproject.commons.ExecutionContext.Implicits.global + import code.api.v4_0_0.dynamic.DynamicCompileEndpoint._ // request method val requestMethod = "POST" val requestUrl = "/my_user/MY_USER_ID" + + // all request case classes + case class RequestRootJsonClass(name: String, age: Long, hobby: List[String]) + + + // all response case classes + case class ResponseRootJsonClass(my_user_id: String, name: String, age: Long, hobby: List[String]) + + // * is any bankId, if bound to other bankId, just modify this value to correct one + override val boundBankId = "abc" + // copy the whole method body as "dynamicResourceDoc" method body - override protected def process(callContext: CallContext, request: Req): Box[JsonResponse] = { + override protected def + process(callContext: CallContext, request: Req, pathParams: Map[String, String]) : Box[JsonResponse] = { // please add import sentences here, those used by this method + import code.api.util.NewStyle + import code.api.v4_0_0.JSONFactory400 val Some(resourceDoc) = callContext.resourceDocument val hasRequestBody = request.body.isDefined @@ -38,14 +52,12 @@ object PractiseEndpoint extends DynamicCompileEndpoint { // if the requestUrl of resourceDoc is /hello/banks/BANK_ID/world // the request path is /hello/banks/bank_x/world //pathParams.get("BANK_ID") will get Option("bank_x") value - val pathParams = getPathParams(callContext, request) val myUserId = pathParams("MY_USER_ID") - val requestEntity = request.json match { case Full(zson) => try { - zson.extract[RequestRootJsonClass] + zson.extract[RequestRootJsonClass] } catch { case e: MappingException => return Full(errorJsonResponse(s"$InvalidJsonFormat ${e.msg}")) @@ -53,12 +65,13 @@ object PractiseEndpoint extends DynamicCompileEndpoint { case _: EmptyBox => return Full(errorJsonResponse(s"$InvalidRequestPayload Current request has no payload")) } - - // please add business logic here - val responseBody:ResponseRootJsonClass = ResponseRootJsonClass(s"${myUserId}_from_path", requestEntity.name, requestEntity.age, requestEntity.hobby) - Future.successful { - (responseBody, HttpCode.`200`(callContext.callContext)) + val responseBody:ResponseRootJsonClass = ResponseRootJsonClass(s"${myUserId}_from_path", requestEntity.name, requestEntity.age, requestEntity.hobby) + + for { + (banks, callContext) <- NewStyle.function.getBanks(Some(callContext)) + } yield { + (JSONFactory400.createBanksJson(banks), HttpCode.`200`(callContext)) } } diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala index 153605a6b..4eefd5a2c 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala @@ -27,9 +27,8 @@ TESOBE (http://www.tesobe.com/) package com.openbankproject.commons.model import java.util.Date - import com.openbankproject.commons.util.{OBPRequired, optional} - +import javax.security.auth.AuthPermission import scala.collection.immutable.List import scala.math.BigDecimal @@ -138,11 +137,25 @@ object AccountId { } case class BankId(value : String) { + BankId.checkPermission(value) + override def toString = value } object BankId { def unapply(id : String) = Some(BankId(id)) + + def checkPermission(bankId: String): Unit = { + val sm = System.getSecurityManager + // use FilePermission to control bankId value, it is a hack way. + if (sm != null) { + val securityContext = sm.getSecurityContext + sm.checkPermission(permission(bankId), securityContext) + } + } + def checkPermission(bankId: Option[String]): Unit = bankId.foreach(checkPermission) + + def permission(bankId: String) = new AuthPermission(s"operateBank.$bankId") } case class AccountRoutingAddress(val value: String) { diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonSerializers.scala b/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonSerializers.scala index e47056df2..768874056 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonSerializers.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/util/JsonSerializers.scala @@ -1,7 +1,6 @@ package com.openbankproject.commons.util import java.lang.reflect.{Constructor, Modifier, Parameter} - import com.openbankproject.commons.model.{JsonFieldReName, ListResult} import com.openbankproject.commons.model.enums.{SimpleEnum, SimpleEnumCollection} import com.openbankproject.commons.util.Functions.Implicits._ @@ -20,6 +19,24 @@ import scala.reflect.runtime.{universe => ru} object JsonSerializers { + object CustomFormats extends DefaultFormats { + private val defaultFormats = net.liftweb.json.DefaultFormats + val losslessDate = defaultFormats.losslessDate + val UTC = defaultFormats.UTC + + /** + * DefaultFormats#parameterNameReader has bug, when execute fail, cause return Nil, this is not reasonable, + * Here override it to: when execute fail, try to call constructor.getParamters + */ + override val parameterNameReader: ParameterNameReader = new ParameterNameReader { + override def lookupParameterNames(constructor: Constructor[_]): Traversable[String] = try { + defaultFormats.parameterNameReader.lookupParameterNames(constructor) + } catch { + case _ => constructor.getParameters.map(_.getName) + } + } + } + val serializers: List[Serializer[_]] = AbstractTypeDeserializer :: SimpleEnumDeserializer :: BigDecimalSerializer :: StringDeserializer :: @@ -27,7 +44,7 @@ object JsonSerializers { JsonAbleSerializer :: ListResultSerializer.asInstanceOf[Serializer[_]] :: // here must do class cast, or it cause compile error, looks like a bug of scala. MapperSerializer :: Nil - implicit val commonFormats = net.liftweb.json.DefaultFormats ++ serializers + implicit val commonFormats = CustomFormats ++ serializers val nullTolerateFormats = commonFormats + JNothingSerializer From 091d048e3604eea67c10ed5f9f6f1405494da2b2 Mon Sep 17 00:00:00 2001 From: shuang Date: Sat, 23 Oct 2021 21:14:17 +0800 Subject: [PATCH 04/37] feature/dynamic_code_sandbox: implemented sandbox --- .../resources/props/sample.props.template | 4 +- .../main/scala/bootstrap/liftweb/Boot.scala | 6 ++ .../main/scala/code/api/util/APIUtil.scala | 8 +- .../scala/code/api/util/DynamicUtil.scala | 16 ++-- .../main/scala/code/api/util/NewStyle.scala | 94 ++++++++++--------- .../api/v4_0_0/dynamic/DynamicEndpoints.scala | 9 +- .../DynamicResourceDocsEndpointGroup.scala | 2 +- .../dynamic/practise/PractiseEndpoint.scala | 2 - .../commons/ExecutionContext.scala | 16 +++- .../commons/model/BankingModel.scala | 4 +- 10 files changed, 97 insertions(+), 64 deletions(-) diff --git a/obp-api/src/main/resources/props/sample.props.template b/obp-api/src/main/resources/props/sample.props.template index 2cd0951af..bb182714c 100644 --- a/obp-api/src/main/resources/props/sample.props.template +++ b/obp-api/src/main/resources/props/sample.props.template @@ -1079,4 +1079,6 @@ webui_developer_user_invitation_email_html_text=\

\ \ - + +# enable dynamic code sandbox, default is false, this will make sandbox works for code running in Future, will make performance lower than disable +dynamic_code_sandbox_enable=false \ No newline at end of file diff --git a/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala b/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala index 8ab2c7a62..27aee1875 100644 --- a/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala +++ b/obp-api/src/main/scala/bootstrap/liftweb/Boot.scala @@ -218,9 +218,15 @@ class Boot extends MdcLoggable { logger.info("external props folder: " + propsPath) TimeZone.setDefault(TimeZone.getTimeZone("UTC")) logger.info("Current Project TimeZone: " + TimeZone.getDefault) + + + // set dynamic_code_sandbox_enable to System.properties, so com.openbankproject.commons.ExecutionContext can read this value + APIUtil.getPropsValue("dynamic_code_sandbox_enable") + .foreach(it => System.setProperty("dynamic_code_sandbox_enable", it)) } + def boot { // set up the way to connect to the relational DB we're using (ok if other connector than relational) if (!DB.jndiJdbcConnAvailable_?) { 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 101a15258..005c7d9fc 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -33,7 +33,6 @@ import java.nio.charset.Charset import java.text.{ParsePosition, SimpleDateFormat} import java.util.concurrent.ConcurrentHashMap import java.util.{Calendar, Date, UUID} - import code.UserRefreshes.UserRefreshes import code.accountholders.AccountHolders import code.api.Constant._ @@ -98,6 +97,7 @@ import javassist.expr.{ExprEditor, MethodCall} import org.apache.commons.io.IOUtils import org.apache.commons.lang3.StringUtils +import java.security.AccessControlException import scala.collection.mutable import scala.concurrent.Future import scala.io.BufferedSource @@ -2467,7 +2467,11 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ case _ => laf.abort } scf.onFailure { - case e: Throwable => laf.fail(Failure(e.getMessage(), Full(e), Empty)) + case e: AccessControlException => + laf.fail(Failure(s"$DynamicResourceDocMethodPermission No permission of: ${e.getPermission.getName}", Full(e), Empty)) + + case e: Throwable => + laf.fail(Failure(e.getMessage(), Full(e), Empty)) } laf } diff --git a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala index 2fb531225..f4bdb23c0 100644 --- a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala +++ b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala @@ -1,5 +1,6 @@ package code.api.util import code.api.JsonResponseException +import code.api.util.ErrorMessages.DynamicResourceDocMethodPermission import com.openbankproject.commons.util.Functions.Memo import com.openbankproject.commons.util.JsonUtils import javassist.{ClassPool, LoaderClassPath} @@ -7,7 +8,7 @@ import net.liftweb.common.{Box, Failure, Full} import net.liftweb.http.JsonResponse import net.liftweb.json.{JValue, prettyRender} -import java.security.{AccessControlContext, AccessController, CodeSource, Permission, PermissionCollection, Permissions, Policy, PrivilegedAction, PrivilegedActionException, PrivilegedExceptionAction, ProtectionDomain} +import java.security.{AccessControlContext, AccessControlException, AccessController, CodeSource, Permission, PermissionCollection, Permissions, Policy, PrivilegedAction, ProtectionDomain} import java.util.concurrent.ConcurrentHashMap import scala.collection.mutable.ListBuffer import scala.reflect.runtime.universe @@ -181,24 +182,19 @@ object DynamicUtil { new Sandbox { @throws[Exception] def runInSandbox[R](action: => R): R = try { - val privilegedActionException: PrivilegedExceptionAction[R] = () => action + val privilegedAction: PrivilegedAction[R] = () => action - AccessController.doPrivileged(privilegedActionException, accessControlContext) + AccessController.doPrivileged(privilegedAction, accessControlContext) } catch { - case pae: PrivilegedActionException => - throw pae.getException - case e: NonLocalReturnControl[Full[JsonResponse]] if e.value.isInstanceOf[Full[JsonResponse]] => throw JsonResponseException(e.value.orNull) case e: NonLocalReturnControl[JsonResponse] if e.value.isInstanceOf[JsonResponse] => throw JsonResponseException(e.value) - case e if e.getClass.getName == "net.liftweb.http.rest.ContinuationException" => - throw e - case e: Throwable => - throw JsonResponseException(e.getMessage, 400, "") + e.printStackTrace() + throw e } } } diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index f10b749b5..cfc501ca5 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -195,7 +195,7 @@ object NewStyle { private def validateBankId(bankId: String, callContext: Option[CallContext]): Unit = try { BankId.checkPermission(bankId) } catch { - case e: AccessControlException => + case _: AccessControlException => val correlationId = callContext.map(_.correlationId).getOrElse("none") throw JsonResponseException(s"$DynamicResourceDocMethodPermission No permission of operate bank $bankId", 400, correlationId) } @@ -381,9 +381,8 @@ object NewStyle { bankRoutingScheme: String, bankRoutingAddress: String, callContext: Option[CallContext]): OBPReturnType[Bank] = { + validateBankId(bankId, callContext) Future { - validateBankId(bankId, callContext) - Connector.connector.vend.createOrUpdateBank( bankId, fullBankName, @@ -2612,20 +2611,22 @@ object NewStyle { } } - def createOrUpdateEndpointMapping(bankId: Option[String], endpointMapping: EndpointMappingT, callContext: Option[CallContext]) = Future { + def createOrUpdateEndpointMapping(bankId: Option[String], endpointMapping: EndpointMappingT, callContext: Option[CallContext]) = { validateBankId(bankId, callContext) - - (EndpointMappingProvider.endpointMappingProvider.vend.createOrUpdate(bankId, endpointMapping), callContext) - } map { - i => (connectorEmptyResponse(i._1, callContext), i._2) + Future { + (EndpointMappingProvider.endpointMappingProvider.vend.createOrUpdate(bankId, endpointMapping), callContext) + } map { + i => (connectorEmptyResponse(i._1, callContext), i._2) + } } - def deleteEndpointMapping(bankId: Option[String], endpointMappingId: String, callContext: Option[CallContext]) = Future { + def deleteEndpointMapping(bankId: Option[String], endpointMappingId: String, callContext: Option[CallContext]) = { validateBankId(bankId, callContext) - - (EndpointMappingProvider.endpointMappingProvider.vend.delete(bankId, endpointMappingId), callContext) - } map { - i => (connectorEmptyResponse(i._1, callContext), i._2) + Future { + (EndpointMappingProvider.endpointMappingProvider.vend.delete(bankId, endpointMappingId), callContext) + } map { + i => (connectorEmptyResponse(i._1, callContext), i._2) + } } def getEndpointMappingById(bankId: Option[String], endpointMappingId : String, callContext: Option[CallContext]): OBPReturnType[EndpointMappingT] = { @@ -2713,22 +2714,23 @@ object NewStyle { * @param dynamicEntityId * @return */ - def deleteDynamicEntity(bankId: Option[String], dynamicEntityId: String): Future[Box[Boolean]] = Future { + def deleteDynamicEntity(bankId: Option[String], dynamicEntityId: String): Future[Box[Boolean]] = { validateBankId(bankId, None) - - for { - entity <- DynamicEntityProvider.connectorMethodProvider.vend.getById(bankId, dynamicEntityId) - deleteEntityResult <- DynamicEntityProvider.connectorMethodProvider.vend.delete(entity) - deleteEntitleMentResult <- if(deleteEntityResult) { - Entitlement.entitlement.vend.deleteDynamicEntityEntitlement(entity.entityName, entity.bankId) - } else { - Box !! false + Future { + for { + entity <- DynamicEntityProvider.connectorMethodProvider.vend.getById(bankId, dynamicEntityId) + deleteEntityResult <- DynamicEntityProvider.connectorMethodProvider.vend.delete(entity) + deleteEntitleMentResult <- if (deleteEntityResult) { + Entitlement.entitlement.vend.deleteDynamicEntityEntitlement(entity.entityName, entity.bankId) + } else { + Box !! false + } + } yield { + if (deleteEntitleMentResult) { + DynamicEntityInfo.roleNames(entity.entityName, entity.bankId).foreach(ApiRole.removeDynamicApiRole(_)) + } + deleteEntitleMentResult } - } yield { - if(deleteEntitleMentResult) { - DynamicEntityInfo.roleNames(entity.entityName, entity.bankId).foreach(ApiRole.removeDynamicApiRole(_)) - } - deleteEntitleMentResult } } @@ -2742,11 +2744,12 @@ object NewStyle { } } - def getDynamicEntityByEntityName(bankId: Option[String], entityName : String, callContext: Option[CallContext]): OBPReturnType[Box[DynamicEntityT]] = Future { + def getDynamicEntityByEntityName(bankId: Option[String], entityName : String, callContext: Option[CallContext]): OBPReturnType[Box[DynamicEntityT]] = { validateBankId(bankId, callContext) - - val boxedDynamicEntity = DynamicEntityProvider.connectorMethodProvider.vend.getByEntityName(entityName) - (boxedDynamicEntity, callContext) + Future { + val boxedDynamicEntity = DynamicEntityProvider.connectorMethodProvider.vend.getByEntityName(entityName) + (boxedDynamicEntity, callContext) + } } private[this] val dynamicEntityTTL = { @@ -2973,20 +2976,22 @@ object NewStyle { getConnectorByName(connectorName).flatMap(_.callableMethods.get(methodName)) } - def createDynamicEndpoint(bankId:Option[String], userId: String, swaggerString: String, callContext: Option[CallContext]): OBPReturnType[DynamicEndpointT] = Future { + def createDynamicEndpoint(bankId:Option[String], userId: String, swaggerString: String, callContext: Option[CallContext]): OBPReturnType[DynamicEndpointT] = { validateBankId(bankId, callContext) - - (DynamicEndpointProvider.connectorMethodProvider.vend.create(bankId:Option[String], userId, swaggerString), callContext) - } map { - i => (connectorEmptyResponse(i._1, callContext), i._2) + Future { + (DynamicEndpointProvider.connectorMethodProvider.vend.create(bankId: Option[String], userId, swaggerString), callContext) + } map { + i => (connectorEmptyResponse(i._1, callContext), i._2) + } } - def updateDynamicEndpointHost(bankId: Option[String], userId: String, swaggerString: String, callContext: Option[CallContext]): OBPReturnType[DynamicEndpointT] = Future { + def updateDynamicEndpointHost(bankId: Option[String], userId: String, swaggerString: String, callContext: Option[CallContext]): OBPReturnType[DynamicEndpointT] = { validateBankId(bankId, callContext) - - (DynamicEndpointProvider.connectorMethodProvider.vend.updateHost(bankId, userId, swaggerString), callContext) - } map { - i => (connectorEmptyResponse(i._1, callContext), i._2) + Future { + (DynamicEndpointProvider.connectorMethodProvider.vend.updateHost(bankId, userId, swaggerString), callContext) + } map { + i => (connectorEmptyResponse(i._1, callContext), i._2) + } } def getDynamicEndpoint(bankId: Option[String], dynamicEndpointId: String, callContext: Option[CallContext]): OBPReturnType[DynamicEndpointT] = { @@ -3004,10 +3009,11 @@ object NewStyle { } } - def getDynamicEndpoints(bankId: Option[String], callContext: Option[CallContext]): OBPReturnType[List[DynamicEndpointT]] = Future { + def getDynamicEndpoints(bankId: Option[String], callContext: Option[CallContext]): OBPReturnType[List[DynamicEndpointT]] = { validateBankId(bankId, callContext) - - (DynamicEndpointProvider.connectorMethodProvider.vend.getAll(bankId), callContext) + Future { + (DynamicEndpointProvider.connectorMethodProvider.vend.getAll(bankId), callContext) + } } def getDynamicEndpointsByUserId(userId: String, callContext: Option[CallContext]): OBPReturnType[List[DynamicEndpointT]] = Future { diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala index bc2438f09..ecb225a5c 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala @@ -278,6 +278,13 @@ object CompiledObjects { ).mapValues(v => StringUtils.split(v, ',').map(_.trim).toSet) + val restrictedTypes = Set( + "scala.reflect.runtime.", + "java.lang.reflect.", + "scala.concurrent.ExecutionContext" + ) + + def isRestrictedType(typeName: String) = ReflectUtils.isObpClass(typeName) || restrictedTypes.exists(typeName.startsWith) def sandbox(bankId: String): Sandbox = memoSandbox.memoize(bankId){ Sandbox.createSandbox(BankId.permission(bankId) :: permissions) @@ -289,7 +296,7 @@ object CompiledObjects { def validateDependency(dependentMethods: List[(String, String, String)]) = { val notAllowedDependentMethods = dependentMethods collect { case (typeName, method, _) - if (ReflectUtils.isObpClass(typeName) || typeName.startsWith("scala.reflect.runtime.") || typeName.startsWith("java.lang.reflect.")) && + if isRestrictedType(typeName) && !allowedMethods.get(typeName).exists(set => set.contains(method) || set.contains("*")) && !allowedMethods.exists { it => val (tpName, allowedMethods) = it diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala index 7b9857cb9..d2a1eca45 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala @@ -37,7 +37,7 @@ object DynamicResourceDocsEndpointGroup extends EndpointGroup { private val toResourceDoc: JsonDynamicResourceDoc => ResourceDoc = { dynamicDoc => val compiledObjects = CompiledObjects(dynamicDoc.exampleRequestBody, dynamicDoc.successResponseBody, dynamicDoc.methodBody) ResourceDoc( - partialFunction = compiledObjects.sandboxEndpoint(None), //connectorMethodBody, TODO add bankId + partialFunction = compiledObjects.sandboxEndpoint(Some("abc")), //connectorMethodBody, TODO add bankId implementedInApiVersion = apiVersion, partialFunctionName = dynamicDoc.partialFunctionName + "_" + (dynamicDoc.requestVerb + dynamicDoc.requestUrl).hashCode, requestVerb = dynamicDoc.requestVerb, diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala index 3b625278e..bcc97151e 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala @@ -1,7 +1,5 @@ package code.api.v4_0_0.dynamic.practise - - // any import statement here need be moved into the process method body /** diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/ExecutionContext.scala b/obp-commons/src/main/scala/com/openbankproject/commons/ExecutionContext.scala index df7965956..ca272c764 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/ExecutionContext.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/ExecutionContext.scala @@ -2,9 +2,12 @@ package com.openbankproject.commons import com.alibaba.ttl.TtlRunnable -import scala.concurrent.{ ExecutionContext => ScalaExecutionContext} +import java.security.{AccessController, PrivilegedAction} +import scala.concurrent.{ExecutionContext => ScalaExecutionContext} object ExecutionContext { + val enableSandbox = System.getProperty("dynamic_code_sandbox_enable", "false").toBoolean + object Implicits { /** * The implicit global `ExecutionContext`. Import `global` when you want to provide the global @@ -24,8 +27,17 @@ object ExecutionContext { */ def wrapExecutionContext(executionContext: ScalaExecutionContext): ScalaExecutionContext = { new ScalaExecutionContext{ - override def execute(runnable: Runnable): Unit = executionContext.execute(TtlRunnable.get(runnable, true, true)) + override def execute(runnable: Runnable): Unit = { + val privilegedRunnable = if(enableSandbox) PrivilegedRunnable(runnable) else runnable + executionContext.execute(TtlRunnable.get(privilegedRunnable, true, true)) + } override def reportFailure(cause: Throwable): Unit = executionContext.reportFailure(cause) } } + + def PrivilegedRunnable(runnable: Runnable): Runnable = { + val acc = AccessController.getContext + val privilegedAction: PrivilegedAction[Unit] = () => runnable.run() + () => AccessController.doPrivileged(privilegedAction, acc) + } } diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala index db0d6b9a7..2a0266eeb 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala @@ -28,6 +28,8 @@ package com.openbankproject.commons.model import java.util.Date import com.openbankproject.commons.util.{OBPRequired, optional} + +import java.security.AccessControlContext import javax.security.auth.AuthPermission import scala.collection.immutable.List import scala.math.BigDecimal @@ -149,7 +151,7 @@ object BankId { val sm = System.getSecurityManager // use FilePermission to control bankId value, it is a hack way. if (sm != null) { - val securityContext = sm.getSecurityContext + val securityContext = sm.getSecurityContext.asInstanceOf[AccessControlContext] sm.checkPermission(permission(bankId), securityContext) } } From 247d2e3dfab2a9560c350f3d44d113061b2e9c8e Mon Sep 17 00:00:00 2001 From: shuang Date: Sun, 24 Oct 2021 23:01:57 +0800 Subject: [PATCH 05/37] feature/dynamic_code_sandbox: validate dependency for dynamic MessageDox --- .../SwaggerDefinitionsJSON.scala | 1 + .../main/scala/code/api/util/APIUtil.scala | 21 +++- .../scala/code/api/util/DynamicUtil.scala | 102 ++++++++++++++-- .../scala/code/api/v4_0_0/APIMethods400.scala | 7 +- .../dynamic/DynamicCompileEndpoint.scala | 5 +- .../api/v4_0_0/dynamic/DynamicEndpoints.scala | 109 ++---------------- .../DynamicResourceDocsEndpointGroup.scala | 2 +- .../bankconnectors/DynamicConnector.scala | 17 +-- .../DynamicResourceDoc.scala | 4 +- .../DynamicResourceDocProvider.scala | 1 + 10 files changed, 145 insertions(+), 124 deletions(-) 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 e9a8a12d4..cbf7e8a97 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 @@ -4257,6 +4257,7 @@ object SwaggerDefinitionsJSON { val jsonConnectorMethodMethodBody = JsonConnectorMethodMethodBody(connectorMethodBodyExample.value) val jsonDynamicResourceDoc = JsonDynamicResourceDoc( + bankId = Some(bankIdExample.value), dynamicResourceDocId = Some(dynamicResourceDocIdExample.value), methodBody = dynamicResourceDocMethodBodyExample.value, partialFunctionName = dynamicResourceDocPartialFunctionNameExample.value, 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 005c7d9fc..b5bb324ec 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -3758,6 +3758,13 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ pool.appendClassPath(new LoaderClassPath(Thread.currentThread.getContextClassLoader)) pool } + private val memoClassPool = new Memo[ClassLoader, ClassPool] + + private def getClassPool(classLoader: ClassLoader) = memoClassPool.memoize(classLoader){ + val cp = ClassPool.getDefault + cp.appendClassPath(new LoaderClassPath(classLoader)) + cp + } /** * according class name, method name and method's signature to get all dependent methods @@ -3780,8 +3787,14 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ * @param endpoint can be OBPEndpoint or other PartialFunction * @return a list of connector method name */ - def getDependentConnectorMethods(endpoint: PartialFunction[_, _]) = { + def getDependentConnectorMethods(endpoint: PartialFunction[_, _]): List[String] = { val connectorTypeName = classOf[Connector].getName + val endpointClassName = endpoint.getClass.getName + // not analyze dynamic code +// if(endpointClassName.startsWith("__wrapper$")) { +// return Nil +// } + val classPool = this.getClassPool(endpoint.getClass.getClassLoader) def getObpTrace(className: String, methodName: String, signature: String, exclude: List[(String, String, String)] = Nil): List[(String, String, String)] = memo.memoize((className, methodName, signature)) { @@ -3791,15 +3804,15 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ val list = methods.distinct.filter(it => ReflectUtils.isObpClass(it._1)).filterNot(exclude.contains) list.collect { case x@(clazzName, _, _) if clazzName == connectorTypeName => x :: Nil - case (clazzName, mName, mSignature) => + case (clazzName, mName, mSignature) if !clazzName.startsWith("__wrapper$") => getObpTrace(clazzName, mName, mSignature, list ::: exclude) }.flatten.distinct } - val endpointClassName = endpoint.getClass.getName + // list of connector method name val connectorMethods: Array[String] = for { - method <- cp.get(endpointClassName).getDeclaredMethods + method <- classPool.get(endpointClassName).getDeclaredMethods (clazzName, methodName, _) <- getObpTrace(endpointClassName, method.getName, method.getSignature) if clazzName == connectorTypeName && !methodName.contains("$default$") } yield methodName diff --git a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala index f4bdb23c0..8ec1d6d48 100644 --- a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala +++ b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala @@ -1,15 +1,27 @@ package code.api.util import code.api.JsonResponseException -import code.api.util.ErrorMessages.DynamicResourceDocMethodPermission +import code.api.util.APIUtil.ResourceDoc +import code.api.util.ErrorMessages.DynamicResourceDocMethodDependency +import code.api.util.NewStyle.HttpCode +import code.api.v4_0_0.JSONFactory400 +import code.api.v4_0_0.dynamic.{CompiledObjects, DynamicCompileEndpoint} +import code.api.v4_0_0.dynamic.practise.PractiseEndpoint +import com.openbankproject.commons.ExecutionContext +import com.openbankproject.commons.model.BankId import com.openbankproject.commons.util.Functions.Memo -import com.openbankproject.commons.util.JsonUtils +import com.openbankproject.commons.util.{JsonUtils, ReflectUtils} import javassist.{ClassPool, LoaderClassPath} import net.liftweb.common.{Box, Failure, Full} import net.liftweb.http.JsonResponse import net.liftweb.json.{JValue, prettyRender} +import org.apache.commons.lang3.StringUtils -import java.security.{AccessControlContext, AccessControlException, AccessController, CodeSource, Permission, PermissionCollection, Permissions, Policy, PrivilegedAction, ProtectionDomain} +import java.lang.reflect.ReflectPermission +import java.net.NetPermission +import java.security.{AccessControlContext, AccessController, CodeSource, Permission, PermissionCollection, Permissions, Policy, PrivilegedAction, ProtectionDomain} +import java.util.PropertyPermission import java.util.concurrent.ConcurrentHashMap +import scala.collection.immutable.List import scala.collection.mutable.ListBuffer import scala.reflect.runtime.universe import scala.reflect.runtime.universe.runtimeMirror @@ -191,13 +203,14 @@ object DynamicUtil { case e: NonLocalReturnControl[JsonResponse] if e.value.isInstanceOf[JsonResponse] => throw JsonResponseException(e.value) - - case e: Throwable => - e.printStackTrace() - throw e } } } + + private val memoSandbox = new Memo[String, Sandbox] + def sandbox(bankId: String): Sandbox = memoSandbox.memoize(bankId) { + Sandbox.createSandbox(BankId.permission(bankId) :: Validation.permissions) + } } /** @@ -249,4 +262,79 @@ object DynamicUtil { |import scala.concurrent.{Await, Future} |import com.openbankproject.commons.dto._ |""".stripMargin + + + object Validation { + // all Permissions put at here + val permissions = List[Permission]( + new NetPermission("specifyStreamHandler"), + new ReflectPermission("suppressAccessChecks"), + new RuntimePermission("getenv.*"), + new PropertyPermission("cglib.useCache", "read"), + new PropertyPermission("net.sf.cglib.test.stressHashCodes", "read"), + new PropertyPermission("cglib.debugLocation", "read"), + new RuntimePermission("accessDeclaredMembers"), + new RuntimePermission("getClassLoader"), + ) + + // all allowed methods put at here, typeName -> methods + val allowedMethods: Map[String, Set[String]] = Map( + // companion objects methods + NewStyle.function.getClass.getTypeName -> "*", + CompiledObjects.getClass.getTypeName -> "sandbox", + HttpCode.getClass.getTypeName -> "200", + DynamicCompileEndpoint.getClass.getTypeName -> "getPathParams, scalaFutureToBoxedJsonResponse", + APIUtil.getClass.getTypeName -> "errorJsonResponse, errorJsonResponse$default$1, errorJsonResponse$default$2, errorJsonResponse$default$3, errorJsonResponse$default$4, scalaFutureToLaFuture, futureToBoxedResponse", + ErrorMessages.getClass.getTypeName -> "*", + ExecutionContext.Implicits.getClass.getTypeName -> "global", + JSONFactory400.getClass.getTypeName -> "createBanksJson", + + // class methods + classOf[Sandbox].getTypeName -> "runInSandbox", + classOf[CallContext].getTypeName -> "*", + classOf[ResourceDoc].getTypeName -> "getPathParams", + "scala.reflect.runtime.package$" -> "universe", + + // allow any method of PractiseEndpoint for test + PractiseEndpoint.getClass.getTypeName + "*" -> "*", + + ).mapValues(v => StringUtils.split(v, ',').map(_.trim).toSet) + + val restrictedTypes = Set( + "scala.reflect.runtime.", + "java.lang.reflect.", + "scala.concurrent.ExecutionContext" + ) + + private def isRestrictedType(typeName: String) = ReflectUtils.isObpClass(typeName) || restrictedTypes.exists(typeName.startsWith) + + /** + * validate dependencies, (className, methodName, signature) + */ + private def validateDependency(dependentMethods: List[(String, String, String)]) = { + val notAllowedDependentMethods = dependentMethods collect { + case (typeName, method, _) + if isRestrictedType(typeName) && + !allowedMethods.get(typeName).exists(set => set.contains(method) || set.contains("*")) && + !allowedMethods.exists { it => + val (tpName, allowedMethods) = it + tpName.endsWith("*") && + typeName.startsWith(StringUtils.substringBeforeLast(tpName, "*")) && + (allowedMethods.contains(method) || allowedMethods.contains("*")) + } + => + s"$typeName.$method" + } + // change to JsonResponseException + if(notAllowedDependentMethods.nonEmpty) { + val illegalDependency = notAllowedDependentMethods.mkString("[", ", ", "]") + throw JsonResponseException(s"$DynamicResourceDocMethodDependency $illegalDependency", 400, "none") + } + } + + def validateDependency(obj: AnyRef): Unit = { + val dependentMethods: List[(String, String, String)] = DynamicUtil.getDynamicCodeDependentMethods(obj.getClass) + validateDependency(dependentMethods) + } + } } diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 416760264..74b5152b7 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -7,6 +7,7 @@ import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._ import code.api.util.APIUtil.{fullBoxOrException, _} import code.api.util.ApiRole._ import code.api.util.ApiTag._ +import code.api.util.DynamicUtil.Validation import code.api.util.ErrorMessages._ import code.api.util.ExampleValue._ import code.api.util.NewStyle.HttpCode @@ -78,9 +79,9 @@ import net.liftweb.util.Mailer.{From, PlainMailBodyType, Subject, To, XHTMLMailB import net.liftweb.util.{Helpers, Mailer, StringHelpers} import org.apache.commons.collections4.CollectionUtils import org.apache.commons.lang3.StringUtils + import java.net.URLEncoder import java.util.{Calendar, Date} - import scala.collection.immutable.{List, Nil} import scala.collection.mutable.ArrayBuffer import scala.concurrent.Future @@ -9269,6 +9270,7 @@ trait APIMethods400 { _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=callContext) { connectorMethod.isDefined } + _ = Validation.validateDependency(connectorMethod.orNull) (dynamicMessageDoc, callContext) <- NewStyle.function.createJsonDynamicMessageDoc(None, dynamicMessageDoc, callContext) } yield { (dynamicMessageDoc, HttpCode.`201`(callContext)) @@ -9312,6 +9314,7 @@ trait APIMethods400 { _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=callContext) { connectorMethod.isDefined } + _ = Validation.validateDependency(connectorMethod.orNull) (dynamicMessageDoc, callContext) <- NewStyle.function.createJsonDynamicMessageDoc(Some(bankId), dynamicMessageDoc, callContext) } yield { (dynamicMessageDoc, HttpCode.`201`(callContext)) @@ -9351,6 +9354,7 @@ trait APIMethods400 { _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=cc.callContext) { connectorMethod.isDefined } + _ = Validation.validateDependency(connectorMethod.orNull) (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(None, dynamicMessageDocId, cc.callContext) (dynamicMessageDoc, callContext) <- NewStyle.function.updateJsonDynamicMessageDoc(None, dynamicMessageDocBody.copy(dynamicMessageDocId=Some(dynamicMessageDocId)), callContext) } yield { @@ -9485,6 +9489,7 @@ trait APIMethods400 { _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=cc.callContext) { connectorMethod.isDefined } + _ = Validation.validateDependency(connectorMethod.orNull) (_, callContext) <- NewStyle.function.getJsonDynamicMessageDocById(Some(bankId), dynamicMessageDocId, cc.callContext) (dynamicMessageDoc, callContext) <- NewStyle.function.updateJsonDynamicMessageDoc(Some(bankId), dynamicMessageDocBody.copy(dynamicMessageDocId=Some(dynamicMessageDocId)), callContext) } yield { diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicCompileEndpoint.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicCompileEndpoint.scala index e21973b80..e73995f84 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicCompileEndpoint.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicCompileEndpoint.scala @@ -1,6 +1,7 @@ package code.api.v4_0_0.dynamic import code.api.util.APIUtil.{OBPEndpoint, OBPReturnType, futureToBoxedResponse, scalaFutureToLaFuture} +import code.api.util.DynamicUtil.{Sandbox, Validation} import code.api.util.{CallContext, CustomJsonFormats, DynamicUtil} import net.liftweb.common.Box import net.liftweb.http.{JsonResponse, Req} @@ -25,7 +26,7 @@ trait DynamicCompileEndpoint { validateDependencies() - CompiledObjects.sandbox(boundBankId).runInSandbox { + Sandbox.sandbox(boundBankId).runInSandbox { process(cc, request, pathParams) } @@ -34,7 +35,7 @@ trait DynamicCompileEndpoint { private def validateDependencies() = { val dependencies = DynamicUtil.getDynamicCodeDependentMethods(this.getClass, "process" == ) - CompiledObjects.validateDependency(dependencies) + Validation.validateDependency(dependencies) } } diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala index ecb225a5c..903d606cf 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala @@ -1,33 +1,17 @@ package code.api.v4_0_0.dynamic - -import code.api.JsonResponseException -import code.api.util.DynamicUtil.Sandbox -import code.api.util.{APIUtil, ErrorMessages, NewStyle} -import code.api.util.NewStyle.HttpCode -import code.api.v4_0_0.JSONFactory400 -import code.api.v4_0_0.dynamic.practise.PractiseEndpoint -import com.openbankproject.commons.ExecutionContext -import com.openbankproject.commons.model.BankId -import com.openbankproject.commons.util.Functions.Memo -import com.openbankproject.commons.util.ReflectUtils - +import code.api.util.DynamicUtil.{Sandbox, Validation} import code.api.util.APIUtil.{BooleanBody, DoubleBody, EmptyBody, LongBody, OBPEndpoint, PrimaryDataBody, ResourceDoc, StringBody, getDisabledEndpointOperationIds} import code.api.util.{CallContext, DynamicUtil} import code.api.v4_0_0.dynamic.practise.{DynamicEndpointCodeGenerator, PractiseEndpointGroup} - import net.liftweb.common.{Box, Failure, Full} import net.liftweb.http.{JsonResponse, Req} import net.liftweb.json.{JNothing, JValue} import net.liftweb.json.JsonAST.{JBool, JDouble, JInt, JString} import org.apache.commons.lang3.StringUtils -import java.lang.reflect.ReflectPermission -import java.net.{NetPermission, URLDecoder} -import java.security.Permission -import java.util.PropertyPermission +import java.net.URLDecoder import scala.collection.immutable.List import scala.util.control.Breaks.{break, breakable} -import code.api.util.ErrorMessages.DynamicResourceDocMethodDependency object DynamicEndpoints { //TODO, better put all other dynamic endpoints into this list. eg: dynamicEntityEndpoints, dynamicSwaggerDocsEndpoints .... @@ -206,15 +190,16 @@ case class CompiledObjects(exampleRequestBody: Option[JValue], successResponseBo } } - def validateDependency(): Unit = { - val dependentMethods: List[(String, String, String)] = DynamicUtil.getDynamicCodeDependentMethods(partialFunction.getClass) - CompiledObjects.validateDependency(dependentMethods); - } + def validateDependency() = Validation.validateDependency(this.partialFunction) def sandboxEndpoint(bankId: Option[String]) : OBPEndpoint = { - val sandbox = CompiledObjects.sandbox(bankId.getOrElse("*")) + val sandbox = bankId match { + case Some(v) if StringUtils.isNotBlank(v) => + Sandbox.sandbox(v) + case _ => Sandbox.sandbox("*") + } - new OBPEndpoint{ + new OBPEndpoint { override def isDefinedAt(req: Req): Boolean = partialFunction.isDefinedAt(req) // run dynamic code in sandbox @@ -241,79 +226,3 @@ case class CompiledObjects(exampleRequestBody: Option[JValue], successResponseBo } } -object CompiledObjects { - private val memoSandbox = new Memo[String, Sandbox] - // all Permissions put at here - private val permissions = List[Permission]( - new NetPermission("specifyStreamHandler"), - new ReflectPermission("suppressAccessChecks"), - new RuntimePermission("getenv.*"), - new PropertyPermission("cglib.useCache", "read"), - new PropertyPermission("net.sf.cglib.test.stressHashCodes", "read"), - new PropertyPermission("cglib.debugLocation", "read"), - new RuntimePermission("accessDeclaredMembers"), - new RuntimePermission("getClassLoader"), - ) - - // all allowed methods put at here, typeName -> methods - val allowedMethods: Map[String, Set[String]] = Map( - // companion objects methods - NewStyle.function.getClass.getTypeName -> "*", - CompiledObjects.getClass.getTypeName -> "sandbox", - HttpCode.getClass.getTypeName -> "200", - DynamicCompileEndpoint.getClass.getTypeName -> "getPathParams, scalaFutureToBoxedJsonResponse", - APIUtil.getClass.getTypeName -> "errorJsonResponse, errorJsonResponse$default$1, errorJsonResponse$default$2, errorJsonResponse$default$3, errorJsonResponse$default$4, scalaFutureToLaFuture, futureToBoxedResponse", - ErrorMessages.getClass.getTypeName -> "*", - ExecutionContext.Implicits.getClass.getTypeName -> "global", - JSONFactory400.getClass.getTypeName -> "createBanksJson", - - // class methods - classOf[Sandbox].getTypeName -> "runInSandbox", - classOf[CallContext].getTypeName -> "*", - classOf[ResourceDoc].getTypeName -> "getPathParams", - "scala.reflect.runtime.package$" -> "universe", - - // allow any method of PractiseEndpoint for test - PractiseEndpoint.getClass.getTypeName + "*" -> "*", - - ).mapValues(v => StringUtils.split(v, ',').map(_.trim).toSet) - - val restrictedTypes = Set( - "scala.reflect.runtime.", - "java.lang.reflect.", - "scala.concurrent.ExecutionContext" - ) - - def isRestrictedType(typeName: String) = ReflectUtils.isObpClass(typeName) || restrictedTypes.exists(typeName.startsWith) - - def sandbox(bankId: String): Sandbox = memoSandbox.memoize(bankId){ - Sandbox.createSandbox(BankId.permission(bankId) :: permissions) - } - - /** - * validate dependencies, (className, methodName, signature) - */ - def validateDependency(dependentMethods: List[(String, String, String)]) = { - val notAllowedDependentMethods = dependentMethods collect { - case (typeName, method, _) - if isRestrictedType(typeName) && - !allowedMethods.get(typeName).exists(set => set.contains(method) || set.contains("*")) && - !allowedMethods.exists { it => - val (tpName, allowedMethods) = it - tpName.endsWith("*") && - typeName.startsWith(StringUtils.substringBeforeLast(tpName, "*")) && - (allowedMethods.contains(method) || allowedMethods.contains("*")) - } - => - s"$typeName.$method" - } - // change to JsonResponseException - if(notAllowedDependentMethods.nonEmpty) { - val illegalDependency = notAllowedDependentMethods.mkString("[", ", ", "]") - throw JsonResponseException(s"$DynamicResourceDocMethodDependency $illegalDependency", 400, "none") - } - } - -} - - diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala index d2a1eca45..622c02ede 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala @@ -37,7 +37,7 @@ object DynamicResourceDocsEndpointGroup extends EndpointGroup { private val toResourceDoc: JsonDynamicResourceDoc => ResourceDoc = { dynamicDoc => val compiledObjects = CompiledObjects(dynamicDoc.exampleRequestBody, dynamicDoc.successResponseBody, dynamicDoc.methodBody) ResourceDoc( - partialFunction = compiledObjects.sandboxEndpoint(Some("abc")), //connectorMethodBody, TODO add bankId + partialFunction = compiledObjects.sandboxEndpoint(dynamicDoc.bankId), implementedInApiVersion = apiVersion, partialFunctionName = dynamicDoc.partialFunctionName + "_" + (dynamicDoc.requestVerb + dynamicDoc.requestUrl).hashCode, requestVerb = dynamicDoc.requestVerb, diff --git a/obp-api/src/main/scala/code/bankconnectors/DynamicConnector.scala b/obp-api/src/main/scala/code/bankconnectors/DynamicConnector.scala index e74ed01c4..c30f3e2bd 100644 --- a/obp-api/src/main/scala/code/bankconnectors/DynamicConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/DynamicConnector.scala @@ -4,9 +4,8 @@ import code.api.util.DynamicUtil.compileScalaCode import code.api.util.{CallContext, DynamicUtil} import code.dynamicMessageDoc.{DynamicMessageDocProvider, JsonDynamicMessageDoc} import net.liftweb.common.Box -import com.openbankproject.commons.ExecutionContext.Implicits.global + import scala.concurrent.Future -import code.api.util.APIUtil.{EntitlementAndScopeStatus, JsonResponseExtractor, OBPReturnType} object DynamicConnector { @@ -24,8 +23,7 @@ object DynamicConnector { def removeSingletonObject(key:String) = singletonObjectMap.remove(key) def invoke(bankId: Option[String], process: String, args: Array[AnyRef], callContext: Option[CallContext]) = { - val function: Box[(Array[AnyRef], Option[CallContext]) => Future[Box[(AnyRef, Option[CallContext])]]] = - getFunction(bankId, process).asInstanceOf[Box[(Array[AnyRef], Option[CallContext]) => Future[Box[(AnyRef, Option[CallContext])]]]] + val function = getFunction(bankId, process) function.map(f =>f(args: Array[AnyRef], callContext: Option[CallContext])).openOrThrowException(s"There is no process $process, it should not be called here") } @@ -44,17 +42,20 @@ object DynamicConnector { * @param methodBody method body of connector method * @return function of connector method that is dynamic created, can be Function0, Function1, Function2... */ - def createFunction(process: String, methodBody:String): Box[Any] = + def createFunction(process: String, methodBody:String): Box[(Array[AnyRef], Option[CallContext]) => Future[Box[(AnyRef, Option[CallContext])]]] = { //messageDoc.process is a bit different with the methodName, we need tweak the format of it: //eg: process("obp.getBank") ==> methodName("getBank") val method = s""" |${DynamicUtil.importStatements} - |def func(args: Array[AnyRef], callContext: Option[CallContext]): Future[Box[(AnyRef, Option[CallContext])]] = { - | $methodBody + | + |val fn = new ((Array[AnyRef], Option[CallContext]) => Future[Box[(AnyRef, Option[CallContext])]]) (){ + | override def apply(args: Array[AnyRef], callContext: Option[CallContext]): Future[Box[(AnyRef, Option[CallContext])]] = { + | $methodBody + | } |} | - |func _ + |fn |""".stripMargin compileScalaCode(method) } diff --git a/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDoc.scala b/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDoc.scala index c4ace87c6..d2db91ec0 100644 --- a/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDoc.scala +++ b/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDoc.scala @@ -10,7 +10,8 @@ import scala.collection.immutable.List class DynamicResourceDoc extends LongKeyedMapper[DynamicResourceDoc] with IdPK { override def getSingleton = DynamicResourceDoc - + + object BankId extends MappedString(this, 255) object DynamicResourceDocId extends UUIDString(this) object PartialFunctionName extends MappedString(this, 255) object RequestVerb extends MappedString(this, 255) @@ -30,6 +31,7 @@ class DynamicResourceDoc extends LongKeyedMapper[DynamicResourceDoc] with IdPK { object DynamicResourceDoc extends DynamicResourceDoc with LongKeyedMetaMapper[DynamicResourceDoc] { override def dbIndexes: List[BaseIndex[DynamicResourceDoc]] = UniqueIndex(DynamicResourceDocId) :: UniqueIndex(RequestUrl,RequestVerb) :: super.dbIndexes def getJsonDynamicResourceDoc(dynamicResourceDoc: DynamicResourceDoc) = JsonDynamicResourceDoc( + bankId = Some(dynamicResourceDoc.BankId.get), dynamicResourceDocId = Some(dynamicResourceDoc.DynamicResourceDocId.get), methodBody = dynamicResourceDoc.MethodBody.get, partialFunctionName = dynamicResourceDoc.PartialFunctionName.get, diff --git a/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDocProvider.scala b/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDocProvider.scala index 51b28ad76..dd60f8c0d 100644 --- a/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDocProvider.scala +++ b/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDocProvider.scala @@ -20,6 +20,7 @@ object DynamicResourceDocProvider extends SimpleInjector { } case class JsonDynamicResourceDoc( + bankId: Option[String], dynamicResourceDocId: Option[String], methodBody: String, partialFunctionName: String, From 1e35baa0657c8368e7793fa3e33450dd76ff80e6 Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 25 Oct 2021 12:34:03 +0200 Subject: [PATCH 06/37] feature/added the bankLevel Dynamic Resource Docs. --- .../main/scala/code/api/util/ApiRole.scala | 15 ++ .../main/scala/code/api/util/NewStyle.scala | 28 +-- .../scala/code/api/v4_0_0/APIMethods400.scala | 231 +++++++++++++++++- .../DynamicResourceDocsEndpointGroup.scala | 2 +- .../DynamicResourceDocProvider.scala | 14 +- .../MappedDynamicResourceDocProvider.scala | 65 +++-- 6 files changed, 311 insertions(+), 44 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/ApiRole.scala b/obp-api/src/main/scala/code/api/util/ApiRole.scala index 34431f6ea..c5fd961df 100644 --- a/obp-api/src/main/scala/code/api/util/ApiRole.scala +++ b/obp-api/src/main/scala/code/api/util/ApiRole.scala @@ -746,6 +746,21 @@ object ApiRole { case class CanDeleteDynamicResourceDoc(requiresBankId: Boolean = false) extends ApiRole lazy val canDeleteDynamicResourceDoc = CanDeleteDynamicResourceDoc() + + case class CanCreateBankLevelDynamicResourceDoc(requiresBankId: Boolean = false) extends ApiRole + lazy val canCreateBankLevelDynamicResourceDoc = CanCreateBankLevelDynamicResourceDoc() + + case class CanUpdateBankLevelDynamicResourceDoc(requiresBankId: Boolean = false) extends ApiRole + lazy val canUpdateBankLevelDynamicResourceDoc = CanUpdateBankLevelDynamicResourceDoc() + + case class CanGetBankLevelDynamicResourceDoc(requiresBankId: Boolean = false) extends ApiRole + lazy val canGetBankLevelDynamicResourceDoc = CanGetBankLevelDynamicResourceDoc() + + case class CanGetAllBankLevelDynamicResourceDocs(requiresBankId: Boolean = false) extends ApiRole + lazy val canGetAllBankLevelDynamicResourceDocs = CanGetAllBankLevelDynamicResourceDocs() + + case class CanDeleteBankLevelDynamicResourceDoc(requiresBankId: Boolean = false) extends ApiRole + lazy val canDeleteBankLevelDynamicResourceDoc = CanDeleteBankLevelDynamicResourceDoc() case class CanCreateDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole lazy val canCreateDynamicMessageDoc = CanCreateDynamicMessageDoc() diff --git a/obp-api/src/main/scala/code/api/util/NewStyle.scala b/obp-api/src/main/scala/code/api/util/NewStyle.scala index cfc501ca5..a71139ca1 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -3325,47 +3325,47 @@ object NewStyle { (unboxFullOrFail(connectorMethod, callContext, s"$ConnectorMethodNotFound Current CONNECTOR_METHOD_ID(${connectorMethodId})", 400), callContext) } - def isJsonDynamicResourceDocExists(requestVerb : String, requestUrl : String, callContext: Option[CallContext]): OBPReturnType[Boolean] = + def isJsonDynamicResourceDocExists(bankId: Option[String], requestVerb : String, requestUrl : String, callContext: Option[CallContext]): OBPReturnType[Boolean] = Future { - val result = DynamicResourceDocProvider.provider.vend.getByVerbAndUrl(requestVerb, requestUrl) + val result = DynamicResourceDocProvider.provider.vend.getByVerbAndUrl(bankId, requestVerb, requestUrl) (result.isDefined, callContext) } - def createJsonDynamicResourceDoc(dynamicResourceDoc: JsonDynamicResourceDoc, callContext: Option[CallContext]): OBPReturnType[JsonDynamicResourceDoc] = + def createJsonDynamicResourceDoc(bankId: Option[String], dynamicResourceDoc: JsonDynamicResourceDoc, callContext: Option[CallContext]): OBPReturnType[JsonDynamicResourceDoc] = Future { - val newInternalConnector = DynamicResourceDocProvider.provider.vend.create(dynamicResourceDoc) + val newInternalConnector = DynamicResourceDocProvider.provider.vend.create(bankId, dynamicResourceDoc) val errorMsg = s"$UnknownError Can not create Dynamic Resource Doc in the backend. " (unboxFullOrFail(newInternalConnector, callContext, errorMsg, 400), callContext) } - def updateJsonDynamicResourceDoc(entity: JsonDynamicResourceDoc, callContext: Option[CallContext]): OBPReturnType[JsonDynamicResourceDoc] = + def updateJsonDynamicResourceDoc(bankId: Option[String], entity: JsonDynamicResourceDoc, callContext: Option[CallContext]): OBPReturnType[JsonDynamicResourceDoc] = Future { - val updatedConnectorMethod = DynamicResourceDocProvider.provider.vend.update(entity: JsonDynamicResourceDoc) + val updatedConnectorMethod = DynamicResourceDocProvider.provider.vend.update(bankId, entity: JsonDynamicResourceDoc) val errorMsg = s"$UnknownError Can not update Dynamic Resource Doc in the backend. " (unboxFullOrFail(updatedConnectorMethod, callContext, errorMsg, 400), callContext) } - def isJsonDynamicResourceDocExists(dynamicResourceDocId: String, callContext: Option[CallContext]): OBPReturnType[Boolean] = + def isJsonDynamicResourceDocExists(bankId: Option[String], dynamicResourceDocId: String, callContext: Option[CallContext]): OBPReturnType[Boolean] = Future { - val result = DynamicResourceDocProvider.provider.vend.getById(dynamicResourceDocId) + val result = DynamicResourceDocProvider.provider.vend.getById(bankId, dynamicResourceDocId) (result.isDefined, callContext) } - def getJsonDynamicResourceDocs(callContext: Option[CallContext]): OBPReturnType[List[JsonDynamicResourceDoc]] = + def getJsonDynamicResourceDocs(bankId: Option[String], callContext: Option[CallContext]): OBPReturnType[List[JsonDynamicResourceDoc]] = Future { - val dynamicResourceDocs: List[JsonDynamicResourceDoc] = DynamicResourceDocProvider.provider.vend.getAll() + val dynamicResourceDocs: List[JsonDynamicResourceDoc] = DynamicResourceDocProvider.provider.vend.getAll(bankId) dynamicResourceDocs -> callContext } - def getJsonDynamicResourceDocById(dynamicResourceDocId: String, callContext: Option[CallContext]): OBPReturnType[JsonDynamicResourceDoc] = + def getJsonDynamicResourceDocById(bankId: Option[String], dynamicResourceDocId: String, callContext: Option[CallContext]): OBPReturnType[JsonDynamicResourceDoc] = Future { - val dynamicResourceDoc = DynamicResourceDocProvider.provider.vend.getById(dynamicResourceDocId) + val dynamicResourceDoc = DynamicResourceDocProvider.provider.vend.getById(bankId, dynamicResourceDocId) (unboxFullOrFail(dynamicResourceDoc, callContext, s"$DynamicResourceDocNotFound Current DYNAMIC_RESOURCE_DOC_ID(${dynamicResourceDocId})", 400), callContext) } - def deleteJsonDynamicResourceDocById(dynamicResourceDocId: String, callContext: Option[CallContext]): OBPReturnType[Boolean] = + def deleteJsonDynamicResourceDocById(bankId: Option[String], dynamicResourceDocId: String, callContext: Option[CallContext]): OBPReturnType[Boolean] = Future { - val dynamicResourceDoc = DynamicResourceDocProvider.provider.vend.deleteById(dynamicResourceDocId) + val dynamicResourceDoc = DynamicResourceDocProvider.provider.vend.deleteById(bankId, dynamicResourceDocId) (unboxFullOrFail(dynamicResourceDoc, callContext, s"$DynamicResourceDocDeleteError Current DYNAMIC_RESOURCE_DOC_ID(${dynamicResourceDocId})", 400), callContext) } diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 74b5152b7..3c67dddd6 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -9014,12 +9014,12 @@ trait APIMethods400 { throw JsonResponseException(jsonResponse) } - (isExists, callContext) <- NewStyle.function.isJsonDynamicResourceDocExists(jsonDynamicResourceDoc.requestVerb, jsonDynamicResourceDoc.requestUrl, Some(cc)) + (isExists, callContext) <- NewStyle.function.isJsonDynamicResourceDocExists(None, jsonDynamicResourceDoc.requestVerb, jsonDynamicResourceDoc.requestUrl, Some(cc)) _ <- Helper.booleanToFuture(failMsg = s"$DynamicResourceDocAlreadyExists The combination of request_url(${jsonDynamicResourceDoc.requestUrl}) and request_verb(${jsonDynamicResourceDoc.requestVerb}) must be unique", cc=callContext) { (!isExists) } - (dynamicResourceDoc, callContext) <- NewStyle.function.createJsonDynamicResourceDoc(jsonDynamicResourceDoc, callContext) + (dynamicResourceDoc, callContext) <- NewStyle.function.createJsonDynamicResourceDoc(None, jsonDynamicResourceDoc, callContext) } yield { (dynamicResourceDoc, HttpCode.`201`(callContext)) } @@ -9079,9 +9079,9 @@ trait APIMethods400 { throw JsonResponseException(jsonResponse) } - (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(dynamicResourceDocId, cc.callContext) + (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(None, dynamicResourceDocId, cc.callContext) - (dynamicResourceDoc, callContext) <- NewStyle.function.updateJsonDynamicResourceDoc(dynamicResourceDocBody.copy(dynamicResourceDocId = Some(dynamicResourceDocId)), callContext) + (dynamicResourceDoc, callContext) <- NewStyle.function.updateJsonDynamicResourceDoc(None, dynamicResourceDocBody.copy(dynamicResourceDocId = Some(dynamicResourceDocId)), callContext) } yield { (dynamicResourceDoc, HttpCode.`200`(callContext)) } @@ -9112,8 +9112,8 @@ trait APIMethods400 { case "management" :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonDelete _ => { cc => for { - (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(dynamicResourceDocId, cc.callContext) - (dynamicResourceDoc, callContext) <- NewStyle.function.deleteJsonDynamicResourceDocById(dynamicResourceDocId, callContext) + (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(None, dynamicResourceDocId, cc.callContext) + (dynamicResourceDoc, callContext) <- NewStyle.function.deleteJsonDynamicResourceDocById(None, dynamicResourceDocId, callContext) } yield { (dynamicResourceDoc, HttpCode.`204`(callContext)) } @@ -9144,7 +9144,7 @@ trait APIMethods400 { case "management" :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonGet _ => { cc => for { - (dynamicResourceDoc, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(dynamicResourceDocId, cc.callContext) + (dynamicResourceDoc, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(None, dynamicResourceDocId, cc.callContext) } yield { (dynamicResourceDoc, HttpCode.`200`(callContext)) } @@ -9175,13 +9175,228 @@ trait APIMethods400 { case "management" :: "dynamic-resource-docs" :: Nil JsonGet _ => { cc => for { - (dynamicResourceDocs, callContext) <- NewStyle.function.getJsonDynamicResourceDocs(cc.callContext) + (dynamicResourceDocs, callContext) <- NewStyle.function.getJsonDynamicResourceDocs(None, cc.callContext) } yield { (ListResult("dynamic-resource-docs", dynamicResourceDocs), HttpCode.`200`(callContext)) } } } + staticResourceDocs += ResourceDoc( + createBankLevelDynamicResourceDoc, + implementedInApiVersion, + nameOf(createBankLevelDynamicResourceDoc), + "POST", + "/management/banks/BANK_ID/dynamic-resource-docs", + "Create Bank Level Dynamic Resource Doc", + s"""Create a Bank Level Dynamic Resource Doc. + | + |The connector_method_body is URL-encoded format String + |""", + jsonDynamicResourceDoc.copy(dynamicResourceDocId=None), + jsonDynamicResourceDoc, + List( + $UserNotLoggedIn, + UserHasMissingRoles, + InvalidJsonFormat, + UnknownError + ), + List(apiTagDynamicResourceDoc, apiTagNewStyle), + Some(List(canCreateBankLevelDynamicResourceDoc))) + + lazy val createBankLevelDynamicResourceDoc: OBPEndpoint = { + case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: Nil JsonPost json -> _ => { + cc => + for { + jsonDynamicResourceDoc <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc", 400, cc.callContext) { + json.extract[JsonDynamicResourceDoc] + } + _ <- Helper.booleanToFuture(failMsg = s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", cc=cc.callContext) { + Set("POST", "PUT", "GET", "DELETE").contains(jsonDynamicResourceDoc.requestVerb) + } + _ <- Helper.booleanToFuture(failMsg = s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String "" or just totally omit the field""", cc=cc.callContext) { + (jsonDynamicResourceDoc.requestVerb, jsonDynamicResourceDoc.exampleRequestBody) match { + case ("GET" | "DELETE", Some(JString(s))) => //we support the empty string "" here + StringUtils.isBlank(s) + case ("GET" | "DELETE", Some(requestBody)) => //we add the guard, we forbid any json objects in GET/DELETE request body. + requestBody == JNothing + case _ => true + } + } + _ = try { + CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) + } catch { + case e: Exception => + val jsonResponse = createErrorJsonResponse(s"$DynamicCodeCompileFail ${e.getMessage}", 400, cc.correlationId) + throw JsonResponseException(jsonResponse) + } + + (isExists, callContext) <- NewStyle.function.isJsonDynamicResourceDocExists(Some(bankId), jsonDynamicResourceDoc.requestVerb, jsonDynamicResourceDoc.requestUrl, Some(cc)) + _ <- Helper.booleanToFuture(failMsg = s"$DynamicResourceDocAlreadyExists The combination of request_url(${jsonDynamicResourceDoc.requestUrl}) and request_verb(${jsonDynamicResourceDoc.requestVerb}) must be unique", cc=callContext) { + (!isExists) + } + + (dynamicResourceDoc, callContext) <- NewStyle.function.createJsonDynamicResourceDoc(Some(bankId), jsonDynamicResourceDoc, callContext) + } yield { + (dynamicResourceDoc, HttpCode.`201`(callContext)) + } + } + } + + staticResourceDocs += ResourceDoc( + updateBankLevelDynamicResourceDoc, + implementedInApiVersion, + nameOf(updateBankLevelDynamicResourceDoc), + "PUT", + "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", + "Update Bank Level Dynamic Resource Doc", + s"""Update a Bank Level Dynamic Resource Doc. + | + |The connector_method_body is URL-encoded format String + |""", + jsonDynamicResourceDoc.copy(dynamicResourceDocId = None), + jsonDynamicResourceDoc, + List( + $UserNotLoggedIn, + UserHasMissingRoles, + InvalidJsonFormat, + UnknownError + ), + List(apiTagDynamicResourceDoc, apiTagNewStyle), + Some(List(canUpdateBankLevelDynamicResourceDoc))) + + lazy val updateBankLevelDynamicResourceDoc: OBPEndpoint = { + case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonPut json -> _ => { + cc => + for { + dynamicResourceDocBody <- NewStyle.function.tryons(s"$InvalidJsonFormat The Json body should be the $JsonDynamicResourceDoc", 400, cc.callContext) { + json.extract[JsonDynamicResourceDoc] + } + + _ <- Helper.booleanToFuture(failMsg = s"""$InvalidJsonFormat The request_verb must be one of ["POST", "PUT", "GET", "DELETE"]""", cc=cc.callContext) { + Set("POST", "PUT", "GET", "DELETE").contains(dynamicResourceDocBody.requestVerb) + } + + _ <- Helper.booleanToFuture(failMsg = s"""$InvalidJsonFormat When request_verb is "GET" or "DELETE", the example_request_body must be a blank String""", cc=cc.callContext) { + (dynamicResourceDocBody.requestVerb, dynamicResourceDocBody.exampleRequestBody) match { + case ("GET" | "DELETE", Some(JString(s))) => + StringUtils.isBlank(s) + case ("GET" | "DELETE", Some(requestBody)) => + requestBody == JNothing + case _ => true + } + } + + _ = try { + CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) + } catch { + case e: Exception => + val jsonResponse = createErrorJsonResponse(s"$DynamicCodeCompileFail ${e.getMessage}", 400, cc.correlationId) + throw JsonResponseException(jsonResponse) + } + + (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(Some(bankId), dynamicResourceDocId, cc.callContext) + + (dynamicResourceDoc, callContext) <- NewStyle.function.updateJsonDynamicResourceDoc(Some(bankId), dynamicResourceDocBody.copy(dynamicResourceDocId = Some(dynamicResourceDocId)), callContext) + } yield { + (dynamicResourceDoc, HttpCode.`200`(callContext)) + } + } + } + + staticResourceDocs += ResourceDoc( + deleteBankLevelDynamicResourceDoc, + implementedInApiVersion, + nameOf(deleteBankLevelDynamicResourceDoc), + "DELETE", + "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", + "Delete Bank Level Dynamic Resource Doc", + s"""Delete a Bank Level Dynamic Resource Doc. + |""", + EmptyBody, + BooleanBody(true), + List( + $UserNotLoggedIn, + UserHasMissingRoles, + InvalidJsonFormat, + UnknownError + ), + List(apiTagDynamicResourceDoc, apiTagNewStyle), + Some(List(canDeleteBankLevelDynamicResourceDoc))) + + lazy val deleteBankLevelDynamicResourceDoc: OBPEndpoint = { + case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonDelete _ => { + cc => + for { + (_, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(Some(bankId), dynamicResourceDocId, cc.callContext) + (dynamicResourceDoc, callContext) <- NewStyle.function.deleteJsonDynamicResourceDocById(Some(bankId), dynamicResourceDocId, callContext) + } yield { + (dynamicResourceDoc, HttpCode.`204`(callContext)) + } + } + } + + staticResourceDocs += ResourceDoc( + getBankLevelDynamicResourceDoc, + implementedInApiVersion, + nameOf(getBankLevelDynamicResourceDoc), + "GET", + "/management/banks/BANK_ID/dynamic-resource-docs/DYNAMIC-RESOURCE-DOC-ID", + "Get Bank Level Dynamic Resource Doc by Id", + s"""Get a Bank Level Dynamic Resource Doc by DYNAMIC-RESOURCE-DOC-ID. + | + |""", + EmptyBody, + jsonDynamicResourceDoc, + List( + $UserNotLoggedIn, + UserHasMissingRoles, + UnknownError + ), + List(apiTagDynamicResourceDoc, apiTagNewStyle), + Some(List(canGetBankLevelDynamicResourceDoc))) + + lazy val getBankLevelDynamicResourceDoc: OBPEndpoint = { + case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: dynamicResourceDocId :: Nil JsonGet _ => { + cc => + for { + (dynamicResourceDoc, callContext) <- NewStyle.function.getJsonDynamicResourceDocById(Some(bankId), dynamicResourceDocId, cc.callContext) + } yield { + (dynamicResourceDoc, HttpCode.`200`(callContext)) + } + } + } + + staticResourceDocs += ResourceDoc( + getAllBankLevelDynamicResourceDocs, + implementedInApiVersion, + nameOf(getAllBankLevelDynamicResourceDocs), + "GET", + "/management/banks/BANK_ID/dynamic-resource-docs", + "Get all Bank Level Dynamic Resource Docs", + s"""Get all Bank Level Dynamic Resource Docs. + | + |""", + EmptyBody, + ListResult("dynamic-resource-docs", jsonDynamicResourceDoc::Nil), + List( + $UserNotLoggedIn, + UserHasMissingRoles, + UnknownError + ), + List(apiTagDynamicResourceDoc, apiTagNewStyle), + Some(List(canGetAllBankLevelDynamicResourceDocs))) + + lazy val getAllBankLevelDynamicResourceDocs: OBPEndpoint = { + case "management" :: "banks" :: bankId :: "dynamic-resource-docs" :: Nil JsonGet _ => { + cc => + for { + (dynamicResourceDocs, callContext) <- NewStyle.function.getJsonDynamicResourceDocs(Some(bankId), cc.callContext) + } yield { + (ListResult("dynamic-resource-docs", dynamicResourceDocs), HttpCode.`200`(callContext)) + } + } + } staticResourceDocs += ResourceDoc( buildDynamicEndpointTemplate, diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala index 622c02ede..7ddae771b 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicResourceDocsEndpointGroup.scala @@ -13,7 +13,7 @@ object DynamicResourceDocsEndpointGroup extends EndpointGroup { override protected def resourceDocs: List[APIUtil.ResourceDoc] = - DynamicResourceDocProvider.provider.vend.getAllAndConvert(toResourceDoc) + DynamicResourceDocProvider.provider.vend.getAllAndConvert(None, toResourceDoc) //TODO need to check if this can be `NONE` private val apiVersion : ScannedApiVersion = ApiVersion.v4_0_0 diff --git a/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDocProvider.scala b/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDocProvider.scala index dd60f8c0d..db23aef98 100644 --- a/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDocProvider.scala +++ b/obp-api/src/main/scala/code/dynamicResourceDoc/DynamicResourceDocProvider.scala @@ -39,15 +39,15 @@ case class JsonDynamicResourceDoc( trait DynamicResourceDocProvider { - def getById(dynamicResourceDocId: String): Box[JsonDynamicResourceDoc] - def getByVerbAndUrl(requestVerb: String, requestUrl: String): Box[JsonDynamicResourceDoc] + def getById(bankId: Option[String], dynamicResourceDocId: String): Box[JsonDynamicResourceDoc] + def getByVerbAndUrl(bankId: Option[String], requestVerb: String, requestUrl: String): Box[JsonDynamicResourceDoc] - def getAll(): List[JsonDynamicResourceDoc] = getAllAndConvert(identity) + def getAll(bankId: Option[String]): List[JsonDynamicResourceDoc] = getAllAndConvert(bankId, identity) - def getAllAndConvert[T: Manifest](transform: JsonDynamicResourceDoc => T): List[T] + def getAllAndConvert[T: Manifest](bankId: Option[String], transform: JsonDynamicResourceDoc => T): List[T] - def create(entity: JsonDynamicResourceDoc): Box[JsonDynamicResourceDoc] - def update(entity: JsonDynamicResourceDoc): Box[JsonDynamicResourceDoc] - def deleteById(dynamicResourceDocId: String): Box[Boolean] + def create(bankId: Option[String], entity: JsonDynamicResourceDoc): Box[JsonDynamicResourceDoc] + def update(bankId: Option[String], entity: JsonDynamicResourceDoc): Box[JsonDynamicResourceDoc] + def deleteById(bankId: Option[String], dynamicResourceDocId: String): Box[Boolean] } diff --git a/obp-api/src/main/scala/code/dynamicResourceDoc/MappedDynamicResourceDocProvider.scala b/obp-api/src/main/scala/code/dynamicResourceDoc/MappedDynamicResourceDocProvider.scala index 15f6222d2..f5c8ae2cc 100644 --- a/obp-api/src/main/scala/code/dynamicResourceDoc/MappedDynamicResourceDocProvider.scala +++ b/obp-api/src/main/scala/code/dynamicResourceDoc/MappedDynamicResourceDocProvider.scala @@ -20,29 +20,58 @@ object MappedDynamicResourceDocProvider extends DynamicResourceDocProvider { else APIUtil.getPropsValue(s"dynamicResourceDoc.cache.ttl.seconds", "40").toInt } - override def getById(dynamicResourceDocId: String): Box[JsonDynamicResourceDoc] = DynamicResourceDoc - .find(By(DynamicResourceDoc.DynamicResourceDocId, dynamicResourceDocId)) - .map(DynamicResourceDoc.getJsonDynamicResourceDoc) + override def getById(bankId: Option[String], dynamicResourceDocId: String): Box[JsonDynamicResourceDoc] = { + if(bankId.isEmpty){ + DynamicResourceDoc + .find(By(DynamicResourceDoc.DynamicResourceDocId, dynamicResourceDocId)) + .map(DynamicResourceDoc.getJsonDynamicResourceDoc) + } else{ + DynamicResourceDoc + .find( + By(DynamicResourceDoc.DynamicResourceDocId, dynamicResourceDocId), + By(DynamicResourceDoc.BankId, bankId.getOrElse("")), + ) + .map(DynamicResourceDoc.getJsonDynamicResourceDoc) + } + } - override def getByVerbAndUrl(requestVerb: String, requestUrl: String): Box[JsonDynamicResourceDoc] = DynamicResourceDoc - .find(By(DynamicResourceDoc.RequestVerb, requestVerb), By(DynamicResourceDoc.RequestUrl, requestUrl)) - .map(DynamicResourceDoc.getJsonDynamicResourceDoc) + override def getByVerbAndUrl(bankId: Option[String], requestVerb: String, requestUrl: String): Box[JsonDynamicResourceDoc] = + if(bankId.isEmpty){ + DynamicResourceDoc + .find(By(DynamicResourceDoc.RequestVerb, requestVerb), By(DynamicResourceDoc.RequestUrl, requestUrl)) + .map(DynamicResourceDoc.getJsonDynamicResourceDoc) + } else{ + DynamicResourceDoc + .find( + By(DynamicResourceDoc.BankId, bankId.getOrElse("")), + By(DynamicResourceDoc.RequestVerb, requestVerb), + By(DynamicResourceDoc.RequestUrl, requestUrl)) + .map(DynamicResourceDoc.getJsonDynamicResourceDoc) + } - override def getAllAndConvert[T: Manifest](transform: JsonDynamicResourceDoc => T): List[T] = { + override def getAllAndConvert[T: Manifest](bankId: Option[String], transform: JsonDynamicResourceDoc => T): List[T] = { var cacheKey = (randomUUID().toString, randomUUID().toString, randomUUID().toString) CacheKeyFromArguments.buildCacheKey { Caching.memoizeSyncWithProvider (Some(cacheKey.toString())) (getDynamicResourceDocTTL second) { - DynamicResourceDoc.findAll() - .map(doc => transform(DynamicResourceDoc.getJsonDynamicResourceDoc(doc))) - }} + if(bankId.isEmpty){ + DynamicResourceDoc.findAll() + .map(doc => transform(DynamicResourceDoc.getJsonDynamicResourceDoc(doc))) + } else { + DynamicResourceDoc.findAll( + By(DynamicResourceDoc.BankId, bankId.getOrElse(""))) + .map(doc => transform(DynamicResourceDoc.getJsonDynamicResourceDoc(doc))) + } + } + } } - override def create(entity: JsonDynamicResourceDoc): Box[JsonDynamicResourceDoc]= + override def create(bankId: Option[String], entity: JsonDynamicResourceDoc): Box[JsonDynamicResourceDoc]= tryo { val requestBody = entity.exampleRequestBody.map(json.compactRender(_)).orNull val responseBody = entity.successResponseBody.map(json.compactRender(_)).orNull DynamicResourceDoc.create + .BankId(bankId.getOrElse(null)) .DynamicResourceDocId(APIUtil.generateUUID()) .PartialFunctionName(entity.partialFunctionName) .RequestVerb(entity.requestVerb) @@ -59,13 +88,14 @@ object MappedDynamicResourceDocProvider extends DynamicResourceDocProvider { }.map(DynamicResourceDoc.getJsonDynamicResourceDoc) - override def update(entity: JsonDynamicResourceDoc): Box[JsonDynamicResourceDoc] = { + override def update(bankId: Option[String], entity: JsonDynamicResourceDoc): Box[JsonDynamicResourceDoc] = { DynamicResourceDoc.find(By(DynamicResourceDoc.DynamicResourceDocId, entity.dynamicResourceDocId.getOrElse(""))) match { case Full(v) => tryo { val requestBody = entity.exampleRequestBody.map(json.compactRender(_)).orNull val responseBody = entity.successResponseBody.map(json.compactRender(_)).orNull v.PartialFunctionName(entity.partialFunctionName) + .BankId(bankId.getOrElse(null)) .RequestVerb(entity.requestVerb) .RequestUrl(entity.requestUrl) .Summary(entity.summary) @@ -82,8 +112,15 @@ object MappedDynamicResourceDocProvider extends DynamicResourceDocProvider { } } - override def deleteById(id: String): Box[Boolean] = tryo { - DynamicResourceDoc.bulkDelete_!!(By(DynamicResourceDoc.DynamicResourceDocId, id)) + override def deleteById(bankId: Option[String], id: String): Box[Boolean] = tryo { + if(bankId.isEmpty) { + DynamicResourceDoc.bulkDelete_!!(By(DynamicResourceDoc.DynamicResourceDocId, id)) + }else{ + DynamicResourceDoc.bulkDelete_!!( + By(DynamicResourceDoc.BankId, bankId.getOrElse("")), + By(DynamicResourceDoc.DynamicResourceDocId, id) + ) + } } } From 0a7ddb1a18f8ad822869ca06c23da2114301ca06 Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 25 Oct 2021 12:34:33 +0200 Subject: [PATCH 07/37] bugfix/tweaked the method name --- obp-api/src/main/scala/code/api/util/DynamicUtil.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala index 8ec1d6d48..f50663bd1 100644 --- a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala +++ b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala @@ -151,7 +151,7 @@ object DynamicUtil { ternary @ (typeName, methodName, signature) <- APIUtil.getDependentMethods(className, method.getName, method.getSignature) } yield { // if method is also dynamic compile code, extract it's dependent method - if(className.startsWith(typeName) && methodName.startsWith(clazz.getPackageName + "$")) { + if(className.startsWith(typeName) && methodName.startsWith(clazz.getPackage.getName+ "$")) { listBuffer.appendAll(APIUtil.getDependentMethods(typeName, methodName, signature)) } else { listBuffer.append(ternary) From 3f1ad7fb5484458671773a05e83c8c9f8912103e Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 25 Oct 2021 13:47:35 +0200 Subject: [PATCH 08/37] feature/modify requiresBankId =true for bankLevel roles --- obp-api/src/main/scala/code/api/util/ApiRole.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/ApiRole.scala b/obp-api/src/main/scala/code/api/util/ApiRole.scala index c5fd961df..a90e1db54 100644 --- a/obp-api/src/main/scala/code/api/util/ApiRole.scala +++ b/obp-api/src/main/scala/code/api/util/ApiRole.scala @@ -747,19 +747,19 @@ object ApiRole { case class CanDeleteDynamicResourceDoc(requiresBankId: Boolean = false) extends ApiRole lazy val canDeleteDynamicResourceDoc = CanDeleteDynamicResourceDoc() - case class CanCreateBankLevelDynamicResourceDoc(requiresBankId: Boolean = false) extends ApiRole + case class CanCreateBankLevelDynamicResourceDoc(requiresBankId: Boolean = true) extends ApiRole lazy val canCreateBankLevelDynamicResourceDoc = CanCreateBankLevelDynamicResourceDoc() - case class CanUpdateBankLevelDynamicResourceDoc(requiresBankId: Boolean = false) extends ApiRole + case class CanUpdateBankLevelDynamicResourceDoc(requiresBankId: Boolean = true) extends ApiRole lazy val canUpdateBankLevelDynamicResourceDoc = CanUpdateBankLevelDynamicResourceDoc() - case class CanGetBankLevelDynamicResourceDoc(requiresBankId: Boolean = false) extends ApiRole + case class CanGetBankLevelDynamicResourceDoc(requiresBankId: Boolean = true) extends ApiRole lazy val canGetBankLevelDynamicResourceDoc = CanGetBankLevelDynamicResourceDoc() - case class CanGetAllBankLevelDynamicResourceDocs(requiresBankId: Boolean = false) extends ApiRole + case class CanGetAllBankLevelDynamicResourceDocs(requiresBankId: Boolean = true) extends ApiRole lazy val canGetAllBankLevelDynamicResourceDocs = CanGetAllBankLevelDynamicResourceDocs() - case class CanDeleteBankLevelDynamicResourceDoc(requiresBankId: Boolean = false) extends ApiRole + case class CanDeleteBankLevelDynamicResourceDoc(requiresBankId: Boolean = true) extends ApiRole lazy val canDeleteBankLevelDynamicResourceDoc = CanDeleteBankLevelDynamicResourceDoc() case class CanCreateDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole @@ -774,7 +774,7 @@ object ApiRole { case class CanGetDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole lazy val canGetDynamicMessageDoc = CanGetDynamicMessageDoc() - case class CanGetBankLevelDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole + case class CanGetBankLevelDynamicMessageDoc(requiresBankId: Boolean = true) extends ApiRole lazy val canGetBankLevelDynamicMessageDoc = CanGetBankLevelDynamicMessageDoc() case class CanGetAllDynamicMessageDocs(requiresBankId: Boolean = false) extends ApiRole @@ -783,7 +783,7 @@ object ApiRole { case class CanDeleteDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole lazy val canDeleteDynamicMessageDoc = CanDeleteDynamicMessageDoc() - case class CanDeleteBankLevelDynamicMessageDoc(requiresBankId: Boolean = false) extends ApiRole + case class CanDeleteBankLevelDynamicMessageDoc(requiresBankId: Boolean = true) extends ApiRole lazy val canDeleteBankLevelDynamicMessageDoc = CanDeleteBankLevelDynamicMessageDoc() case class CanCreateEndpointMapping(requiresBankId: Boolean = false) extends ApiRole From 2bc4f241d8adf25e006295e71cd651b5fce04fb4 Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 25 Oct 2021 15:01:57 +0200 Subject: [PATCH 09/37] feature/added the BankId guard to all the bank level endpoints --- .../src/main/scala/code/api/v4_0_0/APIMethods400.scala | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 3c67dddd6..b43503087 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -9196,6 +9196,7 @@ trait APIMethods400 { jsonDynamicResourceDoc.copy(dynamicResourceDocId=None), jsonDynamicResourceDoc, List( + $BankNotFound, $UserNotLoggedIn, UserHasMissingRoles, InvalidJsonFormat, @@ -9257,6 +9258,7 @@ trait APIMethods400 { jsonDynamicResourceDoc.copy(dynamicResourceDocId = None), jsonDynamicResourceDoc, List( + $BankNotFound, $UserNotLoggedIn, UserHasMissingRoles, InvalidJsonFormat, @@ -9316,6 +9318,7 @@ trait APIMethods400 { EmptyBody, BooleanBody(true), List( + $BankNotFound, $UserNotLoggedIn, UserHasMissingRoles, InvalidJsonFormat, @@ -9349,6 +9352,7 @@ trait APIMethods400 { EmptyBody, jsonDynamicResourceDoc, List( + $BankNotFound, $UserNotLoggedIn, UserHasMissingRoles, UnknownError @@ -9380,6 +9384,7 @@ trait APIMethods400 { EmptyBody, ListResult("dynamic-resource-docs", jsonDynamicResourceDoc::Nil), List( + $BankNotFound, $UserNotLoggedIn, UserHasMissingRoles, UnknownError @@ -9505,6 +9510,7 @@ trait APIMethods400 { jsonDynamicMessageDoc.copy(dynamicMessageDocId=None), jsonDynamicMessageDoc, List( + $BankNotFound, $UserNotLoggedIn, UserHasMissingRoles, InvalidJsonFormat, @@ -9684,6 +9690,7 @@ trait APIMethods400 { jsonDynamicMessageDoc.copy(dynamicMessageDocId=None), jsonDynamicMessageDoc, List( + $BankNotFound, $UserNotLoggedIn, UserHasMissingRoles, InvalidJsonFormat, @@ -9726,6 +9733,7 @@ trait APIMethods400 { EmptyBody, jsonDynamicMessageDoc, List( + $BankNotFound, $UserNotLoggedIn, UserHasMissingRoles, UnknownError @@ -9757,6 +9765,7 @@ trait APIMethods400 { EmptyBody, ListResult("dynamic-message-docs", jsonDynamicMessageDoc::Nil), List( + $BankNotFound, $UserNotLoggedIn, UserHasMissingRoles, UnknownError @@ -9787,6 +9796,7 @@ trait APIMethods400 { EmptyBody, BooleanBody(true), List( + $BankNotFound, $UserNotLoggedIn, UserHasMissingRoles, InvalidJsonFormat, From 94b7fcac99bcc2035f6a552f736ea1836930e81b Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 25 Oct 2021 15:17:13 +0200 Subject: [PATCH 10/37] feature/added the validateDependency for bankLevel endpoints --- .../scala/code/api/v4_0_0/APIMethods400.scala | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index b43503087..92a919e33 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -3,7 +3,7 @@ package code.api.v4_0_0 import code.DynamicData.{DynamicData, DynamicDataProvider} import code.DynamicEndpoint.DynamicEndpointSwagger import code.accountattribute.AccountAttributeX -import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._ +import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{jsonDynamicResourceDoc, _} import code.api.util.APIUtil.{fullBoxOrException, _} import code.api.util.ApiRole._ import code.api.util.ApiTag._ @@ -9224,6 +9224,14 @@ trait APIMethods400 { case _ => true } } + _ = try { + CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) + .validateDependency() + } catch { + case e: Exception => + val jsonResponse = createErrorJsonResponse(s"$DynamicCodeCompileFail ${e.getMessage}", 400, cc.correlationId) + throw JsonResponseException(jsonResponse) + } _ = try { CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) } catch { @@ -9288,9 +9296,17 @@ trait APIMethods400 { case _ => true } } + _ = try { + CompiledObjects(dynamicResourceDocBody.exampleRequestBody, dynamicResourceDocBody.successResponseBody, dynamicResourceDocBody.methodBody) + .validateDependency() + } catch { + case e: Exception => + val jsonResponse = createErrorJsonResponse(s"$DynamicCodeCompileFail ${e.getMessage}", 400, cc.correlationId) + throw JsonResponseException(jsonResponse) + } _ = try { - CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) + CompiledObjects(dynamicResourceDocBody.exampleRequestBody, dynamicResourceDocBody.successResponseBody, jsonDynamicResourceDoc.methodBody) } catch { case e: Exception => val jsonResponse = createErrorJsonResponse(s"$DynamicCodeCompileFail ${e.getMessage}", 400, cc.correlationId) From a99b0cce2fd0fdf1badde04a1672a952d07f58d6 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 30 Nov 2021 12:21:21 +0100 Subject: [PATCH 11/37] bugfix/show clear error message to developers for validateDependency method --- .../src/main/scala/code/api/v4_0_0/APIMethods400.scala | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 92a919e33..c71dcb5d3 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -9009,6 +9009,8 @@ trait APIMethods400 { CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) .validateDependency() } catch { + case e: JsonResponseException => + throw e case e: Exception => val jsonResponse = createErrorJsonResponse(s"$DynamicCodeCompileFail ${e.getMessage}", 400, cc.correlationId) throw JsonResponseException(jsonResponse) @@ -9074,6 +9076,8 @@ trait APIMethods400 { CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) .validateDependency() } catch { + case e: JsonResponseException => + throw e case e: Exception => val jsonResponse = createErrorJsonResponse(s"$DynamicCodeCompileFail ${e.getMessage}", 400, cc.correlationId) throw JsonResponseException(jsonResponse) @@ -9228,6 +9232,8 @@ trait APIMethods400 { CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) .validateDependency() } catch { + case e: JsonResponseException => + throw e case e: Exception => val jsonResponse = createErrorJsonResponse(s"$DynamicCodeCompileFail ${e.getMessage}", 400, cc.correlationId) throw JsonResponseException(jsonResponse) @@ -9300,6 +9306,8 @@ trait APIMethods400 { CompiledObjects(dynamicResourceDocBody.exampleRequestBody, dynamicResourceDocBody.successResponseBody, dynamicResourceDocBody.methodBody) .validateDependency() } catch { + case e: JsonResponseException => + throw e case e: Exception => val jsonResponse = createErrorJsonResponse(s"$DynamicCodeCompileFail ${e.getMessage}", 400, cc.correlationId) throw JsonResponseException(jsonResponse) From 855937cb853c4115c1cfe206cc1657b7727c5fa2 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Dec 2021 09:21:39 +0100 Subject: [PATCH 12/37] docfix/added the document for requestRootJsonClass --- .../SwaggerDefinitionsJSON.scala | 2 ++ .../main/scala/code/api/util/ExampleValue.scala | 3 +++ .../src/main/scala/code/api/util/Glossary.scala | 7 +++++++ .../dynamic/practise/PractiseEndpointGroup.scala | 15 ++++++++++++--- 4 files changed, 24 insertions(+), 3 deletions(-) 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 cbf7e8a97..f5dca13c4 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 @@ -4472,6 +4472,8 @@ object SwaggerDefinitionsJSON { description = descriptionExample.value, meta = metaJson, ) + + val requestRootJsonClass = dynamic.practise.PractiseEndpoint.RequestRootJsonClass(name = nameExample.value, age=ageExample.value.toLong, Nil) //The common error or success format. 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 c8b5aa220..c196dbc8a 100644 --- a/obp-api/src/main/scala/code/api/util/ExampleValue.scala +++ b/obp-api/src/main/scala/code/api/util/ExampleValue.scala @@ -1611,6 +1611,9 @@ object ExampleValue { lazy val nameExample = ConnectorField("ACCOUNT_MANAGEMENT_FEE",NoDescriptionProvided) glossaryItems += makeGlossaryItem("name", nameExample) + lazy val ageExample = ConnectorField("18", "The user age.") + glossaryItems += makeGlossaryItem("age", nameExample) + lazy val productFeeIdExample = ConnectorField(NoExampleProvided,NoDescriptionProvided) glossaryItems += makeGlossaryItem("product_fee_id", nameExample) diff --git a/obp-api/src/main/scala/code/api/util/Glossary.scala b/obp-api/src/main/scala/code/api/util/Glossary.scala index 2bd3a303e..5bd383d30 100644 --- a/obp-api/src/main/scala/code/api/util/Glossary.scala +++ b/obp-api/src/main/scala/code/api/util/Glossary.scala @@ -616,6 +616,13 @@ object Glossary extends MdcLoggable { |""" ) + glossaryItems += GlossaryItem( + title = + "Age", + description = + """The user Age""" + ) + glossaryItems += GlossaryItem( title = "Account.account_id", description = diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpointGroup.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpointGroup.scala index 7f809393e..a1ee62b9e 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpointGroup.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpointGroup.scala @@ -1,5 +1,6 @@ package code.api.v4_0_0.dynamic.practise +import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.requestRootJsonClass import code.api.util.APIUtil import code.api.util.APIUtil.{ResourceDoc, StringBody} import code.api.util.ApiTag.{apiTagDynamicResourceDoc, apiTagNewStyle} @@ -24,10 +25,18 @@ object PractiseEndpointGroup extends EndpointGroup{ PractiseEndpoint.requestUrl, "A test endpoint", s"""A test endpoint. - |Just for debug method body of dynamic resource doc + | + |Just for debug method body of dynamic resource doc. + |better watch the following introduction video first + |* [Dynamic resourceDoc version1](https://vimeo.com/623381607) + | + |The endpoint return the response from PractiseEndpoint code. + |Here, code.api.v4_0_0.dynamic.practise.PractiseEndpoint.process + |You can test the method body grammar, and try the business logic, but need to restart the OBP-API code . + | |""", - StringBody("Any request body"), - StringBody("Any response body"), + requestRootJsonClass, + requestRootJsonClass, List( UnknownError ), From c713e2453ffb4f39fbd09ff0f7f0cd05ae74270c Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Dec 2021 10:01:37 +0100 Subject: [PATCH 13/37] docfix/added the comments for PractiseEndpoint --- .../api/v4_0_0/dynamic/practise/PractiseEndpoint.scala | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala index bcc97151e..86e25a6be 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala @@ -4,6 +4,14 @@ package code.api.v4_0_0.dynamic.practise /** * practise new endpoint at this object, don't commit you practise code to git + * + * This endpoint is only for testing new dynamic resource/messages method body. + * eg: when you try the create dynamic resource doc endpoint, you need to prepare the method body properly. + * you can prepare the obp scala code just under the method: + * `process(callContext: CallContext, request: Req, pathParams: Map[String, String])`, + * + * + * */ object PractiseEndpoint extends code.api.v4_0_0.dynamic.DynamicCompileEndpoint { // don't modify these import statement From 7139560a0bf9ccb2319f6234f73fc1138cee225e Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Dec 2021 16:44:56 +0100 Subject: [PATCH 14/37] feature/tweaked a bit the error message for DynamicResourceDocMethodPermission --- obp-api/src/main/scala/code/api/util/APIUtil.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b5bb324ec..3d8ed0877 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -2468,7 +2468,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{ } scf.onFailure { case e: AccessControlException => - laf.fail(Failure(s"$DynamicResourceDocMethodPermission No permission of: ${e.getPermission.getName}", Full(e), Empty)) + laf.fail(Failure(s"$DynamicResourceDocMethodPermission No permission of: ${e.getPermission.toString}", Full(e), Empty)) case e: Throwable => laf.fail(Failure(e.getMessage(), Full(e), Empty)) From 1673009dd4ce306f97520c4860a68446302925d5 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 1 Dec 2021 18:12:02 +0100 Subject: [PATCH 15/37] docfix/added the comments for `allowedRuntimePermissions`, `allowedCompilationMethods` and `restrictedTypes` variables. --- .../scala/code/api/util/DynamicUtil.scala | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala index f50663bd1..84eeffefc 100644 --- a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala +++ b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala @@ -209,7 +209,7 @@ object DynamicUtil { private val memoSandbox = new Memo[String, Sandbox] def sandbox(bankId: String): Sandbox = memoSandbox.memoize(bankId) { - Sandbox.createSandbox(BankId.permission(bankId) :: Validation.permissions) + Sandbox.createSandbox(BankId.permission(bankId) :: Validation.allowedRuntimePermissions) } } @@ -266,7 +266,14 @@ object DynamicUtil { object Validation { // all Permissions put at here - val permissions = List[Permission]( + // Here is the Java Permission document, please extend these permissions carefully. + // https://docs.oracle.com/javase/8/docs/technotes/guides/security/spec/security-spec.doc3.html#17001 + // If you are not familiar with the permissions, we provide the clear error messages for the missing permissions in the log. + // eg: "OBP-40047: DynamicResourceDoc method have no enough permissions. No permission of: (\"java.io.FilePermission\" \"stop-words-en.txt\" \"write\")" + // --> you can extends following permission: new java.net.SocketPermission("ir.dcs.gla.ac.uk:80", "connect,resolve"), + // + // NOTE: These permissions are only checked during runtime, not the compilation period. + val allowedRuntimePermissions = List[Permission]( new NetPermission("specifyStreamHandler"), new ReflectPermission("suppressAccessChecks"), new RuntimePermission("getenv.*"), @@ -277,8 +284,15 @@ object DynamicUtil { new RuntimePermission("getClassLoader"), ) + /** + * Compilation OBP Dependencies Guard, only checked the OBP methods, not scala/Java libraies(are checked during the runtime.). + * + * allowedCompilationMethods --> + * The following methods will be checked when you call the `Create Dynamic ResourceDoc/MessageDoc` endpoints. + * You can control all the OBP methods here. + */ // all allowed methods put at here, typeName -> methods - val allowedMethods: Map[String, Set[String]] = Map( + val allowedCompilationMethods: Map[String, Set[String]] = Map( // companion objects methods NewStyle.function.getClass.getTypeName -> "*", CompiledObjects.getClass.getTypeName -> "sandbox", @@ -300,6 +314,7 @@ object DynamicUtil { ).mapValues(v => StringUtils.split(v, ',').map(_.trim).toSet) + //Do not touch this Set, try to use the `allowedPermissions` and `allowedMethods` to control the sandbox val restrictedTypes = Set( "scala.reflect.runtime.", "java.lang.reflect.", @@ -315,8 +330,8 @@ object DynamicUtil { val notAllowedDependentMethods = dependentMethods collect { case (typeName, method, _) if isRestrictedType(typeName) && - !allowedMethods.get(typeName).exists(set => set.contains(method) || set.contains("*")) && - !allowedMethods.exists { it => + !allowedCompilationMethods.get(typeName).exists(set => set.contains(method) || set.contains("*")) && + !allowedCompilationMethods.exists { it => val (tpName, allowedMethods) = it tpName.endsWith("*") && typeName.startsWith(StringUtils.substringBeforeLast(tpName, "*")) && From eadf419703b0cb58fd1f6378cfeca7fb8781e215 Mon Sep 17 00:00:00 2001 From: hongwei Date: Fri, 3 Dec 2021 11:06:00 +0100 Subject: [PATCH 16/37] docfix/added some comments for validateDependency --- obp-api/src/main/scala/code/api/util/DynamicUtil.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala index 84eeffefc..d27715822 100644 --- a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala +++ b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala @@ -325,6 +325,8 @@ object DynamicUtil { /** * validate dependencies, (className, methodName, signature) + * + * Here only validate the restricted types(isObpClass + val restrictedTypes), not all scala/java types. */ private def validateDependency(dependentMethods: List[(String, String, String)]) = { val notAllowedDependentMethods = dependentMethods collect { From 2c5bb2ccd1bcb203adad333ade29f89bf6f5177d Mon Sep 17 00:00:00 2001 From: hongwei Date: Fri, 3 Dec 2021 12:00:15 +0100 Subject: [PATCH 17/37] feature/added the props dynamic_code_compile_validate_enable --- obp-api/src/main/resources/props/sample.props.template | 5 ++++- obp-api/src/main/scala/code/api/util/DynamicUtil.scala | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/obp-api/src/main/resources/props/sample.props.template b/obp-api/src/main/resources/props/sample.props.template index bb182714c..42f49a618 100644 --- a/obp-api/src/main/resources/props/sample.props.template +++ b/obp-api/src/main/resources/props/sample.props.template @@ -1081,4 +1081,7 @@ webui_developer_user_invitation_email_html_text=\ # enable dynamic code sandbox, default is false, this will make sandbox works for code running in Future, will make performance lower than disable -dynamic_code_sandbox_enable=false \ No newline at end of file +dynamic_code_sandbox_enable=false +# enable dynamic code compile validation, default is false, if set it to true, it will validate all the dynamic method body when you create/update any +# dynamic scala method. Note, it only check all the obp code dependents for all the method in scala code. +dynamic_code_compile_validate_enable=false \ No newline at end of file diff --git a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala index d27715822..3e625b2ee 100644 --- a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala +++ b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala @@ -350,8 +350,12 @@ object DynamicUtil { } def validateDependency(obj: AnyRef): Unit = { - val dependentMethods: List[(String, String, String)] = DynamicUtil.getDynamicCodeDependentMethods(obj.getClass) - validateDependency(dependentMethods) + if(APIUtil.getPropsAsBoolValue("dynamic_code_compile_validate_enable",false)){ + val dependentMethods: List[(String, String, String)] = DynamicUtil.getDynamicCodeDependentMethods(obj.getClass) + validateDependency(dependentMethods) + } else{ // If false, nothing to do here. + ; + } } } } From c8b9ee6f72f3a437793d94f2a78de656b4c42c7c Mon Sep 17 00:00:00 2001 From: hongwei Date: Fri, 3 Dec 2021 13:27:12 +0100 Subject: [PATCH 18/37] docfix/added the comments for validateDependency and sandboxEndpoint --- .../code/api/v4_0_0/dynamic/DynamicEndpoints.scala | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala index 903d606cf..bffb5c3ec 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEndpoints.scala @@ -190,8 +190,18 @@ case class CompiledObjects(exampleRequestBody: Option[JValue], successResponseBo } } + /** + * this will check all the dynamic scala code dependencies at compile time. + * + *Search for the usage, you can see how to use it in OBP code. + */ def validateDependency() = Validation.validateDependency(this.partialFunction) + /** + * This is used to check the security permission at the run time. + * all the obp partialFunctions will be wrapped into the sandbox which under the permission control. + * + */ def sandboxEndpoint(bankId: Option[String]) : OBPEndpoint = { val sandbox = bankId match { case Some(v) if StringUtils.isNotBlank(v) => From 266ac759ea722fcd209e699e8d42993b68c81eaf Mon Sep 17 00:00:00 2001 From: hongwei Date: Fri, 3 Dec 2021 15:03:20 +0100 Subject: [PATCH 19/37] feature/added the validateDependency for create/update messgeDocs -WIP --- obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala | 3 ++- .../src/main/scala/code/bankconnectors/InternalConnector.scala | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index c71dcb5d3..e83e1c7d6 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -8850,7 +8850,7 @@ trait APIMethods400 { _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=callContext) { connectorMethod.isDefined } - + _ = Validation.validateDependency(connectorMethod.orNull) (connectorMethod, callContext) <- NewStyle.function.createJsonConnectorMethod(jsonConnectorMethod, callContext) } yield { (connectorMethod, HttpCode.`201`(callContext)) @@ -8895,6 +8895,7 @@ trait APIMethods400 { _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=callContext) { connectorMethod.isDefined } + _ = Validation.validateDependency(connectorMethod.orNull) (connectorMethod, callContext) <- NewStyle.function.updateJsonConnectorMethod(connectorMethodId, connectorMethodBody.methodBody, callContext) } yield { (connectorMethod, HttpCode.`200`(callContext)) diff --git a/obp-api/src/main/scala/code/bankconnectors/InternalConnector.scala b/obp-api/src/main/scala/code/bankconnectors/InternalConnector.scala index a35b9f993..aa54a69d1 100644 --- a/obp-api/src/main/scala/code/bankconnectors/InternalConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/InternalConnector.scala @@ -50,7 +50,7 @@ object InternalConnector { * @param methodBody method body of connector method * @return function of connector method that is dynamic created, can be Function0, Function1, Function2... */ - def createFunction(methodName: String, methodBody:String): Box[Any] = + def createFunction(methodName: String, methodBody:String)= methodNameToSignature.get(methodName) match { case Some(signature) => val method = s""" From cfa3bb172c2b8f8be32dee68e100460608fceb13 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 11 Jan 2022 11:29:19 +0100 Subject: [PATCH 20/37] feature/added the new standard BHOBFv100 --- .../v1_0_0/AccountAccessConsentsApi.scala | 259 ++++++ .../api/BahrainOBF/v1_0_0/AccountsApi.scala | 155 ++++ .../api/BahrainOBF/v1_0_0/ApiCollector.scala | 110 +++ .../api/BahrainOBF/v1_0_0/BalancesApi.scala | 299 ++++++ .../BahrainOBF/v1_0_0/BeneficiariesApi.scala | 155 ++++ .../BahrainOBF/v1_0_0/DirectDebitsApi.scala | 259 ++++++ ...omesticFutureDatedPaymentConsentsApi.scala | 689 ++++++++++++++ .../DomesticFutureDatedPaymentsApi.scala | 761 +++++++++++++++ .../v1_0_0/DomesticPaymentsApi.scala | 561 +++++++++++ .../v1_0_0/DomesticPaymentsConsentsApi.scala | 590 ++++++++++++ .../v1_0_0/EventNotificationApi.scala | 121 +++ .../v1_0_0/FilePaymentConsentsApi.scala | 432 +++++++++ .../BahrainOBF/v1_0_0/FilePaymentsApi.scala | 458 +++++++++ .../v1_0_0/FutureDatedPaymentsApi.scala | 155 ++++ .../InternationalPaymentConsentsApi.scala | 778 ++++++++++++++++ .../v1_0_0/InternationalPaymentsApi.scala | 877 ++++++++++++++++++ .../api/BahrainOBF/v1_0_0/OffersApi.scala | 283 ++++++ .../api/BahrainOBF/v1_0_0/PartiesApi.scala | 509 ++++++++++ .../BahrainOBF/v1_0_0/StandingOrdersApi.scala | 155 ++++ .../api/BahrainOBF/v1_0_0/StatementsApi.scala | 299 ++++++ .../v1_0_0/SupplementaryAccountInfoApi.scala | 145 +++ .../BahrainOBF/v1_0_0/TransactionsApi.scala | 155 ++++ .../scala/code/api/MxOF/OBP_MXOF_1_0_0.scala | 2 +- 23 files changed, 8206 insertions(+), 1 deletion(-) create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/AccountAccessConsentsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/AccountsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/BalancesApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/BeneficiariesApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DirectDebitsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticFutureDatedPaymentConsentsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticFutureDatedPaymentsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticPaymentsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticPaymentsConsentsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/EventNotificationApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FilePaymentConsentsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FilePaymentsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FutureDatedPaymentsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/InternationalPaymentConsentsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/InternationalPaymentsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/OffersApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/PartiesApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/StandingOrdersApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/StatementsApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/SupplementaryAccountInfoApi.scala create mode 100644 obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/TransactionsApi.scala diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/AccountAccessConsentsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/AccountAccessConsentsApi.scala new file mode 100644 index 000000000..edce626ae --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/AccountAccessConsentsApi.scala @@ -0,0 +1,259 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_AccountAccessConsentsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountAccessConsentsConsentIdGet :: + accountAccessConsentsConsentIdPatch :: + accountAccessConsentsPost :: + Nil + + + resourceDocs += ResourceDoc( + accountAccessConsentsConsentIdGet, + apiVersion, + nameOf(accountAccessConsentsConsentIdGet), + "GET", + "/account-access-consents/CONSENT_ID", + "Get Account Access Consents by ConsentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Authorised", + "StatusUpdateDateTime" : { }, + "CreationDateTime" : { }, + "TransactionToDateTime" : "2000-01-23T04:56:07.000+00:00", + "Permissions" : [ "ReadAccountsBasic", "ReadAccountsBasic" ], + "ConsentId" : "ConsentId", + "TransactionFromDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Account Access Consents") :: apiTagMockedData :: Nil + ) + + lazy val accountAccessConsentsConsentIdGet : OBPEndpoint = { + case "account-access-consents" :: consentId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Authorised", + "StatusUpdateDateTime" : { }, + "CreationDateTime" : { }, + "TransactionToDateTime" : "2000-01-23T04:56:07.000+00:00", + "Permissions" : [ "ReadAccountsBasic", "ReadAccountsBasic" ], + "ConsentId" : "ConsentId", + "TransactionFromDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + accountAccessConsentsConsentIdPatch, + apiVersion, + nameOf(accountAccessConsentsConsentIdPatch), + "PATCH", + "/account-access-consents/CONSENT_ID", + "Update Account Access Consent Status by ConsentId", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Data" : { + "Status" : "Revoked" + } +}"""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Authorised", + "StatusUpdateDateTime" : { }, + "CreationDateTime" : { }, + "TransactionToDateTime" : "2000-01-23T04:56:07.000+00:00", + "Permissions" : [ "ReadAccountsBasic", "ReadAccountsBasic" ], + "ConsentId" : "ConsentId", + "TransactionFromDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Account Access Consents") :: apiTagMockedData :: Nil + ) + + lazy val accountAccessConsentsConsentIdPatch : OBPEndpoint = { + case "account-access-consents" :: consentId :: Nil JsonPatch _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Authorised", + "StatusUpdateDateTime" : { }, + "CreationDateTime" : { }, + "TransactionToDateTime" : "2000-01-23T04:56:07.000+00:00", + "Permissions" : [ "ReadAccountsBasic", "ReadAccountsBasic" ], + "ConsentId" : "ConsentId", + "TransactionFromDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + accountAccessConsentsPost, + apiVersion, + nameOf(accountAccessConsentsPost), + "POST", + "/account-access-consents", + "Create Account Access Consents", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Data" : { + "TransactionToDateTime" : "2000-01-23T04:56:07.000+00:00", + "Permissions" : [ "ReadAccountsBasic", "ReadAccountsBasic" ], + "TransactionFromDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Authorised", + "StatusUpdateDateTime" : { }, + "CreationDateTime" : { }, + "TransactionToDateTime" : "2000-01-23T04:56:07.000+00:00", + "Permissions" : [ "ReadAccountsBasic", "ReadAccountsBasic" ], + "ConsentId" : "ConsentId", + "TransactionFromDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Account Access Consents") :: apiTagMockedData :: Nil + ) + + lazy val accountAccessConsentsPost : OBPEndpoint = { + case "account-access-consents" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Authorised", + "StatusUpdateDateTime" : { }, + "CreationDateTime" : { }, + "TransactionToDateTime" : "2000-01-23T04:56:07.000+00:00", + "Permissions" : [ "ReadAccountsBasic", "ReadAccountsBasic" ], + "ConsentId" : "ConsentId", + "TransactionFromDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/AccountsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/AccountsApi.scala new file mode 100644 index 000000000..30f60f973 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/AccountsApi.scala @@ -0,0 +1,155 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_AccountsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountsAccountIdGet :: + accountsGet :: + Nil + + + resourceDocs += ResourceDoc( + accountsAccountIdGet, + apiVersion, + nameOf(accountsAccountIdGet), + "GET", + "/accounts/ACCOUNT_ID", + "Get Account by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Account" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Accounts") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdGet : OBPEndpoint = { + case "accounts" :: accountId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Account" : [ { }, { } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + accountsGet, + apiVersion, + nameOf(accountsGet), + "GET", + "/accounts", + "Get Accounts", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Account" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Accounts") :: apiTagMockedData :: Nil + ) + + lazy val accountsGet : OBPEndpoint = { + case "accounts" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Account" : [ { }, { } ] + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala new file mode 100644 index 000000000..dc474f1f9 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala @@ -0,0 +1,110 @@ +/** + * Open Bank Project - API + * Copyright (C) 2011-2022, TESOBE GmbH + ** + *This program is free software: you can redistribute it and/or modify + *it under the terms of the GNU Affero General Public License as published by + *the Free Software Foundation, either version 3 of the License, or + *(at your option) any later version. + ** + *This program is distributed in the hope that it will be useful, + *but WITHOUT ANY WARRANTY; without even the implied warranty of + *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + *GNU Affero General Public License for more details. + ** + *You should have received a copy of the GNU Affero General Public License + *along with this program. If not, see . + ** + *Email: contact@tesobe.com + *TESOBE Ltd + *Osloerstrasse 16/17 + *Berlin 13359, Germany + ** + *This product includes software developed at + *TESOBE (http://www.tesobe.com/) + * by + *Simon Redfern : simon AT tesobe DOT com + *Stefan Bethge : stefan AT tesobe DOT com + *Everett Sochowski : everett AT tesobe DOT com + *Ayoub Benali: ayoub AT tesobe DOT com + * + */ +package code.api.BahrainOBF.v1_0_0 + +import code.api.OBPRestHelper +import code.api.util.APIUtil.{OBPEndpoint, ResourceDoc, getAllowedEndpoints} +import code.api.util.{ScannedApis} +import code.util.Helper.MdcLoggable +import com.openbankproject.commons.util.ScannedApiVersion +import scala.collection.mutable.ArrayBuffer + + + + +/* +This file defines which endpoints from all the versions are available in v1 + */ +object ApiCollector extends OBPRestHelper with MdcLoggable with ScannedApis { + override val apiVersion = ScannedApiVersion("BHOBF", "BHOBF", "v1.0.0") + val versionStatus = "DRAFT" + + private[this] val endpoints = + APIMethods_DomesticFutureDatedPaymentConsentsApi.endpoints ++ + APIMethods_DomesticFutureDatedPaymentsApi.endpoints ++ + APIMethods_DomesticPaymentsApi.endpoints ++ + APIMethods_DomesticPaymentsConsentsApi.endpoints ++ + APIMethods_FilePaymentConsentsApi.endpoints ++ + APIMethods_FilePaymentsApi.endpoints ++ + APIMethods_InternationalPaymentConsentsApi.endpoints ++ + APIMethods_InternationalPaymentsApi.endpoints ++ + APIMethods_AccountAccessConsentsApi.endpoints ++ + APIMethods_AccountsApi.endpoints ++ + APIMethods_BalancesApi.endpoints ++ + APIMethods_BeneficiariesApi.endpoints ++ + APIMethods_DirectDebitsApi.endpoints ++ + APIMethods_FutureDatedPaymentsApi.endpoints ++ + APIMethods_OffersApi.endpoints ++ + APIMethods_PartiesApi.endpoints ++ + APIMethods_StandingOrdersApi.endpoints ++ + APIMethods_StatementsApi.endpoints ++ + APIMethods_SupplementaryAccountInfoApi.endpoints ++ + APIMethods_TransactionsApi.endpoints ++ + APIMethods_EventNotificationApi.endpoints + + override val allResourceDocs: ArrayBuffer[ResourceDoc] = + APIMethods_DomesticFutureDatedPaymentConsentsApi.resourceDocs ++ + APIMethods_DomesticFutureDatedPaymentsApi.resourceDocs ++ + APIMethods_DomesticPaymentsApi.resourceDocs ++ + APIMethods_DomesticPaymentsConsentsApi.resourceDocs ++ + APIMethods_FilePaymentConsentsApi.resourceDocs ++ + APIMethods_FilePaymentsApi.resourceDocs ++ + APIMethods_InternationalPaymentConsentsApi.resourceDocs ++ + APIMethods_InternationalPaymentsApi.resourceDocs ++ + APIMethods_AccountAccessConsentsApi.resourceDocs ++ + APIMethods_AccountsApi.resourceDocs ++ + APIMethods_BalancesApi.resourceDocs ++ + APIMethods_BeneficiariesApi.resourceDocs ++ + APIMethods_DirectDebitsApi.resourceDocs ++ + APIMethods_FutureDatedPaymentsApi.resourceDocs ++ + APIMethods_OffersApi.resourceDocs ++ + APIMethods_PartiesApi.resourceDocs ++ + APIMethods_StandingOrdersApi.resourceDocs ++ + APIMethods_StatementsApi.resourceDocs ++ + APIMethods_SupplementaryAccountInfoApi.resourceDocs ++ + APIMethods_TransactionsApi.resourceDocs ++ + APIMethods_EventNotificationApi.resourceDocs + + private[this] def findResourceDoc(pf: OBPEndpoint): Option[ResourceDoc] = { + allResourceDocs.find(_.partialFunction==pf) + } + + // Filter the possible endpoints by the disabled / enabled Props settings and add them together + override val routes : List[OBPEndpoint] = getAllowedEndpoints(endpoints, allResourceDocs) + + // Make them available for use! + routes.foreach(route => { + registerRoutes(routes, allResourceDocs, apiPrefix) + }) + + logger.info(s"version $version has been run! There are ${routes.length} routes.") +} diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/BalancesApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/BalancesApi.scala new file mode 100644 index 000000000..3e0665c25 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/BalancesApi.scala @@ -0,0 +1,299 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_BalancesApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountsAccountIdBalancesGet :: + balancesGet :: + Nil + + + resourceDocs += ResourceDoc( + accountsAccountIdBalancesGet, + apiVersion, + nameOf(accountsAccountIdBalancesGet), + "GET", + "/accounts/ACCOUNT_ID/balances", + "Get Accounts Balances by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Balance" : [ { + "Type" : { }, + "AccountId" : { }, + "CreditLine" : [ { + "Type" : "Available", + "Amount" : { }, + "Included" : true + }, { + "Type" : "Available", + "Amount" : { }, + "Included" : true + } ], + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "CreditDebitIndicator" : { }, + "DateTime" : "2000-01-23T04:56:07.000+00:00" + }, { + "Type" : { }, + "AccountId" : { }, + "CreditLine" : [ { + "Type" : "Available", + "Amount" : { }, + "Included" : true + }, { + "Type" : "Available", + "Amount" : { }, + "Included" : true + } ], + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "CreditDebitIndicator" : { }, + "DateTime" : "2000-01-23T04:56:07.000+00:00" + } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Balances") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdBalancesGet : OBPEndpoint = { + case "accounts" :: accountId:: "balances" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Balance" : [ { + "Type" : { }, + "AccountId" : { }, + "CreditLine" : [ { + "Type" : "Available", + "Amount" : { }, + "Included" : true + }, { + "Type" : "Available", + "Amount" : { }, + "Included" : true + } ], + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "CreditDebitIndicator" : { }, + "DateTime" : "2000-01-23T04:56:07.000+00:00" + }, { + "Type" : { }, + "AccountId" : { }, + "CreditLine" : [ { + "Type" : "Available", + "Amount" : { }, + "Included" : true + }, { + "Type" : "Available", + "Amount" : { }, + "Included" : true + } ], + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "CreditDebitIndicator" : { }, + "DateTime" : "2000-01-23T04:56:07.000+00:00" + } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + balancesGet, + apiVersion, + nameOf(balancesGet), + "GET", + "/balances", + "Get Balances", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Balance" : [ { + "Type" : { }, + "AccountId" : { }, + "CreditLine" : [ { + "Type" : "Available", + "Amount" : { }, + "Included" : true + }, { + "Type" : "Available", + "Amount" : { }, + "Included" : true + } ], + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "CreditDebitIndicator" : { }, + "DateTime" : "2000-01-23T04:56:07.000+00:00" + }, { + "Type" : { }, + "AccountId" : { }, + "CreditLine" : [ { + "Type" : "Available", + "Amount" : { }, + "Included" : true + }, { + "Type" : "Available", + "Amount" : { }, + "Included" : true + } ], + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "CreditDebitIndicator" : { }, + "DateTime" : "2000-01-23T04:56:07.000+00:00" + } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Balances") :: apiTagMockedData :: Nil + ) + + lazy val balancesGet : OBPEndpoint = { + case "balances" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Balance" : [ { + "Type" : { }, + "AccountId" : { }, + "CreditLine" : [ { + "Type" : "Available", + "Amount" : { }, + "Included" : true + }, { + "Type" : "Available", + "Amount" : { }, + "Included" : true + } ], + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "CreditDebitIndicator" : { }, + "DateTime" : "2000-01-23T04:56:07.000+00:00" + }, { + "Type" : { }, + "AccountId" : { }, + "CreditLine" : [ { + "Type" : "Available", + "Amount" : { }, + "Included" : true + }, { + "Type" : "Available", + "Amount" : { }, + "Included" : true + } ], + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "CreditDebitIndicator" : { }, + "DateTime" : "2000-01-23T04:56:07.000+00:00" + } ] + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/BeneficiariesApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/BeneficiariesApi.scala new file mode 100644 index 000000000..128a0af00 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/BeneficiariesApi.scala @@ -0,0 +1,155 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_BeneficiariesApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountsAccountIdBeneficiariesGet :: + beneficiariesGet :: + Nil + + + resourceDocs += ResourceDoc( + accountsAccountIdBeneficiariesGet, + apiVersion, + nameOf(accountsAccountIdBeneficiariesGet), + "GET", + "/accounts/ACCOUNT_ID/beneficiaries", + "Get Accounts Beneficiaries by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Beneficiary" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Beneficiaries") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdBeneficiariesGet : OBPEndpoint = { + case "accounts" :: accountId:: "beneficiaries" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Beneficiary" : [ { }, { } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + beneficiariesGet, + apiVersion, + nameOf(beneficiariesGet), + "GET", + "/beneficiaries", + "Get Beneficiaries", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Beneficiary" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Beneficiaries") :: apiTagMockedData :: Nil + ) + + lazy val beneficiariesGet : OBPEndpoint = { + case "beneficiaries" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Beneficiary" : [ { }, { } ] + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DirectDebitsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DirectDebitsApi.scala new file mode 100644 index 000000000..e974119ec --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DirectDebitsApi.scala @@ -0,0 +1,259 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_DirectDebitsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountsAccountIdDirectDebitsGet :: + directDebitsGet :: + Nil + + + resourceDocs += ResourceDoc( + accountsAccountIdDirectDebitsGet, + apiVersion, + nameOf(accountsAccountIdDirectDebitsGet), + "GET", + "/accounts/ACCOUNT_ID/direct-debits", + "Get Accounts Direct Debits by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "DirectDebit" : [ { + "SupplementaryData" : { }, + "PreviousPaymentDateTime" : { }, + "AccountId" : { }, + "MandateIdentification" : { }, + "DirectDebitStatusCode" : { }, + "Frequency" : "Frequency", + "DirectDebitId" : { }, + "PreviousPaymentAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "Name" : { } + }, { + "SupplementaryData" : { }, + "PreviousPaymentDateTime" : { }, + "AccountId" : { }, + "MandateIdentification" : { }, + "DirectDebitStatusCode" : { }, + "Frequency" : "Frequency", + "DirectDebitId" : { }, + "PreviousPaymentAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "Name" : { } + } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Direct Debits") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdDirectDebitsGet : OBPEndpoint = { + case "accounts" :: accountId:: "direct-debits" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "DirectDebit" : [ { + "SupplementaryData" : { }, + "PreviousPaymentDateTime" : { }, + "AccountId" : { }, + "MandateIdentification" : { }, + "DirectDebitStatusCode" : { }, + "Frequency" : "Frequency", + "DirectDebitId" : { }, + "PreviousPaymentAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "Name" : { } + }, { + "SupplementaryData" : { }, + "PreviousPaymentDateTime" : { }, + "AccountId" : { }, + "MandateIdentification" : { }, + "DirectDebitStatusCode" : { }, + "Frequency" : "Frequency", + "DirectDebitId" : { }, + "PreviousPaymentAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "Name" : { } + } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + directDebitsGet, + apiVersion, + nameOf(directDebitsGet), + "GET", + "/direct-debits", + "Get Direct Debits", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "DirectDebit" : [ { + "SupplementaryData" : { }, + "PreviousPaymentDateTime" : { }, + "AccountId" : { }, + "MandateIdentification" : { }, + "DirectDebitStatusCode" : { }, + "Frequency" : "Frequency", + "DirectDebitId" : { }, + "PreviousPaymentAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "Name" : { } + }, { + "SupplementaryData" : { }, + "PreviousPaymentDateTime" : { }, + "AccountId" : { }, + "MandateIdentification" : { }, + "DirectDebitStatusCode" : { }, + "Frequency" : "Frequency", + "DirectDebitId" : { }, + "PreviousPaymentAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "Name" : { } + } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Direct Debits") :: apiTagMockedData :: Nil + ) + + lazy val directDebitsGet : OBPEndpoint = { + case "direct-debits" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "DirectDebit" : [ { + "SupplementaryData" : { }, + "PreviousPaymentDateTime" : { }, + "AccountId" : { }, + "MandateIdentification" : { }, + "DirectDebitStatusCode" : { }, + "Frequency" : "Frequency", + "DirectDebitId" : { }, + "PreviousPaymentAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "Name" : { } + }, { + "SupplementaryData" : { }, + "PreviousPaymentDateTime" : { }, + "AccountId" : { }, + "MandateIdentification" : { }, + "DirectDebitStatusCode" : { }, + "Frequency" : "Frequency", + "DirectDebitId" : { }, + "PreviousPaymentAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "Name" : { } + } ] + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticFutureDatedPaymentConsentsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticFutureDatedPaymentConsentsApi.scala new file mode 100644 index 000000000..99b9278bc --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticFutureDatedPaymentConsentsApi.scala @@ -0,0 +1,689 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_DomesticFutureDatedPaymentConsentsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + domesticFutureDatedPaymentCancellationConsentsConsentIdGet :: + domesticFutureDatedPaymentCancellationConsentsPost :: + domesticFutureDatedPaymentConsentsConsentIdGet :: + domesticFutureDatedPaymentConsentsPost :: + Nil + + + resourceDocs += ResourceDoc( + domesticFutureDatedPaymentCancellationConsentsConsentIdGet, + apiVersion, + nameOf(domesticFutureDatedPaymentCancellationConsentsConsentIdGet), + "GET", + "/domestic-future-dated-payment-cancellation-consents/CONSENT_ID", + "Get Domestic Future Dated Payment Cancellation Consents by ConsentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Data" : { + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "DomesticFutureDatedPaymentId" : "DomesticFutureDatedPaymentId", + "Permission" : "Create", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Future Dated Payment Consents") :: apiTagMockedData :: Nil + ) + + lazy val domesticFutureDatedPaymentCancellationConsentsConsentIdGet : OBPEndpoint = { + case "domestic-future-dated-payment-cancellation-consents" :: consentId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Data" : { + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "DomesticFutureDatedPaymentId" : "DomesticFutureDatedPaymentId", + "Permission" : "Create", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + domesticFutureDatedPaymentCancellationConsentsPost, + apiVersion, + nameOf(domesticFutureDatedPaymentCancellationConsentsPost), + "POST", + "/domestic-future-dated-payment-cancellation-consents", + "Create Domestic Future Dated Payment Cancellation Consents", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Data" : { + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "DomesticFutureDatedPaymentId" : "DomesticFutureDatedPaymentId", + "Permission" : "Create", + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + json.parse("""{ + "Data" : { + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "DomesticFutureDatedPaymentId" : "DomesticFutureDatedPaymentId", + "Permission" : "Create", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Future Dated Payment Consents") :: apiTagMockedData :: Nil + ) + + lazy val domesticFutureDatedPaymentCancellationConsentsPost : OBPEndpoint = { + case "domestic-future-dated-payment-cancellation-consents" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Data" : { + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "DomesticFutureDatedPaymentId" : "DomesticFutureDatedPaymentId", + "Permission" : "Create", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + domesticFutureDatedPaymentConsentsConsentIdGet, + apiVersion, + nameOf(domesticFutureDatedPaymentConsentsConsentIdGet), + "GET", + "/domestic-future-dated-payment-consents/CONSENT_ID", + "Get Domestic Future Dated Payment Consents by ConsentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Permission" : "Create", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Future Dated Payment Consents") :: apiTagMockedData :: Nil + ) + + lazy val domesticFutureDatedPaymentConsentsConsentIdGet : OBPEndpoint = { + case "domestic-future-dated-payment-consents" :: consentId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Permission" : "Create", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + domesticFutureDatedPaymentConsentsPost, + apiVersion, + nameOf(domesticFutureDatedPaymentConsentsPost), + "POST", + "/domestic-future-dated-payment-consents", + "Create Domestic Future Dated Payment Consents", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Permission" : "Create", + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Permission" : "Create", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Future Dated Payment Consents") :: apiTagMockedData :: Nil + ) + + lazy val domesticFutureDatedPaymentConsentsPost : OBPEndpoint = { + case "domestic-future-dated-payment-consents" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Permission" : "Create", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticFutureDatedPaymentsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticFutureDatedPaymentsApi.scala new file mode 100644 index 000000000..05c31e834 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticFutureDatedPaymentsApi.scala @@ -0,0 +1,761 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_DomesticFutureDatedPaymentsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdGet :: + domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdPatch :: + domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdPaymentDetailsGet :: + domesticFutureDatedPaymentsPost :: + Nil + + + resourceDocs += ResourceDoc( + domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdGet, + apiVersion, + nameOf(domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdGet), + "GET", + "/domestic-future-dated-payments/DOMESTIC_FUTURE_DATED_PAYMENT_ID", + "Get Domestic Future Dated Payments by DomesticFutureDatedPaymentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Cancelled", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + } + }, + "DomesticFutureDatedPaymentId" : "DomesticFutureDatedPaymentId", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Future Dated Payments") :: apiTagMockedData :: Nil + ) + + lazy val domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdGet : OBPEndpoint = { + case "domestic-future-dated-payments" :: domesticFutureDatedPaymentId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Cancelled", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + } + }, + "DomesticFutureDatedPaymentId" : "DomesticFutureDatedPaymentId", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdPatch, + apiVersion, + nameOf(domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdPatch), + "PATCH", + "/domestic-future-dated-payments/DOMESTIC_FUTURE_DATED_PAYMENT_ID", + "Patch Domestic Future Dated Payments by DomesticFutureDatedPaymentId", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Data" : { + "Status" : "RejectedCancellationRequest", + "ConsentId" : "ConsentId" + } +}"""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Cancelled", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + } + }, + "DomesticFutureDatedPaymentId" : "DomesticFutureDatedPaymentId", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Future Dated Payments") :: apiTagMockedData :: Nil + ) + + lazy val domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdPatch : OBPEndpoint = { + case "domestic-future-dated-payments" :: domesticFutureDatedPaymentId :: Nil JsonPatch _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Cancelled", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + } + }, + "DomesticFutureDatedPaymentId" : "DomesticFutureDatedPaymentId", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdPaymentDetailsGet, + apiVersion, + nameOf(domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdPaymentDetailsGet), + "GET", + "/domestic-future-dated-payments/DOMESTIC_FUTURE_DATED_PAYMENT_ID/payment-details", + "Get Domestic Future Dated Payment Details by DomesticFutureDatedPaymentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "PaymentStatus" : [ { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + }, { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Future Dated Payments") :: apiTagMockedData :: Nil + ) + + lazy val domesticFutureDatedPaymentsDomesticFutureDatedPaymentIdPaymentDetailsGet : OBPEndpoint = { + case "domestic-future-dated-payments" :: domesticFutureDatedPaymentId:: "payment-details" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "PaymentStatus" : [ { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + }, { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + domesticFutureDatedPaymentsPost, + apiVersion, + nameOf(domesticFutureDatedPaymentsPost), + "POST", + "/domestic-future-dated-payments", + "Create Domestic Future Dated Payments", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Cancelled", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + } + }, + "DomesticFutureDatedPaymentId" : "DomesticFutureDatedPaymentId", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Future Dated Payments") :: apiTagMockedData :: Nil + ) + + lazy val domesticFutureDatedPaymentsPost : OBPEndpoint = { + case "domestic-future-dated-payments" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "Cancelled", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + } + }, + "DomesticFutureDatedPaymentId" : "DomesticFutureDatedPaymentId", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + }, + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticPaymentsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticPaymentsApi.scala new file mode 100644 index 000000000..004ab4cc2 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticPaymentsApi.scala @@ -0,0 +1,561 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_DomesticPaymentsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + domesticPaymentsDomesticPaymentIdGet :: + domesticPaymentsDomesticPaymentIdPaymentDetailsGet :: + domesticPaymentsPost :: + Nil + + + resourceDocs += ResourceDoc( + domesticPaymentsDomesticPaymentIdGet, + apiVersion, + nameOf(domesticPaymentsDomesticPaymentIdGet), + "GET", + "/domestic-payments/DOMESTIC_PAYMENT_ID", + "Get Domestic Payments by DomesticPaymentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "DomesticPaymentId" : "DomesticPaymentId", + "Status" : "AcceptedCreditSettlementCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + } + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Payments") :: apiTagMockedData :: Nil + ) + + lazy val domesticPaymentsDomesticPaymentIdGet : OBPEndpoint = { + case "domestic-payments" :: domesticPaymentId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "DomesticPaymentId" : "DomesticPaymentId", + "Status" : "AcceptedCreditSettlementCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + } + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + domesticPaymentsDomesticPaymentIdPaymentDetailsGet, + apiVersion, + nameOf(domesticPaymentsDomesticPaymentIdPaymentDetailsGet), + "GET", + "/domestic-payments/DOMESTIC_PAYMENT_ID/payment-details", + "Get Domestic Payment details by DomesticPaymentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "PaymentStatus" : [ { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + }, { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Payments") :: apiTagMockedData :: Nil + ) + + lazy val domesticPaymentsDomesticPaymentIdPaymentDetailsGet : OBPEndpoint = { + case "domestic-payments" :: domesticPaymentId:: "payment-details" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "PaymentStatus" : [ { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + }, { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + domesticPaymentsPost, + apiVersion, + nameOf(domesticPaymentsPost), + "POST", + "/domestic-payments", + "Create Domestic Payments", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + } + } +}"""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "DomesticPaymentId" : "DomesticPaymentId", + "Status" : "AcceptedCreditSettlementCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + } + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Payments") :: apiTagMockedData :: Nil + ) + + lazy val domesticPaymentsPost : OBPEndpoint = { + case "domestic-payments" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "DomesticPaymentId" : "DomesticPaymentId", + "Status" : "AcceptedCreditSettlementCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + } + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticPaymentsConsentsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticPaymentsConsentsApi.scala new file mode 100644 index 000000000..13975a402 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/DomesticPaymentsConsentsApi.scala @@ -0,0 +1,590 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_DomesticPaymentsConsentsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + domesticPaymentConsentsConsentIdFundsConfirmationGet :: + domesticPaymentConsentsConsentIdGet :: + domesticPaymentConsentsPost :: + Nil + + + resourceDocs += ResourceDoc( + domesticPaymentConsentsConsentIdFundsConfirmationGet, + apiVersion, + nameOf(domesticPaymentConsentsConsentIdFundsConfirmationGet), + "GET", + "/domestic-payment-consents/CONSENT_ID/funds-confirmation", + "Get Domestic Payment Consents Funds Confirmation by ConsentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "SupplementaryData" : { }, + "FundsAvailableResult" : { + "FundsAvailableDateTime" : "2000-01-23T04:56:07.000+00:00", + "FundsAvailable" : true + } + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Payments Consents") :: apiTagMockedData :: Nil + ) + + lazy val domesticPaymentConsentsConsentIdFundsConfirmationGet : OBPEndpoint = { + case "domestic-payment-consents" :: consentId:: "funds-confirmation" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "SupplementaryData" : { }, + "FundsAvailableResult" : { + "FundsAvailableDateTime" : "2000-01-23T04:56:07.000+00:00", + "FundsAvailable" : true + } + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + domesticPaymentConsentsConsentIdGet, + apiVersion, + nameOf(domesticPaymentConsentsConsentIdGet), + "GET", + "/domestic-payment-consents/CONSENT_ID", + "Get Domestic Payment Consents by ConsentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Payments Consents") :: apiTagMockedData :: Nil + ) + + lazy val domesticPaymentConsentsConsentIdGet : OBPEndpoint = { + case "domestic-payment-consents" :: consentId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + domesticPaymentConsentsPost, + apiVersion, + nameOf(domesticPaymentConsentsPost), + "POST", + "/domestic-payment-consents", + "Create Domestic Payment Consents", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + } + } +}"""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Domestic Payments Consents") :: apiTagMockedData :: Nil + ) + + lazy val domesticPaymentConsentsPost : OBPEndpoint = { + case "domestic-payment-consents" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "CreditorPostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/EventNotificationApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/EventNotificationApi.scala new file mode 100644 index 000000000..3c375c69f --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/EventNotificationApi.scala @@ -0,0 +1,121 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_EventNotificationApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + eventNotificationsPost :: + Nil + + + resourceDocs += ResourceDoc( + eventNotificationsPost, + apiVersion, + nameOf(eventNotificationsPost), + "POST", + "/event-notifications", + "The ASPSP to send an event-notification resource to a TPP", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "aud" : "aud", + "sub" : "http://example.com/aeiou", + "iss" : "iss", + "toe" : 0, + "txn" : "txn", + "iat" : 0, + "events" : { + "urn:bh:org:openbanking:events:resource-update" : { + "subject" : { + "http://openbanking.org.bh/rty" : "http://openbanking.org.bh/rty", + "subject_type" : "subject_type", + "http://openbanking.org.bh/rlk" : [ { + "link" : "link", + "version" : "version" + }, { + "link" : "link", + "version" : "version" + } ], + "http://openbanking.org.bh/rid" : "http://openbanking.org.bh/rid" + } + }, + "urn:bh:org:openbanking:events:account-access-consent-linked-account-update" : { + "reason" : "reason", + "subject" : { + "http://openbanking.org.bh/rty" : "http://openbanking.org.bh/rty", + "subject_type" : "subject_type", + "http://openbanking.org.bh/rlk" : [ { + "link" : "link", + "version" : "version" + }, { + "link" : "link", + "version" : "version" + } ], + "http://openbanking.org.bh/rid" : "http://openbanking.org.bh/rid" + } + }, + "urn:bh:org:openbanking:events:consent-authorization-revoked" : { + "reason" : "reason", + "subject" : { + "http://openbanking.org.bh/rty" : "http://openbanking.org.bh/rty", + "subject_type" : "subject_type", + "http://openbanking.org.bh/rlk" : [ { + "link" : "link", + "version" : "version" + }, { + "link" : "link", + "version" : "version" + } ], + "http://openbanking.org.bh/rid" : "http://openbanking.org.bh/rid" + } + } + }, + "jti" : "jti" +}"""), + json.parse(""""""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Event Notification") :: apiTagMockedData :: Nil + ) + + lazy val eventNotificationsPost : OBPEndpoint = { + case "event-notifications" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse(""""""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FilePaymentConsentsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FilePaymentConsentsApi.scala new file mode 100644 index 000000000..8e8ef5976 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FilePaymentConsentsApi.scala @@ -0,0 +1,432 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_FilePaymentConsentsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + filePaymentConsentsConsentIdFileGet :: + filePaymentConsentsConsentIdFilePost :: + filePaymentConsentsConsentIdGet :: + filePaymentConsentsPost :: + Nil + + + resourceDocs += ResourceDoc( + filePaymentConsentsConsentIdFileGet, + apiVersion, + nameOf(filePaymentConsentsConsentIdFileGet), + "GET", + "/file-payment-consents/CONSENT_ID/file", + "Get File Payment Consents File by ConsentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ }"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("File Payment Consents") :: apiTagMockedData :: Nil + ) + + lazy val filePaymentConsentsConsentIdFileGet : OBPEndpoint = { + case "file-payment-consents" :: consentId:: "file" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ }"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + filePaymentConsentsConsentIdFilePost, + apiVersion, + nameOf(filePaymentConsentsConsentIdFilePost), + "POST", + "/file-payment-consents/CONSENT_ID/file", + "Create File Payment Consents File by ConsentId", + s"""${mockedDataText(true)} + + """, + json.parse("""{ }"""), + json.parse(""""""), + List(UserNotLoggedIn, UnknownError), + ApiTag("File Payment Consents") :: apiTagMockedData :: Nil + ) + + lazy val filePaymentConsentsConsentIdFilePost : OBPEndpoint = { + case "file-payment-consents" :: consentId:: "file" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse(""""""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + filePaymentConsentsConsentIdGet, + apiVersion, + nameOf(filePaymentConsentsConsentIdGet), + "GET", + "/file-payment-consents/CONSENT_ID", + "Get File Payment Consents by ConsentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "Status" : "Authorised", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "FileContextFormat" : "FileContextFormat", + "SupplementaryData" : { }, + "ControlSum" : 0.80082819046101150206595775671303272247314453125, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "FileHash" : "FileHash", + "NumberOfTransactions" : "NumberOfTransactions", + "FileReference" : "FileReference", + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("File Payment Consents") :: apiTagMockedData :: Nil + ) + + lazy val filePaymentConsentsConsentIdGet : OBPEndpoint = { + case "file-payment-consents" :: consentId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "Status" : "Authorised", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "FileContextFormat" : "FileContextFormat", + "SupplementaryData" : { }, + "ControlSum" : 0.80082819046101150206595775671303272247314453125, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "FileHash" : "FileHash", + "NumberOfTransactions" : "NumberOfTransactions", + "FileReference" : "FileReference", + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + filePaymentConsentsPost, + apiVersion, + nameOf(filePaymentConsentsPost), + "POST", + "/file-payment-consents", + "Create File Payment Consents", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Data" : { + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Initiation" : { + "FileContextFormat" : "FileContextFormat", + "SupplementaryData" : { }, + "ControlSum" : 0.80082819046101150206595775671303272247314453125, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "FileHash" : "FileHash", + "NumberOfTransactions" : "NumberOfTransactions", + "FileReference" : "FileReference", + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "Status" : "Authorised", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "FileContextFormat" : "FileContextFormat", + "SupplementaryData" : { }, + "ControlSum" : 0.80082819046101150206595775671303272247314453125, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "FileHash" : "FileHash", + "NumberOfTransactions" : "NumberOfTransactions", + "FileReference" : "FileReference", + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("File Payment Consents") :: apiTagMockedData :: Nil + ) + + lazy val filePaymentConsentsPost : OBPEndpoint = { + case "file-payment-consents" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "Status" : "Authorised", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ConsentId" : "ConsentId", + "Initiation" : { + "FileContextFormat" : "FileContextFormat", + "SupplementaryData" : { }, + "ControlSum" : 0.80082819046101150206595775671303272247314453125, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "FileHash" : "FileHash", + "NumberOfTransactions" : "NumberOfTransactions", + "FileReference" : "FileReference", + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FilePaymentsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FilePaymentsApi.scala new file mode 100644 index 000000000..4a89f1262 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FilePaymentsApi.scala @@ -0,0 +1,458 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_FilePaymentsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + filePaymentsFilePaymentIdGet :: + filePaymentsFilePaymentIdPaymentDetailsGet :: + filePaymentsFilePaymentIdReportFileGet :: + filePaymentsPost :: + Nil + + + resourceDocs += ResourceDoc( + filePaymentsFilePaymentIdGet, + apiVersion, + nameOf(filePaymentsFilePaymentIdGet), + "GET", + "/file-payments/FILE_PAYMENT_ID", + "Get File Payments by FilePaymentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "InitiationCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "FilePaymentId" : "FilePaymentId", + "ConsentId" : "ConsentId", + "Initiation" : { + "FileContextFormat" : "FileContextFormat", + "SupplementaryData" : { }, + "ControlSum" : 0.80082819046101150206595775671303272247314453125, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "FileHash" : "FileHash", + "NumberOfTransactions" : "NumberOfTransactions", + "FileReference" : "FileReference", + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("File Payments") :: apiTagMockedData :: Nil + ) + + lazy val filePaymentsFilePaymentIdGet : OBPEndpoint = { + case "file-payments" :: filePaymentId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "InitiationCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "FilePaymentId" : "FilePaymentId", + "ConsentId" : "ConsentId", + "Initiation" : { + "FileContextFormat" : "FileContextFormat", + "SupplementaryData" : { }, + "ControlSum" : 0.80082819046101150206595775671303272247314453125, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "FileHash" : "FileHash", + "NumberOfTransactions" : "NumberOfTransactions", + "FileReference" : "FileReference", + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + filePaymentsFilePaymentIdPaymentDetailsGet, + apiVersion, + nameOf(filePaymentsFilePaymentIdPaymentDetailsGet), + "GET", + "/file-payments/FILE_PAYMENT_ID/payment-details", + "Get File Payment Details by FilePaymentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "PaymentStatus" : [ { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + }, { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("File Payments") :: apiTagMockedData :: Nil + ) + + lazy val filePaymentsFilePaymentIdPaymentDetailsGet : OBPEndpoint = { + case "file-payments" :: filePaymentId:: "payment-details" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "PaymentStatus" : [ { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + }, { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + filePaymentsFilePaymentIdReportFileGet, + apiVersion, + nameOf(filePaymentsFilePaymentIdReportFileGet), + "GET", + "/file-payments/FILE_PAYMENT_ID/report-file", + "Get File Payments Report File by FilePaymentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ }"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("File Payments") :: apiTagMockedData :: Nil + ) + + lazy val filePaymentsFilePaymentIdReportFileGet : OBPEndpoint = { + case "file-payments" :: filePaymentId:: "report-file" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ }"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + filePaymentsPost, + apiVersion, + nameOf(filePaymentsPost), + "POST", + "/file-payments", + "Create File Payments", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Data" : { + "ConsentId" : "ConsentId", + "Initiation" : { + "FileContextFormat" : "FileContextFormat", + "SupplementaryData" : { }, + "ControlSum" : 0.80082819046101150206595775671303272247314453125, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "FileHash" : "FileHash", + "NumberOfTransactions" : "NumberOfTransactions", + "FileReference" : "FileReference", + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "InitiationCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "FilePaymentId" : "FilePaymentId", + "ConsentId" : "ConsentId", + "Initiation" : { + "FileContextFormat" : "FileContextFormat", + "SupplementaryData" : { }, + "ControlSum" : 0.80082819046101150206595775671303272247314453125, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "FileHash" : "FileHash", + "NumberOfTransactions" : "NumberOfTransactions", + "FileReference" : "FileReference", + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("File Payments") :: apiTagMockedData :: Nil + ) + + lazy val filePaymentsPost : OBPEndpoint = { + case "file-payments" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "InitiationCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "FilePaymentId" : "FilePaymentId", + "ConsentId" : "ConsentId", + "Initiation" : { + "FileContextFormat" : "FileContextFormat", + "SupplementaryData" : { }, + "ControlSum" : 0.80082819046101150206595775671303272247314453125, + "LocalInstrument" : { }, + "DebtorAccount" : { + "Name" : "Name" + }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "FileHash" : "FileHash", + "NumberOfTransactions" : "NumberOfTransactions", + "FileReference" : "FileReference", + "RequestedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00" + } + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FutureDatedPaymentsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FutureDatedPaymentsApi.scala new file mode 100644 index 000000000..5e9046b67 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/FutureDatedPaymentsApi.scala @@ -0,0 +1,155 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_FutureDatedPaymentsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountsAccountIdFutureDatedPaymentsGet :: + futureDatedPaymentsGet :: + Nil + + + resourceDocs += ResourceDoc( + accountsAccountIdFutureDatedPaymentsGet, + apiVersion, + nameOf(accountsAccountIdFutureDatedPaymentsGet), + "GET", + "/accounts/ACCOUNT_ID/future-dated-payments", + "Get Accounts Future Dated Payments by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "FutureDatedPayment" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Future Dated Payments") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdFutureDatedPaymentsGet : OBPEndpoint = { + case "accounts" :: accountId:: "future-dated-payments" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "FutureDatedPayment" : [ { }, { } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + futureDatedPaymentsGet, + apiVersion, + nameOf(futureDatedPaymentsGet), + "GET", + "/future-dated-payments", + "Get Future Dated Payments", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "FutureDatedPayment" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Future Dated Payments") :: apiTagMockedData :: Nil + ) + + lazy val futureDatedPaymentsGet : OBPEndpoint = { + case "future-dated-payments" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "FutureDatedPayment" : [ { }, { } ] + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/InternationalPaymentConsentsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/InternationalPaymentConsentsApi.scala new file mode 100644 index 000000000..92ed3aa52 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/InternationalPaymentConsentsApi.scala @@ -0,0 +1,778 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_InternationalPaymentConsentsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + internationalPaymentConsentsConsentIdFundsConfirmationGet :: + internationalPaymentConsentsConsentIdGet :: + internationalPaymentConsentsPost :: + Nil + + + resourceDocs += ResourceDoc( + internationalPaymentConsentsConsentIdFundsConfirmationGet, + apiVersion, + nameOf(internationalPaymentConsentsConsentIdFundsConfirmationGet), + "GET", + "/international-payment-consents/CONSENT_ID/funds-confirmation", + "Get International Payment Consents Funds Confirmation by ConsentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "SupplementaryData" : { }, + "FundsAvailableResult" : { + "FundsAvailableDateTime" : "2000-01-23T04:56:07.000+00:00", + "FundsAvailable" : true + } + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("International Payment Consents") :: apiTagMockedData :: Nil + ) + + lazy val internationalPaymentConsentsConsentIdFundsConfirmationGet : OBPEndpoint = { + case "international-payment-consents" :: consentId:: "funds-confirmation" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "SupplementaryData" : { }, + "FundsAvailableResult" : { + "FundsAvailableDateTime" : "2000-01-23T04:56:07.000+00:00", + "FundsAvailable" : true + } + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + internationalPaymentConsentsConsentIdGet, + apiVersion, + nameOf(internationalPaymentConsentsConsentIdGet), + "GET", + "/international-payment-consents/CONSENT_ID", + "Get International Payment Consents by ConsentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExchangeRateInformation" : { + "ExchangeRate" : 0.80082819046101150206595775671303272247314453125, + "ExpirationDateTime" : "2000-01-23T04:56:07.000+00:00", + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "CreditorAgent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "DebtorAccount" : { + "Name" : "Name" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "CurrencyOfTransfer" : "CurrencyOfTransfer", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "ChargeBearer" : { }, + "Purpose" : "Purpose", + "ExtendedPurpose" : "ExtendedPurpose", + "InstructionPriority" : "Normal", + "LocalInstrument" : { }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "DestinationCountryCode" : "DestinationCountryCode", + "ExchangeRateInformation" : { + "ExchangeRate" : 6.02745618307040320615897144307382404804229736328125, + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("International Payment Consents") :: apiTagMockedData :: Nil + ) + + lazy val internationalPaymentConsentsConsentIdGet : OBPEndpoint = { + case "international-payment-consents" :: consentId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExchangeRateInformation" : { + "ExchangeRate" : 0.80082819046101150206595775671303272247314453125, + "ExpirationDateTime" : "2000-01-23T04:56:07.000+00:00", + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "CreditorAgent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "DebtorAccount" : { + "Name" : "Name" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "CurrencyOfTransfer" : "CurrencyOfTransfer", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "ChargeBearer" : { }, + "Purpose" : "Purpose", + "ExtendedPurpose" : "ExtendedPurpose", + "InstructionPriority" : "Normal", + "LocalInstrument" : { }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "DestinationCountryCode" : "DestinationCountryCode", + "ExchangeRateInformation" : { + "ExchangeRate" : 6.02745618307040320615897144307382404804229736328125, + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + internationalPaymentConsentsPost, + apiVersion, + nameOf(internationalPaymentConsentsPost), + "POST", + "/international-payment-consents", + "Create International Payment Consents", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "CreditorAgent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "DebtorAccount" : { + "Name" : "Name" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "CurrencyOfTransfer" : "CurrencyOfTransfer", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "ChargeBearer" : { }, + "Purpose" : "Purpose", + "ExtendedPurpose" : "ExtendedPurpose", + "InstructionPriority" : "Normal", + "LocalInstrument" : { }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "DestinationCountryCode" : "DestinationCountryCode", + "ExchangeRateInformation" : { + "ExchangeRate" : 6.02745618307040320615897144307382404804229736328125, + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + } + } +}"""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExchangeRateInformation" : { + "ExchangeRate" : 0.80082819046101150206595775671303272247314453125, + "ExpirationDateTime" : "2000-01-23T04:56:07.000+00:00", + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "CreditorAgent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "DebtorAccount" : { + "Name" : "Name" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "CurrencyOfTransfer" : "CurrencyOfTransfer", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "ChargeBearer" : { }, + "Purpose" : "Purpose", + "ExtendedPurpose" : "ExtendedPurpose", + "InstructionPriority" : "Normal", + "LocalInstrument" : { }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "DestinationCountryCode" : "DestinationCountryCode", + "ExchangeRateInformation" : { + "ExchangeRate" : 6.02745618307040320615897144307382404804229736328125, + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("International Payment Consents") :: apiTagMockedData :: Nil + ) + + lazy val internationalPaymentConsentsPost : OBPEndpoint = { + case "international-payment-consents" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "Status" : "Authorised", + "ConsentId" : "ConsentId", + "SCASupportData" : { + "RequestedSCAExemptionType" : "BillPayment", + "AppliedAuthenticationApproach" : "CA", + "ReferencePaymentOrderId" : "ReferencePaymentOrderId" + }, + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "CutOffDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExchangeRateInformation" : { + "ExchangeRate" : 0.80082819046101150206595775671303272247314453125, + "ExpirationDateTime" : "2000-01-23T04:56:07.000+00:00", + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Authorisation" : { + "CompletionDateTime" : "2000-01-23T04:56:07.000+00:00", + "AuthorisationType" : "Single" + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "ReadRefundAccount" : "No", + "Initiation" : { + "SupplementaryData" : { }, + "CreditorAgent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "DebtorAccount" : { + "Name" : "Name" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "CurrencyOfTransfer" : "CurrencyOfTransfer", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "ChargeBearer" : { }, + "Purpose" : "Purpose", + "ExtendedPurpose" : "ExtendedPurpose", + "InstructionPriority" : "Normal", + "LocalInstrument" : { }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "DestinationCountryCode" : "DestinationCountryCode", + "ExchangeRateInformation" : { + "ExchangeRate" : 6.02745618307040320615897144307382404804229736328125, + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/InternationalPaymentsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/InternationalPaymentsApi.scala new file mode 100644 index 000000000..daba5ea27 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/InternationalPaymentsApi.scala @@ -0,0 +1,877 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_InternationalPaymentsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + internationalPaymentsInternationalPaymentIdGet :: + internationalPaymentsInternationalPaymentIdPaymentDetailsGet :: + internationalPaymentsPost :: + Nil + + + resourceDocs += ResourceDoc( + internationalPaymentsInternationalPaymentIdGet, + apiVersion, + nameOf(internationalPaymentsInternationalPaymentIdGet), + "GET", + "/international-payments/INTERNATIONAL_PAYMENT_ID", + "Get International Payments by InternationalPaymentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "AcceptedCreditSettlementCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExchangeRateInformation" : { + "ExchangeRate" : 0.80082819046101150206595775671303272247314453125, + "ExpirationDateTime" : "2000-01-23T04:56:07.000+00:00", + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "Agent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + } + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "InternationalPaymentId" : "InternationalPaymentId", + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "CreditorAgent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "DebtorAccount" : { + "Name" : "Name" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "CurrencyOfTransfer" : "CurrencyOfTransfer", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "ChargeBearer" : { }, + "Purpose" : "Purpose", + "ExtendedPurpose" : "ExtendedPurpose", + "InstructionPriority" : "Normal", + "LocalInstrument" : { }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "DestinationCountryCode" : "DestinationCountryCode", + "ExchangeRateInformation" : { + "ExchangeRate" : 6.02745618307040320615897144307382404804229736328125, + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("International Payments") :: apiTagMockedData :: Nil + ) + + lazy val internationalPaymentsInternationalPaymentIdGet : OBPEndpoint = { + case "international-payments" :: internationalPaymentId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "AcceptedCreditSettlementCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExchangeRateInformation" : { + "ExchangeRate" : 0.80082819046101150206595775671303272247314453125, + "ExpirationDateTime" : "2000-01-23T04:56:07.000+00:00", + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "Agent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + } + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "InternationalPaymentId" : "InternationalPaymentId", + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "CreditorAgent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "DebtorAccount" : { + "Name" : "Name" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "CurrencyOfTransfer" : "CurrencyOfTransfer", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "ChargeBearer" : { }, + "Purpose" : "Purpose", + "ExtendedPurpose" : "ExtendedPurpose", + "InstructionPriority" : "Normal", + "LocalInstrument" : { }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "DestinationCountryCode" : "DestinationCountryCode", + "ExchangeRateInformation" : { + "ExchangeRate" : 6.02745618307040320615897144307382404804229736328125, + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + internationalPaymentsInternationalPaymentIdPaymentDetailsGet, + apiVersion, + nameOf(internationalPaymentsInternationalPaymentIdPaymentDetailsGet), + "GET", + "/international-payments/INTERNATIONAL_PAYMENT_ID/payment-details", + "Get International Payment Details by InternationalPaymentId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "PaymentStatus" : [ { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + }, { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("International Payments") :: apiTagMockedData :: Nil + ) + + lazy val internationalPaymentsInternationalPaymentIdPaymentDetailsGet : OBPEndpoint = { + case "international-payments" :: internationalPaymentId:: "payment-details" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "PaymentStatus" : [ { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + }, { + "PaymentTransactionId" : "PaymentTransactionId", + "Status" : "Accepted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "StatusDetail" : { + "Status" : "Status", + "LocalInstrument" : { }, + "StatusReason" : "Cancelled", + "StatusReasonDescription" : "StatusReasonDescription" + } + } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + internationalPaymentsPost, + apiVersion, + nameOf(internationalPaymentsPost), + "POST", + "/international-payments", + "Create International Payments", + s"""${mockedDataText(true)} + + """, + json.parse("""{ + "Risk" : { + "DeliveryAddress" : { + "CountrySubDivision" : [ "CountrySubDivision", "CountrySubDivision" ], + "AddressLine" : [ "AddressLine", "AddressLine" ], + "Country" : "Country" + }, + "PaymentContextCode" : "BillPayment", + "MerchantCategoryCode" : "MerchantCategoryCode", + "MerchantCustomerIdentification" : "MerchantCustomerIdentification" + }, + "Data" : { + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "CreditorAgent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "DebtorAccount" : { + "Name" : "Name" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "CurrencyOfTransfer" : "CurrencyOfTransfer", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "ChargeBearer" : { }, + "Purpose" : "Purpose", + "ExtendedPurpose" : "ExtendedPurpose", + "InstructionPriority" : "Normal", + "LocalInstrument" : { }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "DestinationCountryCode" : "DestinationCountryCode", + "ExchangeRateInformation" : { + "ExchangeRate" : 6.02745618307040320615897144307382404804229736328125, + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + } + } +}"""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "AcceptedCreditSettlementCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExchangeRateInformation" : { + "ExchangeRate" : 0.80082819046101150206595775671303272247314453125, + "ExpirationDateTime" : "2000-01-23T04:56:07.000+00:00", + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "Agent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + } + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "InternationalPaymentId" : "InternationalPaymentId", + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "CreditorAgent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "DebtorAccount" : { + "Name" : "Name" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "CurrencyOfTransfer" : "CurrencyOfTransfer", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "ChargeBearer" : { }, + "Purpose" : "Purpose", + "ExtendedPurpose" : "ExtendedPurpose", + "InstructionPriority" : "Normal", + "LocalInstrument" : { }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "DestinationCountryCode" : "DestinationCountryCode", + "ExchangeRateInformation" : { + "ExchangeRate" : 6.02745618307040320615897144307382404804229736328125, + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("International Payments") :: apiTagMockedData :: Nil + ) + + lazy val internationalPaymentsPost : OBPEndpoint = { + case "international-payments" :: Nil JsonPost _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Status" : "AcceptedCreditSettlementCompleted", + "StatusUpdateDateTime" : "2000-01-23T04:56:07.000+00:00", + "Debtor" : { + "Name" : "Name" + }, + "CreationDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExpectedExecutionDateTime" : "2000-01-23T04:56:07.000+00:00", + "ExchangeRateInformation" : { + "ExchangeRate" : 0.80082819046101150206595775671303272247314453125, + "ExpirationDateTime" : "2000-01-23T04:56:07.000+00:00", + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Refund" : { + "Account" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "Agent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + } + }, + "Charges" : [ { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + }, { + "Type" : { }, + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "ChargeBearer" : { } + } ], + "InternationalPaymentId" : "InternationalPaymentId", + "ConsentId" : "ConsentId", + "Initiation" : { + "SupplementaryData" : { }, + "CreditorAgent" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Identification" : { }, + "SchemeName" : { }, + "Name" : { } + }, + "DebtorAccount" : { + "Name" : "Name" + }, + "EndToEndIdentification" : "EndToEndIdentification", + "CurrencyOfTransfer" : "CurrencyOfTransfer", + "InstructionIdentification" : "InstructionIdentification", + "CreditorAccount" : { + "Identification" : { }, + "SchemeName" : { }, + "Name" : "Name" + }, + "ChargeBearer" : { }, + "Purpose" : "Purpose", + "ExtendedPurpose" : "ExtendedPurpose", + "InstructionPriority" : "Normal", + "LocalInstrument" : { }, + "RemittanceInformation" : { + "RemittanceDescription" : "RemittanceDescription", + "Reference" : "Reference" + }, + "DestinationCountryCode" : "DestinationCountryCode", + "ExchangeRateInformation" : { + "ExchangeRate" : 6.02745618307040320615897144307382404804229736328125, + "RateType" : "Actual", + "ContractIdentification" : "ContractIdentification", + "UnitCurrency" : "UnitCurrency" + }, + "Creditor" : { + "PostalAddress" : { + "CountrySubDivision" : { }, + "StreetName" : { }, + "Department" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "SubDepartment" : { }, + "AddressType" : { }, + "PostCode" : { } + }, + "Name" : "Name" + }, + "InstructedAmount" : { + "Amount" : { }, + "Currency" : { } + } + }, + "ExpectedSettlementDateTime" : "2000-01-23T04:56:07.000+00:00" + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/OffersApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/OffersApi.scala new file mode 100644 index 000000000..ac5787fdc --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/OffersApi.scala @@ -0,0 +1,283 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_OffersApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountsAccountIdOffersGet :: + offersGet :: + Nil + + + resourceDocs += ResourceDoc( + accountsAccountIdOffersGet, + apiVersion, + nameOf(accountsAccountIdOffersGet), + "GET", + "/accounts/ACCOUNT_ID/offers", + "Get Accounts Offers by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Offer" : [ { + "OfferId" : "OfferId", + "AccountId" : { }, + "Description" : "Description", + "StartDateTime" : "2000-01-23T04:56:07.000+00:00", + "EndDateTime" : "2000-01-23T04:56:07.000+00:00", + "Rate" : "Rate", + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "Fee" : { }, + "Value" : 0, + "Term" : "Term", + "URL" : "http://example.com/aeiou", + "OfferType" : "BalanceTransfer" + }, { + "OfferId" : "OfferId", + "AccountId" : { }, + "Description" : "Description", + "StartDateTime" : "2000-01-23T04:56:07.000+00:00", + "EndDateTime" : "2000-01-23T04:56:07.000+00:00", + "Rate" : "Rate", + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "Fee" : { }, + "Value" : 0, + "Term" : "Term", + "URL" : "http://example.com/aeiou", + "OfferType" : "BalanceTransfer" + } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Offers") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdOffersGet : OBPEndpoint = { + case "accounts" :: accountId:: "offers" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Offer" : [ { + "OfferId" : "OfferId", + "AccountId" : { }, + "Description" : "Description", + "StartDateTime" : "2000-01-23T04:56:07.000+00:00", + "EndDateTime" : "2000-01-23T04:56:07.000+00:00", + "Rate" : "Rate", + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "Fee" : { }, + "Value" : 0, + "Term" : "Term", + "URL" : "http://example.com/aeiou", + "OfferType" : "BalanceTransfer" + }, { + "OfferId" : "OfferId", + "AccountId" : { }, + "Description" : "Description", + "StartDateTime" : "2000-01-23T04:56:07.000+00:00", + "EndDateTime" : "2000-01-23T04:56:07.000+00:00", + "Rate" : "Rate", + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "Fee" : { }, + "Value" : 0, + "Term" : "Term", + "URL" : "http://example.com/aeiou", + "OfferType" : "BalanceTransfer" + } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + offersGet, + apiVersion, + nameOf(offersGet), + "GET", + "/offers", + "Get Offers", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Offer" : [ { + "OfferId" : "OfferId", + "AccountId" : { }, + "Description" : "Description", + "StartDateTime" : "2000-01-23T04:56:07.000+00:00", + "EndDateTime" : "2000-01-23T04:56:07.000+00:00", + "Rate" : "Rate", + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "Fee" : { }, + "Value" : 0, + "Term" : "Term", + "URL" : "http://example.com/aeiou", + "OfferType" : "BalanceTransfer" + }, { + "OfferId" : "OfferId", + "AccountId" : { }, + "Description" : "Description", + "StartDateTime" : "2000-01-23T04:56:07.000+00:00", + "EndDateTime" : "2000-01-23T04:56:07.000+00:00", + "Rate" : "Rate", + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "Fee" : { }, + "Value" : 0, + "Term" : "Term", + "URL" : "http://example.com/aeiou", + "OfferType" : "BalanceTransfer" + } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Offers") :: apiTagMockedData :: Nil + ) + + lazy val offersGet : OBPEndpoint = { + case "offers" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Offer" : [ { + "OfferId" : "OfferId", + "AccountId" : { }, + "Description" : "Description", + "StartDateTime" : "2000-01-23T04:56:07.000+00:00", + "EndDateTime" : "2000-01-23T04:56:07.000+00:00", + "Rate" : "Rate", + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "Fee" : { }, + "Value" : 0, + "Term" : "Term", + "URL" : "http://example.com/aeiou", + "OfferType" : "BalanceTransfer" + }, { + "OfferId" : "OfferId", + "AccountId" : { }, + "Description" : "Description", + "StartDateTime" : "2000-01-23T04:56:07.000+00:00", + "EndDateTime" : "2000-01-23T04:56:07.000+00:00", + "Rate" : "Rate", + "Amount" : { + "Amount" : { }, + "Currency" : { } + }, + "Fee" : { }, + "Value" : 0, + "Term" : "Term", + "URL" : "http://example.com/aeiou", + "OfferType" : "BalanceTransfer" + } ] + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/PartiesApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/PartiesApi.scala new file mode 100644 index 000000000..dd123054f --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/PartiesApi.scala @@ -0,0 +1,509 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_PartiesApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountsAccountIdPartiesGet :: + accountsAccountIdPartyGet :: + partyGet :: + Nil + + + resourceDocs += ResourceDoc( + accountsAccountIdPartiesGet, + apiVersion, + nameOf(accountsAccountIdPartiesGet), + "GET", + "/accounts/ACCOUNT_ID/parties", + "Get Accounts Parties by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Party" : [ { + "BeneficialOwnership" : true, + "Address" : [ { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + }, { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + } ], + "AccountRole" : { }, + "Mobile" : { }, + "EmailAddress" : { }, + "LegalStructure" : { }, + "Name" : { }, + "PartyNumber" : { }, + "Relationships" : { + "Account" : { + "Related" : "http://example.com/aeiou", + "Id" : "Id" + } + }, + "FullLegalName" : { }, + "PartyId" : { }, + "Phone" : { }, + "PartyType" : { } + }, { + "BeneficialOwnership" : true, + "Address" : [ { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + }, { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + } ], + "AccountRole" : { }, + "Mobile" : { }, + "EmailAddress" : { }, + "LegalStructure" : { }, + "Name" : { }, + "PartyNumber" : { }, + "Relationships" : { + "Account" : { + "Related" : "http://example.com/aeiou", + "Id" : "Id" + } + }, + "FullLegalName" : { }, + "PartyId" : { }, + "Phone" : { }, + "PartyType" : { } + } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Parties") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdPartiesGet : OBPEndpoint = { + case "accounts" :: accountId:: "parties" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Party" : [ { + "BeneficialOwnership" : true, + "Address" : [ { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + }, { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + } ], + "AccountRole" : { }, + "Mobile" : { }, + "EmailAddress" : { }, + "LegalStructure" : { }, + "Name" : { }, + "PartyNumber" : { }, + "Relationships" : { + "Account" : { + "Related" : "http://example.com/aeiou", + "Id" : "Id" + } + }, + "FullLegalName" : { }, + "PartyId" : { }, + "Phone" : { }, + "PartyType" : { } + }, { + "BeneficialOwnership" : true, + "Address" : [ { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + }, { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + } ], + "AccountRole" : { }, + "Mobile" : { }, + "EmailAddress" : { }, + "LegalStructure" : { }, + "Name" : { }, + "PartyNumber" : { }, + "Relationships" : { + "Account" : { + "Related" : "http://example.com/aeiou", + "Id" : "Id" + } + }, + "FullLegalName" : { }, + "PartyId" : { }, + "Phone" : { }, + "PartyType" : { } + } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + accountsAccountIdPartyGet, + apiVersion, + nameOf(accountsAccountIdPartyGet), + "GET", + "/accounts/ACCOUNT_ID/party", + "Get Accounts Party by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Party" : { + "BeneficialOwnership" : true, + "Address" : [ { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + }, { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + } ], + "AccountRole" : { }, + "Mobile" : { }, + "EmailAddress" : { }, + "LegalStructure" : { }, + "Name" : { }, + "PartyNumber" : { }, + "Relationships" : { + "Account" : { + "Related" : "http://example.com/aeiou", + "Id" : "Id" + } + }, + "FullLegalName" : { }, + "PartyId" : { }, + "Phone" : { }, + "PartyType" : { } + } + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Parties") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdPartyGet : OBPEndpoint = { + case "accounts" :: accountId:: "party" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Party" : { + "BeneficialOwnership" : true, + "Address" : [ { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + }, { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + } ], + "AccountRole" : { }, + "Mobile" : { }, + "EmailAddress" : { }, + "LegalStructure" : { }, + "Name" : { }, + "PartyNumber" : { }, + "Relationships" : { + "Account" : { + "Related" : "http://example.com/aeiou", + "Id" : "Id" + } + }, + "FullLegalName" : { }, + "PartyId" : { }, + "Phone" : { }, + "PartyType" : { } + } + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + partyGet, + apiVersion, + nameOf(partyGet), + "GET", + "/party", + "Get Party", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Party" : { + "BeneficialOwnership" : true, + "Address" : [ { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + }, { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + } ], + "AccountRole" : { }, + "Mobile" : { }, + "EmailAddress" : { }, + "LegalStructure" : { }, + "Name" : { }, + "PartyNumber" : { }, + "Relationships" : { + "Account" : { + "Related" : "http://example.com/aeiou", + "Id" : "Id" + } + }, + "FullLegalName" : { }, + "PartyId" : { }, + "Phone" : { }, + "PartyType" : { } + } + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Parties") :: apiTagMockedData :: Nil + ) + + lazy val partyGet : OBPEndpoint = { + case "party" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Party" : { + "BeneficialOwnership" : true, + "Address" : [ { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + }, { + "CountrySubDivision" : { }, + "StreetName" : { }, + "AddressLine" : [ "AddressLine", "AddressLine", "AddressLine", "AddressLine", "AddressLine" ], + "BuildingNumber" : { }, + "TownName" : { }, + "Country" : { }, + "AddressType" : { }, + "PostCode" : { } + } ], + "AccountRole" : { }, + "Mobile" : { }, + "EmailAddress" : { }, + "LegalStructure" : { }, + "Name" : { }, + "PartyNumber" : { }, + "Relationships" : { + "Account" : { + "Related" : "http://example.com/aeiou", + "Id" : "Id" + } + }, + "FullLegalName" : { }, + "PartyId" : { }, + "Phone" : { }, + "PartyType" : { } + } + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/StandingOrdersApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/StandingOrdersApi.scala new file mode 100644 index 000000000..984170253 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/StandingOrdersApi.scala @@ -0,0 +1,155 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_StandingOrdersApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountsAccountIdStandingOrdersGet :: + standingOrdersGet :: + Nil + + + resourceDocs += ResourceDoc( + accountsAccountIdStandingOrdersGet, + apiVersion, + nameOf(accountsAccountIdStandingOrdersGet), + "GET", + "/accounts/ACCOUNT_ID/standing-orders", + "Get Accounts Standing Orders by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "StandingOrder" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Standing Orders") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdStandingOrdersGet : OBPEndpoint = { + case "accounts" :: accountId:: "standing-orders" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "StandingOrder" : [ { }, { } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + standingOrdersGet, + apiVersion, + nameOf(standingOrdersGet), + "GET", + "/standing-orders", + "Get Standing Orders", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "StandingOrder" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Standing Orders") :: apiTagMockedData :: Nil + ) + + lazy val standingOrdersGet : OBPEndpoint = { + case "standing-orders" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "StandingOrder" : [ { }, { } ] + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/StatementsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/StatementsApi.scala new file mode 100644 index 000000000..73439fbda --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/StatementsApi.scala @@ -0,0 +1,299 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_StatementsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountsAccountIdStatementsGet :: + accountsAccountIdStatementsStatementIdFileGet :: + accountsAccountIdStatementsStatementIdGet :: + accountsAccountIdStatementsStatementIdTransactionsGet :: + statementsGet :: + Nil + + + resourceDocs += ResourceDoc( + accountsAccountIdStatementsGet, + apiVersion, + nameOf(accountsAccountIdStatementsGet), + "GET", + "/accounts/ACCOUNT_ID/statements", + "Get Accounts Statements by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Statement" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Statements") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdStatementsGet : OBPEndpoint = { + case "accounts" :: accountId:: "statements" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Statement" : [ { }, { } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + accountsAccountIdStatementsStatementIdFileGet, + apiVersion, + nameOf(accountsAccountIdStatementsStatementIdFileGet), + "GET", + "/accounts/ACCOUNT_ID/statements/STATEMENT_ID/file", + "Get Accounts Statements File by AccountId and StatementId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ }"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Statements") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdStatementsStatementIdFileGet : OBPEndpoint = { + case "accounts" :: accountId:: "statements" :: statementId:: "file" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ }"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + accountsAccountIdStatementsStatementIdGet, + apiVersion, + nameOf(accountsAccountIdStatementsStatementIdGet), + "GET", + "/accounts/ACCOUNT_ID/statements/STATEMENT_ID", + "Get Accounts Statement by AccountId and StatementId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Statement" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Statements") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdStatementsStatementIdGet : OBPEndpoint = { + case "accounts" :: accountId:: "statements" :: statementId :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Statement" : [ { }, { } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + accountsAccountIdStatementsStatementIdTransactionsGet, + apiVersion, + nameOf(accountsAccountIdStatementsStatementIdTransactionsGet), + "GET", + "/accounts/ACCOUNT_ID/statements/STATEMENT_ID/transactions", + "Get Accounts Statement Tranactions by AccountId and StatementId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Transaction" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Statements") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdStatementsStatementIdTransactionsGet : OBPEndpoint = { + case "accounts" :: accountId:: "statements" :: statementId:: "transactions" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Transaction" : [ { }, { } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + statementsGet, + apiVersion, + nameOf(statementsGet), + "GET", + "/statements", + "Get Statements", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Statement" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Statements") :: apiTagMockedData :: Nil + ) + + lazy val statementsGet : OBPEndpoint = { + case "statements" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Statement" : [ { }, { } ] + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/SupplementaryAccountInfoApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/SupplementaryAccountInfoApi.scala new file mode 100644 index 000000000..cc625c6f8 --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/SupplementaryAccountInfoApi.scala @@ -0,0 +1,145 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_SupplementaryAccountInfoApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountsAccountIdSupplementaryAccountInfoGet :: + Nil + + + resourceDocs += ResourceDoc( + accountsAccountIdSupplementaryAccountInfoGet, + apiVersion, + nameOf(accountsAccountIdSupplementaryAccountInfoGet), + "GET", + "/accounts/ACCOUNT_ID/supplementary-account-info", + "Get Accounts Supplementary Account Info by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Data" : { + "ReadAccount" : { + "ReadLoanMortgageInfo" : { + "JointHolderName" : "JointHolderName", + "LoanAmount" : "LoanAmount", + "DisbursedAmount" : "DisbursedAmount", + "LoanFrequency" : "LoanFrequency", + "Rate" : "Rate", + "Numberofinstallments" : "Numberofinstallments", + "OutstandingLoanAmount" : "OutstandingLoanAmount" + }, + "AccountID" : "AccountID", + "ReadDepositInfo" : { + "JointHolderName" : "JointHolderName", + "DepositFrequency" : "DepositFrequency", + "MaturityAmount" : "MaturityAmount", + "Rate" : "Rate", + "InitialDepositAmount" : "InitialDepositAmount", + "MaturityDate" : "2000-01-23T04:56:07.000+00:00" + }, + "AccountOpeningDate" : "2000-01-23T04:56:07.000+00:00", + "ReadCASAInfo" : { + "JointHolderName" : "JointHolderName", + "Rate" : "Rate", + "LienAmount" : "LienAmount" + }, + "ReadCreditCardInfo" : { + "Rate" : "Rate", + "GracePeriod" : "GracePeriod", + "CardLimit" : "CardLimit", + "URL" : "URL" + }, + "ReadEWalletInfo" : { + "ChargeFrequency" : "ChargeFrequency", + "Charge" : "Charge" + } + } + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Supplementary Account Info") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdSupplementaryAccountInfoGet : OBPEndpoint = { + case "accounts" :: accountId:: "supplementary-account-info" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Data" : { + "ReadAccount" : { + "ReadLoanMortgageInfo" : { + "JointHolderName" : "JointHolderName", + "LoanAmount" : "LoanAmount", + "DisbursedAmount" : "DisbursedAmount", + "LoanFrequency" : "LoanFrequency", + "Rate" : "Rate", + "Numberofinstallments" : "Numberofinstallments", + "OutstandingLoanAmount" : "OutstandingLoanAmount" + }, + "AccountID" : "AccountID", + "ReadDepositInfo" : { + "JointHolderName" : "JointHolderName", + "DepositFrequency" : "DepositFrequency", + "MaturityAmount" : "MaturityAmount", + "Rate" : "Rate", + "InitialDepositAmount" : "InitialDepositAmount", + "MaturityDate" : "2000-01-23T04:56:07.000+00:00" + }, + "AccountOpeningDate" : "2000-01-23T04:56:07.000+00:00", + "ReadCASAInfo" : { + "JointHolderName" : "JointHolderName", + "Rate" : "Rate", + "LienAmount" : "LienAmount" + }, + "ReadCreditCardInfo" : { + "Rate" : "Rate", + "GracePeriod" : "GracePeriod", + "CardLimit" : "CardLimit", + "URL" : "URL" + }, + "ReadEWalletInfo" : { + "ChargeFrequency" : "ChargeFrequency", + "Charge" : "Charge" + } + } + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/TransactionsApi.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/TransactionsApi.scala new file mode 100644 index 000000000..eb2fbfe8c --- /dev/null +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/TransactionsApi.scala @@ -0,0 +1,155 @@ +package code.api.BahrainOBF.v1_0_0 + +import code.api.APIFailureNewStyle +import code.api.berlin.group.v1_3.JvalueCaseClass +import net.liftweb.json +import net.liftweb.json._ +import code.api.util.APIUtil.{defaultBankId, _} +import code.api.util.NewStyle +import code.api.util.ErrorMessages._ +import code.api.util.ApiTag._ +import code.api.util.NewStyle.HttpCode +import code.bankconnectors.Connector +import code.model._ +import code.util.Helper +import code.views.Views +import net.liftweb.common.Full +import net.liftweb.http.rest.RestHelper +import com.github.dwickern.macros.NameOf.nameOf +import scala.collection.immutable.Nil +import scala.collection.mutable.ArrayBuffer +import com.openbankproject.commons.ExecutionContext.Implicits.global +import scala.concurrent.Future +import code.api.BahrainOBF.v1_0_0.ApiCollector +import code.api.util.ApiTag + +object APIMethods_TransactionsApi extends RestHelper { + val apiVersion = ApiCollector.apiVersion + val resourceDocs = ArrayBuffer[ResourceDoc]() + val apiRelations = ArrayBuffer[ApiRelation]() + protected implicit def JvalueToSuper(what: JValue): JvalueCaseClass = JvalueCaseClass(what) + + val endpoints = + accountsAccountIdTransactionsGet :: + transactionsGet :: + Nil + + + resourceDocs += ResourceDoc( + accountsAccountIdTransactionsGet, + apiVersion, + nameOf(accountsAccountIdTransactionsGet), + "GET", + "/accounts/ACCOUNT_ID/transactions", + "Get Accounts Trabnsactions by AccountId", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Transaction" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Transactions") :: apiTagMockedData :: Nil + ) + + lazy val accountsAccountIdTransactionsGet : OBPEndpoint = { + case "accounts" :: accountId:: "transactions" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Transaction" : [ { }, { } ] + } +}"""), callContext) + } + } + } + + resourceDocs += ResourceDoc( + transactionsGet, + apiVersion, + nameOf(transactionsGet), + "GET", + "/transactions", + "Get Transactions", + s"""${mockedDataText(true)} + + """, + json.parse(""""""), + json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Transaction" : [ { }, { } ] + } +}"""), + List(UserNotLoggedIn, UnknownError), + ApiTag("Transactions") :: apiTagMockedData :: Nil + ) + + lazy val transactionsGet : OBPEndpoint = { + case "transactions" :: Nil JsonGet _ => { + cc => + for { + (Full(u), callContext) <- authenticatedAccess(cc, UserNotLoggedIn) + } yield { + (json.parse("""{ + "Meta" : { + "FirstAvailableDateTime" : { }, + "TotalPages" : 0 + }, + "Links" : { + "Last" : "http://example.com/aeiou", + "Prev" : "http://example.com/aeiou", + "Next" : "http://example.com/aeiou", + "First" : "http://example.com/aeiou", + "Self" : "http://example.com/aeiou" + }, + "Data" : { + "Transaction" : [ { }, { } ] + } +}"""), callContext) + } + } + } + +} + + + diff --git a/obp-api/src/main/scala/code/api/MxOF/OBP_MXOF_1_0_0.scala b/obp-api/src/main/scala/code/api/MxOF/OBP_MXOF_1_0_0.scala index 35e987b7f..04e7b0dee 100644 --- a/obp-api/src/main/scala/code/api/MxOF/OBP_MXOF_1_0_0.scala +++ b/obp-api/src/main/scala/code/api/MxOF/OBP_MXOF_1_0_0.scala @@ -1,6 +1,6 @@ /** * Open Bank Project - API - * Copyright (C) 2011-2018, TESOBE Ltd + * Copyright (C) 2011-2022, TESOBE GmbH ** *This program is free software: you can redistribute it and/or modify *it under the terms of the GNU Affero General Public License as published by From 8c403bfb47040488c9d240446ca5d6466363f112 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 11 Jan 2022 12:31:24 +0100 Subject: [PATCH 21/37] feature/tweaked BHOBF -> BAHRAIN-OBF --- .../main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala index dc474f1f9..33d8723ad 100644 --- a/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala +++ b/obp-api/src/main/scala/code/api/BahrainOBF/v1_0_0/ApiCollector.scala @@ -45,7 +45,7 @@ import scala.collection.mutable.ArrayBuffer This file defines which endpoints from all the versions are available in v1 */ object ApiCollector extends OBPRestHelper with MdcLoggable with ScannedApis { - override val apiVersion = ScannedApiVersion("BHOBF", "BHOBF", "v1.0.0") + override val apiVersion = ScannedApiVersion("BAHRAIN-OBF", "BAHRAIN-OBF", "v1.0.0") val versionStatus = "DRAFT" private[this] val endpoints = From 9764992b8f771c58769efe2f7dbaedd969b4e56d Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 11 Jan 2022 14:04:38 +0100 Subject: [PATCH 22/37] tests/fixed the failed tests --- obp-api/src/test/scala/code/util/ApiVersionUtilsTest.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/obp-api/src/test/scala/code/util/ApiVersionUtilsTest.scala b/obp-api/src/test/scala/code/util/ApiVersionUtilsTest.scala index c415e077d..415c6d14e 100644 --- a/obp-api/src/test/scala/code/util/ApiVersionUtilsTest.scala +++ b/obp-api/src/test/scala/code/util/ApiVersionUtilsTest.scala @@ -5,7 +5,8 @@ import code.api.util.ApiVersionUtils.versions import code.api.v4_0_0.V400ServerSetup class ApiVersionUtilsTest extends V400ServerSetup { - feature("test ApiVersionUtils.valueOf support both fullyQualifiedVersion and apiShortVersion") { + feature("test ApiVersionUtils.valueOf ") { + scenario("support both fullyQualifiedVersion and apiShortVersion") { ApiVersionUtils.valueOf("v4.0.0") ApiVersionUtils.valueOf("OBPv4.0.0") @@ -17,6 +18,6 @@ class ApiVersionUtilsTest extends V400ServerSetup { versions.map(version => ApiVersionUtils.valueOf(version.fullyQualifiedVersion)) //NOTE, when we added the new version, better fix this number manually. and also check the versions - versions.length shouldBe(19) - } + versions.length shouldBe(20) + }} } \ No newline at end of file From 5fa281146ddf5891f8f387e19ba83bf0e1258d6e Mon Sep 17 00:00:00 2001 From: hongwei Date: Thu, 13 Jan 2022 00:20:29 +0100 Subject: [PATCH 23/37] test/added tests for the Sandbox.createSandbox method --- .../scala/code/util/DynamicUtilTest.scala | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/obp-api/src/test/scala/code/util/DynamicUtilTest.scala b/obp-api/src/test/scala/code/util/DynamicUtilTest.scala index c9673d1f2..9e11f0cb4 100644 --- a/obp-api/src/test/scala/code/util/DynamicUtilTest.scala +++ b/obp-api/src/test/scala/code/util/DynamicUtilTest.scala @@ -27,6 +27,7 @@ TESOBE (http://www.tesobe.com/) package code.util +import code.api.util.DynamicUtil.Sandbox import code.api.util._ import code.setup.PropsReset import com.openbankproject.commons.util.{JsonUtils, ReflectUtils} @@ -34,6 +35,10 @@ import net.liftweb.common.Box import net.liftweb.json import org.scalatest.{FeatureSpec, FlatSpec, GivenWhenThen, Matchers, Tag} +import java.io.File +import java.security.AccessControlException +import scala.io.Source + class DynamicUtilTest extends FlatSpec with Matchers { object DynamicUtilsTag extends Tag("DynamicUtil") @@ -48,6 +53,31 @@ class DynamicUtilTest extends FlatSpec with Matchers { getBankResponse should be (125) } + "Sandbox.createSandbox method" should "should throw exception" taggedAs DynamicUtilsTag in { + val permissionList = List( +// new java.net.SocketPermission("ir.dcs.gla.ac.uk:80","connect,resolve"), + ) + + intercept[AccessControlException] { + Sandbox.createSandbox(permissionList).runInSandbox { + scala.io.Source.fromURL("https://apisandbox.openbankproject.com/") + } + } + } + + "Sandbox.createSandbox method" should "should work well" taggedAs DynamicUtilsTag in { + val permissionList = List( + new java.net.SocketPermission("apisandbox.openbankproject.com:443","connect,resolve"), + new java.util.PropertyPermission("user.dir","read"), + new java.io.FilePermission("README.md","read"), + ) + + Sandbox.createSandbox(permissionList).runInSandbox { + scala.io.Source.fromURL("https://apisandbox.openbankproject.com/") + Source.fromFile("README.md").getLines + new File(".").getCanonicalPath + } + } val zson = { """ From 594eff71ebafed9619980ee9634f60569b9d0446 Mon Sep 17 00:00:00 2001 From: hongwei Date: Thu, 13 Jan 2022 11:02:40 +0100 Subject: [PATCH 24/37] docfix/added the comments for permissions --- obp-api/src/main/scala/code/api/util/DynamicUtil.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala index 3e625b2ee..836489fe4 100644 --- a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala +++ b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala @@ -269,9 +269,9 @@ object DynamicUtil { // Here is the Java Permission document, please extend these permissions carefully. // https://docs.oracle.com/javase/8/docs/technotes/guides/security/spec/security-spec.doc3.html#17001 // If you are not familiar with the permissions, we provide the clear error messages for the missing permissions in the log. - // eg: "OBP-40047: DynamicResourceDoc method have no enough permissions. No permission of: (\"java.io.FilePermission\" \"stop-words-en.txt\" \"write\")" + // eg1 scala test level : and have a look at the scala test for `createSandbox` method, you can see how to add permissions there too. + // eg2 api level: "OBP-40047: DynamicResourceDoc method have no enough permissions. No permission of: (\"java.io.FilePermission\" \"stop-words-en.txt\" \"write\")" // --> you can extends following permission: new java.net.SocketPermission("ir.dcs.gla.ac.uk:80", "connect,resolve"), - // // NOTE: These permissions are only checked during runtime, not the compilation period. val allowedRuntimePermissions = List[Permission]( new NetPermission("specifyStreamHandler"), From 5a96502af25c2130188b6391f459b8ff3c3946e4 Mon Sep 17 00:00:00 2001 From: hongwei Date: Thu, 13 Jan 2022 12:24:46 +0100 Subject: [PATCH 25/37] docfix/added the comments for sandbox method and tweaked the bankId permission error message --- obp-api/src/main/scala/code/api/util/DynamicUtil.scala | 4 ++++ .../com/openbankproject/commons/model/BankingModel.scala | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala index 836489fe4..7011335d7 100644 --- a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala +++ b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala @@ -208,6 +208,10 @@ object DynamicUtil { } private val memoSandbox = new Memo[String, Sandbox] + + /** + * this method will call create Sandbox underneath, but will have default permissions and bankId permission and cache. + */ def sandbox(bankId: String): Sandbox = memoSandbox.memoize(bankId) { Sandbox.createSandbox(BankId.permission(bankId) :: Validation.allowedRuntimePermissions) } diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala index 2a0266eeb..b8da25b20 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/BankingModel.scala @@ -149,15 +149,15 @@ object BankId { def checkPermission(bankId: String): Unit = { val sm = System.getSecurityManager - // use FilePermission to control bankId value, it is a hack way. - if (sm != null) { + // use AuthPermission to control bankId value, it is a hack way. + if (sm != null) { //only check the permission when we using the security manager. val securityContext = sm.getSecurityContext.asInstanceOf[AccessControlContext] sm.checkPermission(permission(bankId), securityContext) } } def checkPermission(bankId: Option[String]): Unit = bankId.foreach(checkPermission) - def permission(bankId: String) = new AuthPermission(s"operateBank.$bankId") + def permission(bankId: String) = new AuthPermission(s"You do not have the permission for the BANK_ID($bankId)") } case class AccountRoutingAddress(val value: String) { From 8a01c8d6a0fb3bb217677921669eff734082b971 Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 17 Jan 2022 09:30:52 +0100 Subject: [PATCH 26/37] docfix/added the comments for sandbox method and tweaked the bankId --- .../scala/code/util/DynamicUtilTest.scala | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/obp-api/src/test/scala/code/util/DynamicUtilTest.scala b/obp-api/src/test/scala/code/util/DynamicUtilTest.scala index 9e11f0cb4..6c73d6d15 100644 --- a/obp-api/src/test/scala/code/util/DynamicUtilTest.scala +++ b/obp-api/src/test/scala/code/util/DynamicUtilTest.scala @@ -30,6 +30,7 @@ package code.util import code.api.util.DynamicUtil.Sandbox import code.api.util._ import code.setup.PropsReset +import com.openbankproject.commons.model.BankId import com.openbankproject.commons.util.{JsonUtils, ReflectUtils} import net.liftweb.common.Box import net.liftweb.json @@ -78,6 +79,28 @@ class DynamicUtilTest extends FlatSpec with Matchers { new File(".").getCanonicalPath } } + + "Sandbox.sandbox method test bankId" should "should throw exception" taggedAs DynamicUtilsTag in { + intercept[AccessControlException] { + Sandbox.sandbox(bankId= "abc").runInSandbox { + BankId("123" ) + } + } + } + + "Sandbox.sandbox method test bankId" should "should work well" taggedAs DynamicUtilsTag in { + Sandbox.sandbox(bankId= "abc").runInSandbox { + BankId("abc" ) + } + } + + "Sandbox.sandbox method test default permission" should "should throw exception" taggedAs DynamicUtilsTag in { + intercept[AccessControlException] { + Sandbox.sandbox(bankId= "abc").runInSandbox { + scala.io.Source.fromURL("https://apisandbox.openbankproject.com/") + } + } + } val zson = { """ From dd6b671ca5c4e33eaecb0ccdad51b0a51e53b831 Mon Sep 17 00:00:00 2001 From: hongwei Date: Mon, 17 Jan 2022 14:07:55 +0100 Subject: [PATCH 27/37] test/added the test for DynamicEndpoints.CompiledObjects.validateDependency --- .../scala/code/api/util/ExampleValue.scala | 30 ++++++----- .../code/util/DynamicEndpointsTest.scala | 51 +++++++++++++++++++ 2 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala 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 c196dbc8a..43a6488c4 100644 --- a/obp-api/src/main/scala/code/api/util/ExampleValue.scala +++ b/obp-api/src/main/scala/code/api/util/ExampleValue.scala @@ -396,21 +396,23 @@ object ExampleValue { lazy val connectorMethodIdExample = ConnectorField("ace0352a-9a0f-4bfa-b30b-9003aa467f51", "A string that MUST uniquely identify the connector method on this OBP instance, can be used in all cache. ") glossaryItems += makeGlossaryItem("ConnectorMethod.connectorMethodId", connectorMethodIdExample) - lazy val dynamicResourceDocMethodBodyExample = ConnectorField("%20%20%20%20val%20Some(resourceDoc)%20%3D%20callContext.resourceDocument%0A%20%20%20%20" + - "val%20hasRequestBody%20%3D%20request.body.isDefined%0A%0A%20%20%20%20%2F%2F%20get%20Path%20Parameters%2C%20example%3A%0A%20%20%20" + - "%20%2F%2F%20if%20the%20requestUrl%20of%20resourceDoc%20is%20%2Fhello%2Fbanks%2FBANK_ID%2Fworld%0A%20%20%20%20%2F%2F%20the%20reque" + - "st%20path%20is%20%2Fhello%2Fbanks%2Fbank_x%2Fworld%0A%20%20%20%20%2F%2FpathParams.get(%22BANK_ID%22)%20will%20get%20Option(%22bank" + - "_x%22)%20value%0A%20%20%20%20val%20pathParams%20%3D%20getPathParams(callContext%2C%20request)%0A%20%20%20%20val%20myUserId%20%3D%2" + - "0pathParams(%22MY_USER_ID%22)%0A%0A%0A%20%20%20%20val%20requestEntity%20%3D%20request.json%20match%20%7B%0A%20%20%20%20%20%20case%" + - "20Full(zson)%20%3D%3E%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20zson.extract%5BRequestRootJsonClass%5D%0" + - "A%20%20%20%20%20%20%20%20%7D%20catch%20%7B%0A%20%20%20%20%20%20%20%20%20%20case%20e%3A%20MappingException%20%3D%3E%0A%20%20%20%20%" + - "20%20%20%20%20%20%20%20return%20Full(errorJsonResponse(s%22%24InvalidJsonFormat%20%24%7Be.msg%7D%22))%0A%20%20%20%20%20%20%20%20%7" + - "D%0A%20%20%20%20%20%20case%20_%3A%20EmptyBox%20%3D%3E%0A%20%20%20%20%20%20%20%20return%20Full(errorJsonResponse(s%22%24InvalidRequ" + - "estPayload%20Current%20request%20has%20no%20payload%22))%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%2F%2F%20please%20add%20business%20" + - "logic%20here%0A%20%20%20%20val%20responseBody%3AResponseRootJsonClass%20%3D%20ResponseRootJsonClass(s%22%24%7BmyUserId%7D_from_pat" + - "h%22%2C%20requestEntity.name%2C%20requestEntity.age%2C%20requestEntity.hobby)%0A%20%20%20%20Future.successful%20%7B%0A%20%20%20%20" + - "%20%20(responseBody%2C%20HttpCode.%60200%60(callContext.callContext))%0A%20%20%20%20%7D", + lazy val dynamicResourceDocMethodBodyExample = ConnectorField("%20%20%20%20val%20Some(resourceDoc)%20%3D%20callContext." + + "resourceDocument%0A%20%20%20%20val%20hasRequestBody%20%3D%20request.body.isDefined%0A%0A%20%20%20%20%2F%2F%20get%20" + + "Path%20Parameters%2C%20example%3A%0A%20%20%20%20%2F%2F%20if%20the%20requestUrl%20of%20resourceDoc%20is%20%2Fhello%2" + + "Fbanks%2FBANK_ID%2Fworld%0A%20%20%20%20%2F%2F%20the%20request%20path%20is%20%2Fhello%2Fbanks%2Fbank_x%2Fworld%0A%20" + + "%20%20%20%2F%2FpathParams.get(%22BANK_ID%22)%20will%20get%20Option(%22bank_x%22)%20value%0A%0A%20%20%20%20val%20my" + + "UserId%20%3D%20pathParams(%22MY_USER_ID%22)%0A%0A%0A%20%20%20%20val%20requestEntity%20%3D%20request.json%20match%20" + + "%7B%0A%20%20%20%20%20%20case%20Full(zson)%20%3D%3E%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%" + + "20%20zson.extract%5BRequestRootJsonClass%5D%0A%20%20%20%20%20%20%20%20%7D%20catch%20%7B%0A%20%20%20%20%20%20%20%20%" + + "20%20case%20e%3A%20MappingException%20%3D%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20Full(errorJsonResponse(" + + "s%22%24InvalidJsonFormat%20%24%7Be.msg%7D%22))%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20case%20_%3A%20Emp" + + "tyBox%20%3D%3E%0A%20%20%20%20%20%20%20%20return%20Full(errorJsonResponse(s%22%24InvalidRequestPayload%20Current%20" + + "request%20has%20no%20payload%22))%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%2F%2F%20please%20add%20business%20logic%20" + + "here%0A%20%20%20%20val%20responseBody%3AResponseRootJsonClass%20%3D%20ResponseRootJsonClass(s%22%24%7BmyUserId%7D_" + + "from_path%22%2C%20requestEntity.name%2C%20requestEntity.age%2C%20requestEntity.hobby)%0A%20%20%20%20Future.successf" + + "ul%20%7B%0A%20%20%20%20%20%20(responseBody%2C%20HttpCode.%60200%60(callContext.callContext))%0A%20%20%20%20%7D", "the URL-encoded format String, the original code is the OBP connector method body.") + glossaryItems += makeGlossaryItem("DynamicResourceDoc.methodBody", dynamicResourceDocMethodBodyExample) lazy val connectorMethodBodyExample = ConnectorField("%20%20%20%20%20%20Future.successful%28%0A%20%20%20%20%20%20%20%20Full%28%" + diff --git a/obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala b/obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala new file mode 100644 index 000000000..7f893ddd7 --- /dev/null +++ b/obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala @@ -0,0 +1,51 @@ +/** +Open Bank Project - API +Copyright (C) 2011-2022, TESOBE GmbH. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +Email: contact@tesobe.com +TESOBE GmbH. +Osloer Strasse 16/17 +Berlin 13359, Germany + +This product includes software developed at +TESOBE (http://www.tesobe.com/) + + */ + +package code.util + +import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON +import code.api.v4_0_0.V400ServerSetup +import code.api.v4_0_0.dynamic.CompiledObjects +import code.setup.PropsReset +import org.scalatest.Tag + + + +class DynamicEndpointsTest extends V400ServerSetup with PropsReset { + object DynamicUtilsTag extends Tag("DynamicEndpoints") + + feature("test DynamicEndpoints.CompiledObjects.validateDependency method") { + //This mean, we are only disabled the v4.0.0, all other versions should be enabled + setPropsValues( + "dynamic_code_compile_validate_enable" -> "true" + ) + + val jsonDynamicResourceDoc = SwaggerDefinitionsJSON.jsonDynamicResourceDoc + val compiledObject = CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) + .validateDependency() + } +} \ No newline at end of file From 5a332c2150a671b53a88b47cde4e29dfd1bde566 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 18 Jan 2022 09:22:45 +0100 Subject: [PATCH 28/37] test/added the tests for permission props --- .../scala/code/util/DynamicUtilTest.scala | 74 ++++++++++++++++++- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/obp-api/src/test/scala/code/util/DynamicUtilTest.scala b/obp-api/src/test/scala/code/util/DynamicUtilTest.scala index 6c73d6d15..17738107f 100644 --- a/obp-api/src/test/scala/code/util/DynamicUtilTest.scala +++ b/obp-api/src/test/scala/code/util/DynamicUtilTest.scala @@ -32,12 +32,13 @@ import code.api.util._ import code.setup.PropsReset import com.openbankproject.commons.model.BankId import com.openbankproject.commons.util.{JsonUtils, ReflectUtils} -import net.liftweb.common.Box +import net.liftweb.common.{Box} import net.liftweb.json import org.scalatest.{FeatureSpec, FlatSpec, GivenWhenThen, Matchers, Tag} import java.io.File -import java.security.AccessControlException +import java.security.{AccessControlException} +import scala.collection.immutable.List import scala.io.Source class DynamicUtilTest extends FlatSpec with Matchers { @@ -54,6 +55,71 @@ class DynamicUtilTest extends FlatSpec with Matchers { getBankResponse should be (125) } + "DynamicUtil.compileScalaCode method" should "compile the permissions and dependences" taggedAs DynamicUtilsTag in { + + val permissions:Box[List[java.security.Permission]] = DynamicUtil.compileScalaCode(""" + |List[java.security.Permission]( + | new java.net.NetPermission("specifyStreamHandler"), + | new java.lang.reflect.ReflectPermission("suppressAccessChecks"), + | new java.lang.RuntimePermission("getenv.*") + | ) """.stripMargin) + + val permissionList = permissions.openOrThrowException("Can not compile the string to permissions") + Sandbox.createSandbox(permissionList) + permissionList.toString contains ("""java.net.NetPermission""") shouldBe (true) + + val permissionString = + """[new java.net.NetPermission("specifyStreamHandler"), + |new java.lang.reflect.ReflectPermission("suppressAccessChecks"), + |new java.lang.RuntimePermission("getenv.*"), + |new java.util.PropertyPermission("cglib.useCache", "read"), + |new java.util.PropertyPermission("net.sf.cglib.test.stressHashCodes", "read"), + |new java.util.PropertyPermission("cglib.debugLocation", "read"), + |new java.lang.RuntimePermission("accessDeclaredMembers"), + |new java.lang.RuntimePermission("getClassLoader")]""".stripMargin + + val scalaCode = "List[java.security.Permission]"+permissionString.replaceFirst("\\[","(").dropRight(1)+")" + val permissions2:Box[List[java.security.Permission]] = DynamicUtil.compileScalaCode(scalaCode) + + val permissionList2 = permissions2.openOrThrowException("Can not compile the string to permissions") + Sandbox.createSandbox(permissionList2) + permissionList2.toString contains ("""java.net.NetPermission""") shouldBe (true) + + + val dependenciesBox: Box[Map[String, Set[String]]] = DynamicUtil.compileScalaCode(s"${DynamicUtil.importStatements}"+""" + | + |Map( + | // companion objects methods + | NewStyle.function.getClass.getTypeName -> "*", + | CompiledObjects.getClass.getTypeName -> "sandbox", + | HttpCode.getClass.getTypeName -> "200", + | DynamicCompileEndpoint.getClass.getTypeName -> "getPathParams, scalaFutureToBoxedJsonResponse", + | APIUtil.getClass.getTypeName -> "errorJsonResponse, errorJsonResponse$default$1, errorJsonResponse$default$2, errorJsonResponse$default$3, errorJsonResponse$default$4, scalaFutureToLaFuture, futureToBoxedResponse", + | ErrorMessages.getClass.getTypeName -> "*", + | ExecutionContext.Implicits.getClass.getTypeName -> "global", + | JSONFactory400.getClass.getTypeName -> "createBanksJson", + | + | // class methods + | classOf[Sandbox].getTypeName -> "runInSandbox", + | classOf[CallContext].getTypeName -> "*", + | classOf[ResourceDoc].getTypeName -> "getPathParams", + | "scala.reflect.runtime.package$" -> "universe", + | + | // allow any method of PractiseEndpoint for test + | PractiseEndpoint.getClass.getTypeName + "*" -> "*", + | + | ).mapValues(v => StringUtils.split(v, ',').map(_.trim).toSet)""".stripMargin) + val dependencies = dependenciesBox.openOrThrowException("Can not compile the string to Map") + dependencies.toString contains ("code.api.util.NewStyle") shouldBe (true) + + val dependenciesString = """[NewStyle.function.getClass.getTypeName -> "*",CompiledObjects.getClass.getTypeName -> "sandbox",HttpCode.getClass.getTypeName -> "200",DynamicCompileEndpoint.getClass.getTypeName -> "getPathParams, scalaFutureToBoxedJsonResponse",APIUtil.getClass.getTypeName -> "errorJsonResponse, errorJsonResponse$default$1, errorJsonResponse$default$2, errorJsonResponse$default$3, errorJsonResponse$default$4, scalaFutureToLaFuture, futureToBoxedResponse",ErrorMessages.getClass.getTypeName -> "*",ExecutionContext.Implicits.getClass.getTypeName -> "global",JSONFactory400.getClass.getTypeName -> "createBanksJson",classOf[Sandbox].getTypeName -> "runInSandbox",classOf[CallContext].getTypeName -> "*",classOf[ResourceDoc].getTypeName -> "getPathParams","scala.reflect.runtime.package$" -> "universe",PractiseEndpoint.getClass.getTypeName + "*" -> "*"]""".stripMargin + + val scalaCode2 = s"${DynamicUtil.importStatements}"+dependenciesString.replaceFirst("\\[","Map(").dropRight(1) +").mapValues(v => StringUtils.split(v, ',').map(_.trim).toSet)" + val dependenciesBox2: Box[Map[String, Set[String]]] = DynamicUtil.compileScalaCode(scalaCode2) + val dependencies2 = dependenciesBox2.openOrThrowException("Can not compile the string to Map") + dependencies2.toString contains ("code.api.util.NewStyle") shouldBe (true) + } + "Sandbox.createSandbox method" should "should throw exception" taggedAs DynamicUtilsTag in { val permissionList = List( // new java.net.SocketPermission("ir.dcs.gla.ac.uk:80","connect,resolve"), @@ -95,11 +161,11 @@ class DynamicUtilTest extends FlatSpec with Matchers { } "Sandbox.sandbox method test default permission" should "should throw exception" taggedAs DynamicUtilsTag in { - intercept[AccessControlException] { +// intercept[AccessControlException] { Sandbox.sandbox(bankId= "abc").runInSandbox { scala.io.Source.fromURL("https://apisandbox.openbankproject.com/") } - } +// } } val zson = { From f14b69692be0c94fce7cef1dbe45d77ce0d99f01 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 18 Jan 2022 09:23:38 +0100 Subject: [PATCH 29/37] feature/move the permissions and dependencies to props --- .../scala/code/api/util/DynamicUtil.scala | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala index 7011335d7..b66430a0c 100644 --- a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala +++ b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala @@ -13,7 +13,7 @@ import com.openbankproject.commons.util.{JsonUtils, ReflectUtils} import javassist.{ClassPool, LoaderClassPath} import net.liftweb.common.{Box, Failure, Full} import net.liftweb.http.JsonResponse -import net.liftweb.json.{JValue, prettyRender} +import net.liftweb.json.{ JValue, prettyRender} import org.apache.commons.lang3.StringUtils import java.lang.reflect.ReflectPermission @@ -265,10 +265,33 @@ object DynamicUtil { |import scala.concurrent.duration._ |import scala.concurrent.{Await, Future} |import com.openbankproject.commons.dto._ + |import code.api.util.APIUtil.ResourceDoc + |import code.api.util.DynamicUtil.Sandbox + |import code.api.util.NewStyle.HttpCode + |import code.api.util._ + |import code.api.v4_0_0.JSONFactory400 + |import code.api.v4_0_0.dynamic.{CompiledObjects, DynamicCompileEndpoint} + |import code.api.v4_0_0.dynamic.practise.PractiseEndpoint + |import com.openbankproject.commons.ExecutionContext + |import com.openbankproject.commons.model.BankId + |import com.openbankproject.commons.util.{JsonUtils, ReflectUtils} + |import net.liftweb.common.{Box, Full} + |import org.apache.commons.lang3.StringUtils + | + |import java.io.File + |import java.security.{AccessControlException, Permission} + |import java.util.PropertyPermission + |import scala.collection.immutable.List + |import scala.io.Source |""".stripMargin object Validation { + + val dynamicCodeSandboxPermissions = APIUtil.getPropsValue("dynamic_code_sandbox_permissions", "[]").trim + val scalaCodePermissioins = "List[java.security.Permission]"+dynamicCodeSandboxPermissions.replaceFirst("\\[","(").dropRight(1)+")" + val permissions:Box[List[java.security.Permission]] = DynamicUtil.compileScalaCode(scalaCodePermissioins) + // all Permissions put at here // Here is the Java Permission document, please extend these permissions carefully. // https://docs.oracle.com/javase/8/docs/technotes/guides/security/spec/security-spec.doc3.html#17001 @@ -277,17 +300,12 @@ object DynamicUtil { // eg2 api level: "OBP-40047: DynamicResourceDoc method have no enough permissions. No permission of: (\"java.io.FilePermission\" \"stop-words-en.txt\" \"write\")" // --> you can extends following permission: new java.net.SocketPermission("ir.dcs.gla.ac.uk:80", "connect,resolve"), // NOTE: These permissions are only checked during runtime, not the compilation period. - val allowedRuntimePermissions = List[Permission]( - new NetPermission("specifyStreamHandler"), - new ReflectPermission("suppressAccessChecks"), - new RuntimePermission("getenv.*"), - new PropertyPermission("cglib.useCache", "read"), - new PropertyPermission("net.sf.cglib.test.stressHashCodes", "read"), - new PropertyPermission("cglib.debugLocation", "read"), - new RuntimePermission("accessDeclaredMembers"), - new RuntimePermission("getClassLoader"), - ) + val allowedRuntimePermissions = permissions.openOrThrowException("Can not compile the props `dynamic_code_sandbox_permissions` to permissions") + val dependenciesString = APIUtil.getPropsValue("dynamic_code_compile_validate_dependencies", "[]").trim + val scalaCodeDependencies = s"${DynamicUtil.importStatements}"+dependenciesString.replaceFirst("\\[","Map(").dropRight(1) +").mapValues(v => StringUtils.split(v, ',').map(_.trim).toSet)" + val dependenciesBox: Box[Map[String, Set[String]]] = DynamicUtil.compileScalaCode(scalaCodeDependencies) + /** * Compilation OBP Dependencies Guard, only checked the OBP methods, not scala/Java libraies(are checked during the runtime.). * @@ -296,27 +314,7 @@ object DynamicUtil { * You can control all the OBP methods here. */ // all allowed methods put at here, typeName -> methods - val allowedCompilationMethods: Map[String, Set[String]] = Map( - // companion objects methods - NewStyle.function.getClass.getTypeName -> "*", - CompiledObjects.getClass.getTypeName -> "sandbox", - HttpCode.getClass.getTypeName -> "200", - DynamicCompileEndpoint.getClass.getTypeName -> "getPathParams, scalaFutureToBoxedJsonResponse", - APIUtil.getClass.getTypeName -> "errorJsonResponse, errorJsonResponse$default$1, errorJsonResponse$default$2, errorJsonResponse$default$3, errorJsonResponse$default$4, scalaFutureToLaFuture, futureToBoxedResponse", - ErrorMessages.getClass.getTypeName -> "*", - ExecutionContext.Implicits.getClass.getTypeName -> "global", - JSONFactory400.getClass.getTypeName -> "createBanksJson", - - // class methods - classOf[Sandbox].getTypeName -> "runInSandbox", - classOf[CallContext].getTypeName -> "*", - classOf[ResourceDoc].getTypeName -> "getPathParams", - "scala.reflect.runtime.package$" -> "universe", - - // allow any method of PractiseEndpoint for test - PractiseEndpoint.getClass.getTypeName + "*" -> "*", - - ).mapValues(v => StringUtils.split(v, ',').map(_.trim).toSet) + val allowedCompilationMethods: Map[String, Set[String]] = dependenciesBox.openOrThrowException("Can not compile the props `dynamic_code_compile_validate_dependencies` to Map") //Do not touch this Set, try to use the `allowedPermissions` and `allowedMethods` to control the sandbox val restrictedTypes = Set( From 4aa6933ad6b65c6ab532d757e2770c485a4ef41e Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 18 Jan 2022 09:45:16 +0100 Subject: [PATCH 30/37] test/fixed the failed test --- .../code/util/DynamicEndpointsTest.scala | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala b/obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala index 7f893ddd7..879e19725 100644 --- a/obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala +++ b/obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala @@ -39,13 +39,30 @@ class DynamicEndpointsTest extends V400ServerSetup with PropsReset { object DynamicUtilsTag extends Tag("DynamicEndpoints") feature("test DynamicEndpoints.CompiledObjects.validateDependency method") { - //This mean, we are only disabled the v4.0.0, all other versions should be enabled - setPropsValues( - "dynamic_code_compile_validate_enable" -> "true" - ) - - val jsonDynamicResourceDoc = SwaggerDefinitionsJSON.jsonDynamicResourceDoc - val compiledObject = CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) - .validateDependency() + scenario("validateDependency should work well "){ + //This mean, we are only disabled the v4.0.0, all other versions should be enabled + setPropsValues( + "dynamic_code_compile_validate_enable" -> "true", + "dynamic_code_compile_validate_dependencies" -> """[ + | NewStyle.function.getClass.getTypeName -> "*", + | CompiledObjects.getClass.getTypeName -> "sandbox", + | HttpCode.getClass.getTypeName -> "200", + | DynamicCompileEndpoint.getClass.getTypeName -> "getPathParams, scalaFutureToBoxedJsonResponse", + | APIUtil.getClass.getTypeName -> "errorJsonResponse, errorJsonResponse$default$1, errorJsonResponse$default$2, errorJsonResponse$default$3, errorJsonResponse$default$4, scalaFutureToLaFuture, futureToBoxedResponse", + | ErrorMessages.getClass.getTypeName -> "*", + | ExecutionContext.Implicits.getClass.getTypeName -> "global", + | JSONFactory400.getClass.getTypeName -> "createBanksJson", + | classOf[Sandbox].getTypeName -> "runInSandbox", + | classOf[CallContext].getTypeName -> "*", + | classOf[ResourceDoc].getTypeName -> "getPathParams", + | "scala.reflect.runtime.package$" -> "universe", + | PractiseEndpoint.getClass.getTypeName + "*" -> "*" + |]""".stripMargin + ) + + val jsonDynamicResourceDoc = SwaggerDefinitionsJSON.jsonDynamicResourceDoc + CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) + .validateDependency() + } } } \ No newline at end of file From ffbcfca6394483b624383cacb81056d0e5b60e1c Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 18 Jan 2022 12:14:31 +0100 Subject: [PATCH 31/37] test/fixed the failed tests --- obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala | 4 ++-- .../main/scala/code/bankconnectors/InternalConnector.scala | 2 +- obp-api/src/test/scala/code/util/DynamicUtilTest.scala | 6 ++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 981bbd1fe..78708b186 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -9239,7 +9239,7 @@ trait APIMethods400 { _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=callContext) { connectorMethod.isDefined } - _ = Validation.validateDependency(connectorMethod.orNull) + _ = Validation.validateDependency(connectorMethod.head) (connectorMethod, callContext) <- NewStyle.function.createJsonConnectorMethod(jsonConnectorMethod, callContext) } yield { (connectorMethod, HttpCode.`201`(callContext)) @@ -9284,7 +9284,7 @@ trait APIMethods400 { _ <- Helper.booleanToFuture(failMsg = errorMsg, cc=callContext) { connectorMethod.isDefined } - _ = Validation.validateDependency(connectorMethod.orNull) + _ = Validation.validateDependency(connectorMethod.head) (connectorMethod, callContext) <- NewStyle.function.updateJsonConnectorMethod(connectorMethodId, connectorMethodBody.methodBody, callContext) } yield { (connectorMethod, HttpCode.`200`(callContext)) diff --git a/obp-api/src/main/scala/code/bankconnectors/InternalConnector.scala b/obp-api/src/main/scala/code/bankconnectors/InternalConnector.scala index aa54a69d1..c424364b9 100644 --- a/obp-api/src/main/scala/code/bankconnectors/InternalConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/InternalConnector.scala @@ -50,7 +50,7 @@ object InternalConnector { * @param methodBody method body of connector method * @return function of connector method that is dynamic created, can be Function0, Function1, Function2... */ - def createFunction(methodName: String, methodBody:String)= + def createFunction(methodName: String, methodBody:String): Box[AnyRef]= methodNameToSignature.get(methodName) match { case Some(signature) => val method = s""" diff --git a/obp-api/src/test/scala/code/util/DynamicUtilTest.scala b/obp-api/src/test/scala/code/util/DynamicUtilTest.scala index 17738107f..4cfd178e5 100644 --- a/obp-api/src/test/scala/code/util/DynamicUtilTest.scala +++ b/obp-api/src/test/scala/code/util/DynamicUtilTest.scala @@ -136,12 +136,10 @@ class DynamicUtilTest extends FlatSpec with Matchers { val permissionList = List( new java.net.SocketPermission("apisandbox.openbankproject.com:443","connect,resolve"), new java.util.PropertyPermission("user.dir","read"), - new java.io.FilePermission("README.md","read"), ) Sandbox.createSandbox(permissionList).runInSandbox { scala.io.Source.fromURL("https://apisandbox.openbankproject.com/") - Source.fromFile("README.md").getLines new File(".").getCanonicalPath } } @@ -161,11 +159,11 @@ class DynamicUtilTest extends FlatSpec with Matchers { } "Sandbox.sandbox method test default permission" should "should throw exception" taggedAs DynamicUtilsTag in { -// intercept[AccessControlException] { + intercept[AccessControlException] { Sandbox.sandbox(bankId= "abc").runInSandbox { scala.io.Source.fromURL("https://apisandbox.openbankproject.com/") } -// } + } } val zson = { From eb843281afacac2d4f197c5403a443f01b7a760e Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 18 Jan 2022 13:17:18 +0100 Subject: [PATCH 32/37] test/removed this test case --- .../code/util/DynamicEndpointsTest.scala | 68 ------------------- 1 file changed, 68 deletions(-) delete mode 100644 obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala diff --git a/obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala b/obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala deleted file mode 100644 index 879e19725..000000000 --- a/obp-api/src/test/scala/code/util/DynamicEndpointsTest.scala +++ /dev/null @@ -1,68 +0,0 @@ -/** -Open Bank Project - API -Copyright (C) 2011-2022, TESOBE GmbH. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . - -Email: contact@tesobe.com -TESOBE GmbH. -Osloer Strasse 16/17 -Berlin 13359, Germany - -This product includes software developed at -TESOBE (http://www.tesobe.com/) - - */ - -package code.util - -import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON -import code.api.v4_0_0.V400ServerSetup -import code.api.v4_0_0.dynamic.CompiledObjects -import code.setup.PropsReset -import org.scalatest.Tag - - - -class DynamicEndpointsTest extends V400ServerSetup with PropsReset { - object DynamicUtilsTag extends Tag("DynamicEndpoints") - - feature("test DynamicEndpoints.CompiledObjects.validateDependency method") { - scenario("validateDependency should work well "){ - //This mean, we are only disabled the v4.0.0, all other versions should be enabled - setPropsValues( - "dynamic_code_compile_validate_enable" -> "true", - "dynamic_code_compile_validate_dependencies" -> """[ - | NewStyle.function.getClass.getTypeName -> "*", - | CompiledObjects.getClass.getTypeName -> "sandbox", - | HttpCode.getClass.getTypeName -> "200", - | DynamicCompileEndpoint.getClass.getTypeName -> "getPathParams, scalaFutureToBoxedJsonResponse", - | APIUtil.getClass.getTypeName -> "errorJsonResponse, errorJsonResponse$default$1, errorJsonResponse$default$2, errorJsonResponse$default$3, errorJsonResponse$default$4, scalaFutureToLaFuture, futureToBoxedResponse", - | ErrorMessages.getClass.getTypeName -> "*", - | ExecutionContext.Implicits.getClass.getTypeName -> "global", - | JSONFactory400.getClass.getTypeName -> "createBanksJson", - | classOf[Sandbox].getTypeName -> "runInSandbox", - | classOf[CallContext].getTypeName -> "*", - | classOf[ResourceDoc].getTypeName -> "getPathParams", - | "scala.reflect.runtime.package$" -> "universe", - | PractiseEndpoint.getClass.getTypeName + "*" -> "*" - |]""".stripMargin - ) - - val jsonDynamicResourceDoc = SwaggerDefinitionsJSON.jsonDynamicResourceDoc - CompiledObjects(jsonDynamicResourceDoc.exampleRequestBody, jsonDynamicResourceDoc.successResponseBody, jsonDynamicResourceDoc.methodBody) - .validateDependency() - } - } -} \ No newline at end of file From 150a4d5362c77b0b6a29e69957104306da353bc1 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 18 Jan 2022 13:27:26 +0100 Subject: [PATCH 33/37] docfix/added the props dynamic_code_sandbox_permissions and dynamic_code_compile_validate_dependencies --- .../resources/props/sample.props.template | 36 +++++++++++++++++-- .../scala/code/api/util/DynamicUtil.scala | 31 ++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/obp-api/src/main/resources/props/sample.props.template b/obp-api/src/main/resources/props/sample.props.template index a95d47215..92e8a2340 100644 --- a/obp-api/src/main/resources/props/sample.props.template +++ b/obp-api/src/main/resources/props/sample.props.template @@ -1118,6 +1118,38 @@ personal_data_collection_consent_country_waiver_list = Austria, Belgium, Bulgari # enable dynamic code sandbox, default is false, this will make sandbox works for code running in Future, will make performance lower than disable dynamic_code_sandbox_enable=false +# Here is the default permissions if you set the dynamic_code_sandbox_enable = true. If you need more permission need to add it manually here. +# Better search for comment code `val allowedRuntimePermissions = List[Permission]( ....` need to provide the fully qualified class name and proper parameters. +dynamic_code_sandbox_permissions=[\ + new java.net.NetPermission("specifyStreamHandler"),\ + new java.lang.reflect.ReflectPermission("suppressAccessChecks"),\ + new java.lang.RuntimePermission("getenv.*"),\ + new java.util.PropertyPermission("cglib.useCache", "read"),\ + new java.util.PropertyPermission("net.sf.cglib.test.stressHashCodes", "read"),\ + new java.util.PropertyPermission("cglib.debugLocation", "read"),\ + new java.lang.RuntimePermission("accessDeclaredMembers"),\ + new java.lang.RuntimePermission("getClassLoader")\ +] + + # enable dynamic code compile validation, default is false, if set it to true, it will validate all the dynamic method body when you create/update any -# dynamic scala method. Note, it only check all the obp code dependents for all the method in scala code. -dynamic_code_compile_validate_enable=false \ No newline at end of file +# dynamic scala method. Note, it only check all the obp code dependents for all the method in OBP code. +dynamic_code_compile_validate_enable=false +# The default support dependencies if set dynamic_code_compile_validate_enable = true. it can be the class level or the method level, +# you can add them in the following list. Better check search for comment code: val allowedCompilationMethods: Map[String, Set[String]] = Map( ... +# need to prepare the correct OBP scala code. +dynamic_code_compile_validate_dependencies=[\ + NewStyle.function.getClass.getTypeName -> "*",\ + CompiledObjects.getClass.getTypeName -> "sandbox",\ + HttpCode.getClass.getTypeName -> "200",\ + DynamicCompileEndpoint.getClass.getTypeName -> "getPathParams, scalaFutureToBoxedJsonResponse",\ + APIUtil.getClass.getTypeName -> "errorJsonResponse, errorJsonResponse\$default\$1, errorJsonResponse\$default\$2, errorJsonResponse\$default\$3, errorJsonResponse\$default\$4, scalaFutureToLaFuture, futureToBoxedResponse",\ + ErrorMessages.getClass.getTypeName -> "*",\ + ExecutionContext.Implicits.getClass.getTypeName -> "global",\ + JSONFactory400.getClass.getTypeName -> "createBanksJson",\ + classOf[Sandbox].getTypeName -> "runInSandbox",\ + classOf[CallContext].getTypeName -> "*",\ + classOf[ResourceDoc].getTypeName -> "getPathParams",\ + "scala.reflect.runtime.package\$" -> "universe",\ + PractiseEndpoint.getClass.getTypeName + "*" -> "*"\ +] \ No newline at end of file diff --git a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala index b66430a0c..7ff5e43ac 100644 --- a/obp-api/src/main/scala/code/api/util/DynamicUtil.scala +++ b/obp-api/src/main/scala/code/api/util/DynamicUtil.scala @@ -300,6 +300,16 @@ object DynamicUtil { // eg2 api level: "OBP-40047: DynamicResourceDoc method have no enough permissions. No permission of: (\"java.io.FilePermission\" \"stop-words-en.txt\" \"write\")" // --> you can extends following permission: new java.net.SocketPermission("ir.dcs.gla.ac.uk:80", "connect,resolve"), // NOTE: These permissions are only checked during runtime, not the compilation period. +// val allowedRuntimePermissions = List[Permission]( +// new NetPermission("specifyStreamHandler"), +// new ReflectPermission("suppressAccessChecks"), +// new RuntimePermission("getenv.*"), +// new PropertyPermission("cglib.useCache", "read"), +// new PropertyPermission("net.sf.cglib.test.stressHashCodes", "read"), +// new PropertyPermission("cglib.debugLocation", "read"), +// new RuntimePermission("accessDeclaredMembers"), +// new RuntimePermission("getClassLoader"), +// ) val allowedRuntimePermissions = permissions.openOrThrowException("Can not compile the props `dynamic_code_sandbox_permissions` to permissions") val dependenciesString = APIUtil.getPropsValue("dynamic_code_compile_validate_dependencies", "[]").trim @@ -314,6 +324,27 @@ object DynamicUtil { * You can control all the OBP methods here. */ // all allowed methods put at here, typeName -> methods +// val allowedCompilationMethods: Map[String, Set[String]] = Map( +// // companion objects methods +// NewStyle.function.getClass.getTypeName -> "*", +// CompiledObjects.getClass.getTypeName -> "sandbox", +// HttpCode.getClass.getTypeName -> "200", +// DynamicCompileEndpoint.getClass.getTypeName -> "getPathParams, scalaFutureToBoxedJsonResponse", +// APIUtil.getClass.getTypeName -> "errorJsonResponse, errorJsonResponse$default$1, errorJsonResponse$default$2, errorJsonResponse$default$3, errorJsonResponse$default$4, scalaFutureToLaFuture, futureToBoxedResponse", +// ErrorMessages.getClass.getTypeName -> "*", +// ExecutionContext.Implicits.getClass.getTypeName -> "global", +// JSONFactory400.getClass.getTypeName -> "createBanksJson", +// +// // class methods +// classOf[Sandbox].getTypeName -> "runInSandbox", +// classOf[CallContext].getTypeName -> "*", +// classOf[ResourceDoc].getTypeName -> "getPathParams", +// "scala.reflect.runtime.package$" -> "universe", +// +// // allow any method of PractiseEndpoint for test +// PractiseEndpoint.getClass.getTypeName + "*" -> "*", +// +// ).mapValues(v => StringUtils.split(v, ',').map(_.trim).toSet) val allowedCompilationMethods: Map[String, Set[String]] = dependenciesBox.openOrThrowException("Can not compile the props `dynamic_code_compile_validate_dependencies` to Map") //Do not touch this Set, try to use the `allowedPermissions` and `allowedMethods` to control the sandbox From 34e4a9e3cb346ef567daaad05fcf2bf9e71cd8e2 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 18 Jan 2022 13:31:17 +0100 Subject: [PATCH 34/37] docfix/added the props to release_notes.md --- release_notes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/release_notes.md b/release_notes.md index a8a9ce2dc..8ab2001f2 100644 --- a/release_notes.md +++ b/release_notes.md @@ -3,6 +3,11 @@ ### Most recent changes at top of file ``` Date Commit Action +18/01/2022 150a4d53 Added the security manager relevant props,they only used for the dynamic code endpoints + dynamic_code_sandbox_enable, default is false + dynamic_code_sandbox_permissions, default is a list, please check sample.props.template + dynamic_code_compile_validate_enable, default is false + dynamic_code_compile_validate_dependencies, default is a list, please check sample.props.template 01/11/2021 03305d2b Added props: rest_connector_sends_x-sign_header, default is false 17/09/2021 e65cd51d Added props: webui_main_faq_external_link, default is obp static file: /main-faq.html 09/09/2021 65952225 Added props: webui_support_email, default is contact@openbankproject.com From 8e3183e8ae784e6d6b0964f2c359cccfd889e17b Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 18 Jan 2022 13:47:11 +0100 Subject: [PATCH 35/37] feature/no permission check for the bankId at the moment --- .../code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala index 86e25a6be..0947ddadd 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/practise/PractiseEndpoint.scala @@ -42,7 +42,7 @@ object PractiseEndpoint extends code.api.v4_0_0.dynamic.DynamicCompileEndpoint { case class ResponseRootJsonClass(my_user_id: String, name: String, age: Long, hobby: List[String]) // * is any bankId, if bound to other bankId, just modify this value to correct one - override val boundBankId = "abc" + override val boundBankId = "*" // copy the whole method body as "dynamicResourceDoc" method body override protected def From 44cdd99d1f93ce26056b2ffe0b68617e5fc728c0 Mon Sep 17 00:00:00 2001 From: hongwei Date: Tue, 18 Jan 2022 14:21:46 +0100 Subject: [PATCH 36/37] bugfix/added the bankId for query the bank level dynamicMessageDoc --- .../dynamicMessageDoc/MappedDynamicMessageDocProvider.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/obp-api/src/main/scala/code/dynamicMessageDoc/MappedDynamicMessageDocProvider.scala b/obp-api/src/main/scala/code/dynamicMessageDoc/MappedDynamicMessageDocProvider.scala index f691ec793..63a636950 100644 --- a/obp-api/src/main/scala/code/dynamicMessageDoc/MappedDynamicMessageDocProvider.scala +++ b/obp-api/src/main/scala/code/dynamicMessageDoc/MappedDynamicMessageDocProvider.scala @@ -77,7 +77,8 @@ object MappedDynamicMessageDocProvider extends DynamicMessageDocProvider { override def update(bankId: Option[String], entity: JsonDynamicMessageDoc): Box[JsonDynamicMessageDoc] = { val dynamicMessageDocBox = if(bankId.isDefined){ DynamicMessageDoc.find( - By(DynamicMessageDoc.DynamicMessageDocId, entity.dynamicMessageDocId.getOrElse("")) + By(DynamicMessageDoc.DynamicMessageDocId, entity.dynamicMessageDocId.getOrElse("")), + By(DynamicMessageDoc.BankId, bankId.head) ) } else { DynamicMessageDoc.find( From b7df34e986a7401e792c01adfdd6b7a0d3be6425 Mon Sep 17 00:00:00 2001 From: hongwei Date: Wed, 19 Jan 2022 14:07:25 +0100 Subject: [PATCH 37/37] feature/added the is_locked field to V400 UserJson --- .../ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala | 6 ++++-- .../main/scala/code/api/v4_0_0/APIMethods400.scala | 8 +++++--- .../scala/code/api/v4_0_0/JSONFactory4.0.0.scala | 13 ++++++++----- 3 files changed, 17 insertions(+), 10 deletions(-) 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 d3c177bde..145e50d4a 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 @@ -1716,7 +1716,8 @@ object SwaggerDefinitionsJSON { views = None, agreements = None, is_deleted = false, - last_marketing_agreement_signed_date = Some(DateWithDayExampleObject) + last_marketing_agreement_signed_date = Some(DateWithDayExampleObject), + is_locked = false ) val userJsonWithAgreementsV400 = UserJsonV400( user_id = ExampleValue.userIdExample.value, @@ -1728,7 +1729,8 @@ object SwaggerDefinitionsJSON { views = None, agreements = Some(Nil), is_deleted = false, - last_marketing_agreement_signed_date = Some(DateWithDayExampleObject) + last_marketing_agreement_signed_date = Some(DateWithDayExampleObject), + is_locked = false ) val userIdJsonV400 = UserIdJsonV400( user_id = ExampleValue.userIdExample.value diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 78708b186..aaef2bbf1 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -3,7 +3,6 @@ package code.api.v4_0_0 import java.net.URLEncoder import java.text.SimpleDateFormat import java.util.{Calendar, Date} - import code.DynamicData.{DynamicData, DynamicDataProvider} import code.DynamicEndpoint.DynamicEndpointSwagger import code.accountattribute.AccountAttributeX @@ -45,6 +44,7 @@ import code.dynamicMessageDoc.JsonDynamicMessageDoc import code.dynamicResourceDoc.JsonDynamicResourceDoc import code.endpointMapping.EndpointMappingCommons import code.entitlement.Entitlement +import code.loginattempts.LoginAttempt import code.metadata.counterparties.{Counterparties, MappedCounterparty} import code.metadata.tags.Tags import code.model.dataAccess.{AuthUser, BankAccountCreation} @@ -3564,9 +3564,10 @@ trait APIMethods400 { acceptMarketingInfo <- NewStyle.function.getAgreementByUserId(user.userId, "accept_marketing_info", cc.callContext) termsAndConditions <- NewStyle.function.getAgreementByUserId(user.userId, "terms_and_conditions", cc.callContext) privacyConditions <- NewStyle.function.getAgreementByUserId(user.userId, "privacy_conditions", cc.callContext) + isLocked = LoginAttempt.userIsLocked(user.name) } yield { val agreements = acceptMarketingInfo.toList ::: termsAndConditions.toList ::: privacyConditions.toList - (JSONFactory400.createUserInfoJSON(user, entitlements, Some(agreements)), HttpCode.`200`(cc.callContext)) + (JSONFactory400.createUserInfoJSON(user, entitlements, Some(agreements), isLocked), HttpCode.`200`(cc.callContext)) } } } @@ -3600,8 +3601,9 @@ trait APIMethods400 { x => unboxFullOrFail(x, cc.callContext, UserNotFoundByUsername, 404) } entitlements <- NewStyle.function.getEntitlementsByUserId(user.userId, cc.callContext) + isLocked = LoginAttempt.userIsLocked(user.name) } yield { - (JSONFactory400.createUserInfoJSON(user, entitlements, None), HttpCode.`200`(cc.callContext)) + (JSONFactory400.createUserInfoJSON(user, entitlements, None, isLocked), HttpCode.`200`(cc.callContext)) } } } diff --git a/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala b/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala index 6ac025190..12985b240 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/JSONFactory4.0.0.scala @@ -28,7 +28,6 @@ package code.api.v4_0_0 import java.text.SimpleDateFormat import java.util.Date - import code.api.Constant import code.api.attributedefinition.AttributeDefinition import code.api.util.APIUtil @@ -50,6 +49,7 @@ import code.atms.Atms.Atm import code.bankattribute.BankAttribute import code.consent.MappedConsent import code.entitlement.Entitlement +import code.loginattempts.LoginAttempt import code.model.dataAccess.ResourceUser import code.model.{Consumer, ModeratedBankAccount, ModeratedBankAccountCore} import code.ratelimiting.RateLimiting @@ -948,13 +948,14 @@ case class UserJsonV400( views: Option[ViewsJSON300], agreements: Option[List[UserAgreementJson]], is_deleted: Boolean, - last_marketing_agreement_signed_date: Option[Date] + last_marketing_agreement_signed_date: Option[Date], + is_locked: Boolean ) case class UsersJsonV400(users: List[UserJsonV400]) object JSONFactory400 { - def createUserInfoJSON(user : User, entitlements: List[Entitlement], agreements: Option[List[UserAgreement]]) : UserJsonV400 = { + def createUserInfoJSON(user : User, entitlements: List[Entitlement], agreements: Option[List[UserAgreement]], isLocked:Boolean) : UserJsonV400 = { UserJsonV400( user_id = user.userId, email = user.emailAddress, @@ -967,7 +968,8 @@ object JSONFactory400 { UserAgreementJson(`type` = i.agreementType, text = i.agreementText)) ), is_deleted = user.isDeleted.getOrElse(false), - last_marketing_agreement_signed_date = user.lastMarketingAgreementSignedDate + last_marketing_agreement_signed_date = user.lastMarketingAgreementSignedDate, + is_locked = isLocked, ) } @@ -977,7 +979,8 @@ object JSONFactory400 { createUserInfoJSON( t._1, t._2.getOrElse(Nil), - t._3 + t._3, + LoginAttempt.userIsLocked(t._1.name) ) ) )