feat(server): workspace roles taken into account in project queries (#4319)
* Workspace.projects fixed * Query.project tested & fixed * personalOnly flag added * withProjectRoleOnly flag * authorizeResolver implicit workspace roles * minor cleanup * reorg + support for throwing auth errors * global error mapping * undo special borkage * CR fixes * more CR fixes * shared tests fix * minor adjustment * tests fix * see if removing cached roles fixes it? * more fixes * clean up debugging garbage
This commit is contained in:
committed by
GitHub
parent
e3d3c1446b
commit
820a1e2ebf
@@ -7,7 +7,7 @@ export const workspaceEventNamespace = 'workspace' as const
|
||||
const eventPrefix = `${workspaceEventNamespace}.` as const
|
||||
|
||||
export const WorkspaceEvents = {
|
||||
Authorized: `${eventPrefix}authorized`,
|
||||
Authorizing: `${eventPrefix}authorizing`,
|
||||
Created: `${eventPrefix}created`,
|
||||
Updated: `${eventPrefix}updated`,
|
||||
Deleted: `${eventPrefix}deleted`,
|
||||
@@ -47,7 +47,7 @@ type WorkspaceJoinedFromDiscoveryPayload = {
|
||||
}
|
||||
|
||||
export type WorkspaceEventsPayloads = {
|
||||
[WorkspaceEvents.Authorized]: WorkspaceAuthorizedPayload
|
||||
[WorkspaceEvents.Authorizing]: WorkspaceAuthorizedPayload
|
||||
[WorkspaceEvents.Created]: WorkspaceCreatedPayload
|
||||
[WorkspaceEvents.Updated]: WorkspaceUpdatedPayload
|
||||
[WorkspaceEvents.Deleted]: { workspaceId: string }
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { WorkspaceAcl, WorkspaceSeat } from '@/modules/workspacesCore/domain/types'
|
||||
import { Nullable } from '@speckle/shared'
|
||||
|
||||
export type GetWorkspaceRolesAndSeats = (params: {
|
||||
workspaceId: string
|
||||
userIds?: string[]
|
||||
}) => Promise<{
|
||||
[userId: string]: {
|
||||
role: WorkspaceAcl
|
||||
seat: Nullable<WorkspaceSeat>
|
||||
userId: string
|
||||
}
|
||||
}>
|
||||
|
||||
export type GetWorkspaceRoleAndSeat = (params: {
|
||||
workspaceId: string
|
||||
userId: string
|
||||
}) => Promise<
|
||||
| {
|
||||
role: WorkspaceAcl
|
||||
seat: Nullable<WorkspaceSeat>
|
||||
userId: string
|
||||
}
|
||||
| undefined
|
||||
>
|
||||
@@ -72,3 +72,18 @@ export type WorkspaceJoinRequest = {
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
}
|
||||
|
||||
export const WorkspaceSeatType = <const>{
|
||||
Viewer: 'viewer',
|
||||
Editor: 'editor'
|
||||
}
|
||||
export type WorkspaceSeatType =
|
||||
(typeof WorkspaceSeatType)[keyof typeof WorkspaceSeatType]
|
||||
|
||||
export type WorkspaceSeat = {
|
||||
workspaceId: string
|
||||
userId: string
|
||||
type: WorkspaceSeatType
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
}
|
||||
|
||||
@@ -36,3 +36,11 @@ export const WorkspaceJoinRequests = buildTableHelper('workspace_join_requests',
|
||||
'createdAt',
|
||||
'updatedAt'
|
||||
])
|
||||
|
||||
export const WorkspaceSeats = buildTableHelper('workspace_seats', [
|
||||
'workspaceId',
|
||||
'userId',
|
||||
'type',
|
||||
'createdAt',
|
||||
'updatedAt'
|
||||
])
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { formatJsonArrayRecords } from '@/modules/shared/helpers/dbHelper'
|
||||
import {
|
||||
GetWorkspaceRoleAndSeat,
|
||||
GetWorkspaceRolesAndSeats
|
||||
} from '@/modules/workspacesCore/domain/operations'
|
||||
import {
|
||||
WorkspaceSeat,
|
||||
WorkspaceAcl as WorkspaceAclRecord
|
||||
} from '@/modules/workspacesCore/domain/types'
|
||||
import { WorkspaceAcl, WorkspaceSeats } from '@/modules/workspacesCore/helpers/db'
|
||||
import { Knex } from 'knex'
|
||||
|
||||
const tables = {
|
||||
workspaceSeats: (db: Knex) => db<WorkspaceSeat>(WorkspaceSeats.name),
|
||||
workspaceAcl: (db: Knex) => db<WorkspaceAclRecord>(WorkspaceAcl.name)
|
||||
}
|
||||
|
||||
export const getWorkspaceRolesAndSeatsFactory =
|
||||
(deps: { db: Knex }): GetWorkspaceRolesAndSeats =>
|
||||
async ({ workspaceId, userIds }) => {
|
||||
const q = tables
|
||||
.workspaceAcl(deps.db)
|
||||
.select<Array<{ seats: WorkspaceSeat[]; roles: WorkspaceAclRecord[] }>>([
|
||||
// There's only ever gonna be 1 role and seat per user, but this way we can avoid having to group
|
||||
// by many columns and we can get everything in 1 query
|
||||
WorkspaceAcl.groupArray('roles'),
|
||||
WorkspaceSeats.groupArray('seats')
|
||||
])
|
||||
.leftJoin(WorkspaceSeats.name, (j1) => {
|
||||
j1.on(WorkspaceSeats.col.userId, WorkspaceAcl.col.userId).andOnVal(
|
||||
WorkspaceSeats.col.workspaceId,
|
||||
workspaceId
|
||||
)
|
||||
})
|
||||
.where(WorkspaceAcl.col.workspaceId, workspaceId)
|
||||
.groupBy(WorkspaceAcl.col.userId)
|
||||
|
||||
if (userIds?.length) {
|
||||
q.whereIn(WorkspaceAcl.col.userId, userIds)
|
||||
}
|
||||
|
||||
const res = await q
|
||||
return res.reduce((acc, row) => {
|
||||
const role = formatJsonArrayRecords(row.roles)[0]
|
||||
if (!role) return acc
|
||||
|
||||
acc[role.userId] = {
|
||||
role,
|
||||
seat: formatJsonArrayRecords(row.seats || [])[0] || null,
|
||||
userId: role.userId
|
||||
}
|
||||
return acc
|
||||
}, {} as Awaited<ReturnType<GetWorkspaceRolesAndSeats>>)
|
||||
}
|
||||
|
||||
export const getWorkspaceRoleAndSeatFactory =
|
||||
(deps: { db: Knex }): GetWorkspaceRoleAndSeat =>
|
||||
async ({ workspaceId, userId }) => {
|
||||
const getWorkspaceRolesAndSeats = getWorkspaceRolesAndSeatsFactory(deps)
|
||||
const rolesAndSeats = await getWorkspaceRolesAndSeats({
|
||||
workspaceId,
|
||||
userIds: [userId]
|
||||
})
|
||||
return rolesAndSeats[userId]
|
||||
}
|
||||
Reference in New Issue
Block a user