chore(ui): refactor permission computation
parent
cd10b614dd
commit
7c1f492cfe
|
@ -22,7 +22,7 @@ import EmptyRow from 'src/admin/components/EmptyRow'
|
|||
import RoleRow from 'src/admin/components/RoleRow'
|
||||
import {useCallback} from 'react'
|
||||
import allOrParticularSelection from './util/allOrParticularSelection'
|
||||
import computeEffectiveDBPermissions from './util/computeEffectiveDBPermissions'
|
||||
import {computeEntitiesDBPermissions} from './util/computeEffectiveDBPermissions'
|
||||
import useDebounce from 'src/utils/useDebounce'
|
||||
import useChangeEffect from 'src/utils/useChangeEffect'
|
||||
import {ComponentSize, MultiSelectDropdown, SlideToggle} from 'src/reusable_ui'
|
||||
|
@ -99,7 +99,7 @@ const RolesPage = ({
|
|||
// effective permissions
|
||||
const visibleRoles = useMemo(() => roles.filter(x => !x.hidden), [roles])
|
||||
const perDBPermissions = useMemo(
|
||||
() => computeEffectiveDBPermissions(visibleRoles, visibleDBNames),
|
||||
() => computeEntitiesDBPermissions(visibleRoles, visibleDBNames),
|
||||
[visibleDBNames, visibleRoles]
|
||||
)
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import useDebounce from 'src/utils/useDebounce'
|
|||
import useChangeEffect from 'src/utils/useChangeEffect'
|
||||
import MultiSelectDropdown from 'src/reusable_ui/components/dropdowns/MultiSelectDropdown'
|
||||
import {ComponentSize, SlideToggle} from 'src/reusable_ui'
|
||||
import computeEffectiveDBPermissions from './util/computeEffectiveDBPermissions'
|
||||
import {computeEntitiesDBPermissions} from './util/computeEffectiveDBPermissions'
|
||||
import allOrParticularSelection from './util/allOrParticularSelection'
|
||||
import CreateUserDialog, {
|
||||
validatePassword,
|
||||
|
@ -107,7 +107,7 @@ const UsersPage = ({
|
|||
// effective permissions
|
||||
const visibleUsers = useMemo(() => users.filter(x => !x.hidden), [users])
|
||||
const userDBPermissions = useMemo(
|
||||
() => computeEffectiveDBPermissions(visibleUsers, visibleDBNames),
|
||||
() => computeEntitiesDBPermissions(visibleUsers, visibleDBNames),
|
||||
[visibleDBNames, visibleUsers]
|
||||
)
|
||||
|
||||
|
|
|
@ -1,40 +1,63 @@
|
|||
import {User, UserPermission, UserRole} from 'src/types/influxAdmin'
|
||||
|
||||
/** Array of users with Arrays of databases containing granted permission records */
|
||||
/** Array of corresponding users/roles with Arrays of corresponding databases containing granted permission records */
|
||||
type EntitiesDBPermissions = Array<Array<Record<string, boolean>>>
|
||||
/** record with database names and their permissions */
|
||||
type DBPermRecords = Record<string, Record<string, boolean>>
|
||||
|
||||
/**
|
||||
* Creates effective user permissions as a record
|
||||
* that contains permission names as keys and `true` values
|
||||
* for every assigned permission.
|
||||
* ComputeDBPermRecords computes EntitiesDBPermissions for
|
||||
* a suplied user/role and database names.
|
||||
*/
|
||||
export default function computeEffectiveDBPermissions(
|
||||
users: User[] | UserRole[],
|
||||
export function computeDBPermRecords(
|
||||
u: User | UserRole,
|
||||
dbNames: string[]
|
||||
): DBPermRecords {
|
||||
return u.permissions.reduce((acc: DBPermRecords, perm: UserPermission) => {
|
||||
if (perm.scope === 'all') {
|
||||
const allowed = perm.allowed.includes('ALL')
|
||||
? {READ: true, WRITE: true}
|
||||
: perm.allowed.reduce((obj, x) => {
|
||||
obj[x] = true
|
||||
return obj
|
||||
}, {})
|
||||
dbNames.forEach(name => (acc[name] = {...allowed, ...acc[name]}))
|
||||
} else if (perm.scope === 'database') {
|
||||
acc[perm.name] = perm.allowed.reduce<Record<string, boolean>>(
|
||||
(obj, permValue) => {
|
||||
obj[permValue] = true
|
||||
return obj
|
||||
},
|
||||
acc[perm.name] || {}
|
||||
)
|
||||
}
|
||||
return acc
|
||||
}, {} as DBPermRecords)
|
||||
}
|
||||
|
||||
/**
|
||||
* MergeDBPermRecords merges supplied DBPermRecords in to a new DBPermRecords instance.
|
||||
*/
|
||||
export function mergeDBPermRecords(...records: DBPermRecords[]): DBPermRecords {
|
||||
return records.reduce((acc: DBPermRecords, record: DBPermRecords) => {
|
||||
Object.entries(record).forEach(([db, perms]) => {
|
||||
const dbPerms = acc[db] || (acc[db] = {})
|
||||
Object.entries(perms).forEach(([perm, val]) => (dbPerms[perm] = val))
|
||||
})
|
||||
return acc
|
||||
}, {} as DBPermRecords)
|
||||
}
|
||||
|
||||
/**
|
||||
* ComputeEntitiesDBPermissions computes EntitiesDBPermissions for
|
||||
* suplied users/roles and database names.
|
||||
*/
|
||||
export function computeEntitiesDBPermissions(
|
||||
entities: User[] | UserRole[],
|
||||
dbNames: string[]
|
||||
): EntitiesDBPermissions {
|
||||
return users.map((u: User | UserRole) => {
|
||||
const permRecord = u.permissions.reduce(
|
||||
(acc: EntitiesDBPermissions, perm: UserPermission) => {
|
||||
if (perm.scope === 'all') {
|
||||
const allowed = perm.allowed.includes('ALL')
|
||||
? {READ: true, WRITE: true}
|
||||
: perm.allowed.reduce((obj, x) => {
|
||||
obj[x] = true
|
||||
return obj
|
||||
}, {})
|
||||
dbNames.forEach(name => (acc[name] = {...allowed, ...acc[name]}))
|
||||
} else if (perm.scope === 'database') {
|
||||
acc[perm.name] = perm.allowed.reduce<Record<string, boolean>>(
|
||||
(obj, permValue) => {
|
||||
obj[permValue] = true
|
||||
return obj
|
||||
},
|
||||
acc[perm.name] || {}
|
||||
)
|
||||
}
|
||||
return acc
|
||||
},
|
||||
{} as EntitiesDBPermissions
|
||||
)
|
||||
return dbNames.map(name => permRecord[name] || {})
|
||||
return entities.map((u: User | UserRole) => {
|
||||
const dbPermRecords = computeDBPermRecords(u, dbNames)
|
||||
return dbNames.map(dbName => dbPermRecords[dbName] || {})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import subject from 'src/admin/containers/influxdb/util/computeEffectiveDBPermissions'
|
||||
import {computeEntitiesDBPermissions} from 'src/admin/containers/influxdb/util/computeEffectiveDBPermissions'
|
||||
import {User} from 'src/types/influxAdmin'
|
||||
const redundantUserProperties: Pick<User, 'roles' | 'links'> = {
|
||||
roles: [],
|
||||
|
@ -6,91 +6,94 @@ const redundantUserProperties: Pick<User, 'roles' | 'links'> = {
|
|||
}
|
||||
|
||||
describe('admin/containers/influxdb/util/computeEffectiveDBPermissions', () => {
|
||||
it('creates values for empty users', () => {
|
||||
expect(subject([], ['whateverdb'])).toEqual([])
|
||||
})
|
||||
it('creates values for no databases', () => {
|
||||
expect(
|
||||
subject([{name: 'a', permissions: [], ...redundantUserProperties}], [])
|
||||
).toEqual([[]])
|
||||
})
|
||||
it('computes db-specific permissions', () => {
|
||||
expect(
|
||||
subject(
|
||||
describe('computeEntitiesDBPermissions', () => {
|
||||
const subject = computeEntitiesDBPermissions
|
||||
it('creates values for empty users', () => {
|
||||
expect(subject([], ['whateverdb'])).toEqual([])
|
||||
})
|
||||
it('creates values for no databases', () => {
|
||||
expect(
|
||||
subject([{name: 'a', permissions: [], ...redundantUserProperties}], [])
|
||||
).toEqual([[]])
|
||||
})
|
||||
it('computes db-specific permissions', () => {
|
||||
expect(
|
||||
subject(
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
permissions: [
|
||||
{scope: 'database', name: 'db1', allowed: ['A']},
|
||||
{scope: 'database', name: 'db3', allowed: ['B', 'C']},
|
||||
],
|
||||
...redundantUserProperties,
|
||||
},
|
||||
],
|
||||
['db1', 'db2', 'db3']
|
||||
)
|
||||
).toEqual([[{A: true}, {}, {B: true, C: true}]])
|
||||
})
|
||||
it('maps all-scoped ALL permission to READ, WRITE', () => {
|
||||
expect(
|
||||
subject(
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
permissions: [{scope: 'all', allowed: ['ALL']}],
|
||||
...redundantUserProperties,
|
||||
},
|
||||
],
|
||||
['db1', 'db2']
|
||||
)
|
||||
).toEqual([
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
permissions: [
|
||||
{scope: 'database', name: 'db1', allowed: ['A']},
|
||||
{scope: 'database', name: 'db3', allowed: ['B', 'C']},
|
||||
],
|
||||
...redundantUserProperties,
|
||||
},
|
||||
{READ: true, WRITE: true},
|
||||
{READ: true, WRITE: true},
|
||||
],
|
||||
['db1', 'db2', 'db3']
|
||||
)
|
||||
).toEqual([[{A: true}, {}, {B: true, C: true}]])
|
||||
})
|
||||
it('maps all-scoped ALL permission to READ, WRITE', () => {
|
||||
expect(
|
||||
subject(
|
||||
])
|
||||
})
|
||||
it('inherits all permissions', () => {
|
||||
expect(
|
||||
subject(
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
permissions: [
|
||||
{scope: 'all', allowed: ['Read']},
|
||||
{scope: 'database', name: 'db1', allowed: ['Write']},
|
||||
{scope: 'database', name: 'db2', allowed: ['Other']},
|
||||
],
|
||||
...redundantUserProperties,
|
||||
},
|
||||
],
|
||||
['db1', 'db2']
|
||||
)
|
||||
).toEqual([
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
permissions: [{scope: 'all', allowed: ['ALL']}],
|
||||
...redundantUserProperties,
|
||||
},
|
||||
{Read: true, Write: true},
|
||||
{Read: true, Other: true},
|
||||
],
|
||||
['db1', 'db2']
|
||||
)
|
||||
).toEqual([
|
||||
[
|
||||
{READ: true, WRITE: true},
|
||||
{READ: true, WRITE: true},
|
||||
],
|
||||
])
|
||||
})
|
||||
it('inherits all permissions', () => {
|
||||
expect(
|
||||
subject(
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
permissions: [
|
||||
{scope: 'all', allowed: ['Read']},
|
||||
{scope: 'database', name: 'db1', allowed: ['Write']},
|
||||
{scope: 'database', name: 'db2', allowed: ['Other']},
|
||||
],
|
||||
...redundantUserProperties,
|
||||
},
|
||||
],
|
||||
['db1', 'db2']
|
||||
)
|
||||
).toEqual([
|
||||
[
|
||||
{Read: true, Write: true},
|
||||
{Read: true, Other: true},
|
||||
],
|
||||
])
|
||||
})
|
||||
it('inherits independently on order', () => {
|
||||
expect(
|
||||
subject(
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
permissions: [
|
||||
{scope: 'database', name: 'db2', allowed: ['Other']},
|
||||
{scope: 'database', name: 'db1', allowed: ['Write']},
|
||||
{scope: 'all', allowed: ['Read']},
|
||||
],
|
||||
...redundantUserProperties,
|
||||
},
|
||||
],
|
||||
['db1', 'db2', 'db3']
|
||||
)
|
||||
).toEqual([
|
||||
[{Read: true, Write: true}, {Read: true, Other: true}, {Read: true}],
|
||||
])
|
||||
])
|
||||
})
|
||||
it('inherits independently on order', () => {
|
||||
expect(
|
||||
subject(
|
||||
[
|
||||
{
|
||||
name: 'a',
|
||||
permissions: [
|
||||
{scope: 'database', name: 'db2', allowed: ['Other']},
|
||||
{scope: 'database', name: 'db1', allowed: ['Write']},
|
||||
{scope: 'all', allowed: ['Read']},
|
||||
],
|
||||
...redundantUserProperties,
|
||||
},
|
||||
],
|
||||
['db1', 'db2', 'db3']
|
||||
)
|
||||
).toEqual([
|
||||
[{Read: true, Write: true}, {Read: true, Other: true}, {Read: true}],
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue