diff --git a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala index f980fbfea..27f1f147b 100644 --- a/obp-api/src/main/scala/code/api/util/ErrorMessages.scala +++ b/obp-api/src/main/scala/code/api/util/ErrorMessages.scala @@ -455,6 +455,8 @@ object ErrorMessages { val DeleteCustomViewError = "OBP-30256: Could not delete the custom view" val CannotFindCustomViewError = "OBP-30257: Could not find the custom view" val SystemViewCannotBePublicError = "OBP-30258: System view cannot be public" + val CreateCustomViewError = "OBP-30259: Could not create the custom view" + val UpdateCustomViewError = "OBP-30260: Could not update the custom view" val TaxResidenceNotFound = "OBP-30300: Tax Residence not found by TAX_RESIDENCE_ID. " val CustomerAddressNotFound = "OBP-30310: Customer's Address not found by CUSTOMER_ADDRESS_ID. " 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 8a8901313..4a17c2590 100644 --- a/obp-api/src/main/scala/code/api/util/NewStyle.scala +++ b/obp-api/src/main/scala/code/api/util/NewStyle.scala @@ -529,11 +529,6 @@ object NewStyle extends MdcLoggable{ } map { fullBoxOrException(_) } map { unboxFull(_) } - def removeView(account: BankAccount, user: User, viewId: ViewId, callContext: Option[CallContext]) = Future { - account.removeView(user, viewId, callContext) - } map { fullBoxOrException(_) - } map { unboxFull(_) } - def grantAccessToView(account: BankAccount, u: User, viewIdBankIdAccountId : ViewIdBankIdAccountId, provider : String, providerId: String, callContext: Option[CallContext]) = Future { account.grantAccessToView(u, viewIdBankIdAccountId, provider, providerId, callContext: Option[CallContext]) } map { fullBoxOrException(_) @@ -3956,6 +3951,28 @@ object NewStyle extends MdcLoggable{ .slice(offset.getOrElse("0").toInt, offset.getOrElse("0").toInt + limit.getOrElse("100").toInt) , callContext) } + + def createCustomView(bankAccountId: BankIdAccountId, createViewJson: CreateViewJson, callContext: Option[CallContext]): OBPReturnType[View] = + Future { + Views.views.vend.createCustomView(bankAccountId, createViewJson) + } map { i => + (unboxFullOrFail(i, callContext, s"$CreateCustomViewError", 404), callContext) + } + + def updateCustomView(bankAccountId : BankIdAccountId, viewId : ViewId, viewUpdateJson : UpdateViewJSON, callContext: Option[CallContext]): OBPReturnType[View] = + Future { + Views.views.vend.updateCustomView(bankAccountId, viewId, viewUpdateJson) + } map { i => + (unboxFullOrFail(i, callContext, s"$UpdateCustomViewError", 404), callContext) + } + + def removeCustomView(viewId: ViewId, bankAccountId: BankIdAccountId, callContext: Option[CallContext]) = + Future { + Views.views.vend.removeCustomView(viewId, bankAccountId) + } map { i => + (unboxFullOrFail(i, callContext, s"$DeleteCustomViewError", 404), callContext) + } + } } diff --git a/obp-api/src/main/scala/code/api/util/migration/MigrationOfViewDefinitionPermissions.scala b/obp-api/src/main/scala/code/api/util/migration/MigrationOfViewDefinitionPermissions.scala index abecac516..2b05a20b9 100644 --- a/obp-api/src/main/scala/code/api/util/migration/MigrationOfViewDefinitionPermissions.scala +++ b/obp-api/src/main/scala/code/api/util/migration/MigrationOfViewDefinitionPermissions.scala @@ -24,6 +24,9 @@ object MigrationOfViewDefinitionPermissions { .canSeeTransactionRequests_(true) .canSeeAvailableViewsForBankAccount_(true) .canUpdateBankAccountLabel_(true) + .canCreateCustomView_(true) + .canDeleteCustomView_(true) + .canUpdateCustomView_(true) .save ).head @@ -37,6 +40,9 @@ object MigrationOfViewDefinitionPermissions { |${ViewDefinition.canSeeTransactionRequests_.dbColumnName} |${ViewDefinition.canSeeAvailableViewsForBankAccount_.dbColumnName} |${ViewDefinition.canUpdateBankAccountLabel_.dbColumnName} + |${ViewDefinition.canCreateCustomView_.dbColumnName} + |${ViewDefinition.canDeleteCustomView_.dbColumnName} + |${ViewDefinition.canUpdateCustomView_.dbColumnName} |Duration: ${endDate - startDate} ms; """.stripMargin saveLog(name, commitId, isSuccessful, startDate, endDate, comment) diff --git a/obp-api/src/main/scala/code/api/v1_2_1/APIMethods121.scala b/obp-api/src/main/scala/code/api/v1_2_1/APIMethods121.scala index 02da45806..7e2f60d4d 100644 --- a/obp-api/src/main/scala/code/api/v1_2_1/APIMethods121.scala +++ b/obp-api/src/main/scala/code/api/v1_2_1/APIMethods121.scala @@ -622,7 +622,13 @@ trait APIMethods121 { createViewJsonV121.hide_metadata_if_alias_used, createViewJsonV121.allowed_actions ) - view <- account createCustomView (u, createViewJson, Some(cc)) + anyViewContainsCanCreateCustomViewPermission = Views.views.vend.permission(BankIdAccountId(account.bankId, account.accountId), u) + .map(_.views.map(_.canCreateCustomView).find(_.==(true)).getOrElse(false)).getOrElse(false) + _ <- booleanToBox( + anyViewContainsCanCreateCustomViewPermission, + s"${ErrorMessages.CreateCustomViewError} You need the `${ViewDefinition.canCreateCustomView_.dbColumnName}` permission on any your views" + ) + view <- Views.views.vend.createCustomView(BankIdAccountId(bankId,accountId), createViewJson)?~ CreateCustomViewError } yield { val viewJSON = JSONFactory.createViewJSON(view) successJsonResponse(Extraction.decompose(viewJSON), 201) @@ -677,7 +683,13 @@ trait APIMethods121 { hide_metadata_if_alias_used = updateJsonV121.hide_metadata_if_alias_used, allowed_actions = updateJsonV121.allowed_actions ) - updatedView <- account.updateView(u, viewId, updateViewJson, Some(cc)) + anyViewContainsCancanUpdateCustomViewPermission = Views.views.vend.permission(BankIdAccountId(account.bankId, account.accountId), u) + .map(_.views.map(_.canUpdateCustomView).find(_.==(true)).getOrElse(false)).getOrElse(false) + _ <- booleanToBox( + anyViewContainsCancanUpdateCustomViewPermission, + s"${ErrorMessages.CreateCustomViewError} You need the `${ViewDefinition.canUpdateCustomView_.dbColumnName}` permission on any your views" + ) + updatedView <- Views.views.vend.updateCustomView(BankIdAccountId(bankId, accountId),viewId, updateViewJson) ?~ CreateCustomViewError } yield { val viewJSON = JSONFactory.createViewJSON(updatedView) successJsonResponse(Extraction.decompose(viewJSON), 200) @@ -716,7 +728,17 @@ trait APIMethods121 { // custom views start with `_` eg _play, _work, and System views start with a letter, eg: owner _ <- Helper.booleanToFuture(InvalidCustomViewFormat+s"Current view_name (${viewId.value})", cc=callContext) { viewId.value.startsWith("_") } _ <- NewStyle.function.customView(viewId, BankIdAccountId(bankId, accountId), callContext) - deleted <- NewStyle.function.removeView(account, u, viewId, callContext) + + anyViewContainsCanDeleteCustomViewPermission = Views.views.vend.permission(BankIdAccountId(account.bankId, account.accountId), u) + .map(_.views.map(_.canDeleteCustomView).find(_.==(true)).getOrElse(false)).getOrElse(false) + _ <- Helper.booleanToFuture( + s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${ViewDefinition.canDeleteCustomView_.dbColumnName}` permission on any your views", + cc = callContext + ) { + anyViewContainsCanDeleteCustomViewPermission + } + + deleted <- NewStyle.function.removeCustomView(viewId, BankIdAccountId(bankId, accountId),callContext) } yield { (Full(deleted), HttpCode.`204`(callContext)) } diff --git a/obp-api/src/main/scala/code/api/v2_2_0/APIMethods220.scala b/obp-api/src/main/scala/code/api/v2_2_0/APIMethods220.scala index d5a936023..64dd1ab34 100644 --- a/obp-api/src/main/scala/code/api/v2_2_0/APIMethods220.scala +++ b/obp-api/src/main/scala/code/api/v2_2_0/APIMethods220.scala @@ -170,8 +170,14 @@ trait APIMethods220 { createViewJsonV121.which_alias_to_use, createViewJsonV121.hide_metadata_if_alias_used, createViewJsonV121.allowed_actions + ) + anyViewContainsCanCreateCustomViewPermission = Views.views.vend.permission(BankIdAccountId(account.bankId, account.accountId), u) + .map(_.views.map(_.canCreateCustomView).find(_.==(true)).getOrElse(false)).getOrElse(false) + _ <- booleanToBox( + anyViewContainsCanCreateCustomViewPermission, + s"${ErrorMessages.CreateCustomViewError} You need the `${ViewDefinition.canCreateCustomView_.dbColumnName}` permission on any your views" ) - view <- account.createCustomView(u, createViewJson, Some(cc)) + view <- Views.views.vend.createCustomView(BankIdAccountId(bankId, accountId), createViewJson) ?~ CreateCustomViewError } yield { val viewJSON = JSONFactory220.createViewJSON(view) successJsonResponse(Extraction.decompose(viewJSON), 201) @@ -224,7 +230,13 @@ trait APIMethods220 { hide_metadata_if_alias_used = updateJsonV121.hide_metadata_if_alias_used, allowed_actions = updateJsonV121.allowed_actions ) - updatedView <- account.updateView(u, viewId, updateViewJson, Some(cc)) + anyViewContainsCancanUpdateCustomViewPermission = Views.views.vend.permission(BankIdAccountId(account.bankId, account.accountId), u) + .map(_.views.map(_.canUpdateCustomView).find(_.==(true)).getOrElse(false)).getOrElse(false) + _ <- booleanToBox( + anyViewContainsCancanUpdateCustomViewPermission, + s"${ErrorMessages.CreateCustomViewError} You need the `${ViewDefinition.canUpdateCustomView_.dbColumnName}` permission on any your views" + ) + updatedView <- Views.views.vend.updateCustomView(BankIdAccountId(bankId, accountId), viewId, updateViewJson) ?~ CreateCustomViewError } yield { val viewJSON = JSONFactory220.createViewJSON(updatedView) successJsonResponse(Extraction.decompose(viewJSON), 200) diff --git a/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala b/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala index 5e7db318d..b307f05bd 100644 --- a/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala +++ b/obp-api/src/main/scala/code/api/v3_0_0/APIMethods300.scala @@ -27,6 +27,7 @@ import code.users.Users import code.util.Helper import code.util.Helper.booleanToBox import code.views.Views +import code.views.system.ViewDefinition import com.github.dwickern.macros.NameOf.nameOf import com.grum.geocalc.{Coordinate, EarthCalc, Point} import com.openbankproject.commons.model._ @@ -167,7 +168,6 @@ trait APIMethods300 { //creates a view on an bank account case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: Nil JsonPost json -> _ => { cc => - val res = for { (Full(u), callContext) <- authenticatedAccess(cc) createViewJson <- Future { tryo{json.extract[CreateViewJson]} } map { @@ -179,14 +179,18 @@ trait APIMethods300 { checkCustomViewIdOrName(createViewJson.name) } (account, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext) + + anyViewContainsCanCreateCustomViewPermission = Views.views.vend.permission(BankIdAccountId(account.bankId, account.accountId), u) + .map(_.views.map(_.canCreateCustomView).find(_.==(true)).getOrElse(false)).getOrElse(false) + + _ <- Helper.booleanToFuture( + s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${ViewDefinition.canCreateCustomView_.dbColumnName}` permission on any your views", + cc = callContext + ) {anyViewContainsCanCreateCustomViewPermission} + (view, callContext) <- NewStyle.function.createCustomView(BankIdAccountId(bankId, accountId), createViewJson, callContext) } yield { - for { - view <- account.createCustomView (u, createViewJson, callContext) - } yield { - (JSONFactory300.createViewJSON(view), callContext.map(_.copy(httpCode = Some(201)))) - } + (JSONFactory300.createViewJSON(view), HttpCode.`200`(callContext)) } - res map { fullBoxOrException(_) } map { unboxFull(_) } } } @@ -253,7 +257,6 @@ trait APIMethods300 { //updates a view on a bank account case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: "views" :: ViewId(viewId) :: Nil JsonPut json -> _ => { cc => - val res = for { (Full(u), callContext) <- authenticatedAccess(cc) updateJson <- Future { tryo{json.extract[UpdateViewJsonV300]} } map { @@ -273,14 +276,20 @@ trait APIMethods300 { !view.isSystem } (account, callContext) <- NewStyle.function.getBankAccount(bankId, accountId, callContext) - } yield { - for { - updatedView <- account.updateView(u, viewId, updateJson.toUpdateViewJson, callContext) - } yield { - (JSONFactory300.createViewJSON(updatedView), HttpCode.`200`(callContext)) + + anyViewContainsCancanUpdateCustomViewPermission = Views.views.vend.permission(BankIdAccountId(account.bankId, account.accountId), u) + .map(_.views.map(_.canUpdateCustomView).find(_.==(true)).getOrElse(false)).getOrElse(false) + + _ <- Helper.booleanToFuture( + s"${ErrorMessages.ViewDoesNotPermitAccess} You need the `${ViewDefinition.canUpdateCustomView_.dbColumnName}` permission on any your views", + cc = callContext + ) { + anyViewContainsCancanUpdateCustomViewPermission } + (view, callContext) <- NewStyle.function.updateCustomView(BankIdAccountId(bankId, accountId), viewId, updateJson.toUpdateViewJson, callContext) + } yield { + (JSONFactory300.createViewJSON(view), HttpCode.`200`(callContext)) } - res map { fullBoxOrException(_) } map { unboxFull(_) } } } diff --git a/obp-api/src/main/scala/code/model/BankingData.scala b/obp-api/src/main/scala/code/model/BankingData.scala index 80d45118f..549c37277 100644 --- a/obp-api/src/main/scala/code/model/BankingData.scala +++ b/obp-api/src/main/scala/code/model/BankingData.scala @@ -338,51 +338,6 @@ case class BankAccountExtended(val bankAccount: BankAccount) extends MdcLoggable Failure(UserNoOwnerView+"user's email : " + user.emailAddress + ". account : " + accountId, Empty, Empty) } - - final def createCustomView(userDoingTheCreate : User,v: CreateViewJson, callContext: Option[CallContext]): Box[View] = { - if(!userDoingTheCreate.hasOwnerViewAccess(BankIdAccountId(bankId,accountId), callContext)) { - Failure({"user: " + userDoingTheCreate.idGivenByProvider + " at provider " + userDoingTheCreate.provider + " does not have owner access"}) - } else { - val view = Views.views.vend.createCustomView(BankIdAccountId(bankId,accountId), v) - - //if(view.isDefined) { - // logger.debug("user: " + userDoingTheCreate.idGivenByProvider + " at provider " + userDoingTheCreate.provider + " created view: " + view.get + - // " for account " + accountId + "at bank " + bankId) - //} - - view - } - } - - final def updateView(userDoingTheUpdate : User, viewId : ViewId, v: UpdateViewJSON, callContext: Option[CallContext]) : Box[View] = { - if(!userDoingTheUpdate.hasOwnerViewAccess(BankIdAccountId(bankId,accountId), callContext)) { - Failure({"user: " + userDoingTheUpdate.idGivenByProvider + " at provider " + userDoingTheUpdate.provider + " does not have owner access"}) - } else { - val view = Views.views.vend.updateCustomView(BankIdAccountId(bankId,accountId), viewId, v) - //if(view.isDefined) { - // logger.debug("user: " + userDoingTheUpdate.idGivenByProvider + " at provider " + userDoingTheUpdate.provider + " updated view: " + view.get + - // " for account " + accountId + "at bank " + bankId) - //} - - view - } - } - - final def removeView(userDoingTheRemove : User, viewId: ViewId, callContext: Option[CallContext]) : Box[Boolean] = { - if(!userDoingTheRemove.hasOwnerViewAccess(BankIdAccountId(bankId,accountId), callContext)) { - return Failure({"user: " + userDoingTheRemove.idGivenByProvider + " at provider " + userDoingTheRemove.provider + " does not have owner access"}) - } else { - val deleted = Views.views.vend.removeCustomView(viewId, BankIdAccountId(bankId,accountId)) - - //if (deleted.isDefined) { - // logger.debug("user: " + userDoingTheRemove.idGivenByProvider + " at provider " + userDoingTheRemove.provider + " deleted view: " + viewId + - // " for account " + accountId + "at bank " + bankId) - //} - - deleted - } - } - final def moderatedTransaction(transactionId: TransactionId, view: View, bankIdAccountId: BankIdAccountId, user: Box[User], callContext: Option[CallContext] = None) : Box[(ModeratedTransaction, Option[CallContext])] = { if(APIUtil.hasAccountAccess(view, bankIdAccountId, user, callContext)) for{ diff --git a/obp-api/src/main/scala/code/model/dataAccess/MappedView.scala b/obp-api/src/main/scala/code/model/dataAccess/MappedView.scala index 0108fd6a1..8a1d427d2 100644 --- a/obp-api/src/main/scala/code/model/dataAccess/MappedView.scala +++ b/obp-api/src/main/scala/code/model/dataAccess/MappedView.scala @@ -439,6 +439,15 @@ class ViewImpl extends View with LongKeyedMapper[ViewImpl] with ManyToMany with object canSeeBankAccountCreditLimit_ extends MappedBoolean(this){ override def defaultValue = false } + object canCreateCustomView_ extends MappedBoolean(this){ + override def defaultValue = false + } + object canDeleteCustomView_ extends MappedBoolean(this){ + override def defaultValue = false + } + object canUpdateCustomView_ extends MappedBoolean(this){ + override def defaultValue = false + } def id: Long = id_.get def isSystem: Boolean = isSystem_.get @@ -555,6 +564,10 @@ class ViewImpl extends View with LongKeyedMapper[ViewImpl] with ManyToMany with def canCreateStandingOrder: Boolean = false //TODO: if you add new permissions here, remember to set them wherever views are created // (e.g. BankAccountCreationDispatcher) + + def canCreateCustomView: Boolean = canCreateCustomView_.get + def canDeleteCustomView: Boolean = canDeleteCustomView_.get + def canUpdateCustomView: Boolean = canUpdateCustomView_.get } object ViewImpl extends ViewImpl with LongKeyedMetaMapper[ViewImpl]{ diff --git a/obp-api/src/main/scala/code/views/MapperViews.scala b/obp-api/src/main/scala/code/views/MapperViews.scala index e29229f65..44a40a3f0 100644 --- a/obp-api/src/main/scala/code/views/MapperViews.scala +++ b/obp-api/src/main/scala/code/views/MapperViews.scala @@ -791,9 +791,12 @@ object MapperViews extends Views with MdcLoggable { .canAddTransactionRequestToOwnAccount_(true) //added following two for payments .canAddTransactionRequestToAnyAccount_(true) .canSeeAvailableViewsForBankAccount_(false) - .canSeeTransactionRequests_(true) - .canSeeTransactionRequestTypes_(true) - .canUpdateBankAccountLabel_(true) + .canSeeTransactionRequests_(false) + .canSeeTransactionRequestTypes_(false) + .canUpdateBankAccountLabel_(false) + .canCreateCustomView_(false) + .canDeleteCustomView_(false) + .canUpdateCustomView_(false) viewId match { case SYSTEM_OWNER_VIEW_ID => @@ -801,6 +804,10 @@ object MapperViews extends Views with MdcLoggable { .canSeeAvailableViewsForBankAccount_(true) .canSeeTransactionRequests_(true) .canSeeTransactionRequestTypes_(true) + .canUpdateBankAccountLabel_(true) + .canCreateCustomView_(true) + .canDeleteCustomView_(true) + .canUpdateCustomView_(true) case SYSTEM_STAGE_ONE_VIEW_ID => entity .canSeeTransactionDescription_(false) diff --git a/obp-api/src/main/scala/code/views/system/ViewDefinition.scala b/obp-api/src/main/scala/code/views/system/ViewDefinition.scala index 773902977..1cf88b3d8 100644 --- a/obp-api/src/main/scala/code/views/system/ViewDefinition.scala +++ b/obp-api/src/main/scala/code/views/system/ViewDefinition.scala @@ -304,6 +304,16 @@ class ViewDefinition extends View with LongKeyedMapper[ViewDefinition] with Many object canCreateStandingOrder_ extends MappedBoolean(this){ override def defaultValue = false } + + object canCreateCustomView_ extends MappedBoolean(this){ + override def defaultValue = false + } + object canDeleteCustomView_ extends MappedBoolean(this){ + override def defaultValue = false + } + object canUpdateCustomView_ extends MappedBoolean(this){ + override def defaultValue = false + } //Important! If you add a field, be sure to handle it here in this function def setFromViewData(viewData : ViewSpecification) = { @@ -410,6 +420,9 @@ class ViewDefinition extends View with LongKeyedMapper[ViewDefinition] with Many canSeeTransactionRequestTypes_(actions.exists(_ == "can_see_transaction_request_types")) canUpdateBankAccountLabel_(actions.exists(_ == "can_update_bank_account_label")) canSeeAvailableViewsForBankAccount_(actions.exists(_ == "can_see_available_views_for_bank_account")) + canCreateCustomView_(actions.exists(_ == "can_create_custom_view")) + canDeleteCustomView_(actions.exists(_ == "can_delete_custom_view")) + canUpdateCustomView_(actions.exists(_ == "can_update_custom_view")) } @@ -544,6 +557,9 @@ class ViewDefinition extends View with LongKeyedMapper[ViewDefinition] with Many def canCreateDirectDebit: Boolean = canCreateDirectDebit_.get def canCreateStandingOrder: Boolean = canCreateStandingOrder_.get + def canCreateCustomView: Boolean = canCreateCustomView_.get + def canDeleteCustomView: Boolean = canDeleteCustomView_.get + def canUpdateCustomView: Boolean = canUpdateCustomView_.get //TODO: if you add new permissions here, remember to set them wherever views are created // (e.g. BankAccountCreationDispatcher) } diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala b/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala index 998ca7789..21e1bf2c1 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/model/ViewModel.scala @@ -421,4 +421,8 @@ trait View { def canCreateDirectDebit: Boolean def canCreateStandingOrder: Boolean + + def canCreateCustomView: Boolean + def canDeleteCustomView: Boolean + def canUpdateCustomView: Boolean } \ No newline at end of file