157 lines
4.1 KiB
TypeScript
157 lines
4.1 KiB
TypeScript
import { WorkspaceSeatType } from '@/modules/gatekeeper/domain/billing'
|
|
import {
|
|
CreateWorkspaceSeat,
|
|
GetWorkspaceUserSeat
|
|
} from '@/modules/gatekeeper/domain/operations'
|
|
import { NotFoundError } from '@/modules/shared/errors'
|
|
import { EventBusEmit } from '@/modules/shared/services/eventBus'
|
|
import {
|
|
AssignWorkspaceSeat,
|
|
EnsureValidWorkspaceRoleSeat,
|
|
GetWorkspaceRoleForUser
|
|
} from '@/modules/workspaces/domain/operations'
|
|
import { InvalidWorkspaceSeatTypeError } from '@/modules/workspaces/errors/workspaceSeat'
|
|
import { WorkspaceEvents } from '@/modules/workspacesCore/domain/events'
|
|
import { Roles, WorkspaceRoles } from '@speckle/shared'
|
|
import { z } from 'zod'
|
|
|
|
const getDefaultWorkspaceSeatTypeByWorkspaceRole = ({
|
|
workspaceRole
|
|
}: {
|
|
workspaceRole: WorkspaceRoles
|
|
}): WorkspaceSeatType => {
|
|
if (workspaceRole === Roles.Workspace.Admin) {
|
|
return WorkspaceSeatType.Editor
|
|
}
|
|
return WorkspaceSeatType.Viewer
|
|
}
|
|
|
|
const WorkspaceRoleWorkspaceSeatTypeMapping = z.union([
|
|
z.object({
|
|
workspaceRole: z.literal(Roles.Workspace.Admin),
|
|
workspaceSeatType: z.literal(WorkspaceSeatType.Editor)
|
|
}),
|
|
z.object({
|
|
workspaceRole: z.literal(Roles.Workspace.Member),
|
|
workspaceSeatType: z.union([
|
|
z.literal(WorkspaceSeatType.Editor),
|
|
z.literal(WorkspaceSeatType.Viewer)
|
|
])
|
|
}),
|
|
z.object({
|
|
workspaceRole: z.literal(Roles.Workspace.Guest),
|
|
workspaceSeatType: z.union([
|
|
z.literal(WorkspaceSeatType.Editor),
|
|
z.literal(WorkspaceSeatType.Viewer)
|
|
])
|
|
})
|
|
])
|
|
|
|
type WorkspaceRoleWorkspaceSeatTypeMapping = z.infer<
|
|
typeof WorkspaceRoleWorkspaceSeatTypeMapping
|
|
>
|
|
|
|
export const isWorkspaceRoleWorkspaceSeatTypeValid = ({
|
|
workspaceRole,
|
|
workspaceSeatType
|
|
}: {
|
|
workspaceRole: WorkspaceRoles
|
|
workspaceSeatType: WorkspaceSeatType
|
|
}): boolean => {
|
|
return WorkspaceRoleWorkspaceSeatTypeMapping.safeParse({
|
|
workspaceRole,
|
|
workspaceSeatType
|
|
}).success
|
|
}
|
|
|
|
export const ensureValidWorkspaceRoleSeatFactory =
|
|
(deps: {
|
|
createWorkspaceSeat: CreateWorkspaceSeat
|
|
getWorkspaceUserSeat: GetWorkspaceUserSeat
|
|
eventEmit: EventBusEmit
|
|
}): EnsureValidWorkspaceRoleSeat =>
|
|
async (params) => {
|
|
const workspaceSeat = await deps.getWorkspaceUserSeat({
|
|
workspaceId: params.workspaceId,
|
|
userId: params.userId
|
|
})
|
|
if (
|
|
workspaceSeat &&
|
|
isWorkspaceRoleWorkspaceSeatTypeValid({
|
|
workspaceRole: params.role,
|
|
workspaceSeatType: workspaceSeat.type
|
|
})
|
|
) {
|
|
return workspaceSeat
|
|
}
|
|
|
|
// Upsert default seat type assignment
|
|
const seat = await deps.createWorkspaceSeat({
|
|
workspaceId: params.workspaceId,
|
|
userId: params.userId,
|
|
type: getDefaultWorkspaceSeatTypeByWorkspaceRole({ workspaceRole: params.role })
|
|
})
|
|
|
|
if (!params.skipEvent) {
|
|
await deps.eventEmit({
|
|
eventName: WorkspaceEvents.SeatUpdated,
|
|
payload: {
|
|
seat,
|
|
updatedByUserId: params.updatedByUserId
|
|
}
|
|
})
|
|
}
|
|
|
|
return seat
|
|
}
|
|
|
|
export const assignWorkspaceSeatFactory =
|
|
({
|
|
createWorkspaceSeat,
|
|
getWorkspaceRoleForUser,
|
|
eventEmit: eventEmit
|
|
}: {
|
|
createWorkspaceSeat: CreateWorkspaceSeat
|
|
getWorkspaceRoleForUser: GetWorkspaceRoleForUser
|
|
eventEmit: EventBusEmit
|
|
}): AssignWorkspaceSeat =>
|
|
async ({ workspaceId, userId, type, assignedByUserId }) => {
|
|
const workspaceAcl = await getWorkspaceRoleForUser({ workspaceId, userId })
|
|
if (!workspaceAcl) {
|
|
throw new NotFoundError('User does not have a role in the workspace')
|
|
}
|
|
|
|
if (
|
|
!isWorkspaceRoleWorkspaceSeatTypeValid({
|
|
workspaceRole: workspaceAcl.role,
|
|
workspaceSeatType: type
|
|
})
|
|
) {
|
|
throw new InvalidWorkspaceSeatTypeError(
|
|
`User with workspace role ${workspaceAcl.role} cannot have a seat of type ${type}`,
|
|
{
|
|
info: {
|
|
workspaceId,
|
|
userId
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
const seat = await createWorkspaceSeat({
|
|
workspaceId,
|
|
userId,
|
|
type
|
|
})
|
|
|
|
await eventEmit({
|
|
eventName: WorkspaceEvents.SeatUpdated,
|
|
payload: {
|
|
seat,
|
|
updatedByUserId: assignedByUserId
|
|
}
|
|
})
|
|
|
|
return seat
|
|
}
|