Files
speckle-server/packages/server/modules/workspaces/graph/directives/hasWorkspaceRole.ts
T
Kristaps Fabians Geikins ede566eed9 feat(server): serverInvites refactor + workspace invites CRUD & GQL API (#2530)
* prep for new resources algo

* typescriptifying stuff

* minor types fix

* migrate to resources col

* repo & creation updated, WIP processing/retrieval

* WIP invite processing

* finished finalization refactor

* project invite management

* transformed all invites services

* fixed up projects & core serverinvites resolvers

* test fixes

* WIP workspace create GQL & test

* basic invite creation test works

* a buncha working tests

* more tests

* cancelation tests

* minor invite use refactor

* invite retrieval tasks

* invite use() works as expected

* filtering out broken invites

* enabled invite retrieval by token irregardless of who is it for

* minor adjustments

* tests fix

* test config improvements

* test env adjustment

* extra test case

* making resource access limits harder to ignore

* linter fixes

* eventBus type cleanup

* better generic names

* refactored serverinvites resource migration

* fix(server): better error message in project invite edge case
2024-07-29 14:37:54 +03:00

70 lines
2.3 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-unsafe-return */
import { GraphqlDirectiveBuilder } from '@/modules/core/graph/helpers/directiveHelper'
import { authorizeResolver } from '@/modules/shared'
import { ForbiddenError } from '@/modules/shared/errors'
import { mapGqlWorkspaceRoleToMainRole } from '@/modules/workspaces/helpers/roles'
import { mapSchema, getDirective, MapperKind } from '@graphql-tools/utils'
import { defaultFieldResolver } from 'graphql'
export const hasWorkspaceRole: GraphqlDirectiveBuilder = () => {
const directiveName = 'hasWorkspaceRole'
return {
typeDefs: `
enum WorkspaceRole {
ADMIN
MEMBER
GUEST
}
"""
Ensure that the active user has the specified Workspace role
Note: Only supported on Workspace type fields
"""
directive @${directiveName}(role: WorkspaceRole!) on FIELD_DEFINITION
`,
schemaTransformer: (schema) =>
mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
const directive = getDirective(schema, fieldConfig, directiveName)?.[0]
if (!directive) return undefined
const { role } = directive
const requiredRole = mapGqlWorkspaceRoleToMainRole(role)
const { resolve = defaultFieldResolver } = fieldConfig
fieldConfig.resolve = async function (...args) {
const [parent, , context, info] = args
// Validate stream role only if parent is a Stream type
if (['Workspace'].includes(info.parentType?.name) && parent) {
if (!parent.id) {
// This should never happen as long as our resolvers always return workspaces with their IDs
throw new ForbiddenError(
'Unexpected access of unidentifiable workspace'
)
}
if (!context.userId) {
throw new ForbiddenError(
'User must be authenticated to access this data'
)
}
await authorizeResolver(
context.userId,
parent.id,
requiredRole,
context.resourceAccessRules
)
}
const data = await resolve.apply(this, args)
return data
}
return fieldConfig
}
})
}
}