Skip to content

Commit

Permalink
Merge pull request #2341 from constantine2nd/develop
Browse files Browse the repository at this point in the history
Regulated Entities
  • Loading branch information
simonredfern authored Dec 1, 2023
2 parents f730e3c + 760eb0b commit e14cb81
Show file tree
Hide file tree
Showing 13 changed files with 599 additions and 17 deletions.
1 change: 1 addition & 0 deletions obp-api/src/main/resources/props/sample.props.template
Original file line number Diff line number Diff line change
Expand Up @@ -1278,4 +1278,5 @@ validate_iban=false
#show_used_connector_methods=false

# This returns Regulated Entities
# sample props regulated_entities = [{"certificate_authority_ca_owner_id":"CY_CBC","entity_certificate_public_key":"-----BEGIN CERTIFICATE-----MIICsjCCAZqgAwIBAgIGAYwQ62R0MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTAeFw0yMzExMjcxMzE1MTFaFw0yNTExMjYxMzE1MTFaMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK9WIodZHWzKyCcf9YfWEhPURbfO6zKuMqzHN27GdqHsVVEGxP4F/J4mso+0ENcRr6ur4u81iREaVdCc40rHDHVJNEtniD8Icbz7tcsqAewIVhc/q6WXGqImJpCq7hA0m247dDsaZT0lb/MVBiMoJxDEmAE/GYYnWTEn84R35WhJsMvuQ7QmLvNg6RkChY6POCT/YKe9NKwa1NqI1U+oA5RFzAaFtytvZCE3jtp+aR0brL7qaGfgxm6B7dEpGyhg0NcVCV7xMQNq2JxZTVdAr6lcsRGaAFulakmW3aNnmK+L35Wu8uW+OxNxwUuC6f3b4FVBa276FMuUTRfu7gc+k6kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAU5CjEyAoyTn7PgFpQD48ZNPuUsEQ19gzYgJvHMzFIoZ7jKBodjO5mCzWBcR7A4mpeAsdyiNBl2sTiZscSnNqxk61jVzP5Ba1D7XtOjjr7+3iqowrThj6BY40QqhYh/6BSY9fDzVZQiHnvlo6ZUM5kUK6OavZOovKlp5DIl5sGqoP0qAJnpQ4nhB2WVVsKfPlOXc+2KSsbJ23g9l8zaTMr+X0umlvfEKqyEl1Fa2L1dO0y/KFQ+ILmxcZLpRdq1hRAjd0quq9qGC8ucXhRWDgM4hslVpau0da68g0aItWNez3mc5lB82b3dcZpFMzO41bgw7gvw10AvvTfQDqEYIuQ==-----END CERTIFICATE-----","entity_code":"PSD_PICY_CBC!12345","entity_type":"PSD_PI","entity_address":"EXAMPLE COMPANY LTD, 5 SOME STREET","entity_town_city":"SOME CITY","entity_post_code":"1060","entity_country":"CY","entity_web_site":"www.example.com","services":[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]}]
regulated_entities = []
4 changes: 3 additions & 1 deletion obp-api/src/main/scala/bootstrap/liftweb/Boot.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ package bootstrap.liftweb
import java.io.{File, FileInputStream}
import java.util.stream.Collectors
import java.util.{Locale, TimeZone}

import code.CustomerDependants.MappedCustomerDependant
import code.DynamicData.DynamicData
import code.DynamicEndpoint.DynamicEndpoint
Expand Down Expand Up @@ -107,6 +106,7 @@ import code.productcollectionitem.MappedProductCollectionItem
import code.productfee.ProductFee
import code.products.MappedProduct
import code.ratelimiting.RateLimiting
import code.regulatedentities.MappedRegulatedEntity
import code.remotedata.RemotedataActors
import code.scheduler.{DataBaseCleanerScheduler, DatabaseDriverScheduler, JobScheduler, MetricsArchiveScheduler}
import code.scope.{MappedScope, MappedUserScope}
Expand Down Expand Up @@ -135,6 +135,7 @@ import code.webuiprops.WebUiProps
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.Functions.Implicits._
import com.openbankproject.commons.util.{ApiVersion, Functions}

import javax.mail.internet.MimeMessage
import net.liftweb.common._
import net.liftweb.db.{DB, DBLogEntry}
Expand Down Expand Up @@ -1034,6 +1035,7 @@ object ToSchemify {
AuthUser,
JobScheduler,
MappedETag,
MappedRegulatedEntity,
AtmAttribute,
Admin,
MappedBank,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,33 @@ import scala.collection.immutable.List
object SwaggerDefinitionsJSON {


lazy val regulatedEntitiesJsonV510: RegulatedEntitiesJsonV510 = RegulatedEntitiesJsonV510(List(regulatedEntityJsonV510))
lazy val regulatedEntityJsonV510: RegulatedEntityJsonV510 = RegulatedEntityJsonV510(
entity_id = "0af807d7-3c39-43ef-9712-82bcfde1b9ca",
certificate_authority_ca_owner_id = "CY_CBC",
entity_certificate_public_key = "-----BEGIN CERTIFICATE-----MIICsjCCAZqgAwIBAgIGAYwQ62R0MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTAeFw0yMzExMjcxMzE1MTFaFw0yNTExMjYxMzE1MTFaMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK9WIodZHWzKyCcf9YfWEhPURbfO6zKuMqzHN27GdqHsVVEGxP4F/J4mso+0ENcRr6ur4u81iREaVdCc40rHDHVJNEtniD8Icbz7tcsqAewIVhc/q6WXGqImJpCq7hA0m247dDsaZT0lb/MVBiMoJxDEmAE/GYYnWTEn84R35WhJsMvuQ7QmLvNg6RkChY6POCT/YKe9NKwa1NqI1U+oA5RFzAaFtytvZCE3jtp+aR0brL7qaGfgxm6B7dEpGyhg0NcVCV7xMQNq2JxZTVdAr6lcsRGaAFulakmW3aNnmK+L35Wu8uW+OxNxwUuC6f3b4FVBa276FMuUTRfu7gc+k6kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAU5CjEyAoyTn7PgFpQD48ZNPuUsEQ19gzYgJvHMzFIoZ7jKBodjO5mCzWBcR7A4mpeAsdyiNBl2sTiZscSnNqxk61jVzP5Ba1D7XtOjjr7+3iqowrThj6BY40QqhYh/6BSY9fDzVZQiHnvlo6ZUM5kUK6OavZOovKlp5DIl5sGqoP0qAJnpQ4nhB2WVVsKfPlOXc+2KSsbJ23g9l8zaTMr+X0umlvfEKqyEl1Fa2L1dO0y/KFQ+ILmxcZLpRdq1hRAjd0quq9qGC8ucXhRWDgM4hslVpau0da68g0aItWNez3mc5lB82b3dcZpFMzO41bgw7gvw10AvvTfQDqEYIuQ==-----END CERTIFICATE-----",
entity_code = "PSD_PICY_CBC!12345",
entity_type = "PSD_PI",
entity_address = "EXAMPLE COMPANY LTD, 5 SOME STREET",
entity_town_city = "SOME CITY",
entity_post_code = "1060",
entity_country = "CY",
entity_web_site = "www.example.com",
services = json.parse("""[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]""")
)

lazy val regulatedEntityPostJsonV510: RegulatedEntityPostJsonV510 = RegulatedEntityPostJsonV510(
certificate_authority_ca_owner_id = "CY_CBC",
entity_certificate_public_key = "-----BEGIN CERTIFICATE-----MIICsjCCAZqgAwIBAgIGAYwQ62R0MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTAeFw0yMzExMjcxMzE1MTFaFw0yNTExMjYxMzE1MTFaMBoxGDAWBgNVBAMMD2FwcC5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK9WIodZHWzKyCcf9YfWEhPURbfO6zKuMqzHN27GdqHsVVEGxP4F/J4mso+0ENcRr6ur4u81iREaVdCc40rHDHVJNEtniD8Icbz7tcsqAewIVhc/q6WXGqImJpCq7hA0m247dDsaZT0lb/MVBiMoJxDEmAE/GYYnWTEn84R35WhJsMvuQ7QmLvNg6RkChY6POCT/YKe9NKwa1NqI1U+oA5RFzAaFtytvZCE3jtp+aR0brL7qaGfgxm6B7dEpGyhg0NcVCV7xMQNq2JxZTVdAr6lcsRGaAFulakmW3aNnmK+L35Wu8uW+OxNxwUuC6f3b4FVBa276FMuUTRfu7gc+k6kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAU5CjEyAoyTn7PgFpQD48ZNPuUsEQ19gzYgJvHMzFIoZ7jKBodjO5mCzWBcR7A4mpeAsdyiNBl2sTiZscSnNqxk61jVzP5Ba1D7XtOjjr7+3iqowrThj6BY40QqhYh/6BSY9fDzVZQiHnvlo6ZUM5kUK6OavZOovKlp5DIl5sGqoP0qAJnpQ4nhB2WVVsKfPlOXc+2KSsbJ23g9l8zaTMr+X0umlvfEKqyEl1Fa2L1dO0y/KFQ+ILmxcZLpRdq1hRAjd0quq9qGC8ucXhRWDgM4hslVpau0da68g0aItWNez3mc5lB82b3dcZpFMzO41bgw7gvw10AvvTfQDqEYIuQ==-----END CERTIFICATE-----",
entity_code = "PSD_PICY_CBC!12345",
entity_type = "PSD_PI",
entity_address = "EXAMPLE COMPANY LTD, 5 SOME STREET",
entity_town_city = "SOME CITY",
entity_post_code = "1060",
entity_country = "CY",
entity_web_site = "www.example.com",
services = """[{"CY":["PS_010","PS_020","PS_03C","PS_04C"]}]"""
)

val license = License(
id = licenseIdExample.value,
Expand Down
5 changes: 5 additions & 0 deletions obp-api/src/main/scala/code/api/util/ApiRole.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ object RoleCombination {

object ApiRole extends MdcLoggable{

case class CanCreateRegulatedEntity(requiresBankId: Boolean = false) extends ApiRole
lazy val canCreateRegulatedEntity = CanCreateRegulatedEntity()
case class CanDeleteRegulatedEntity(requiresBankId: Boolean = false) extends ApiRole
lazy val canDeleteRegulatedEntity = CanDeleteRegulatedEntity()

case class CanSearchWarehouse(requiresBankId: Boolean = false) extends ApiRole
lazy val canSearchWarehouse = CanSearchWarehouse()

Expand Down
3 changes: 3 additions & 0 deletions obp-api/src/main/scala/code/api/util/ApiTag.scala
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ object ApiTag {
val apiTagPSD2PIIS=ResourceDocTag("Confirmation of Funds Service (PIIS)")
val apiTagPSD2PIS=ResourceDocTag("Payment Initiation Service (PIS)")


val apiTagDirectory = ResourceDocTag("Directory")


//Note: the followings are for the code generator -- UKOpenBankingV3.1.0
val apiTagUkAccountAccess = ResourceDocTag("UK-AccountAccess")
Expand Down
5 changes: 4 additions & 1 deletion obp-api/src/main/scala/code/api/util/ErrorMessages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,10 @@ object ErrorMessages {
// Bank related messages
val bankIdAlreadyExists = "OBP-34000: Bank Id already exists. Please specify a different value."
val updateBankError = "OBP-34001: Could not update the Bank"


val RegulatedEntityNotFound = "OBP-34100: Regulated Entity not found. Please specify a valid value for REGULATED_ENTITY_ID."
val RegulatedEntityNotDeleted = "OBP-34101: Regulated Entity cannot be deleted. Please specify a valid value for REGULATED_ENTITY_ID."

// Consents
val ConsentNotFound = "OBP-35001: Consent not found by CONSENT_ID. "
val ConsentNotBeforeIssue = "OBP-35002: The time Consent-ID token was issued is set in the future. "
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package code.api.util.newstyle

import code.api.util.APIUtil.{OBPReturnType, unboxFull, unboxFullOrFail}
import code.api.util.ErrorMessages.{RegulatedEntityNotDeleted, RegulatedEntityNotFound}
import code.api.util.{APIUtil, CallContext}
import code.consumer.Consumers
import code.model.{AppType, Consumer}
import code.regulatedentities.MappedRegulatedEntityProvider
import com.openbankproject.commons.model.RegulatedEntityTrait
import net.liftweb.common.Box

import scala.concurrent.Future

object RegulatedEntityNewStyle {

import com.openbankproject.commons.ExecutionContext.Implicits.global

def createRegulatedEntityNewStyle(certificateAuthorityCaOwnerId: Option[String],
entityCertificatePublicKey: Option[String],
entityCode: Option[String],
entityType: Option[String],
entityAddress: Option[String],
entityTownCity: Option[String],
entityPostCode: Option[String],
entityCountry: Option[String],
entityWebSite: Option[String],
services: Option[String],
callContext: Option[CallContext]): OBPReturnType[RegulatedEntityTrait] = {
Future {
MappedRegulatedEntityProvider.createRegulatedEntity(
certificateAuthorityCaOwnerId: Option[String],
entityCertificatePublicKey: Option[String],
entityCode: Option[String],
entityType: Option[String],
entityAddress: Option[String],
entityTownCity: Option[String],
entityPostCode: Option[String],
entityCountry: Option[String],
entityWebSite: Option[String],
services: Option[String]
) map {
(_, callContext)
}
} map {
unboxFull(_)
}
}

def getRegulatedEntitiesNewStyle(callContext: Option[CallContext]): OBPReturnType[List[RegulatedEntityTrait]] = {
Future {
MappedRegulatedEntityProvider.getRegulatedEntities()
} map {
(_, callContext)
}
}
def getRegulatedEntityByEntityIdNewStyle(id: String,
callContext: Option[CallContext]
): OBPReturnType[RegulatedEntityTrait] = {
Future {
MappedRegulatedEntityProvider.getRegulatedEntityByEntityId(id)
} map {
(_, callContext)
} map {
x => (unboxFullOrFail(x._1, callContext, RegulatedEntityNotFound, 404), x._2)
}
}
def deleteRegulatedEntityNewStyle(id: String,
callContext: Option[CallContext]
): OBPReturnType[Boolean] = {
Future {
MappedRegulatedEntityProvider.deleteRegulatedEntity(id)
} map {
(_, callContext)
} map {
x => (unboxFullOrFail(x._1, callContext, RegulatedEntityNotDeleted, 400), x._2)
}
}


}
145 changes: 132 additions & 13 deletions obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,28 @@ package code.api.v5_1_0


import code.api.Constant
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{apiCollectionJson400, apiCollectionsJson400, apiInfoJson400, postApiCollectionJson400, revokedConsentJsonV310, _}
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
import code.api.util.APIUtil._
import code.api.util.ApiRole._
import code.api.util.ApiTag._
import code.api.util.ErrorMessages.{$UserNotLoggedIn, BankNotFound, ConsentNotFound, InvalidJsonFormat, UnknownError, UserNotFoundByUserId, UserNotLoggedIn, _}
import code.api.util.FutureUtil.{EndpointContext, EndpointTimeout}
import code.api.util.NewStyle.HttpCode
import code.api.util._
import code.api.v2_0_0.{EntitlementJSONs, JSONFactory200}
import code.api.util.newstyle.RegulatedEntityNewStyle.{createRegulatedEntityNewStyle, deleteRegulatedEntityNewStyle, getRegulatedEntitiesNewStyle, getRegulatedEntityByEntityIdNewStyle}
import code.api.v3_0_0.JSONFactory300
import code.api.v3_0_0.JSONFactory300.createAggregateMetricJson
import code.api.v3_1_0.ConsentJsonV310
import code.api.v3_1_0.JSONFactory310.createBadLoginStatusJson
import code.api.v4_0_0.{JSONFactory400, PostApiCollectionJson400}
import code.api.v5_0_0.ConsentJsonV500
import code.api.v5_1_0.JSONFactory510.{createRegulatedEntitiesJson, createRegulatedEntityJson}
import code.atmattribute.AtmAttribute
import code.bankconnectors.Connector
import code.consent.Consents
import code.loginattempts.LoginAttempt
import code.metrics.APIMetrics
import code.model.dataAccess.MappedBankAccount
import code.regulatedentities.MappedRegulatedEntityProvider
import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{apply => _}
import code.userlocks.UserLocksProvider
import code.users.Users
Expand All @@ -32,12 +33,10 @@ import code.views.Views
import code.views.system.{AccountAccess, ViewDefinition}
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.dto.CustomerAndAttribute
import com.openbankproject.commons.model.enums.{AtmAttributeType, UserAttributeType}
import com.openbankproject.commons.model.{AtmId, AtmT, BankId, Permission}
import com.openbankproject.commons.model._
import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
import net.liftweb.common.{Box, Full}
import net.liftweb.http.S
import net.liftweb.common.Full
import net.liftweb.http.rest.RestHelper
import net.liftweb.json.parse
import net.liftweb.mapper.By
Expand Down Expand Up @@ -134,19 +133,139 @@ trait APIMethods510 {
|* Regulated Entities
""",
EmptyBody,
EmptyBody,
regulatedEntitiesJsonV510,
List(UnknownError),
apiTagApi :: Nil)
apiTagDirectory :: apiTagApi :: Nil)

lazy val regulatedEntities: OBPEndpoint = {
case "regulated-entities" :: Nil JsonGet _ =>
cc => implicit val ec = EndpointContext(Some(cc))
APIUtil.scalaFutureToBoxedJsonResponse(for {
regulatedEntities <- Future(APIUtil.getPropsValue("regulated_entities", "[]"))
for {
(entities, callContext) <- getRegulatedEntitiesNewStyle(cc.callContext)
} yield {
(createRegulatedEntitiesJson(entities), HttpCode.`200`(callContext))
}
}

staticResourceDocs += ResourceDoc(
getRegulatedEntityById,
implementedInApiVersion,
nameOf(getRegulatedEntityById),
"GET",
"/regulated-entities/REGULATED_ENTITY_ID",
"Get Regulated Entity",
"""Get Regulated Entity By REGULATED_ENTITY_ID
""",
EmptyBody,
regulatedEntitiesJsonV510,
List(UnknownError),
apiTagDirectory :: apiTagApi :: Nil)

lazy val getRegulatedEntityById: OBPEndpoint = {
case "regulated-entities" :: regulatedEntityId :: Nil JsonGet _ =>
cc => implicit val ec = EndpointContext(Some(cc))
for {
(entity, callContext) <- getRegulatedEntityByEntityIdNewStyle(regulatedEntityId, cc.callContext)
} yield {
(createRegulatedEntityJson(entity), HttpCode.`200`(callContext))
}
}


staticResourceDocs += ResourceDoc(
createRegulatedEntity,
implementedInApiVersion,
nameOf(createRegulatedEntity),
"POST",
"/regulated-entities",
"Create Regulated Entity",
s"""Create Regulated Entity
|
|${authenticationRequiredMessage(true)}
|
|""",
regulatedEntityPostJsonV510,
regulatedEntitiesJsonV510,
List(
$UserNotLoggedIn,
UserHasMissingRoles,
InvalidJsonFormat,
UnknownError
),
List(apiTagDirectory, apiTagApi),
Some(List(canCreateRegulatedEntity))
)

lazy val createRegulatedEntity: OBPEndpoint = {
case "regulated-entities" :: Nil JsonPost json -> _ => {
cc =>
implicit val ec = EndpointContext(Some(cc))
val failMsg = s"$InvalidJsonFormat The Json body should be the $RegulatedEntityPostJsonV510 "
for {
postedData <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
json.extract[RegulatedEntityPostJsonV510]
}
failMsg = s"$InvalidJsonFormat The `services` field is not valid JSON"
_ <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
parse(postedData.services)
}
(entity, callContext) <- createRegulatedEntityNewStyle(
certificateAuthorityCaOwnerId = Some(postedData.certificate_authority_ca_owner_id),
entityCertificatePublicKey = Some(postedData.entity_certificate_public_key),
entityCode = Some(postedData.entity_code),
entityType = Some(postedData.entity_type),
entityAddress = Some(postedData.entity_address),
entityTownCity = Some(postedData.entity_town_city),
entityPostCode = Some(postedData.entity_post_code),
entityCountry = Some(postedData.entity_country),
entityWebSite = Some(postedData.entity_web_site),
services = Some(postedData.services),
cc.callContext
)
} yield {
(createRegulatedEntityJson(entity), HttpCode.`201`(callContext))
}
}
}

resourceDocs += ResourceDoc(
deleteRegulatedEntity,
implementedInApiVersion,
nameOf(deleteRegulatedEntity),
"DELETE",
"/regulated-entities/REGULATED_ENTITY_ID",
"Delete Regulated Entity",
s"""Delete Regulated Entity specified by REGULATED_ENTITY_ID
|
|${authenticationRequiredMessage(true)}
|""".stripMargin,
EmptyBody,
EmptyBody,
List(
$UserNotLoggedIn,
UserHasMissingRoles,
InvalidConnectorResponse,
UnknownError
),
List(apiTagDirectory, apiTagApi),
Some(List(canDeleteRegulatedEntity)))

lazy val deleteRegulatedEntity: OBPEndpoint = {
case "regulated-entities" :: regulatedEntityId :: Nil JsonDelete _ => {
cc =>
implicit val ec = EndpointContext(Some(cc))
for {
(deleted, callContext) <- deleteRegulatedEntityNewStyle(
regulatedEntityId: String,
cc.callContext: Option[CallContext]
)
} yield {
(parse(regulatedEntities), HttpCode.`200`(cc.callContext))
})
org.scalameta.logger.elem(deleted)
(Full(deleted), HttpCode.`200`(callContext))
}
}
}


staticResourceDocs += ResourceDoc(
waitingForGodot,
Expand Down
Loading

0 comments on commit e14cb81

Please sign in to comment.