mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 13:26:51 +00:00
Merge remote-tracking branch 'Simon/develop' into develop
This commit is contained in:
commit
4a21b9f64e
@ -93,7 +93,7 @@ import code.metadata.tags.MappedTag
|
||||
import code.metadata.transactionimages.MappedTransactionImage
|
||||
import code.metadata.wheretags.MappedWhereTag
|
||||
import code.methodrouting.MethodRouting
|
||||
import code.metrics.{MappedConnectorMetric, MappedMetric, MetricsArchive}
|
||||
import code.metrics.{MappedConnectorMetric, MappedMetric, MetricArchive}
|
||||
import code.migration.MigrationScriptLog
|
||||
import code.model.dataAccess._
|
||||
import code.model.dataAccess.internalMapping.AccountIdMapping
|
||||
@ -955,7 +955,7 @@ object ToSchemify {
|
||||
MappedTransactionRequest,
|
||||
TransactionRequestAttribute,
|
||||
MappedMetric,
|
||||
MetricsArchive,
|
||||
MetricArchive,
|
||||
MapperAccountHolders,
|
||||
MappedEntitlement,
|
||||
MappedConnectorMetric,
|
||||
|
||||
@ -1802,7 +1802,7 @@ object ExampleValue {
|
||||
lazy val canSeeBankRoutingAddressExample = ConnectorField(booleanTrue,NoDescriptionProvided)
|
||||
glossaryItems += makeGlossaryItem("can_see_bank_routing_address", canSeeBankRoutingAddressExample)
|
||||
|
||||
lazy val usersExample = ConnectorField(NoExampleProvided,NoDescriptionProvided)
|
||||
lazy val usersExample = ConnectorField("user list", "Please refer to the user object.")
|
||||
glossaryItems += makeGlossaryItem("users", usersExample)
|
||||
|
||||
lazy val staffNameExample = ConnectorField(NoExampleProvided,NoDescriptionProvided)
|
||||
|
||||
@ -26,6 +26,8 @@ import java.util.regex.Pattern
|
||||
|
||||
import com.openbankproject.commons.model.enums.LanguageParam
|
||||
|
||||
import java.lang.reflect.Field
|
||||
|
||||
object JSONFactory1_4_0 extends MdcLoggable{
|
||||
implicit def formats: Formats = CustomJsonFormats.formats
|
||||
case class PostCustomerJson(
|
||||
@ -450,7 +452,7 @@ object JSONFactory1_4_0 extends MdcLoggable{
|
||||
def boldIfMandatory() = {
|
||||
optionalTypeFields.exists(i => i._1 == parameter && i._2 == false) match {
|
||||
case true =>
|
||||
s"***$parameter**"
|
||||
s"**$parameter**"
|
||||
case false =>
|
||||
s"$parameter"
|
||||
}
|
||||
@ -460,33 +462,55 @@ object JSONFactory1_4_0 extends MdcLoggable{
|
||||
} else {
|
||||
s"""
|
||||
|
|
||||
|* [${boldIfMandatory()}](/glossary#$glossaryItemTitle): $exampleFieldValue
|
||||
|[${boldIfMandatory()}](/glossary#$glossaryItemTitle): $exampleFieldValue
|
||||
|
|
||||
|""".stripMargin
|
||||
}
|
||||
}
|
||||
|
||||
def prepareJsonFieldDescription(jsonBody: scala.Product, jsonType: String): String = {
|
||||
jsonBody.productIterator
|
||||
val (jsonBodyJValue: json.JValue, optionalTypeFields) = jsonBody match {
|
||||
case JvalueCaseClass(jValue) =>
|
||||
val types = Nil
|
||||
(jValue, types)
|
||||
case _ =>
|
||||
val types = jsonBody.getClass()
|
||||
.getDeclaredFields().toList
|
||||
.map(f => (f.getName(), f.getType().getCanonicalName().contains("Option")))
|
||||
(decompose(jsonBody), types)
|
||||
def getAllFields(jsonBody: scala.Product): List[Field] = {
|
||||
def loopAllFields(rootFields: List[Field]) = {
|
||||
val fields = for {
|
||||
field <- jsonBody.productIterator.toList if (field.isInstanceOf[scala.Product] && field != jsonBody)
|
||||
fields = getAllFields(field.asInstanceOf[scala.Product])
|
||||
} yield
|
||||
fields
|
||||
(rootFields ++ fields.flatten).toSet.toList
|
||||
}
|
||||
|
||||
//The root level is a list: eg: List[Users]
|
||||
if(jsonBody.isInstanceOf[List[Any]] && jsonBody.productIterator.toList.nonEmpty){
|
||||
val rootFields: List[Field] = jsonBody.productIterator.toSet.head.getClass.getDeclaredFields.toList
|
||||
loopAllFields(rootFields)
|
||||
}else {
|
||||
jsonBody match {
|
||||
case JvalueCaseClass(jValue) =>
|
||||
val types = Nil
|
||||
types
|
||||
case _ =>
|
||||
val rootFields: List[Field] = jsonBody.getClass().getDeclaredFields().toSet.toList
|
||||
loopAllFields(rootFields)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def checkFieldOption(jsonBody: scala.Product, rootFields: List[Field]) = {
|
||||
val types = rootFields.map(f => (f.getName(), f.getType().getCanonicalName().contains("Option")))
|
||||
(decompose(jsonBody), types)
|
||||
}
|
||||
|
||||
|
||||
def prepareJsonFieldDescription(jsonBody: scala.Product, jsonType: String): String = {
|
||||
val allFields = getAllFields(jsonBody)
|
||||
val (jsonBodyJValue: json.JValue, allFieldsAndOptionStatus) = checkFieldOption(jsonBody, allFields)
|
||||
// Group by is mandatory criteria and sort those 2 groups by name of the field
|
||||
val jsonBodyFieldsOptional = JsonUtils.collectFieldNames(jsonBodyJValue).keySet.toList
|
||||
.filter(x => optionalTypeFields.exists(i => i._1 == x && i._2 == true)).sorted
|
||||
.filter(x => allFieldsAndOptionStatus.exists(i => i._1 == x && i._2 == true)).sorted
|
||||
val jsonBodyFieldsMandatory = JsonUtils.collectFieldNames(jsonBodyJValue).keySet.toList
|
||||
.filter(x => optionalTypeFields.exists(i => i._1 == x && i._2 == false)).sorted
|
||||
.filter(x => allFieldsAndOptionStatus.exists(i => i._1 == x && i._2 == false)).sorted
|
||||
val jsonBodyFields = jsonBodyFieldsMandatory ::: jsonBodyFieldsOptional
|
||||
|
||||
val jsonFieldsDescription = jsonBodyFields.map(i => prepareDescription(i, optionalTypeFields))
|
||||
val jsonFieldsDescription = jsonBodyFields.map(i => prepareDescription(i, allFieldsAndOptionStatus))
|
||||
|
||||
val jsonTitleType = if (jsonType.contains("request")) "\n\n\n**JSON request body fields:**\n\n" else "\n\n\n**JSON response body fields:**\n\n"
|
||||
|
||||
@ -527,6 +551,7 @@ object JSONFactory1_4_0 extends MdcLoggable{
|
||||
""
|
||||
}
|
||||
//3rd: get the fields description from the response body:
|
||||
//response body can be a nest class, need to loop all the fields.
|
||||
val responseFieldsDescription = prepareJsonFieldDescription(resourceDocUpdatedTags.successResponseBody,"response")
|
||||
urlParametersDescription ++ exampleRequestBodyFieldsDescription ++ responseFieldsDescription
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ object MappedMetrics extends APIMetrics with MdcLoggable{
|
||||
metric.save
|
||||
}
|
||||
override def saveMetricsArchive(primaryKey: Long, userId: String, url: String, date: Date, duration: Long, userName: String, appName: String, developerEmail: String, consumerId: String, implementedByPartialFunction: String, implementedInVersion: String, verb: String, httpCode: Option[Int], correlationId: String): Unit = {
|
||||
val metric = MetricsArchive.find(By(MetricsArchive.id, primaryKey)).getOrElse(MetricsArchive.create)
|
||||
val metric = MetricArchive.find(By(MetricArchive.id, primaryKey)).getOrElse(MetricArchive.create)
|
||||
metric
|
||||
.metricId(primaryKey)
|
||||
.userId(userId)
|
||||
@ -548,8 +548,8 @@ object MappedMetric extends MappedMetric with LongKeyedMetaMapper[MappedMetric]
|
||||
}
|
||||
|
||||
|
||||
class MetricsArchive extends APIMetric with LongKeyedMapper[MetricsArchive] with IdPK {
|
||||
override def getSingleton = MetricsArchive
|
||||
class MetricArchive extends APIMetric with LongKeyedMapper[MetricArchive] with IdPK {
|
||||
override def getSingleton = MetricArchive
|
||||
|
||||
object metricId extends MappedLong(this)
|
||||
object userId extends UUIDString(this)
|
||||
@ -589,7 +589,7 @@ class MetricsArchive extends APIMetric with LongKeyedMapper[MetricsArchive] with
|
||||
override def getHttpCode(): Int = httpCode.get
|
||||
override def getCorrelationId(): String = correlationId.get
|
||||
}
|
||||
object MetricsArchive extends MetricsArchive with LongKeyedMetaMapper[MetricsArchive] {
|
||||
object MetricArchive extends MetricArchive with LongKeyedMetaMapper[MetricArchive] {
|
||||
override def dbIndexes =
|
||||
Index(userId) :: Index(consumerId) :: Index(url) :: Index(date) :: Index(userName) ::
|
||||
Index(appName) :: Index(developerEmail) :: super.dbIndexes
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.{Calendar, Date}
|
||||
|
||||
import code.actorsystem.ObpLookupSystem
|
||||
import code.api.util.{APIUtil, OBPToDate}
|
||||
import code.metrics.{APIMetric, APIMetrics, MappedMetric, MetricsArchive}
|
||||
import code.metrics.{APIMetric, APIMetrics, MappedMetric, MetricArchive}
|
||||
import code.util.Helper.MdcLoggable
|
||||
import net.liftweb.common.Full
|
||||
import net.liftweb.mapper.{By, By_<=}
|
||||
@ -42,7 +42,7 @@ object MetricsArchiveScheduler extends MdcLoggable {
|
||||
}
|
||||
val someYearsAgo: Date = new Date(currentTime.getTime - (oneDayInMillis * days))
|
||||
// Delete the outdated rows from the table "MetricsArchive"
|
||||
MetricsArchive.bulkDelete_!!(By_<=(MetricsArchive.date, someYearsAgo))
|
||||
MetricArchive.bulkDelete_!!(By_<=(MetricArchive.date, someYearsAgo))
|
||||
}
|
||||
|
||||
def conditionalDeleteMetricsRow() = {
|
||||
@ -60,7 +60,7 @@ object MetricsArchiveScheduler extends MdcLoggable {
|
||||
}
|
||||
val maybeDeletedRows: List[(Boolean, Long)] = canditateMetricRowsToMove map { i =>
|
||||
// and delete it after successful coping
|
||||
MetricsArchive.find(By(MetricsArchive.metricId, i.getMetricId())) match {
|
||||
MetricArchive.find(By(MetricArchive.metricId, i.getMetricId())) match {
|
||||
case Full(_) => (MappedMetric.bulkDelete_!!(By(MappedMetric.id, i.getMetricId())), i.getMetricId())
|
||||
case _ => (false, i.getMetricId())
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
package code.api.v1_4_0
|
||||
|
||||
import java.util.Date
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.usersJsonV400
|
||||
|
||||
import java.util.Date
|
||||
import code.api.util.APIUtil.ResourceDoc
|
||||
import code.api.util.{APIUtil, ExampleValue}
|
||||
import code.api.v1_4_0.JSONFactory1_4_0.ResourceDocJson
|
||||
@ -51,6 +52,40 @@ class JSONFactory1_4_0Test extends V140ServerSetup with DefaultUsers {
|
||||
description.contains("[BANK_ID](/glossary#Bank.bank_id): gh.29.uk") should be (true)
|
||||
}
|
||||
|
||||
scenario("prepareJsonFieldDescription should work well - users object") {
|
||||
val usersJson = usersJsonV400
|
||||
val description = JSONFactory1_4_0.prepareJsonFieldDescription(usersJson, "response")
|
||||
description.contains(
|
||||
"""
|
||||
|JSON response body fields:
|
||||
|
|
||||
|*user_id = 9ca9a7e4-6d02-40e3-a129-0b2bf89de9b1,
|
||||
|
|
||||
|*email = felixsmith@example.com,
|
||||
|
|
||||
|*provider_id = ,
|
||||
|
|
||||
|*provider = ,
|
||||
|
|
||||
|*username = felixsmith,
|
||||
|
|
||||
|*entitlements = ,
|
||||
|
|
||||
|*views = ,
|
||||
|
|
||||
|*agreements = ,
|
||||
|
|
||||
|*is_deleted = false,
|
||||
|
|
||||
|*last_marketing_agreement_signed_date = ,
|
||||
|
|
||||
|*is_locked = false
|
||||
|
|
||||
|""".stripMargin
|
||||
) should be (false)
|
||||
println(description)
|
||||
}
|
||||
|
||||
scenario("PrepareUrlParameterDescription should work well, extract the parameters from URL") {
|
||||
val requestUrl1 = "/obp/v4.0.0/banks/BANK_ID/accounts/account_ids/private"
|
||||
val requestUrl1Description = JSONFactory1_4_0.prepareUrlParameterDescription(requestUrl1)
|
||||
|
||||
@ -0,0 +1,115 @@
|
||||
package code.api.v1_4_0
|
||||
|
||||
import code.api.util.CustomJsonFormats
|
||||
import code.util.Helper.MdcLoggable
|
||||
import org.scalatest.{BeforeAndAfterAll, BeforeAndAfterEach, FeatureSpec, GivenWhenThen, Matchers}
|
||||
|
||||
import java.lang.reflect.Field
|
||||
import java.util.Date
|
||||
|
||||
class JSONFactory1_4_0_LightTest extends FeatureSpec
|
||||
with BeforeAndAfterEach
|
||||
with GivenWhenThen
|
||||
with BeforeAndAfterAll
|
||||
with Matchers
|
||||
with MdcLoggable
|
||||
with CustomJsonFormats {
|
||||
|
||||
feature("Test JSONFactory1_4_0.getJValueAndAllFields method") {
|
||||
case class ClassOne(
|
||||
string1: String = "1"
|
||||
)
|
||||
|
||||
case class ClassTwo(
|
||||
string2: String = "2",
|
||||
strings2: List[String] = List("List-2")
|
||||
)
|
||||
|
||||
val oneObject = ClassOne()
|
||||
|
||||
case class NestedClass(
|
||||
classes: List[ClassOne] = List(oneObject)
|
||||
)
|
||||
|
||||
val twoObject = ClassTwo()
|
||||
|
||||
case class NestedListClass(
|
||||
classes1: List[ClassOne] = List(oneObject)
|
||||
)
|
||||
|
||||
val nestedClass = NestedClass()
|
||||
|
||||
val nestedListClass = NestedListClass()
|
||||
|
||||
case class ComplexNestedClass(
|
||||
complexNestedClassString: String = "ComplexNestedClass1",
|
||||
complexNestedClassInt: Int = 1,
|
||||
complexNestedClassDate: Date = new Date(),
|
||||
complexNestedClassOptionSomeInt: Option[Int] = Some(1),
|
||||
complexNestedClassOptionNoneInt: Option[Int] = None,
|
||||
classes1: List[ClassOne] = List(oneObject),
|
||||
classes2: List[ClassTwo] = List(twoObject),
|
||||
)
|
||||
|
||||
val complexNestedClass = ComplexNestedClass()
|
||||
|
||||
|
||||
|
||||
scenario("getJValueAndAllFields -input is the oneObject, basic no nested, no List inside") {
|
||||
val listFields: List[Field] = JSONFactory1_4_0.getAllFields(oneObject)
|
||||
|
||||
val expectedListFieldsString = "List(private final java.lang.String code.api.v1_4_0.JSONFactory1_4_0_LightTest$ClassOne$1.string1, " +
|
||||
"private final code.api.v1_4_0.JSONFactory1_4_0_LightTest code.api.v1_4_0.JSONFactory1_4_0_LightTest$ClassOne$1.$outer)"
|
||||
|
||||
listFields.toString shouldBe (expectedListFieldsString)
|
||||
// println(listFields)
|
||||
}
|
||||
|
||||
scenario("getJValueAndAllFields -input it the nestedClass") {
|
||||
val listFields: List[Field] = JSONFactory1_4_0.getAllFields(nestedClass)
|
||||
val expectedListFieldsString = "List(" +
|
||||
"public static final long scala.collection.immutable.Nil$.serialVersionUID, public static scala.collection.immutable.Nil$ scala.collection.immutable.Nil$.MODULE$, " +
|
||||
"private final code.api.v1_4_0.JSONFactory1_4_0_LightTest code.api.v1_4_0.JSONFactory1_4_0_LightTest$ClassOne$1.$outer, " +
|
||||
"private final code.api.v1_4_0.JSONFactory1_4_0_LightTest code.api.v1_4_0.JSONFactory1_4_0_LightTest$NestedClass$1.$outer, " +
|
||||
"private final java.lang.String code.api.v1_4_0.JSONFactory1_4_0_LightTest$ClassOne$1.string1, " +
|
||||
"private final scala.collection.immutable.List code.api.v1_4_0.JSONFactory1_4_0_LightTest$NestedClass$1.classes)"
|
||||
listFields.toString shouldBe (expectedListFieldsString)
|
||||
// println(listFields)
|
||||
}
|
||||
|
||||
scenario("getJValueAndAllFields - input is the List[nestedClass]") {
|
||||
val listFields: List[Field] = JSONFactory1_4_0.getAllFields(List(oneObject))
|
||||
// it should return all the fields in the List
|
||||
val expectedListFieldsString = "List(private final java.lang.String code.api.v1_4_0.JSONFactory1_4_0_LightTest$ClassOne$1.string1, " +
|
||||
"private final code.api.v1_4_0.JSONFactory1_4_0_LightTest code.api.v1_4_0.JSONFactory1_4_0_LightTest$ClassOne$1.$outer, " +
|
||||
"public static scala.collection.immutable.Nil$ scala.collection.immutable.Nil$.MODULE$, " +
|
||||
"public static final long scala.collection.immutable.Nil$.serialVersionUID)"
|
||||
listFields.toString shouldBe (expectedListFieldsString)
|
||||
// println(listFields)
|
||||
}
|
||||
|
||||
scenario("getJValueAndAllFields -input it the complexNestedClass") {
|
||||
val listFields: List[Field] = JSONFactory1_4_0.getAllFields(complexNestedClass)
|
||||
|
||||
listFields.toString contains ("private final java.lang.String code.api.v1_4_0.JSONFactory1_4_0_LightTest$ComplexNestedClass$1.complexNestedClassString, ") shouldBe (true)
|
||||
listFields.toString contains ("private final int code.api.v1_4_0.JSONFactory1_4_0_LightTest$ComplexNestedClass$1.complexNestedClassInt, ") shouldBe (true)
|
||||
listFields.toString contains ("private final code.api.v1_4_0.JSONFactory1_4_0_LightTest code.api.v1_4_0.JSONFactory1_4_0_LightTest$ComplexNestedClass$1.$outer,") shouldBe (true)
|
||||
listFields.toString contains ("public static final long scala.collection.immutable.Nil$.serialVersionUID, ") shouldBe (true)
|
||||
listFields.toString contains ("private final scala.collection.immutable.List code.api.v1_4_0.JSONFactory1_4_0_LightTest$ComplexNestedClass$1.classes2, ") shouldBe (true)
|
||||
listFields.toString contains ("private final java.lang.String code.api.v1_4_0.JSONFactory1_4_0_LightTest$ClassTwo$1.string2, ") shouldBe (true)
|
||||
listFields.toString contains ("public static scala.collection.immutable.Nil$ scala.collection.immutable.Nil$.MODULE$, public static final long scala.None$.serialVersionUID, ") shouldBe (true)
|
||||
listFields.toString contains ("private final code.api.v1_4_0.JSONFactory1_4_0_LightTest code.api.v1_4_0.JSONFactory1_4_0_LightTest$ClassOne$1.$outer, ") shouldBe (true)
|
||||
listFields.toString contains ("private final scala.Option code.api.v1_4_0.JSONFactory1_4_0_LightTest$ComplexNestedClass$1.complexNestedClassOptionSomeInt") shouldBe (true)
|
||||
listFields.toString contains ("public static scala.None$ scala.None$.MODULE$, private final java.lang.Object scala.Some.value, private final scala.collection.immutable.List code.api.v1_4_0.JSONFactory1_4_0_LightTest$ComplexNestedClass$1.classes1, ") shouldBe (true)
|
||||
listFields.toString contains ("private final java.util.Date code.api.v1_4_0.JSONFactory1_4_0_LightTest$ComplexNestedClass$1.complexNestedClassDate, ") shouldBe (true)
|
||||
listFields.toString contains ("private final scala.collection.immutable.List code.api.v1_4_0.JSONFactory1_4_0_LightTest$ClassTwo$1.strings2, ") shouldBe (true)
|
||||
listFields.toString contains ("private int java.lang.String.hash, private final java.lang.String code.api.v1_4_0.JSONFactory1_4_0_LightTest$ClassOne$1.string1, ") shouldBe (true)
|
||||
listFields.toString contains ("private static final long java.lang.String.serialVersionUID, private final code.api.v1_4_0.JSONFactory1_4_0_LightTest code.api.v1_4_0.JSONFactory1_4_0_LightTest$ClassTwo$1.$outer, ") shouldBe (true)
|
||||
listFields.toString contains ("private final scala.Option code.api.v1_4_0.JSONFactory1_4_0_LightTest$ComplexNestedClass$1.complexNestedClassOptionNoneIn") shouldBe (true)
|
||||
// println(listFields)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -37,10 +37,11 @@ class IndexPageTest extends V510ServerSetup {
|
||||
*
|
||||
* This is made possible by the scalatest maven plugin
|
||||
*/
|
||||
/*
|
||||
|
||||
feature("Test the response of the page /index.html ") {
|
||||
scenario("We create the apiCollection get All API collections back") {
|
||||
When("We make a request ")
|
||||
feature(s"Test the response of the page http://${server.host}:${server.port}/index.html") {
|
||||
scenario(s"We try to load the page at http://${server.host}:${server.port}/index.html") {
|
||||
When("We make the request")
|
||||
val client = new OkHttpClient
|
||||
val request = new Request.Builder().url(s"http://${server.host}:${server.port}/index.html").build
|
||||
val responseFirst = client.newCall(request).execute
|
||||
@ -51,8 +52,10 @@ class IndexPageTest extends V510ServerSetup {
|
||||
responseSecond.code should equal(200)
|
||||
val duration: Long = endTime - startTime
|
||||
And(s"And duration($duration) is less than 1000 ms")
|
||||
duration should be <= 1000L
|
||||
println(s"Duration of the loading the page http://${server.host}:${server.port}/index.html is: $duration ms")
|
||||
// duration should be <= 1000L // TODO Make this check adjustable
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user