Skip to content

Commit

Permalink
Merge pull request #2431 from constantine2nd/develop
Browse files Browse the repository at this point in the history
Few features
  • Loading branch information
simonredfern authored Nov 4, 2024
2 parents a4a5b4c + 260072f commit 64d570f
Show file tree
Hide file tree
Showing 24 changed files with 230 additions and 86 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -674,3 +674,13 @@ resourceDocs += ResourceDoc(
...
)
```
## Language support
### Add a new language
An additional language can be added via props `supported_locales`
Steps to add Spanish language:
* tweak the property supported_locales = en_GB to `supported_locales = en_GB,es_ES`
* add file `lift-core_es_ES.properties` at the folder `/resources/i18n`
Please note that default translation file is `lift-core.properties`
2 changes: 2 additions & 0 deletions cheat_sheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@

[API Tester](https://github.com/OpenBankProject/API-Tester/blob/master/README.md)

[Language support](https://github.com/OpenBankProject/OBP-API/tree/develop?tab=readme-ov-file#language-support)


7 changes: 0 additions & 7 deletions obp-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -449,13 +449,6 @@
<version>3.2.7-RELEASE</version>
</dependency>

<!--macro cache-->
<dependency>
<groupId>com.github.OpenBankProject</groupId>
<artifactId>macmemo</artifactId>
<version>0.6-OBP-SNAPSHOT</version>
</dependency>

<!-- util convert Future to js Promise
<dependency>
<groupId>org.scala-js</groupId>
Expand Down
2 changes: 1 addition & 1 deletion obp-api/src/main/resources/props/sample.props.template
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ webui_register_consumer_success_message_email = Thank you for registering to use

# Please note that depricated name ot this props is: language_tag
default_locale = en_GB
supported_locales = en_GB,es_ES
supported_locales = en_GB,es_ES,ro_RO


## API Options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2632,6 +2632,7 @@ object SwaggerDefinitionsJSON {

val putCustomerBranchJsonV310 = PutUpdateCustomerBranchJsonV310(branch_id = "123")
val postCustomerNumberJsonV310 = PostCustomerNumberJsonV310(customer_number = ExampleValue.customerNumberExample.value)
val postCustomerLegalNameJsonV510 = PostCustomerLegalNameJsonV510(legal_name = ExampleValue.legalNameExample.value)
val postCustomerPhoneNumberJsonV400 = PostCustomerPhoneNumberJsonV400(mobile_phone_number = ExampleValue.mobileNumberExample.value)
val putUpdateCustomerEmailJsonV310 = PutUpdateCustomerEmailJsonV310("[email protected]")
val putUpdateCustomerNumberJsonV310 = PutUpdateCustomerNumberJsonV310(customerNumberExample.value)
Expand Down
41 changes: 0 additions & 41 deletions obp-api/src/main/scala/code/api/cache/Caching.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ package code.api.cache
import code.api.Constant._
import code.api.JedisMethod
import code.api.cache.Redis.use
import code.api.util.APIUtil
import code.util.Helper.MdcLoggable
import com.softwaremill.macmemo.{Cache, MemoCacheBuilder, MemoizeParams}

import scala.concurrent.Future
import scala.concurrent.duration.Duration
import scala.language.postfixOps
import scala.reflect.runtime.universe._
object Caching extends MdcLoggable {

def memoizeSyncWithProvider[A](cacheKey: Option[String])(ttl: Duration)(f: => A)(implicit m: Manifest[A]): A = {
Expand Down Expand Up @@ -60,44 +57,6 @@ object Caching extends MdcLoggable {
}
}

/**
* the default MemoCacheBuilder for annotation OBPMemoize
*
* e.g:
*{{{
* import Caching._
*
* @OBPMemoize(ttl = 2 hours, maxSize = 111)
* def hello(name: String, age: Int): Future[String] = ???
*}}}
*/
implicit object OBPCacheBuilder extends MemoCacheBuilder {
override def build[V : TypeTag : Manifest](bucketId: String, params: MemoizeParams): Cache[V] = new Cache[V] {
val ttl = params.expiresAfterMillis
var isFuture = implicitly[TypeTag[V]].tpe <:< typeOf[Future[_]]
var fixedReturnType = false

override def get(key: List[Any], compute: => V): V = {
val cacheKey = bucketId + "_" + key.mkString("_")
if(isFuture) {
val result = memoizeWithProvider(Some(cacheKey))(ttl)(compute.asInstanceOf[Future[Any]])
result.asInstanceOf[V]
} else if(implicitly[TypeTag[V]].tpe =:= typeOf[Any] && !fixedReturnType) {
val result = compute
isFuture = result.isInstanceOf[Future[_]]
fixedReturnType = true
this.get(key, result)
} else {
val result = memoizeSyncWithProvider(Some(cacheKey))(ttl)(compute)
if(result.isInstanceOf[Future[_]]) {
isFuture = true
}
result
}
}
}
}

def getLocalisedResourceDocCache(key: String) = {
use(JedisMethod.GET, (LOCALISED_RESOURCE_DOC_PREFIX + key).intern(), Some(CREATE_LOCALISED_RESOURCE_DOC_JSON_TTL))
}
Expand Down
24 changes: 18 additions & 6 deletions obp-api/src/main/scala/code/api/openidconnect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -141,22 +141,34 @@ object OpenIdConnect extends OBPRestHelper with MdcLoggable {
saveAuthorizationToken(tokenType, accessToken, idToken, refreshToken, scope, expiresIn, authUser.id.get) match {
case Full(token) => (200, "OK", Some(authUser))
case badObj@Failure(_, _, _) => chainErrorMessage(badObj, ErrorMessages.CouldNotHandleOpenIDConnectData+ "saveAuthorizationToken")
case _ => (401, ErrorMessages.CouldNotHandleOpenIDConnectData + "saveAuthorizationToken", Some(authUser))
case everythingElse =>
logger.debug("Error at saveAuthorizationToken: " + everythingElse)
(401, ErrorMessages.CouldNotHandleOpenIDConnectData + "saveAuthorizationToken", Some(authUser))
}
case badObj@Failure(_, _, _) => chainErrorMessage(badObj, ErrorMessages.CouldNotHandleOpenIDConnectData + "getOrCreateConsumer")
case _ => (401, ErrorMessages.CouldNotHandleOpenIDConnectData + "getOrCreateConsumer", Some(authUser))
case everythingElse =>
logger.debug("Error at getOrCreateConsumer: " + everythingElse)
(401, ErrorMessages.CouldNotHandleOpenIDConnectData + "getOrCreateConsumer", Some(authUser))
}
case badObj@Failure(_, _, _) => chainErrorMessage(badObj, ErrorMessages.CouldNotHandleOpenIDConnectData + "getOrCreateAuthUser")
case _ => (401, ErrorMessages.CouldNotHandleOpenIDConnectData + "getOrCreateAuthUser", None)
case everythingElse =>
logger.debug("Error at getOrCreateAuthUser: " + everythingElse)
(401, ErrorMessages.CouldNotHandleOpenIDConnectData + "getOrCreateAuthUser", None)
}
case badObj@Failure(_, _, _) => chainErrorMessage(badObj, ErrorMessages.CouldNotSaveOpenIDConnectUser)
case _ => (401, ErrorMessages.CouldNotSaveOpenIDConnectUser, None)
case everythingElse =>
logger.debug("Error at getOrCreateResourceUser: " + everythingElse)
(401, ErrorMessages.CouldNotSaveOpenIDConnectUser, None)
}
case badObj@Failure(_, _, _) => chainErrorMessage(badObj, ErrorMessages.CouldNotValidateIDToken)
case _ => (401, ErrorMessages.CouldNotValidateIDToken, None)
case everythingElse =>
logger.debug("Error at JwtUtil.validateIdToken: " + everythingElse)
(401, ErrorMessages.CouldNotValidateIDToken, None)
}
case badObj@Failure(_, _, _) => chainErrorMessage(badObj, ErrorMessages.CouldNotExchangeAuthorizationCodeForTokens)
case _ => (401, ErrorMessages.CouldNotExchangeAuthorizationCodeForTokens, None)
case everythingElse =>
logger.debug("Error at exchangeAuthorizationCodeForTokens: " + everythingElse)
(401, ErrorMessages.CouldNotExchangeAuthorizationCodeForTokens, None)
}
} else {
(401, ErrorMessages.InvalidOpenIDConnectState, None)
Expand Down
2 changes: 1 addition & 1 deletion obp-api/src/main/scala/code/api/util/APIUtil.scala
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ object APIUtil extends MdcLoggable with CustomJsonFormats{

/** only support en_GB, es_ES at the moment, will support more later*/
def obpLocaleValidation(value:String): String ={
if(value.equalsIgnoreCase("es_Es")|| value.equalsIgnoreCase("en_GB"))
if(value.equalsIgnoreCase("es_Es") || value.equalsIgnoreCase("ro_RO") || value.equalsIgnoreCase("en_GB"))
SILENCE_IS_GOLDEN
else
ErrorMessages.InvalidLocale
Expand Down
2 changes: 1 addition & 1 deletion obp-api/src/main/scala/code/api/util/ErrorMessages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ object ErrorMessages {
val InvalidHttpMethod = "OBP-10037: Incorrect http_method."
val InvalidHttpProtocol = "OBP-10038: Incorrect http_protocol."
val ServiceIsTooBusy = "OBP-10040: The Service is too busy, please try it later."
val InvalidLocale = "OBP-10041: This locale is not supported. Only the following can be used: en_GB , es_ES."
val InvalidLocale = "OBP-10041: This locale is not supported. Only the following can be used: en_GB, es_ES, ro_RO."

// General Sort and Paging
val FilterSortDirectionError = "OBP-10023: obp_sort_direction parameter can only take two values: DESC or ASC!" // was OBP-20023
Expand Down
5 changes: 5 additions & 0 deletions obp-api/src/main/scala/code/api/util/NewStyle.scala
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,11 @@ object NewStyle extends MdcLoggable{
i => (connectorEmptyResponse(i._1, callContext), i._2)
}
}
def getCustomersByCustomerLegalName(bankId : BankId, legalName: String, callContext: Option[CallContext]): OBPReturnType[List[Customer]] = {
Connector.connector.vend.getCustomersByCustomerLegalName(bankId, legalName, callContext) map {
i => (connectorEmptyResponse(i._1, callContext), i._2)
}
}
def getCustomerByCustomerId(customerId : String, callContext: Option[CallContext]): OBPReturnType[Customer] = {
Connector.connector.vend.getCustomerByCustomerId(customerId, callContext) map {
unboxFullOrFail(_, callContext, s"$CustomerNotFoundByCustomerId. Current CustomerId($customerId)", 404)
Expand Down
4 changes: 2 additions & 2 deletions obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala
Original file line number Diff line number Diff line change
Expand Up @@ -528,11 +528,11 @@ trait APIMethods300 {
|
|optional request parameters for filter with attributes
|URL params example:
| /banks/some-bank-id/firehose/accounts/views/owner?manager=John&count=8
| /banks/some-bank-id/firehose/accounts/views/owner?&limit=50&offset=1
|
|to invalid Browser cache, add timestamp query parameter as follow, the parameter name must be `_timestamp_`
|URL params example:
| `/banks/some-bank-id/firehose/accounts/views/owner?manager=John&count=8&_timestamp_=1596762180358`
| `/banks/some-bank-id/firehose/accounts/views/owner?&limit=50&offset=1&_timestamp_=1596762180358`
|
|${authenticationRequiredMessage(true)}
|
Expand Down
2 changes: 1 addition & 1 deletion obp-api/src/main/scala/code/api/v3_1_0/APIMethods310.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2598,7 +2598,7 @@ trait APIMethods310 {
|* License the data under this endpoint is released under
|
|Can filter with attributes name and values.
|URL params example: /banks/some-bank-id/products?manager=John&count=8
|URL params example: /banks/some-bank-id/products?&limit=50&offset=1
|
|${authenticationRequiredMessage(!getProductsIsPublic)}""".stripMargin,
EmptyBody,
Expand Down
16 changes: 9 additions & 7 deletions obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3416,11 +3416,11 @@ trait APIMethods400 extends MdcLoggable {
|
|optional request parameters for filter with attributes
|URL params example:
| /banks/some-bank-id/firehose/accounts/views/owner?manager=John&count=8
| /banks/some-bank-id/firehose/accounts/views/owner?&limit=50&offset=1
|
|to invalid Browser cache, add timestamp query parameter as follow, the parameter name must be `_timestamp_`
|URL params example:
| `/banks/some-bank-id/firehose/accounts/views/owner?manager=John&count=8&_timestamp_=1596762180358`
| `/banks/some-bank-id/firehose/accounts/views/owner?&limit=50&offset=1&_timestamp_=1596762180358`
|
|${authenticationRequiredMessage(true)}
|
Expand Down Expand Up @@ -3556,7 +3556,9 @@ trait APIMethods400 extends MdcLoggable {
UserCustomerLinksNotFoundForUser,
UnknownError
),
List(apiTagCustomer, apiTagKyc))
List(apiTagCustomer, apiTagKyc),
Some(List(canGetCustomer))
)

lazy val getCustomersByCustomerPhoneNumber : OBPEndpoint = {
case "banks" :: BankId(bankId) :: "search" :: "customers" :: "mobile-phone-number" :: Nil JsonPost json -> _ => {
Expand All @@ -3568,7 +3570,7 @@ trait APIMethods400 extends MdcLoggable {
}
(customers, callContext) <- NewStyle.function.getCustomersByCustomerPhoneNumber(bankId, postedData.mobile_phone_number , cc.callContext)
} yield {
(JSONFactory300.createCustomersJson(customers), HttpCode.`201`(callContext))
(JSONFactory300.createCustomersJson(customers), HttpCode.`200`(callContext))
}
}
}
Expand Down Expand Up @@ -4787,7 +4789,7 @@ trait APIMethods400 extends MdcLoggable {
s"""Gets the Customers specified by attributes
|
|URL params example: /banks/some-bank-id/customers?name=John&age=8
|URL params example: /banks/some-bank-id/customers?manager=John&count=8
|URL params example: /banks/some-bank-id/customers?&limit=50&offset=1
|
|
|""",
Expand Down Expand Up @@ -5206,7 +5208,7 @@ trait APIMethods400 extends MdcLoggable {
|Each account must have at least one private View.
|
|optional request parameters for filter with attributes
|URL params example: /banks/some-bank-id/accounts?manager=John&count=8
|URL params example: /banks/some-bank-id/accounts?&limit=50&offset=1
|
|
""".stripMargin,
Expand Down Expand Up @@ -12182,7 +12184,7 @@ trait APIMethods400 extends MdcLoggable {
|* License the data under this endpoint is released under
|
|Can filter with attributes name and values.
|URL params example: /banks/some-bank-id/products?manager=John&count=8
|URL params example: /banks/some-bank-id/products?&limit=50&offset=1
|
|${authenticationRequiredMessage(!getProductsIsPublic)}""".stripMargin,
EmptyBody,
Expand Down
46 changes: 45 additions & 1 deletion obp-api/src/main/scala/code/api/v5_1_0/APIMethods510.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import code.api.v2_1_0.{ConsumerRedirectUrlJSON, JSONFactory210}
import code.api.v2_2_0.JSONFactory220
import code.api.v3_0_0.JSONFactory300
import code.api.v3_0_0.JSONFactory300.createAggregateMetricJson
import code.api.v3_1_0.{ConsentJsonV310, PostConsentBodyCommonJson}
import code.api.v3_1_0.{ConsentJsonV310, JSONFactory310, PostConsentBodyCommonJson}
import code.api.v3_1_0.JSONFactory310.createBadLoginStatusJson
import code.api.v4_0_0.JSONFactory400.{createAccountBalancesJson, createBalancesJson, createNewCoreBankAccountJson}
import code.api.v4_0_0.{JSONFactory400, PostAccountAccessJsonV400, PostApiCollectionJson400, RevokedJsonV400}
Expand Down Expand Up @@ -1600,6 +1600,50 @@ trait APIMethods510 {
}
}
}


resourceDocs += ResourceDoc(
getCustomersByLegalName,
implementedInApiVersion,
nameOf(getCustomersByLegalName),
"POST",
"/banks/BANK_ID/customers/legal-name",
"Get Customers by Legal Name",
s"""Gets the Customers specified by Legal Name.
|
|
|${authenticationRequiredMessage(true)}
|
|""",
postCustomerLegalNameJsonV510,
customerJsonV310,
List(
UserNotLoggedIn,
UserCustomerLinksNotFoundForUser,
UnknownError
),
List(apiTagCustomer, apiTagKyc),
Some(List(canGetCustomer))
)

lazy val getCustomersByLegalName: OBPEndpoint = {
case "banks" :: BankId(bankId) :: "customers" :: "legal-name" :: Nil JsonPost json -> _ => {
cc =>
implicit val ec = EndpointContext(Some(cc))
for {
(Full(u), callContext) <- authenticatedAccess(cc)
(bank, callContext) <- NewStyle.function.getBank(bankId, callContext)
_ <- NewStyle.function.hasEntitlement(bankId.value, u.userId, canGetCustomer, callContext)
failMsg = s"$InvalidJsonFormat The Json body should be the $PostCustomerLegalNameJsonV510 "
postedData <- NewStyle.function.tryons(failMsg, 400, callContext) {
json.extract[PostCustomerLegalNameJsonV510]
}
(customer, callContext) <- NewStyle.function.getCustomersByCustomerLegalName(bank.bankId, postedData.legal_name, callContext)
} yield {
(JSONFactory300.createCustomersJson(customer), HttpCode.`200`(callContext))
}
}
}


staticResourceDocs += ResourceDoc(
Expand Down
2 changes: 2 additions & 0 deletions obp-api/src/main/scala/code/api/v5_1_0/JSONFactory5.1.0.scala
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ case class UserAttributesResponseJsonV510(
case class CustomerIdJson(id: String)
case class CustomersIdsJsonV510(customers: List[CustomerIdJson])

case class PostCustomerLegalNameJsonV510(legal_name: String)

case class MetricJsonV510(
user_id: String,
url: String,
Expand Down
2 changes: 1 addition & 1 deletion obp-api/src/main/scala/code/bankconnectors/Connector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,7 @@ trait Connector extends MdcLoggable {

def getCustomersByCustomerPhoneNumber(bankId : BankId, phoneNumber: String, callContext: Option[CallContext]): OBPReturnType[Box[List[Customer]]] = Future{(Failure(setUnimplementedError(nameOf(getCustomersByCustomerPhoneNumber _))), callContext)}


def getCustomersByCustomerLegalName(bankId: BankId, legalName: String, callContext: Option[CallContext]): OBPReturnType[Box[List[Customer]]] = Future{(Failure(setUnimplementedError(nameOf(getCustomersByCustomerLegalName _))), callContext)}
def getCheckbookOrders(
bankId: String,
accountId: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3217,6 +3217,10 @@ object LocalMappedConnector extends Connector with MdcLoggable {
CustomerX.customerProvider.vend.getCustomersByCustomerPhoneNumber(bankId, phoneNumber) map {
(_, callContext)
}
override def getCustomersByCustomerLegalName(bankId: BankId, legalName: String, callContext: Option[CallContext]): OBPReturnType[Box[List[Customer]]] =
CustomerX.customerProvider.vend.getCustomersByCustomerLegalName(bankId, legalName) map {
(_, callContext)
}

override def getCustomerAddress(customerId: String, callContext: Option[CallContext]): OBPReturnType[Box[List[CustomerAddress]]] =
CustomerAddressX.address.vend.getAddress(customerId) map {
Expand Down
3 changes: 2 additions & 1 deletion obp-api/src/main/scala/code/customer/CustomerProvider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ trait CustomerProvider {
def getCustomersFuture(bankId : BankId, queryParams: List[OBPQueryParam]): Future[Box[List[Customer]]]

def getCustomersByCustomerPhoneNumber(bankId: BankId, phoneNumber: String): Future[Box[List[Customer]]]

def getCustomersByCustomerLegalName(bankId: BankId, legalName: String): Future[Box[List[Customer]]]

def getCustomerByUserId(bankId: BankId, userId: String): Box[Customer]

def getCustomersByUserId(userId: String): List[Customer]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ object MappedCustomerProvider extends CustomerProvider with MdcLoggable {
)
Full(result)
}
override def getCustomersByCustomerLegalName(bankId: BankId, legalName: String): Future[Box[List[Customer]]] = Future {
val result = MappedCustomer.findAll(
By(MappedCustomer.mBank, bankId.value),
Like(MappedCustomer.mLegalName, legalName)
)
Full(result)
}


override def checkCustomerNumberAvailable(bankId : BankId, customerNumber : String) : Boolean = {
Expand Down
Loading

0 comments on commit 64d570f

Please sign in to comment.