refactor/enhance view permission migration logic and add special permission handling

This commit is contained in:
hongwei 2025-07-08 11:21:28 +02:00
parent 59d319cc76
commit 538371f8c9
4 changed files with 105 additions and 33 deletions

View File

@ -313,10 +313,9 @@ object Constant extends MdcLoggable {
CAN_SEE_TRANSACTION_THIS_BANK_ACCOUNT,
CAN_SEE_TRANSACTION_STATUS,
CAN_SEE_BANK_ACCOUNT_CURRENCY,
CAN_ADD_TRANSACTION_REQUEST_TO_BENEFICIARY
//TODO These two are speicial permissions, they need metaData for the view list, will fix it later
// CAN_GRANT_ACCESS_TO_VIEWS,
// CAN_REVOKE_ACCESS_TO_VIEWS,
CAN_ADD_TRANSACTION_REQUEST_TO_BENEFICIARY,
CAN_GRANT_ACCESS_TO_VIEWS,
CAN_REVOKE_ACCESS_TO_VIEWS,
)
}

View File

@ -13,12 +13,14 @@ object MigrationOfViewPermissions {
val commitId: String = APIUtil.gitCommit
val allViewDefinitions = ViewDefinition.findAll()
val viewPermissionRowNumberBefore = ViewPermission.count
allViewDefinitions.map(v => MapperViews.migrateViewPermissions(v))
val viewPermissionRowNumberAfter = ViewPermission.count
val isSuccessful = true
val endDate = System.currentTimeMillis()
val comment: String = s"""migrate all permissions from ViewDefinition (${allViewDefinitions.length} rows) to ViewPermission .""".stripMargin
val comment: String = s"""migrate all permissions from ViewDefinition (${allViewDefinitions.length} rows) to ViewPermission (${viewPermissionRowNumberAfter-viewPermissionRowNumberBefore} added) .""".stripMargin
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
isSuccessful

View File

@ -632,33 +632,83 @@ object MapperViews extends Views with MdcLoggable {
theView
}
def migrateViewPermissions(view: View): Unit = {
/**
* This migrates the current View permissions to the new ViewPermission model.
* this will not add any new permission, it will only migrate the existing permissions.
* @param viewDefinition
*/
def migrateViewPermissions(viewDefinition: View): Unit = {
//first, we list all the current view permissions.
val permissionNames: List[String] = code.api.Constant.VIEW_PERMISSION_NAMES
permissionNames.foreach { permissionName =>
// Get permission value
val permissionValue = view.getClass.getMethod(permissionName).invoke(view).asInstanceOf[Boolean]
ViewPermission.findViewPermissions(view).find(_.permission.get == permissionName) match {
case Some(permission) if !permissionValue =>
ViewPermission.delete_!(permission)
case Some(permission) if permissionValue =>
// View definition is in accordance with View permission
case _ if(view.isSystem) =>
ViewPermission.create
.bank_id(null)
.account_id(null)
.view_id(view.viewId.value)
.permission(permissionName) //TODO here ,we need to handle canRevokeAccessToViews and canGrantAccessToViews
.save
case _ =>
ViewPermission.create
.bank_id(view.bankId.value)
.account_id(view.accountId.value)
.view_id(view.viewId.value)
.permission(permissionName)
.save
permissionNames.foreach { permissionName =>
// CAN_REVOKE_ACCESS_TO_VIEWS and CAN_GRANT_ACCESS_TO_VIEWS are special cases, they have a list of view ids as metadata.
// For the rest of the permissions, they are just boolean values.
if (permissionName == CAN_REVOKE_ACCESS_TO_VIEWS || permissionName == CAN_GRANT_ACCESS_TO_VIEWS) {
val permissionValueFromViewdefinition = viewDefinition.getClass.getMethod(permissionName).invoke(viewDefinition).asInstanceOf[Option[List[String]]]
ViewPermission.findViewPermission(viewDefinition, permissionName) match {
// If the permission already exists in ViewPermission, but permissionValueFromViewdefinition is empty, we delete it.
case Full(permission) if permissionValueFromViewdefinition.isEmpty =>
permission.delete_!
// If the permission already exists and permissionValueFromViewdefinition is defined, we update the metadata.
case Full(permission) if permissionValueFromViewdefinition.isDefined =>
permission.metaData(permissionValueFromViewdefinition.get.mkString(",")).save
//if the permission is not existing in ViewPermission,but it is defined in the viewDefinition, we create it. --systemView
case Empty if (viewDefinition.isSystem && permissionValueFromViewdefinition.isDefined) =>
ViewPermission.create
.bank_id(null)
.account_id(null)
.view_id(viewDefinition.viewId.value)
.permission(permissionName)
.metaData(permissionValueFromViewdefinition.get.mkString(","))
.save
//if the permission is not existing in ViewPermission,but it is defined in the viewDefinition, we create it. --customView
case Empty if (!viewDefinition.isSystem && permissionValueFromViewdefinition.isDefined) =>
ViewPermission.create
.bank_id(viewDefinition.bankId.value)
.account_id(viewDefinition.accountId.value)
.view_id(viewDefinition.viewId.value)
.permission(permissionName)
.metaData(permissionValueFromViewdefinition.get.mkString(","))
.save
case _ =>
// This case should not happen, but if it does, we add an error log
logger.error(s"Unexpected case for permission $permissionName for view ${viewDefinition.viewId.value}. No action taken.")
}
} else {
// For the rest of the permissions, they are just boolean values.
val permissionValue = viewDefinition.getClass.getMethod(permissionName).invoke(viewDefinition).asInstanceOf[Boolean]
ViewPermission.findViewPermission(viewDefinition, permissionName) match {
// If the permission already exists in ViewPermission, but permissionValueFromViewdefinition is false, we delete it.
case Full(permission) if !permissionValue =>
permission.delete_!
// If the permission already exists in ViewPermission, but permissionValueFromViewdefinition is empty, we udpate it.
case Full(permission) if permissionValue =>
permission.permission(permissionName).save
//if the permission is not existing in ViewPermission, but it is defined in the viewDefinition, we create it. --systemView
case _ if (viewDefinition.isSystem && permissionValue) =>
ViewPermission.create
.bank_id(null)
.account_id(null)
.view_id(viewDefinition.viewId.value)
.permission(permissionName)
.save
//if the permission is not existing in ViewPermission, but it is defined in the viewDefinition, we create it. --customerView
case _ if (!viewDefinition.isSystem && permissionValue) =>
ViewPermission.create
.bank_id(viewDefinition.bankId.value)
.account_id(viewDefinition.accountId.value)
.view_id(viewDefinition.viewId.value)
.permission(permissionName)
.save
case _ =>
// This case should not happen, but if it does, we do nothing
logger.warn(s"Unexpected case for permission $permissionName for view ${viewDefinition.viewId.value}. No action taken.")
}
}
}
}

View File

@ -2,7 +2,9 @@ package code.views.system
import code.util.UUIDString
import com.openbankproject.commons.model._
import net.liftweb.common.Box
import net.liftweb.mapper._
class ViewPermission extends LongKeyedMapper[ViewPermission] with IdPK with CreatedUpdated {
def getSingleton = ViewPermission
object bank_id extends MappedString(this, 255)
@ -13,10 +15,7 @@ class ViewPermission extends LongKeyedMapper[ViewPermission] with IdPK with Crea
}
object ViewPermission extends ViewPermission with LongKeyedMetaMapper[ViewPermission] {
override def dbIndexes: List[BaseIndex[ViewPermission]] = UniqueIndex(bank_id, account_id, view_id, permission) :: super.dbIndexes
// "ReadAccountsBerlinGroup"
//Work in progress
def findCustomViewPermissions(bankId: BankId, accountId: AccountId, viewId: ViewId): List[ViewPermission] =
ViewPermission.findAll(
By(ViewPermission.bank_id, bankId.value),
@ -24,13 +23,28 @@ object ViewPermission extends ViewPermission with LongKeyedMetaMapper[ViewPermis
By(ViewPermission.view_id, viewId.value)
)
//Work in progress
def findSystemViewPermissions(viewId: ViewId): List[ViewPermission] =
ViewPermission.findAll(
NullRef(ViewPermission.bank_id),
NullRef(ViewPermission.account_id),
By(ViewPermission.view_id, viewId.value)
)
def findCustomViewPermission(bankId: BankId, accountId: AccountId, viewId: ViewId, permission: String): Box[ViewPermission] =
ViewPermission.find(
By(ViewPermission.bank_id, bankId.value),
By(ViewPermission.account_id, accountId.value),
By(ViewPermission.view_id, viewId.value),
By(ViewPermission.permission,permission)
)
def findSystemViewPermission(viewId: ViewId, permission: String): Box[ViewPermission] =
ViewPermission.find(
NullRef(ViewPermission.bank_id),
NullRef(ViewPermission.account_id),
By(ViewPermission.view_id, viewId.value),
By(ViewPermission.permission,permission),
)
/**
* Finds the permissions for a given view, if it is sytem view,
@ -44,4 +58,11 @@ object ViewPermission extends ViewPermission with LongKeyedMetaMapper[ViewPermis
} else {
findCustomViewPermissions(view.bankId, view.accountId, view.viewId)
}
def findViewPermission(view: View, permission: String): Box[ViewPermission] =
if(view.isSystem) {
findSystemViewPermission(view.viewId, permission)
} else {
findCustomViewPermission(view.bankId, view.accountId, view.viewId, permission)
}
}