update handling of group roles
This commit is contained in:
parent
ca41e88045
commit
ba74fa9500
|
@ -8,7 +8,7 @@
|
||||||
"editor.defaultFormatter": "vscode.json-language-features"
|
"editor.defaultFormatter": "vscode.json-language-features"
|
||||||
},
|
},
|
||||||
"[javascript]": {
|
"[javascript]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||||
},
|
},
|
||||||
"debug.javascript.terminalOptions": {
|
"debug.javascript.terminalOptions": {
|
||||||
"skipFiles": [
|
"skipFiles": [
|
||||||
|
@ -16,4 +16,7 @@
|
||||||
"<node_internals>/**"
|
"<node_internals>/**"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
notifications,
|
notifications,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { apps, organisation, auth } from "stores/portal"
|
import { apps, organisation, auth, groups } from "stores/portal"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
import { AppStatus } from "constants"
|
import { AppStatus } from "constants"
|
||||||
import { gradient } from "actions"
|
import { gradient } from "actions"
|
||||||
|
@ -30,20 +30,37 @@
|
||||||
try {
|
try {
|
||||||
await organisation.init()
|
await organisation.init()
|
||||||
await apps.load()
|
await apps.load()
|
||||||
|
await groups.actions.init()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error("Error loading apps")
|
notifications.error("Error loading apps")
|
||||||
}
|
}
|
||||||
loaded = true
|
loaded = true
|
||||||
})
|
})
|
||||||
|
|
||||||
const publishedAppsOnly = app => app.status === AppStatus.DEPLOYED
|
const publishedAppsOnly = app => app.status === AppStatus.DEPLOYED
|
||||||
|
|
||||||
|
$: userGroups = $groups.filter(group =>
|
||||||
|
group.users.find(user => user._id === $auth.user?._id)
|
||||||
|
)
|
||||||
|
let userApps = []
|
||||||
$: publishedApps = $apps.filter(publishedAppsOnly)
|
$: publishedApps = $apps.filter(publishedAppsOnly)
|
||||||
$: userApps = $auth.user?.builder?.global
|
|
||||||
|
$: {
|
||||||
|
if (!Object.keys($auth.user?.roles).length) {
|
||||||
|
userApps = $auth.user?.builder?.global
|
||||||
|
? publishedApps
|
||||||
|
: publishedApps.filter(app => {
|
||||||
|
return userGroups.find(group => {
|
||||||
|
return Object.keys(group.roles).includes(app.prodId)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
userApps = $auth.user?.builder?.global
|
||||||
? publishedApps
|
? publishedApps
|
||||||
: publishedApps.filter(app =>
|
: publishedApps.filter(app =>
|
||||||
Object.keys($auth.user?.roles).includes(app.prodId)
|
Object.keys($auth.user?.roles).includes(app.prodId)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getUrl(app) {
|
function getUrl(app) {
|
||||||
if (app.url) {
|
if (app.url) {
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
$: page = $pageInfo.page
|
$: page = $pageInfo.page
|
||||||
$: fetchUsers(page, search)
|
$: fetchUsers(page, search)
|
||||||
$: group = $groups.find(x => x._id === groupId)
|
$: group = $groups.find(x => x._id === groupId)
|
||||||
|
$: console.log(group.users)
|
||||||
async function addAll() {
|
async function addAll() {
|
||||||
group.users = selectedUsers
|
group.users = selectedUsers
|
||||||
await groups.actions.save(group)
|
await groups.actions.save(group)
|
||||||
|
@ -175,9 +175,11 @@
|
||||||
iconBackground={app?.icon?.color || ""}
|
iconBackground={app?.icon?.color || ""}
|
||||||
>
|
>
|
||||||
<div class="title ">
|
<div class="title ">
|
||||||
<StatusLight color={RoleUtils.getRoleColour(group.role)} />
|
<StatusLight
|
||||||
|
color={RoleUtils.getRoleColour(group.roles[app.prodId])}
|
||||||
|
/>
|
||||||
<div style="margin-left: var(--spacing-s);">
|
<div style="margin-left: var(--spacing-s);">
|
||||||
<Body size="XS">{group.role}</Body>
|
<Body size="XS">{group.roles[app.prodId]}</Body>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
let selectedGroups = []
|
let selectedGroups = []
|
||||||
let allAppList = []
|
let allAppList = []
|
||||||
|
|
||||||
|
$: user = users.get(userId)
|
||||||
$: isProPlan = $auth.user?.license.plan.type !== Constants.PlanType.FREE
|
$: isProPlan = $auth.user?.license.plan.type !== Constants.PlanType.FREE
|
||||||
|
|
||||||
$: allAppList = $apps
|
$: allAppList = $apps
|
||||||
|
@ -69,7 +70,7 @@
|
||||||
selectedGroups &&
|
selectedGroups &&
|
||||||
group?.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
group?.name?.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
)
|
)
|
||||||
|
$: console.log($groups)
|
||||||
$: userGroups = $groups.filter(x => {
|
$: userGroups = $groups.filter(x => {
|
||||||
return x.users?.find(y => {
|
return x.users?.find(y => {
|
||||||
return y._id === userId
|
return y._id === userId
|
||||||
|
@ -133,16 +134,15 @@
|
||||||
|
|
||||||
async function addGroup(groupId) {
|
async function addGroup(groupId) {
|
||||||
let selectedGroup = selectedGroups.includes(groupId)
|
let selectedGroup = selectedGroups.includes(groupId)
|
||||||
let newUser = $users.find(user => user._id === userId)
|
|
||||||
let group = $groups.find(group => group._id === groupId)
|
let group = $groups.find(group => group._id === groupId)
|
||||||
|
|
||||||
if (selectedGroup) {
|
if (selectedGroup) {
|
||||||
selectedGroups = selectedGroups.filter(id => id === selectedGroup)
|
selectedGroups = selectedGroups.filter(id => id === selectedGroup)
|
||||||
let newUsers = group.users.filter(user => user._id !== newUser._id)
|
let newUsers = group.users.filter(groupUser => user._id !== groupUser._id)
|
||||||
group.users = newUsers
|
group.users = newUsers
|
||||||
} else {
|
} else {
|
||||||
selectedGroups = [...selectedGroups, groupId]
|
selectedGroups = [...selectedGroups, groupId]
|
||||||
group.users.push(newUser)
|
group.users.push(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
await groups.actions.save(group)
|
await groups.actions.save(group)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
Modal,
|
Modal,
|
||||||
notifications,
|
notifications,
|
||||||
Pagination,
|
Pagination,
|
||||||
|
Icon,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
$: fetchUsers(page, search)
|
$: fetchUsers(page, search)
|
||||||
|
|
||||||
$: isProPlan = $auth.user?.license.plan.type !== Constants.PlanType.FREE
|
$: isProPlan = $auth.user?.license.plan.type !== Constants.PlanType.FREE
|
||||||
$: console.log($users.data)
|
|
||||||
$: appUsers =
|
$: appUsers =
|
||||||
$users.data?.filter(x => {
|
$users.data?.filter(x => {
|
||||||
return Object.keys(x.roles).find(y => {
|
return Object.keys(x.roles).find(y => {
|
||||||
|
@ -48,7 +49,6 @@
|
||||||
async function addData(appData) {
|
async function addData(appData) {
|
||||||
let gr_prefix = "gr"
|
let gr_prefix = "gr"
|
||||||
let us_prefix = "us"
|
let us_prefix = "us"
|
||||||
console.log(appData)
|
|
||||||
appData.forEach(async data => {
|
appData.forEach(async data => {
|
||||||
if (data.id.startsWith(gr_prefix)) {
|
if (data.id.startsWith(gr_prefix)) {
|
||||||
let matchedGroup = $groups.find(group => {
|
let matchedGroup = $groups.find(group => {
|
||||||
|
@ -75,6 +75,35 @@
|
||||||
await users.search({ page, appId: app.prodId })
|
await users.search({ page, appId: app.prodId })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function removeUser(user) {
|
||||||
|
// Remove the user role
|
||||||
|
const filteredRoles = { ...user.roles }
|
||||||
|
delete filteredRoles[app?.prodId]
|
||||||
|
await users.save({
|
||||||
|
...user,
|
||||||
|
roles: {
|
||||||
|
...filteredRoles,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await users.search({ page, appId: app.prodId })
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeGroup(group) {
|
||||||
|
// Remove the user role
|
||||||
|
|
||||||
|
let filteredApps = group.apps.filter(x => x.appId !== app.appId)
|
||||||
|
const filteredRoles = { ...group.roles }
|
||||||
|
delete filteredRoles[app?.prodId]
|
||||||
|
|
||||||
|
await groups.actions.save({
|
||||||
|
...group,
|
||||||
|
apps: filteredApps,
|
||||||
|
roles: { ...filteredRoles },
|
||||||
|
})
|
||||||
|
|
||||||
|
await users.search({ page, appId: app.prodId })
|
||||||
|
}
|
||||||
|
|
||||||
async function updateUserRole(role, user) {
|
async function updateUserRole(role, user) {
|
||||||
user.roles[app.prodId] = role
|
user.roles[app.prodId] = role
|
||||||
users.save(user)
|
users.save(user)
|
||||||
|
@ -145,6 +174,12 @@
|
||||||
Object.keys(group.roles).find(x => x === app.prodId)
|
Object.keys(group.roles).find(x => x === app.prodId)
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
<Icon
|
||||||
|
on:click={() => removeGroup(group)}
|
||||||
|
hoverable
|
||||||
|
size="S"
|
||||||
|
name="Close"
|
||||||
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
{/each}
|
{/each}
|
||||||
</List>
|
</List>
|
||||||
|
@ -161,6 +196,12 @@
|
||||||
Object.keys(user.roles).find(x => x === app.prodId)
|
Object.keys(user.roles).find(x => x === app.prodId)
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
<Icon
|
||||||
|
on:click={() => removeUser(user)}
|
||||||
|
hoverable
|
||||||
|
size="S"
|
||||||
|
name="Close"
|
||||||
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
{/each}
|
{/each}
|
||||||
</List>
|
</List>
|
||||||
|
|
|
@ -17,7 +17,8 @@ export function createUsersStore() {
|
||||||
|
|
||||||
async function get(userId) {
|
async function get(userId) {
|
||||||
try {
|
try {
|
||||||
return await API.getUser(userId)
|
let user = await API.getUser(userId)
|
||||||
|
return user
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,9 @@ exports.updateAppRole = async (user, { appId } = {}) => {
|
||||||
// if a role wasn't found then either set as admin (builder) or public (everyone else)
|
// if a role wasn't found then either set as admin (builder) or public (everyone else)
|
||||||
if (!user.roleId && user.builder && user.builder.global) {
|
if (!user.roleId && user.builder && user.builder.global) {
|
||||||
user.roleId = BUILTIN_ROLE_IDS.ADMIN
|
user.roleId = BUILTIN_ROLE_IDS.ADMIN
|
||||||
} else if (!user.roleId) {
|
} else if (!user.roleId && !user?.userGroups?.length) {
|
||||||
user.roleId = BUILTIN_ROLE_IDS.PUBLIC
|
user.roleId = BUILTIN_ROLE_IDS.PUBLIC
|
||||||
} else if (user?.userGroups?.length) {
|
} else if (!user.roleId && user?.userGroups?.length) {
|
||||||
let roleId = await groups.getGroupRoleId(user, appId)
|
let roleId = await groups.getGroupRoleId(user, appId)
|
||||||
user.roleId = roleId
|
user.roleId = roleId
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,7 +14,8 @@ export interface User extends Document {
|
||||||
password?: string
|
password?: string
|
||||||
status?: string
|
status?: string
|
||||||
|
|
||||||
createdAt?: number // override the default createdAt behaviour - users sdk historically set this to Date.now()
|
createdAt?: number
|
||||||
|
userGroups?: string[] // override the default createdAt behaviour - users sdk historically set this to Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserRoles {
|
export interface UserRoles {
|
||||||
|
|
|
@ -18,6 +18,12 @@ export interface GroupUsersAddedEvent extends BaseEvent {
|
||||||
groupId: string
|
groupId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GroupUsersDeletedEvent extends BaseEvent {
|
||||||
|
emails: string[]
|
||||||
|
count: number
|
||||||
|
groupId: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface GroupsAddedOnboarding extends BaseEvent {
|
export interface GroupsAddedOnboarding extends BaseEvent {
|
||||||
groupId: string
|
groupId: string
|
||||||
onboarding: boolean
|
onboarding: boolean
|
||||||
|
|
|
@ -47,13 +47,15 @@ export const bulkSave = async (ctx: any) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let response = []
|
let response: any[] = []
|
||||||
for (const user of newUsers) {
|
for (const user of newUsers) {
|
||||||
response = await users.save(user, {
|
response.push(
|
||||||
|
await users.save(user, {
|
||||||
hashPassword: true,
|
hashPassword: true,
|
||||||
requirePassword: user.requirePassword,
|
requirePassword: user.requirePassword,
|
||||||
bulkCreate: false,
|
bulkCreate: false,
|
||||||
})
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete passwords and add to group
|
// delete passwords and add to group
|
||||||
|
@ -63,7 +65,7 @@ export const bulkSave = async (ctx: any) => {
|
||||||
|
|
||||||
if (groupsToSave.length) {
|
if (groupsToSave.length) {
|
||||||
groupsToSave.forEach(async (userGroup: UserGroup) => {
|
groupsToSave.forEach(async (userGroup: UserGroup) => {
|
||||||
userGroup.users = [...userGroup.users, ...newUsers]
|
userGroup.users = [...userGroup.users, ...response]
|
||||||
await db.put(userGroup)
|
await db.put(userGroup)
|
||||||
events.group.usersAdded(
|
events.group.usersAdded(
|
||||||
newUsers.map(u => u.email),
|
newUsers.map(u => u.email),
|
||||||
|
@ -141,7 +143,24 @@ export const adminUser = async (ctx: any) => {
|
||||||
|
|
||||||
export const destroy = async (ctx: any) => {
|
export const destroy = async (ctx: any) => {
|
||||||
const id = ctx.params.id
|
const id = ctx.params.id
|
||||||
|
const db = tenancy.getGlobalDB()
|
||||||
|
let user: User = await db.get(id)
|
||||||
|
let groups = user.userGroups
|
||||||
|
|
||||||
await users.destroy(id, ctx.user)
|
await users.destroy(id, ctx.user)
|
||||||
|
|
||||||
|
// Remove asssosicated groups
|
||||||
|
if (groups) {
|
||||||
|
for (const groupId of groups) {
|
||||||
|
let group = await db.get(groupId)
|
||||||
|
let updatedUsersGroup = group.users.filter(
|
||||||
|
(groupUser: any) => groupUser.email !== user.email
|
||||||
|
)
|
||||||
|
group.users = updatedUsersGroup
|
||||||
|
await db.put(group)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
message: `User ${id} deleted.`,
|
message: `User ${id} deleted.`,
|
||||||
}
|
}
|
||||||
|
@ -149,10 +168,27 @@ export const destroy = async (ctx: any) => {
|
||||||
|
|
||||||
export const bulkDelete = async (ctx: any) => {
|
export const bulkDelete = async (ctx: any) => {
|
||||||
const { userIds } = ctx.request.body
|
const { userIds } = ctx.request.body
|
||||||
|
const db = tenancy.getGlobalDB()
|
||||||
|
|
||||||
let deleted = 0
|
let deleted = 0
|
||||||
|
|
||||||
for (const id of userIds) {
|
for (const id of userIds) {
|
||||||
|
let user: User = await db.get(id)
|
||||||
|
let groups = user.userGroups
|
||||||
|
|
||||||
await users.destroy(id, ctx.user)
|
await users.destroy(id, ctx.user)
|
||||||
|
|
||||||
|
if (groups) {
|
||||||
|
for (const groupId of groups) {
|
||||||
|
let group = await db.get(groupId)
|
||||||
|
let updatedUsersGroup = group.users.filter(
|
||||||
|
(groupUser: any) => groupUser.email !== user.email
|
||||||
|
)
|
||||||
|
console.log(updatedUsersGroup)
|
||||||
|
group.users = updatedUsersGroup
|
||||||
|
await db.put(group)
|
||||||
|
}
|
||||||
|
}
|
||||||
deleted++
|
deleted++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue