Skip to content

Commit 66e32a4

Browse files
authored
Merge pull request OpenBankProject#2676 from simonredfern/develop
Feature: Featured collections. Fixing examples in v6.0.0 Transactions.
2 parents 2f2401e + 0d4cfe6 commit 66e32a4

10 files changed

Lines changed: 449 additions & 10 deletions

File tree

obp-api/src/main/scala/bootstrap/liftweb/Boot.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import code.api.util._
4949
import code.api.util.migration.Migration
5050
import code.api.util.migration.Migration.DbFunction
5151
import code.apicollection.ApiCollection
52+
import code.featuredapicollection.FeaturedApiCollection
5253
import code.apicollectionendpoint.ApiCollectionEndpoint
5354
import code.atmattribute.AtmAttribute
5455
import code.atms.MappedAtm
@@ -1118,6 +1119,7 @@ object ToSchemify {
11181119
MappedUserRefreshes,
11191120
ApiCollection,
11201121
ApiCollectionEndpoint,
1122+
FeaturedApiCollection,
11211123
JsonSchemaValidation,
11221124
AuthenticationTypeValidation,
11231125
ConnectorMethod,

obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5176,6 +5176,12 @@ object SwaggerDefinitionsJSON {
51765176
lazy val apiCollectionEndpointJson400 = ApiCollectionEndpointJson400(apiCollectionEndpointIdExample.value, apiCollectionIdExample.value, operationIdExample.value)
51775177
lazy val apiCollectionEndpointsJson400 = ApiCollectionEndpointsJson400(List(apiCollectionEndpointJson400))
51785178

5179+
// Featured API Collections (v6.0.0)
5180+
lazy val postFeaturedApiCollectionJsonV600 = PostFeaturedApiCollectionJsonV600(apiCollectionIdExample.value, 1)
5181+
lazy val putFeaturedApiCollectionJsonV600 = PutFeaturedApiCollectionJsonV600(1)
5182+
lazy val featuredApiCollectionJsonV600 = FeaturedApiCollectionJsonV600(featuredApiCollectionIdExample.value, apiCollectionIdExample.value, 1)
5183+
lazy val featuredApiCollectionsJsonV600 = FeaturedApiCollectionsJsonV600(List(featuredApiCollectionJsonV600))
5184+
51795185
lazy val jsonScalaConnectorMethod = JsonConnectorMethod(Some(connectorMethodIdExample.value),"getBank", connectorMethodBodyScalaExample.value, "Scala")
51805186
lazy val jsonScalaConnectorMethodMethodBody = JsonConnectorMethodMethodBody(connectorMethodBodyScalaExample.value, "Scala")
51815187

obp-api/src/main/scala/code/api/util/ApiRole.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,10 @@ object ApiRole extends MdcLoggable{
377377

378378
case class CanGetAllApiCollections(requiresBankId: Boolean = false) extends ApiRole
379379
lazy val canGetAllApiCollections = CanGetAllApiCollections()
380-
380+
381+
case class CanManageFeaturedApiCollections(requiresBankId: Boolean = false) extends ApiRole
382+
lazy val canManageFeaturedApiCollections = CanManageFeaturedApiCollections()
383+
381384
case class CanGetCounterpartyAtAnyBank(requiresBankId: Boolean = false) extends ApiRole
382385
lazy val canGetCounterpartyAtAnyBank = CanGetCounterpartyAtAnyBank()
383386

obp-api/src/main/scala/code/api/util/ErrorMessages.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,12 @@ object ErrorMessages {
436436
val ApiCollectionEndpointAlreadyExists = "OBP-30085: The ApiCollectionEndpoint is already exists."
437437
val ApiCollectionAlreadyExists = "OBP-30086: The ApiCollection is already exists."
438438

439+
val FeaturedApiCollectionNotFound = "OBP-30400: FeaturedApiCollection not found. Please specify a valid value for API_COLLECTION_ID."
440+
val CreateFeaturedApiCollectionError = "OBP-30401: Could not create FeaturedApiCollection."
441+
val UpdateFeaturedApiCollectionError = "OBP-30402: Could not update FeaturedApiCollection."
442+
val DeleteFeaturedApiCollectionError = "OBP-30403: Could not delete FeaturedApiCollection."
443+
val FeaturedApiCollectionAlreadyExists = "OBP-30404: The ApiCollection is already featured."
444+
439445
val DoubleEntryTransactionNotFound = "OBP-30087: Double Entry Transaction not found."
440446

441447
val InvalidAuthContextUpdateRequestKey = "OBP-30088: Invalid Auth Context Update Request Key."

obp-api/src/main/scala/code/api/util/ExampleValue.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,13 @@ object ExampleValue {
285285

286286
lazy val apiCollectionEndpointIdExample = ConnectorField("8uy8a7e4-6d02-40e3-a129-0b2bf89de8uh", "A string that MUST uniquely identify the session on this OBP instance, can be used in all cache.")
287287
glossaryItems += makeGlossaryItem("ApiCollectionEndpoint.apiCollectionEndpointId", apiCollectionEndpointIdExample)
288-
288+
289+
lazy val featuredApiCollectionIdExample = ConnectorField("9uy8a7e4-6d02-40e3-a129-0b2bf89de8uh", "A string that uniquely identifies this featured API collection entry.")
290+
glossaryItems += makeGlossaryItem("FeaturedApiCollection.featuredApiCollectionId", featuredApiCollectionIdExample)
291+
292+
lazy val sortOrderExample = ConnectorField("1", "The sort order for displaying featured API collections. Lower numbers appear first.")
293+
glossaryItems += makeGlossaryItem("FeaturedApiCollection.sortOrder", sortOrderExample)
294+
289295
lazy val operationIdExample = ConnectorField("OBPv4.0.0-getBanks", "A uniquely identify the obp endpoint on OBP instance, you can get it from Get Resource endpoints.")
290296
glossaryItems += makeGlossaryItem("ApiCollectionEndpoint.operationId", operationIdExample)
291297

obp-api/src/main/scala/code/api/util/NewStyle.scala

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import code.api.util.ErrorMessages.{InsufficientAuthorisationToCreateTransaction
1313
import code.api.{APIFailureNewStyle, Constant, JsonResponseException}
1414
import code.apicollection.{ApiCollectionTrait, MappedApiCollectionsProvider}
1515
import code.apicollectionendpoint.{ApiCollectionEndpointTrait, MappedApiCollectionEndpointsProvider}
16+
import code.featuredapicollection.{FeaturedApiCollectionTrait, MappedFeaturedApiCollectionsProvider}
1617
import code.atmattribute.AtmAttribute
1718
import code.authtypevalidation.{AuthenticationTypeValidationProvider, JsonAuthTypeValidation}
1819
import code.bankattribute.BankAttribute
@@ -3715,11 +3716,35 @@ object NewStyle extends MdcLoggable{
37153716
}
37163717

37173718
def getFeaturedApiCollections(callContext: Option[CallContext]) : OBPReturnType[List[ApiCollectionTrait]] = {
3718-
//we get the getFeaturedApiCollectionIds from props, and remove the deplication there.
3719-
val featuredApiCollectionIds = APIUtil.getPropsValue("featured_api_collection_ids","").split(",").map(_.trim).toSet.toList
3720-
//We filter the isDefined and is isSharable collections.
3721-
val apiCollections = featuredApiCollectionIds.map(MappedApiCollectionsProvider.getApiCollectionById).filter(_.isDefined).filter(_.head.isSharable).map(_.head)
3722-
Future{(apiCollections.sortBy(_.apiCollectionName), callContext)}
3719+
// First get featured collections from database, sorted by sortOrder
3720+
val dbFeaturedApiCollections = MappedFeaturedApiCollectionsProvider.getAllFeaturedApiCollections()
3721+
val dbApiCollectionIds = dbFeaturedApiCollections.map(_.apiCollectionId).toSet
3722+
3723+
// Get actual ApiCollections for database featured entries
3724+
val dbApiCollections = dbFeaturedApiCollections
3725+
.map(f => MappedApiCollectionsProvider.getApiCollectionById(f.apiCollectionId))
3726+
.filter(_.isDefined)
3727+
.filter(_.head.isSharable)
3728+
.map(_.head)
3729+
3730+
// Get props-based featured IDs that are NOT in database
3731+
val propsApiCollectionIds = APIUtil.getPropsValue("featured_api_collection_ids", "")
3732+
.split(",")
3733+
.map(_.trim)
3734+
.filter(_.nonEmpty)
3735+
.toList
3736+
.filterNot(dbApiCollectionIds.contains)
3737+
3738+
// Get actual ApiCollections for props entries and sort them by name
3739+
val propsApiCollections = propsApiCollectionIds
3740+
.map(MappedApiCollectionsProvider.getApiCollectionById)
3741+
.filter(_.isDefined)
3742+
.filter(_.head.isSharable)
3743+
.map(_.head)
3744+
.sortBy(_.apiCollectionName)
3745+
3746+
// Merge: database entries first (preserve sortOrder), then props entries (sorted by name)
3747+
Future{(dbApiCollections ++ propsApiCollections, callContext)}
37233748
}
37243749

37253750
def createApiCollection(
@@ -3813,6 +3838,69 @@ object NewStyle extends MdcLoggable{
38133838
}
38143839
}
38153840

3841+
// Featured API Collections functions
3842+
def createFeaturedApiCollection(
3843+
apiCollectionId: String,
3844+
sortOrder: Int,
3845+
callContext: Option[CallContext]
3846+
): OBPReturnType[FeaturedApiCollectionTrait] = {
3847+
Future(MappedFeaturedApiCollectionsProvider.createFeaturedApiCollection(apiCollectionId, sortOrder)) map {
3848+
i => (unboxFullOrFail(i, callContext, CreateFeaturedApiCollectionError), callContext)
3849+
}
3850+
}
3851+
3852+
def getFeaturedApiCollectionByApiCollectionId(
3853+
apiCollectionId: String,
3854+
callContext: Option[CallContext]
3855+
): OBPReturnType[FeaturedApiCollectionTrait] = {
3856+
Future(MappedFeaturedApiCollectionsProvider.getFeaturedApiCollectionByApiCollectionId(apiCollectionId)) map {
3857+
i => (unboxFullOrFail(i, callContext, s"$FeaturedApiCollectionNotFound Current API_COLLECTION_ID($apiCollectionId)"), callContext)
3858+
}
3859+
}
3860+
3861+
def getAllFeaturedApiCollectionsAdmin(callContext: Option[CallContext]): OBPReturnType[List[FeaturedApiCollectionTrait]] = {
3862+
Future(MappedFeaturedApiCollectionsProvider.getAllFeaturedApiCollections(), callContext)
3863+
}
3864+
3865+
def updateFeaturedApiCollection(
3866+
apiCollectionId: String,
3867+
sortOrder: Int,
3868+
callContext: Option[CallContext]
3869+
): OBPReturnType[FeaturedApiCollectionTrait] = {
3870+
Future {
3871+
val featured = MappedFeaturedApiCollectionsProvider.getFeaturedApiCollectionByApiCollectionId(apiCollectionId)
3872+
featured.flatMap { f =>
3873+
MappedFeaturedApiCollectionsProvider.updateFeaturedApiCollection(f.featuredApiCollectionId, sortOrder)
3874+
}
3875+
} map {
3876+
i => (unboxFullOrFail(i, callContext, s"$UpdateFeaturedApiCollectionError Current API_COLLECTION_ID($apiCollectionId)"), callContext)
3877+
}
3878+
}
3879+
3880+
def deleteFeaturedApiCollectionByApiCollectionId(
3881+
apiCollectionId: String,
3882+
callContext: Option[CallContext]
3883+
): OBPReturnType[Boolean] = {
3884+
Future(MappedFeaturedApiCollectionsProvider.deleteFeaturedApiCollectionByApiCollectionId(apiCollectionId)) map {
3885+
i => (unboxFullOrFail(i, callContext, s"$DeleteFeaturedApiCollectionError Current API_COLLECTION_ID($apiCollectionId)"), callContext)
3886+
}
3887+
}
3888+
3889+
def checkFeaturedApiCollectionDoesNotExist(
3890+
apiCollectionId: String,
3891+
callContext: Option[CallContext]
3892+
): OBPReturnType[Boolean] = {
3893+
Future {
3894+
val existing = MappedFeaturedApiCollectionsProvider.getFeaturedApiCollectionByApiCollectionId(apiCollectionId)
3895+
existing match {
3896+
case net.liftweb.common.Full(_) =>
3897+
throw new RuntimeException(FeaturedApiCollectionAlreadyExists)
3898+
case _ =>
3899+
(true, callContext)
3900+
}
3901+
}
3902+
}
3903+
38163904
def createJsonSchemaValidation(validation: JsonValidation, callContext: Option[CallContext]): OBPReturnType[JsonValidation] =
38173905
Future {
38183906
val newValidation = JsonSchemaValidationProvider.validationProvider.vend.create(validation)

0 commit comments

Comments
 (0)