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 f8e65dbca..4a0c5a6a7 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -64,7 +64,7 @@ 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.dynamic.{DynamicEndpointHelper, DynamicEntityInfo} +import code.api.v4_0_0.dynamic.{DynamicEndpointHelper, DynamicEntityHelper, DynamicEntityInfo} import code.bankattribute.BankAttribute import code.connectormethod.{ConnectorMethodProvider, JsonConnectorMethod} import code.dynamicMessageDoc.{DynamicMessageDocProvider, JsonDynamicMessageDoc} @@ -2895,10 +2895,7 @@ object NewStyle extends MdcLoggable{ // check if there is (entityIdName, entityIdValue) pair in the requestBody, if no, we will add it. val requestBodyDynamicInstance: Option[JObject] = requestBody.map { requestJsonJObject => - // (?<=[a-z0-9])(?=[A-Z]) --> mean `Positive Lookbehind (?<=[a-z0-9])` && Positive Lookahead (?=[A-Z]) --> So we can find the space to replace to `_` - val regexPattern = "(?<=[a-z0-9])(?=[A-Z])|-" - // eg: entityName = PetEntity => entityIdName = pet_entity_id - val entityIdName = s"${entityName}_Id".replaceAll(regexPattern, "_").toLowerCase + val entityIdName = DynamicEntityHelper.createEntityId(entityName) val entityIdValue = requestJsonJObject \ entityIdName 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 8543c8b55..71fc3ac10 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 @@ -5716,21 +5716,42 @@ trait APIMethods400 { responseBody } } else if (method.value.equalsIgnoreCase("delete")) { -// for { -// (entityName, entityIdKey, entityIdValueFromUrl) <- NewStyle.function.tryons(s"$InvalidEndpointMapping `response_mapping` must be linked to at least one valid dynamic entity!", 400, cc.callContext) { -// DynamicEndpointHelper.getEntityNameKeyAndValue(responseMappingString, pathParams) -// } -// isDeleted <- NewStyle.function.tryons(s"$InvalidEndpointMapping `response_mapping` must be linked to at least one valid dynamic entity!", 400, cc.callContext) { - //We need to delete the record by the the request key and value, -// DynamicDataProvider.connectorMethodProvider.vend.delete(entityName, entityIdValueFromUrl.head).head -// } -// }yield{ -// JBool(isDeleted) -// } - throw new RuntimeException(s"$NotImplemented We only support the Http Methods GET and POST . The current method is: ${method.value}") + for { + (entityName, entityIdKey, entityIdValueFromUrl) <- NewStyle.function.tryons(s"$InvalidEndpointMapping `response_mapping` must be linked to at least one valid dynamic entity!", 400, cc.callContext) { + DynamicEndpointHelper.getEntityNameKeyAndValue(responseMappingString, pathParams) + } + dynamicData = DynamicDataProvider.connectorMethodProvider.vend.getAll(entityName) + dynamicJsonData = JArray(dynamicData.map(it => net.liftweb.json.parse(it.dataJson)).map(_.asInstanceOf[JObject])) + entityObject = DynamicEndpointHelper.getObjectByKeyValuePair(dynamicJsonData, entityIdKey, entityIdValueFromUrl.get) + isDeleted <- NewStyle.function.tryons(s"$InvalidEndpointMapping `response_mapping` must be linked to at least one valid dynamic entity!", 400, cc.callContext) { + val entityIdName = DynamicEntityHelper.createEntityId(entityName) + val entityIdValue = (entityObject \ entityIdName).asInstanceOf[JString].s + DynamicDataProvider.connectorMethodProvider.vend.delete(entityName, entityIdValue).head + } + }yield{ + JBool(isDeleted) + } } else if (method.value.equalsIgnoreCase("put")) { - - throw new RuntimeException(s"$NotImplemented We only support the Http Methods GET and POST . The current method is: ${method.value}") + for { + (entityName, entityIdKey, entityIdValueFromUrl) <- NewStyle.function.tryons(s"$InvalidEndpointMapping `response_mapping` must be linked to at least one valid dynamic entity!", 400, cc.callContext) { + DynamicEndpointHelper.getEntityNameKeyAndValue(responseMappingString, pathParams) + } + dynamicData = DynamicDataProvider.connectorMethodProvider.vend.getAll(entityName) + dynamicJsonData = JArray(dynamicData.map(it => net.liftweb.json.parse(it.dataJson)).map(_.asInstanceOf[JObject])) + entityObject = DynamicEndpointHelper.getObjectByKeyValuePair(dynamicJsonData, entityIdKey, entityIdValueFromUrl.get) + _ <- NewStyle.function.tryons(s"$InvalidEndpointMapping `response_mapping` must be linked to at least one valid dynamic entity!", 400, cc.callContext) { + val entityIdName = DynamicEntityHelper.createEntityId(entityName) + val entityIdValue = (entityObject \ entityIdName).asInstanceOf[JString].s + DynamicDataProvider.connectorMethodProvider.vend.delete(entityName, entityIdValue).head + } + entityBody = JsonUtils.buildJson(json,requestMappingJvalue) + (box, _) <- NewStyle.function.invokeDynamicConnector(CREATE, entityName, Some(entityBody.asInstanceOf[JObject]), None, None, None, Some(cc)) + singleObject: JValue = unboxResult(box.asInstanceOf[Box[JValue]], entityName) + responseBodyScheme = DynamicEndpointHelper.prepareMappingFields(responseMappingJvalue) + responseBody = JsonUtils.buildJson(singleObject, responseBodyScheme) + }yield{ + responseBody + } }else { NewStyle.function.tryons(s"$InvalidEndpointMapping `request_mapping` must be linked to at least one valid dynamic entity!", 400, cc.callContext) { DynamicEndpointHelper.getEntityNameKeyAndValue(responseMappingString, pathParams) diff --git a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEntityHelper.scala b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEntityHelper.scala index 8e2442a62..4e6dee204 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEntityHelper.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/dynamic/DynamicEntityHelper.scala @@ -56,6 +56,13 @@ object DynamicEntityHelper { collection.mutable.ArrayBuffer(docs:_*) } + def createEntityId(entityName: String) = { + // (?<=[a-z0-9])(?=[A-Z]) --> mean `Positive Lookbehind (?<=[a-z0-9])` && Positive Lookahead (?=[A-Z]) --> So we can find the space to replace to `_` + val regexPattern = "(?<=[a-z0-9])(?=[A-Z])|-" + // eg: entityName = PetEntity => entityIdName = pet_entity_id + s"${entityName}_Id".replaceAll(regexPattern, "_").toLowerCase + } + def operationToResourceDoc: Map[(DynamicEntityOperation, String), ResourceDoc] = { val addPrefix = APIUtil.getPropsAsBoolValue("dynamic_entities_have_prefix", true) diff --git a/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala b/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala index 9b7f5adfe..d7bcae9ac 100644 --- a/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala +++ b/obp-api/src/test/scala/code/api/v3_1_0/AccountTest.scala @@ -23,6 +23,7 @@ import net.liftweb.json.Serialization.write import org.scalatest.Tag import java.util.UUID +import java.util.concurrent.TimeUnit import scala.util.Random class AccountTest extends V310ServerSetup with DefaultUsers { @@ -205,6 +206,10 @@ class AccountTest extends V310ServerSetup with DefaultUsers { account.label should be (putCreateAccountJSONV310.label) account.account_routings should be (putCreateAccountJSONV310.account_routings) + + //We need to waite some time for the account creation, because we introduce `AuthUser.refreshUser(user, callContext)` + //It may not finished when we call the get accounts directly. + TimeUnit.SECONDS.sleep(2) Then(s"we call $ApiEndpoint4 to get the account back") val requestApiEndpoint4 = (v3_1_0_Request / "my" / "accounts" ).PUT <@(user1) @@ -213,8 +218,7 @@ class AccountTest extends V310ServerSetup with DefaultUsers { responseApiEndpoint4.code should equal(200) val accounts = responseApiEndpoint4.body.extract[CoreAccountsJsonV300].accounts accounts.map(_.id).toList.toString() contains(account.account_id) should be (true) - - + Then(s"we call $ApiEndpoint5 to get the account back") val requestApiEndpoint5 = (v3_1_0_Request /"banks" / testBankId.value / "accounts").GET <@ (user1) val responseApiEndpoint5 = makeGetRequest(requestApiEndpoint5) diff --git a/obp-api/src/test/scala/code/util/JsonUtilsTest.scala b/obp-api/src/test/scala/code/util/JsonUtilsTest.scala index 550a74538..367c4bd3f 100644 --- a/obp-api/src/test/scala/code/util/JsonUtilsTest.scala +++ b/obp-api/src/test/scala/code/util/JsonUtilsTest.scala @@ -9,128 +9,130 @@ import net.liftweb.json.JsonAST.{JNothing, JValue} class JsonUtilsTest extends FlatSpec with Matchers { object JsonUtilsTag extends Tag("JsonUtils") - val zson = json.parse( - """ - |{ - | "level": 3, - | "banks":[{ - | "id":"dmo.01.uk.uk", - | "short_name":"uk", - | "full_name":"uk", - | "is_deleted": true, - | "is_new": true, - | "score": 10, - | "logo":"http://www.example.com", - | "website":"http://www.example.com", - | "bank_routings":[{ - | "scheme":"OBP", - | "address":"dmo.01.uk.uk" - | }] - | },{ - | "id":"dmo.02.uk.uk", - | "short_name":"uk", - | "full_name":"uk", - | "is_deleted": false, - | "is_new": true, - | "score": 5.3, - | "logo":"https://static.openbankproject.com/images/sandbox/bank_y.png", - | "website":"http://www.example.com" - | },{ - | "id":"dmo.02.de.de", - | "short_name":"de", - | "full_name":"de", - | "is_deleted": false, - | "is_new": false, - | "score": 2, - | "logo":"https://static.openbankproject.com/images/sandbox/bank_z.png", - | "website":"http://www.example.com", - | "bank_routings":[{ - | "scheme":"OBP", - | "address":"dmo.02.de.de" - | }] - | }] - |} - |""".stripMargin) - - val schema = json.parse( - """ - |{ - | "value": " 'number: 1.0' + 'int:1' * level", - | "code": 200, - | "meta$default": { - | "count": 10, - | "classInfo": { - | "someInfo": "hello" - | } - | }, - | "result[]": { - | "bkId": "banks.id", - | "bkName": "'hello:' + banks.short_name+ ' + ' + banks.full_name", - | "is_exists": "!banks.is_deleted", - | "newBank": "!banks.is_deleted & banks.is_new", - | "routing": "banks.bank_routings[0]" - | }, - | "secondBank[1]": { - | "id": "banks.id", - | "name": "banks.short_name", - | "count": "banks.score * 'int: 2'" - | } - |} - |""".stripMargin) - - val expectedJson = json.parse( - """ - |{ - | "value":6.0, - | "code":200, - | "meta":{ - | "count":10, - | "classInfo":{ - | "someInfo":"hello" - | } - | }, - | "result":[ - | { - | "bkId":"dmo.01.uk.uk", - | "bkName":"hello:uk + uk", - | "is_exists":false, - | "newBank":false, - | "routing":{ - | "scheme":"OBP", - | "address":"dmo.01.uk.uk" - | } - | }, - | { - | "bkId":"dmo.02.uk.uk", - | "bkName":"hello:uk + uk", - | "is_exists":true, - | "newBank":true - | }, - | { - | "bkId":"dmo.02.de.de", - | "bkName":"hello:de + de", - | "is_exists":true, - | "newBank":false, - | "routing":{ - | "scheme":"OBP", - | "address":"dmo.02.de.de" - | } - | } - | ], - | "secondBank": { - | "id":"dmo.02.uk.uk", - | "name":"uk", - | "count":10.6 - | } - |} - |""".stripMargin) "buildJson" should "generate JValue according schema" taggedAs JsonUtilsTag in { + + val zson = json.parse( + """ + |{ + | "level": 3, + | "banks":[{ + | "id":"dmo.01.uk.uk", + | "short_name":"uk", + | "full_name":"uk", + | "is_deleted": true, + | "is_new": true, + | "score": 10, + | "logo":"http://www.example.com", + | "website":"http://www.example.com", + | "bank_routings":[{ + | "scheme":"OBP", + | "address":"dmo.01.uk.uk" + | }] + | },{ + | "id":"dmo.02.uk.uk", + | "short_name":"uk", + | "full_name":"uk", + | "is_deleted": false, + | "is_new": true, + | "score": 5.3, + | "logo":"https://static.openbankproject.com/images/sandbox/bank_y.png", + | "website":"http://www.example.com" + | },{ + | "id":"dmo.02.de.de", + | "short_name":"de", + | "full_name":"de", + | "is_deleted": false, + | "is_new": false, + | "score": 2, + | "logo":"https://static.openbankproject.com/images/sandbox/bank_z.png", + | "website":"http://www.example.com", + | "bank_routings":[{ + | "scheme":"OBP", + | "address":"dmo.02.de.de" + | }] + | }] + |} + |""".stripMargin) + + val schema = json.parse( + """ + |{ + | "value": " 'number: 1.0' + 'int:1' * level", + | "code": 200, + | "meta$default": { + | "count": 10, + | "classInfo": { + | "someInfo": "hello" + | } + | }, + | "result[]": { + | "bkId": "banks.id", + | "bkName": "'hello:' + banks.short_name+ ' + ' + banks.full_name", + | "is_exists": "!banks.is_deleted", + | "newBank": "!banks.is_deleted & banks.is_new", + | "routing": "banks.bank_routings[0]" + | }, + | "secondBank[1]": { + | "id": "banks.id", + | "name": "banks.short_name", + | "count": "banks.score * 'int: 2'" + | } + |} + |""".stripMargin) + + val expectedJson = json.parse( + """ + |{ + | "value":6.0, + | "code":200, + | "meta":{ + | "count":10, + | "classInfo":{ + | "someInfo":"hello" + | } + | }, + | "result":[ + | { + | "bkId":"dmo.01.uk.uk", + | "bkName":"hello:uk + uk", + | "is_exists":false, + | "newBank":false, + | "routing":{ + | "scheme":"OBP", + | "address":"dmo.01.uk.uk" + | } + | }, + | { + | "bkId":"dmo.02.uk.uk", + | "bkName":"hello:uk + uk", + | "is_exists":true, + | "newBank":true + | }, + | { + | "bkId":"dmo.02.de.de", + | "bkName":"hello:de + de", + | "is_exists":true, + | "newBank":false, + | "routing":{ + | "scheme":"OBP", + | "address":"dmo.02.de.de" + | } + | } + | ], + | "secondBank": { + | "id":"dmo.02.uk.uk", + | "name":"uk", + | "count":10.6 + | } + |} + |""".stripMargin) + val resultJson = buildJson(zson, schema) val str1 = json.prettyRender(resultJson) -// println(str1) + val str2 = json.prettyRender(expectedJson) -// println(str2) + str1 shouldEqual str2 } @@ -160,12 +162,11 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(zson, schema) val str1 = json.prettyRender(resultJson) - println(str1) + val str2 = json.prettyRender(expectedJson) str1 shouldEqual str2 } - - + """buildJson-request single{}, mapping is {"photoUrls[]":"field5"}""" should "generate JValue according schema3" taggedAs JsonUtilsTag in { val zson = ( """{ @@ -220,7 +221,7 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(zson, mapping) val str1 = json.prettyRender(resultJson) - println(str1) + val str2 = json.prettyRender(expectedJson) str1 shouldEqual str2 } @@ -254,7 +255,7 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(requestJson, mapping) val str1 = json.prettyRender(resultJson) - println(str1) + val str2 = json.prettyRender(expectedJson) str1 shouldEqual str2 } @@ -308,7 +309,7 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(zson, schema) val str1 = json.prettyRender(resultJson) - println(str1) + val str2 = json.prettyRender(expectedJson) str1 shouldEqual str2 } @@ -368,9 +369,9 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(requestJson, mapping) val str1 = json.prettyRender(resultJson) - println(str1) + val str2 = json.prettyRender(expectedJson) - println(str2) + str1 shouldEqual str2 } @@ -394,7 +395,6 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(zson, schema) val str1 = json.prettyRender(resultJson) - println(str1) val str2 = json.prettyRender(expectedJson) str1 shouldEqual str2 @@ -494,7 +494,7 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(requestJson, mapping) val str1 = json.prettyRender(resultJson) - println(str1) + val str2 = json.prettyRender(expectedJson) str1 shouldEqual str2 } @@ -516,7 +516,6 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(requestJson, mapping) val str1 = json.prettyRender(resultJson) - println(str1) val str2 = json.prettyRender(expectedJson) str1 shouldEqual str2 } @@ -545,7 +544,7 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(requestJson, mapping) val str1 = json.prettyRender(resultJson) - println(str1) + val expectedJson = json.parse( """ @@ -689,7 +688,6 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(jsonList, jsonListSchema) val str1 = json.prettyRender(resultJson) - println(str1) val str2 = json.prettyRender(expectListResult) str1 shouldEqual str2 } @@ -730,6 +728,7 @@ class JsonUtilsTest extends FlatSpec with Matchers { str1 shouldEqual expectedJson } + "$root[] name field and subField[][] type field" should "properly be converted" taggedAs JsonUtilsTag in { val jsonList = json.parse( """ @@ -802,7 +801,6 @@ class JsonUtilsTest extends FlatSpec with Matchers { |]""".stripMargin) val resultJson = buildJson(jsonList, schema) val str1 = json.prettyRender(resultJson) -// println(str1) val str2 = json.prettyRender(expectedJson) str1 shouldEqual str2 @@ -843,7 +841,6 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(requestJson, mapping) val str1 = json.prettyRender(resultJson) - println(str1) val str2 = json.prettyRender(expectedJson) str1 shouldEqual str2 } @@ -876,7 +873,44 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(requestJson, mapping) val str1 = json.prettyRender(resultJson) - println(str1) + val str2 = json.prettyRender(expectedJson) + str1 shouldEqual str2 + } + + "buildJson - request is Array1, mapping is []object" should "work well" taggedAs JsonUtilsTag in { + val requestJson = ( + """[ + | { + | "name": "family account200", + | "number": 200, + | "sample_entity_id": "9b344781-32f5-4afb-a4f1-2c93087e6e71" + | }, + | { + | "name": "family account201", + | "number": 201, + | "sample_entity_id": "38ff936d-6780-444f-81b9-ac7ab8565035" + | } + |]""".stripMargin) + val mapping = ("""{ + | "$root[]": { + | "name": "name", + | "balance": "number" + | } + |}""".stripMargin) + val expectedJson = json.parse( + """[ + | { + | "name":"family account200", + | "balance":200, + | }, + | { + | "name":"family account201", + | "balance":201 + | } + |]""".stripMargin) + + val resultJson = buildJson(requestJson, mapping) + val str1 = json.prettyRender(resultJson) val str2 = json.prettyRender(expectedJson) str1 shouldEqual str2 } @@ -888,7 +922,6 @@ class JsonUtilsTest extends FlatSpec with Matchers { val resultJson = buildJson(requestJson, mapping) val str1 = json.prettyRender(resultJson) - println(str1) val str2 = json.prettyRender(expectedJson) str1 shouldEqual str2 }