Files
speckle-server/packages/server/modules/accessrequests/graph/resolvers/index.ts
T
Kristaps Fabians Geikins bde148f286 chore(server): migrating fully to ESM (#5042)
* wip

* some extra fixes

* stuff kinda works?

* need to figure out mocks

* need to figure out mocks

* fix db listener

* gqlgen fix

* minor gqlgen watch adjustment

* lint fixes

* delete old codegen file

* converting migrations to ESM

* getModuleDIrectory

* vitest sort of works

* added back ts-vitest

* resolve gql double load

* fixing test timeout configs

* TSC lint fix

* fix automate tests

* moar debugging

* debugging

* more debugging

* codegen update

* server works

* yargs migrated

* chore(server): getting rid of global mocks for Server ESM (#5046)

* got rid of email mock

* got rid of comment mocks

* got rid of multi region mocks

* got rid of stripe mock

* admin override mock updated

* removed final mock

* fixing import.meta.resolve calls

* another import.meta.resolve fix

* added requested test

* nyc ESM fix

* removed unneeded deps + linting

* yarn lock forgot to commit

* tryna fix flakyness

* email capture util fix

* sendEmail fix

* fix TSX check

* sender transporter fix + CR comments

* merge main fix

* test fixx

* circleci fix

* gqlgen bigint fix

* error formatter fix

* more error formatting improvements

* esmloader added to Dockerfile

* more dockerfile fixes

* bg jobs fix
2025-07-14 10:26:19 +03:00

272 lines
7.7 KiB
TypeScript

import { db } from '@/db/knex'
import {
AccessRequestType,
createNewRequestFactory,
deleteRequestByIdFactory,
getPendingAccessRequestFactory,
getPendingAccessRequestsFactory,
getUsersPendingAccessRequestFactory
} from '@/modules/accessrequests/repositories'
import {
getPendingProjectRequestsFactory,
getPendingStreamRequestsFactory,
getUserProjectAccessRequestFactory,
getUserStreamAccessRequestFactory,
processPendingStreamRequestFactory,
requestProjectAccessFactory,
requestStreamAccessFactory
} from '@/modules/accessrequests/services/stream'
import { Resolvers } from '@/modules/core/graph/generated/graphql'
import { mapStreamRoleToValue } from '@/modules/core/helpers/graphTypes'
import { Roles } from '@/modules/core/helpers/mainConstants'
import {
getStreamFactory,
getStreamRolesFactory,
grantStreamPermissionsFactory
} from '@/modules/core/repositories/streams'
import { getUserFactory } from '@/modules/core/repositories/users'
import {
addOrUpdateStreamCollaboratorFactory,
validateStreamAccessFactory
} from '@/modules/core/services/streams/access'
import { authorizeResolver } from '@/modules/shared'
import { LogicError } from '@/modules/shared/errors'
import { getEventBus } from '@/modules/shared/services/eventBus'
import { withOperationLogging } from '@/observability/domain/businessLogging'
const getUser = getUserFactory({ db })
const getStream = getStreamFactory({ db })
const getUserProjectAccessRequest = getUserProjectAccessRequestFactory({
getUsersPendingAccessRequest: getUsersPendingAccessRequestFactory({ db })
})
const getUserStreamAccessRequest = getUserStreamAccessRequestFactory({
getUserProjectAccessRequest
})
const requestProjectAccess = requestProjectAccessFactory({
getUserStreamAccessRequest,
getStream,
createNewRequest: createNewRequestFactory({ db }),
emitEvent: getEventBus().emit
})
const requestStreamAccess = requestStreamAccessFactory({
requestProjectAccess
})
const getPendingProjectRequests = getPendingProjectRequestsFactory({
getPendingAccessRequests: getPendingAccessRequestsFactory({ db })
})
const getPendingStreamRequests = getPendingStreamRequestsFactory({
getPendingProjectRequests
})
const validateStreamAccess = validateStreamAccessFactory({
authorizeResolver
})
const addOrUpdateStreamCollaborator = addOrUpdateStreamCollaboratorFactory({
validateStreamAccess,
getUser,
grantStreamPermissions: grantStreamPermissionsFactory({ db }),
getStreamRoles: getStreamRolesFactory({ db }),
emitEvent: getEventBus().emit
})
const processPendingStreamRequest = processPendingStreamRequestFactory({
getPendingAccessRequest: getPendingAccessRequestFactory({ db }),
validateStreamAccess,
addOrUpdateStreamCollaborator,
deleteRequestById: deleteRequestByIdFactory({ db }),
emitEvent: getEventBus().emit
})
const processPendingProjectRequest = processPendingStreamRequest
const resolvers: Resolvers = {
Mutation: {
async streamAccessRequestUse(_parent, args, ctx) {
const { userId, resourceAccessRules } = ctx
const { requestId, accept, role } = args
if (!userId) throw new LogicError('User ID unexpectedly false')
await processPendingStreamRequest(
userId,
requestId,
accept,
mapStreamRoleToValue(role),
resourceAccessRules
)
return true
},
async streamAccessRequestCreate(_parent, args, ctx) {
const { userId } = ctx
if (!userId) throw new LogicError('User ID unexpectedly false')
const { streamId } = args
const logger = ctx.log.child({
streamId,
projectId: streamId
})
return await withOperationLogging(
async () => await requestStreamAccess(userId, streamId),
{
logger,
operationName: 'requestStreamAccess',
operationDescription: 'Request for stream access'
}
)
}
},
ProjectMutations: {
accessRequestMutations: () => ({})
},
ProjectAccessRequestMutations: {
async create(_parent, args, ctx) {
const { userId } = ctx
const { projectId } = args
const logger = ctx.log.child({
projectId,
streamId: projectId // for legacy compatibility
})
return await withOperationLogging(
async () => await requestProjectAccess(userId!, projectId),
{
logger,
operationName: 'CreateProjectAccessRequest',
operationDescription: 'Create a request for project access'
}
)
},
async use(_parent, args, ctx) {
const { userId, resourceAccessRules } = ctx
const { requestId, accept, role } = args
const logger = ctx.log
const usedReq = await withOperationLogging(
async () =>
await processPendingProjectRequest(
userId!,
requestId,
accept,
mapStreamRoleToValue(role),
resourceAccessRules
),
{
logger,
operationName: 'ProcessProjectAccessRequest',
operationDescription: 'Use a request for project access'
}
)
const project = await ctx.loaders.streams.getStream.load(usedReq.resourceId)
if (!project) {
throw new LogicError('Unexpectedly unable to find request project')
}
return project
}
},
Query: {
async streamAccessRequest(_, args, ctx) {
const { streamId } = args
const { userId } = ctx
if (!userId) throw new LogicError('User ID unexpectedly false')
return await getUserStreamAccessRequest(userId, streamId)
}
},
User: {
async projectAccessRequest(parent, args) {
const { id: userId } = parent
const { projectId } = args
return await getUserProjectAccessRequest(userId, projectId)
}
},
Stream: {
async pendingAccessRequests(parent) {
const { id } = parent
return await getPendingStreamRequests(id)
}
},
Project: {
async pendingAccessRequests(parent) {
const { id } = parent
return await getPendingProjectRequests(id)
}
},
StreamAccessRequest: {
async requester(parent, _args, ctx) {
const { requesterId } = parent
const user = await ctx.loaders.users.getUser.load(requesterId)
if (!user) {
throw new LogicError('Unable to find requester')
}
return user
},
async stream(parent, _args, ctx) {
const { streamId } = parent
const stream = await ctx.loaders.streams.getStream.load(streamId)
if (!stream) {
throw new LogicError('Unable to find request stream')
}
await validateStreamAccess(
ctx.userId,
stream.id,
Roles.Stream.Reviewer,
ctx.resourceAccessRules
)
return stream
}
},
ProjectAccessRequest: {
async requester(parent, _args, ctx) {
const { requesterId } = parent
const user = await ctx.loaders.users.getUser.load(requesterId)
if (!user) {
throw new LogicError('Unable to find requester')
}
return user
},
async projectId(parent) {
const { resourceId, resourceType } = parent
if (resourceType !== AccessRequestType.Stream) {
throw new LogicError('Unexpectedly returned invalid resource type')
}
return resourceId
},
async project(parent, _args, ctx) {
const { resourceId, resourceType } = parent
if (resourceType !== AccessRequestType.Stream) {
throw new LogicError('Unexpectedly returned invalid resource type')
}
const project = await ctx.loaders.streams.getStream.load(resourceId)
if (!project) {
throw new LogicError('Unable to find request project')
}
await validateStreamAccess(
ctx.userId,
project.id,
Roles.Stream.Reviewer,
ctx.resourceAccessRules
)
return project
}
}
}
export default resolvers