forked from tsai/budibase
23 changed files with 398 additions and 61 deletions
@ -0,0 +1,43 @@ |
|||
<script> |
|||
import { TextButton, Icon, Popover } from "@budibase/bbui" |
|||
import { backendUiStore } from "builderStore" |
|||
import { Roles } from "constants/backend" |
|||
import api from "builderStore/api" |
|||
import ManageAccessPopover from "../popovers/ManageAccessPopover.svelte" |
|||
|
|||
export let resourceId |
|||
|
|||
let anchor |
|||
let dropdown |
|||
let levels |
|||
let permissions |
|||
|
|||
async function openDropdown() { |
|||
permissions = await backendUiStore.actions.permissions.forResource( |
|||
resourceId |
|||
) |
|||
levels = await backendUiStore.actions.permissions.fetchLevels() |
|||
dropdown.show() |
|||
} |
|||
</script> |
|||
|
|||
<div bind:this={anchor}> |
|||
<TextButton text small on:click={openDropdown}> |
|||
<i class="ri-lock-line" /> |
|||
Manage Access |
|||
</TextButton> |
|||
</div> |
|||
<Popover bind:this={dropdown} {anchor} align="left"> |
|||
<ManageAccessPopover |
|||
{resourceId} |
|||
{levels} |
|||
{permissions} |
|||
onClosed={dropdown.hide} /> |
|||
</Popover> |
|||
|
|||
<style> |
|||
i { |
|||
margin-right: var(--spacing-xs); |
|||
font-size: var(--font-size-s); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,92 @@ |
|||
<script> |
|||
import { onMount } from "svelte" |
|||
import { backendUiStore } from "builderStore" |
|||
import { Roles } from "constants/backend" |
|||
import api from "builderStore/api" |
|||
import { notifier } from "builderStore/store/notifications" |
|||
import { Button, Label, Input, Select, Spacer } from "@budibase/bbui" |
|||
|
|||
export let resourceId |
|||
export let permissions |
|||
export let onClosed |
|||
|
|||
async function changePermission(level, role) { |
|||
await backendUiStore.actions.permissions.save({ |
|||
level, |
|||
role, |
|||
resource: resourceId, |
|||
}) |
|||
|
|||
// Show updated permissions in UI: REMOVE |
|||
permissions = await backendUiStore.actions.permissions.forResource( |
|||
resourceId |
|||
) |
|||
notifier.success("Updated permissions.") |
|||
// TODO: update permissions |
|||
// permissions[] |
|||
} |
|||
</script> |
|||
|
|||
<div class="popover"> |
|||
<h5>Who Can Access This Data?</h5> |
|||
<div class="note"> |
|||
<Label extraSmall grey>Specify the minimum access level role for this data.</Label> |
|||
</div> |
|||
<Spacer large /> |
|||
<div class="row"> |
|||
<Label extraSmall grey>Level</Label> |
|||
<Label extraSmall grey>Role</Label> |
|||
{#each Object.keys(permissions) as level} |
|||
<Input secondary thin value={level} disabled={true} /> |
|||
<Select |
|||
secondary |
|||
thin |
|||
value={permissions[level]} |
|||
on:change={e => changePermission(level, e.target.value)}> |
|||
{#each $backendUiStore.roles as role} |
|||
<option value={role._id}>{role.name}</option> |
|||
{/each} |
|||
</Select> |
|||
{/each} |
|||
</div> |
|||
|
|||
<Spacer large /> |
|||
|
|||
<div class="footer"> |
|||
<Button secondary on:click={onClosed}>Cancel</Button> |
|||
</div> |
|||
</div> |
|||
|
|||
<style> |
|||
.popover { |
|||
display: grid; |
|||
width: 400px; |
|||
} |
|||
|
|||
h5 { |
|||
margin: 0; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
hr { |
|||
margin: var(--spacing-s) 0 var(--spacing-m) 0; |
|||
} |
|||
|
|||
.footer { |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
gap: var(--spacing-m); |
|||
margin-top: var(--spacing-l); |
|||
} |
|||
|
|||
.row { |
|||
display: grid; |
|||
grid-template-columns: 1fr 1fr; |
|||
grid-gap: var(--spacing-m); |
|||
} |
|||
|
|||
.note { |
|||
margin-top: 10px; |
|||
margin-bottom: 0; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,70 @@ |
|||
const { |
|||
PermissionLevels, |
|||
PermissionTypes, |
|||
getBuiltinPermissionByID, |
|||
isPermissionLevelHigherThanRead, |
|||
} = require("../../utilities/security/permissions") |
|||
const { |
|||
lowerBuiltinRoleID, |
|||
BUILTIN_ROLES, |
|||
} = require("../../utilities/security/roles") |
|||
const { DocumentTypes } = require("../../db/utils") |
|||
|
|||
const CURRENTLY_SUPPORTED_LEVELS = [ |
|||
PermissionLevels.WRITE, |
|||
PermissionLevels.READ, |
|||
] |
|||
|
|||
exports.getPermissionType = resourceId => { |
|||
const docType = Object.values(DocumentTypes).filter(docType => |
|||
resourceId.startsWith(docType) |
|||
)[0] |
|||
switch (docType) { |
|||
case DocumentTypes.TABLE: |
|||
case DocumentTypes.ROW: |
|||
return PermissionTypes.TABLE |
|||
case DocumentTypes.AUTOMATION: |
|||
return PermissionTypes.AUTOMATION |
|||
case DocumentTypes.WEBHOOK: |
|||
return PermissionTypes.WEBHOOK |
|||
case DocumentTypes.QUERY: |
|||
case DocumentTypes.DATASOURCE: |
|||
return PermissionTypes.QUERY |
|||
default: |
|||
// views don't have an ID, will end up here
|
|||
return PermissionTypes.VIEW |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* works out the basic permissions based on builtin roles for a resource, using its ID |
|||
* @param resourceId |
|||
* @returns {{}} |
|||
*/ |
|||
exports.getBasePermissions = resourceId => { |
|||
const type = exports.getPermissionType(resourceId) |
|||
const permissions = {} |
|||
for (let [roleId, role] of Object.entries(BUILTIN_ROLES)) { |
|||
if (!role.permissionId) { |
|||
continue |
|||
} |
|||
const perms = getBuiltinPermissionByID(role.permissionId) |
|||
const typedPermission = perms.permissions.find(perm => perm.type === type) |
|||
if ( |
|||
typedPermission && |
|||
CURRENTLY_SUPPORTED_LEVELS.indexOf(typedPermission.level) !== -1 |
|||
) { |
|||
const level = typedPermission.level |
|||
permissions[level] = lowerBuiltinRoleID(permissions[level], roleId) |
|||
if (isPermissionLevelHigherThanRead(level)) { |
|||
permissions[PermissionLevels.READ] = lowerBuiltinRoleID( |
|||
permissions[PermissionLevels.READ], |
|||
roleId |
|||
) |
|||
} |
|||
} |
|||
} |
|||
return permissions |
|||
} |
|||
|
|||
exports.CURRENTLY_SUPPORTED_LEVELS = CURRENTLY_SUPPORTED_LEVELS |
|||
Loading…
Reference in new issue