Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions admin-ui/app/utils/PermissionMappingUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Utilities for resolving permission keys, computing mapped roles, and building user-friendly messages

export type ApiPermissionItem = {
inum?: string
permission?: string
[key: string]: unknown
}

export type RolePermissionMappingEntry = {
role: string
permissions: string[]
}

type ActionData =
| { inum?: string; permission?: string; [key: string]: unknown }
| string
| null
| undefined

/**
* Resolve the permission key (string) from actionData and the list of apiPermissions.
* actionData may be an object with { inum, permission } or just an inum string.
*/
export function resolvePermissionKey(
actionData: ActionData,
apiPermissions: ApiPermissionItem[] | undefined,
): string | undefined {
const isObject = (value: ActionData): value is { inum?: string; permission?: string } => {
return typeof value === 'object' && value !== null
}

const permissionFromAction = isObject(actionData) ? actionData.permission : undefined
if (permissionFromAction) return permissionFromAction

const permissionInum = isObject(actionData) ? actionData.inum : actionData
if (!permissionInum) return undefined

const found = Array.isArray(apiPermissions)
? apiPermissions.find((p) => p?.inum === permissionInum)
: undefined
return found?.permission
}

/**
* Find roles that contain the given permission key using the role-permission mapping from the store.
*/
export function findRolesForPermission(
permissionKey: string | undefined,
rolePermissionMapping: RolePermissionMappingEntry[] | undefined,
): string[] {
if (!permissionKey || !Array.isArray(rolePermissionMapping)) return []
return rolePermissionMapping
.filter((r) => Array.isArray(r?.permissions) && r.permissions.includes(permissionKey))
.map((r) => r.role)
}

export function buildMappingGuidanceMessage(
permissionKey: string | undefined,
mappedRoles: string[] | undefined,
): string {
if (!permissionKey) {
return 'Unable to delete permission. Permission identifier not found.'
}

if (!mappedRoles || mappedRoles.length === 0) {
return `Unable to delete permission "${permissionKey}". Please check if it's still in use.`
}

const rolesList = mappedRoles.join(', ')
const rolesWord = mappedRoles.length > 1 ? 'roles' : 'role'
return `Unable to delete permission "${permissionKey}". It is currently mapped to ${rolesWord}: ${rolesList}. Please remove it from the role mapping menu first.`
}

export function buildPermissionDeleteErrorMessage(
actionData: ActionData,
apiPermissions: ApiPermissionItem[] | undefined,
rolePermissionMapping: RolePermissionMappingEntry[] | undefined,
): string {
const permissionKey = resolvePermissionKey(actionData, apiPermissions)
const mappedRoles = findRolesForPermission(permissionKey, rolePermissionMapping)
return buildMappingGuidanceMessage(permissionKey, mappedRoles)
}
4 changes: 3 additions & 1 deletion admin-ui/plugins/admin/redux/api/PermissionApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ export default class PermissionApi {
}

deletePermission = (data) => {
const options = {}
options['adminPermission'] = data
return new Promise((resolve, reject) => {
this.api.deleteAdminuiPermission(encodeURIComponent(data.permission), (error, data) => {
this.api.deleteAdminuiPermission(options, (error, data) => {
handleResponse(error, reject, resolve, data)
})
})
Expand Down
18 changes: 17 additions & 1 deletion admin-ui/plugins/admin/redux/sagas/ApiPermissionSaga.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { updateToast } from 'Redux/features/toastSlice'

const JansConfigApi = require('jans_config_api')
import { initAudit } from 'Redux/sagas/SagaUtils'
import { buildPermissionDeleteErrorMessage } from 'Utils/PermissionMappingUtils'

function* newFunction() {
const token = yield select((state) => state.authReducer.token.access_token)
Expand Down Expand Up @@ -121,7 +122,22 @@ export function* deletePermission({ payload }) {
})
return data
} catch (e) {
yield put(updateToast(true, 'error'))
const actionData = payload?.action?.action_data
const apiPermissions = yield select((state) => state.apiPermissionReducer.items || [])
const rolePermissionMapping = yield select((state) => state.mappingReducer.items || [])
let finalMessage
try {
finalMessage = buildPermissionDeleteErrorMessage(
actionData,
apiPermissions,
rolePermissionMapping,
)
} catch (msgError) {
console.error('Error building permission delete message:', msgError)
finalMessage =
e?.response?.body?.responseMessage || e.message || 'Failed to delete permission'
}
yield put(updateToast(true, 'error', finalMessage))
yield put(deletePermissionResponse({ inum: null }))
if (isFourZeroOneError(e)) {
const jwt = yield select((state) => state.authReducer.userinfo_jwt)
Expand Down
1 change: 0 additions & 1 deletion admin-ui/plugins/auth-server/redux/sagas/LoggingSaga.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export function* editLogging({ payload }) {
delete audit.payload

console.log(audit)
debugger

const api = yield* newFunction()
const data = yield call(api.editLoggingConfig, payload.data)
Expand Down
Loading