Merge branch 'main' into iain/ratelimiter-should-respect-configuration

This commit is contained in:
Iain Sproat
2025-05-19 13:37:26 +01:00
637 changed files with 21869 additions and 25058 deletions
@@ -15,6 +15,13 @@ export default {
})
return Authz.toGraphqlResult(canCreateProject)
},
canInvite: async (parent, _args, ctx) => {
const canInvite = await ctx.authPolicies.workspace.canInvite({
workspaceId: parent.workspaceId,
userId: ctx.userId
})
return Authz.toGraphqlResult(canInvite)
},
canMoveProjectToWorkspace: async (parent, args, ctx) => {
const canMoveProjectToWorkspace =
await ctx.authPolicies.project.canMoveToWorkspace({
@@ -1,8 +1,10 @@
import { db } from '@/db/knex'
import { StreamNotFoundError } from '@/modules/core/errors/stream'
import { Resolvers } from '@/modules/core/graph/generated/graphql'
import { getFeatureFlags } from '@/modules/shared/helpers/envHelper'
import { getPaginatedItemsFactory } from '@/modules/shared/services/paginatedItems'
import { WorkspaceTeamMember } from '@/modules/workspaces/domain/types'
import { WorkspaceNotFoundError } from '@/modules/workspaces/errors/workspace'
import { intersectProjectCollaboratorsAndWorkspaceCollaboratorsFactory } from '@/modules/workspaces/repositories/projects'
import {
countInvitableCollaboratorsByProjectIdFactory,
@@ -68,6 +70,28 @@ export default FF_WORKSPACES_MODULE_ENABLED
addedToWorkspaceTotalCount: async (parent) => {
return parent.length
}
},
PendingStreamCollaborator: {
workspaceSlug: async (parent, _args, ctx) => {
const project = await ctx.loaders.streams.getStream.load(parent.streamId)
if (!project) {
throw new StreamNotFoundError(null, {
info: { projectId: parent.streamId }
})
}
if (!project.workspaceId) {
return null
}
const workspace = await ctx.loaders.workspaces?.getWorkspace.load(
project.workspaceId
)
if (!workspace) {
throw new WorkspaceNotFoundError(null, {
info: { workspaceId: project.workspaceId }
})
}
return workspace.slug
}
}
} as Resolvers)
: {}
@@ -1,7 +1,10 @@
import { db } from '@/db/knex'
import { Resolvers } from '@/modules/core/graph/generated/graphql'
import { getServerInfoFactory } from '@/modules/core/repositories/server'
import { findEmailsByUserIdFactory } from '@/modules/core/repositories/userEmails'
import {
findEmailsByUserIdFactory,
findVerifiedEmailsByUserIdFactory
} from '@/modules/core/repositories/userEmails'
import { getUserFactory } from '@/modules/core/repositories/users'
import { renderEmail } from '@/modules/emails/services/emailRendering'
import { sendEmail } from '@/modules/emails/services/sending'
@@ -27,8 +30,11 @@ import {
} from '@/modules/workspaces/repositories/workspaceJoinRequests'
import {
getWorkspaceFactory,
getWorkspaceRolesFactory,
getWorkspaceWithDomainsFactory,
upsertWorkspaceRoleFactory
} from '@/modules/workspaces/repositories/workspaces'
import { addOrUpdateWorkspaceRoleFactory } from '@/modules/workspaces/services/management'
import { sendWorkspaceJoinRequestApprovedEmailFactory } from '@/modules/workspaces/services/workspaceJoinRequestEmails/approved'
import { sendWorkspaceJoinRequestDeniedEmailFactory } from '@/modules/workspaces/services/workspaceJoinRequestEmails/denied'
import {
@@ -160,12 +166,20 @@ export default FF_WORKSPACES_MODULE_ENABLED
getWorkspaceJoinRequest: getWorkspaceJoinRequestFactory({
db
}),
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db }),
emit,
ensureValidWorkspaceRoleSeat: ensureValidWorkspaceRoleSeatFactory({
createWorkspaceSeat: createWorkspaceSeatFactory({ db }),
getWorkspaceUserSeat: getWorkspaceUserSeatFactory({ db }),
eventEmit: emit
addOrUpdateWorkspaceRole: addOrUpdateWorkspaceRoleFactory({
getWorkspaceWithDomains: getWorkspaceWithDomainsFactory({ db }),
findVerifiedEmailsByUserId: findVerifiedEmailsByUserIdFactory({
db
}),
getWorkspaceRoles: getWorkspaceRolesFactory({ db }),
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db }),
emitWorkspaceEvent: emit,
ensureValidWorkspaceRoleSeat: ensureValidWorkspaceRoleSeatFactory({
createWorkspaceSeat: createWorkspaceSeatFactory({ db }),
getWorkspaceUserSeat: getWorkspaceUserSeatFactory({ db }),
eventEmit: emit
})
})
})
}
@@ -49,7 +49,6 @@ import { getEventBus } from '@/modules/shared/services/eventBus'
import { WorkspaceInviteResourceType } from '@/modules/workspacesCore/domain/constants'
import {
WorkspaceInvalidRoleError,
WorkspaceJoinNotAllowedError,
WorkspaceNotFoundError,
WorkspacePaidPlanActiveError,
WorkspacesNotAuthorizedError
@@ -63,7 +62,6 @@ import {
getWorkspaceRolesForUserFactory,
upsertWorkspaceFactory,
upsertWorkspaceRoleFactory,
workspaceInviteValidityFilter,
getWorkspaceCollaboratorsTotalCountFactory,
deleteWorkspaceDomainFactory as repoDeleteWorkspaceDomainFactory,
storeWorkspaceDomainFactory,
@@ -97,7 +95,7 @@ import {
deleteWorkspaceRoleFactory,
generateValidSlugFactory,
updateWorkspaceFactory,
updateWorkspaceRoleFactory,
addOrUpdateWorkspaceRoleFactory,
validateSlugFactory
} from '@/modules/workspaces/services/management'
import {
@@ -126,7 +124,6 @@ import {
ensureNoPrimaryEmailForUserFactory,
findEmailFactory
} from '@/modules/core/repositories/userEmails'
import { joinWorkspaceFactory } from '@/modules/workspaces/services/join'
import { validateAndCreateUserEmailFactory } from '@/modules/core/services/userEmails'
import { requestNewEmailVerificationFactory } from '@/modules/emails/services/verification/request'
import {
@@ -151,7 +148,6 @@ import { updateStreamRoleAndNotifyFactory } from '@/modules/core/services/stream
import { getUserFactory, getUsersFactory } from '@/modules/core/repositories/users'
import { getServerInfoFactory } from '@/modules/core/repositories/server'
import { asOperation, commandFactory } from '@/modules/shared/command'
import { withTransaction } from '@/modules/shared/helpers/dbHelper'
import { throwIfRateLimitedFactory } from '@/modules/core/utils/ratelimiter'
import { getRegionDb } from '@/modules/multiregion/utils/dbSelector'
import {
@@ -217,6 +213,11 @@ import {
throwIfAuthNotOk
} from '@/modules/shared/helpers/errorHelper'
import { withOperationLogging } from '@/observability/domain/businessLogging'
import {
processFinalizedProjectInviteFactory,
validateProjectInviteBeforeFinalizationFactory
} from '@/modules/serverinvites/services/coreFinalization'
import { WorkspaceInvitesLimit } from '@/modules/workspaces/domain/constants'
const eventBus = getEventBus()
const getServerInfo = getServerInfoFactory({ db })
@@ -244,16 +245,103 @@ const buildCollectAndValidateResourceTargets = () =>
getWorkspaceRoleAndSeat: getWorkspaceRoleAndSeatFactory({ db }),
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db }),
getWorkspaceRoleToDefaultProjectRoleMapping:
getWorkspaceRoleToDefaultProjectRoleMappingFactory({
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db })
}),
getWorkspaceRoleToDefaultProjectRoleMappingFactory(),
getWorkspaceSeatTypeToProjectRoleMapping:
getWorkspaceSeatTypeToProjectRoleMappingFactory({
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db })
})
getWorkspaceSeatTypeToProjectRoleMappingFactory()
})
})
const buildFinalizeWorkspaceInvite = () =>
finalizeResourceInviteFactory({
findInvite: findInviteFactory({
db
}),
deleteInvitesByTarget: deleteInvitesByTargetFactory({ db }),
insertInviteAndDeleteOld: insertInviteAndDeleteOldFactory({ db }),
emitEvent: ({ eventName, payload }) =>
getEventBus().emit({
eventName,
payload
}),
validateInvite: validateWorkspaceInviteBeforeFinalizationFactory({
getWorkspace: getWorkspaceFactory({ db }),
validateProjectInviteBeforeFinalization:
validateProjectInviteBeforeFinalizationFactory({
getProject: getStream
})
}),
processInvite: processFinalizedWorkspaceInviteFactory({
getWorkspace: getWorkspaceFactory({ db }),
updateWorkspaceRole: addOrUpdateWorkspaceRoleFactory({
getWorkspaceWithDomains: getWorkspaceWithDomainsFactory({ db }),
findVerifiedEmailsByUserId: findVerifiedEmailsByUserIdFactory({ db }),
getWorkspaceRoles: getWorkspaceRolesFactory({ db }),
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db }),
emitWorkspaceEvent: getEventBus().emit,
ensureValidWorkspaceRoleSeat: ensureValidWorkspaceRoleSeatFactory({
createWorkspaceSeat: createWorkspaceSeatFactory({ db }),
getWorkspaceUserSeat: getWorkspaceUserSeatFactory({ db }),
eventEmit: getEventBus().emit
})
}),
processFinalizedProjectInvite: processFinalizedProjectInviteFactory({
getProject: getStream,
addProjectRole: addOrUpdateStreamCollaborator
})
}),
findEmail: findEmailFactory({ db }),
validateAndCreateUserEmail: validateAndCreateUserEmailFactory({
createUserEmail: createUserEmailFactory({ db }),
ensureNoPrimaryEmailForUser: ensureNoPrimaryEmailForUserFactory({ db }),
findEmail: findEmailFactory({ db }),
updateEmailInvites: finalizeInvitedServerRegistrationFactory({
deleteServerOnlyInvites: deleteServerOnlyInvitesFactory({ db }),
updateAllInviteTargets: updateAllInviteTargetsFactory({ db })
}),
requestNewEmailVerification
}),
collectAndValidateResourceTargets: buildCollectAndValidateResourceTargets(),
getUser,
getServerInfo
})
const validateStreamAccess = validateStreamAccessFactory({ authorizeResolver })
const addOrUpdateStreamCollaborator = addOrUpdateStreamCollaboratorFactory({
validateStreamAccess,
getUser,
grantStreamPermissions: grantStreamPermissionsFactory({ db }),
emitEvent: getEventBus().emit
})
const buildFinalizeProjectInvite = () =>
finalizeResourceInviteFactory({
findInvite: findInviteFactory({ db }),
validateInvite: validateProjectInviteBeforeFinalizationFactory({
getProject: getStream
}),
processInvite: processFinalizedProjectInviteFactory({
getProject: getStream,
addProjectRole: addOrUpdateStreamCollaborator
}),
deleteInvitesByTarget: deleteInvitesByTargetFactory({ db }),
insertInviteAndDeleteOld: insertInviteAndDeleteOldFactory({ db }),
emitEvent: (...args) => getEventBus().emit(...args),
findEmail: findEmailFactory({ db }),
validateAndCreateUserEmail: validateAndCreateUserEmailFactory({
createUserEmail: createUserEmailFactory({ db }),
ensureNoPrimaryEmailForUser: ensureNoPrimaryEmailForUserFactory({ db }),
findEmail: findEmailFactory({ db }),
updateEmailInvites: finalizeInvitedServerRegistrationFactory({
deleteServerOnlyInvites: deleteServerOnlyInvitesFactory({ db }),
updateAllInviteTargets: updateAllInviteTargetsFactory({ db })
}),
requestNewEmailVerification
}),
collectAndValidateResourceTargets: buildCollectAndValidateResourceTargets(),
getUser,
getServerInfo
})
const buildCreateAndSendServerOrProjectInvite = () =>
createAndSendInviteFactory({
findUserByTarget: findUserByTargetFactory({ db }),
@@ -268,7 +356,8 @@ const buildCreateAndSendServerOrProjectInvite = () =>
payload
}),
getUser,
getServerInfo
getServerInfo,
finalizeInvite: buildFinalizeProjectInvite()
})
const buildCreateAndSendWorkspaceInvite = () =>
@@ -286,9 +375,9 @@ const buildCreateAndSendWorkspaceInvite = () =>
payload
}),
getUser,
getServerInfo
getServerInfo,
finalizeInvite: buildFinalizeWorkspaceInvite()
})
const validateStreamAccess = validateStreamAccessFactory({ authorizeResolver })
const isStreamCollaborator = isStreamCollaboratorFactory({
getStream
})
@@ -300,12 +389,7 @@ const removeStreamCollaborator = removeStreamCollaboratorFactory({
})
const updateStreamRoleAndNotify = updateStreamRoleAndNotifyFactory({
isStreamCollaborator,
addOrUpdateStreamCollaborator: addOrUpdateStreamCollaboratorFactory({
validateStreamAccess,
getUser,
grantStreamPermissions: grantStreamPermissionsFactory({ db }),
emitEvent: getEventBus().emit
}),
addOrUpdateStreamCollaborator,
removeStreamCollaborator
})
@@ -363,8 +447,7 @@ export = FF_WORKSPACES_MODULE_ENABLED
workspaceInvite: async (_parent, args, ctx) => {
const getPendingInvite = getUserPendingWorkspaceInviteFactory({
findInvite: findInviteFactory({
db,
filterQuery: workspaceInviteValidityFilter
db
}),
getUser,
getWorkspaceBySlug: getWorkspaceBySlugFactory({ db })
@@ -397,9 +480,9 @@ export = FF_WORKSPACES_MODULE_ENABLED
const { projectId } = args
const inviteCount = args.inputs.length
if (inviteCount > 10 && ctx.role !== Roles.Server.Admin) {
if (inviteCount > WorkspaceInvitesLimit && ctx.role !== Roles.Server.Admin) {
throw new InviteCreateValidationError(
'Maximum 10 invites can be sent at once by non admins'
`Maximum ${WorkspaceInvitesLimit} invites can be sent at once by non admins`
)
}
@@ -518,12 +601,20 @@ export = FF_WORKSPACES_MODULE_ENABLED
getWorkspaceBySlug: getWorkspaceBySlugFactory({ db })
}),
upsertWorkspace: upsertWorkspaceFactory({ db }),
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db }),
emitWorkspaceEvent: emit,
ensureValidWorkspaceRoleSeat: ensureValidWorkspaceRoleSeatFactory({
createWorkspaceSeat: createWorkspaceSeatFactory({ db }),
getWorkspaceUserSeat: getWorkspaceUserSeatFactory({ db }),
eventEmit: emit
addOrUpdateWorkspaceRole: addOrUpdateWorkspaceRoleFactory({
getWorkspaceWithDomains: getWorkspaceWithDomainsFactory({ db }),
findVerifiedEmailsByUserId: findVerifiedEmailsByUserIdFactory({
db
}),
getWorkspaceRoles: getWorkspaceRolesFactory({ db }),
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db }),
emitWorkspaceEvent: emit,
ensureValidWorkspaceRoleSeat: ensureValidWorkspaceRoleSeatFactory({
createWorkspaceSeat: createWorkspaceSeatFactory({ db }),
getWorkspaceUserSeat: getWorkspaceUserSeatFactory({ db }),
eventEmit: emit
})
})
})
@@ -606,17 +697,12 @@ export = FF_WORKSPACES_MODULE_ENABLED
case 'teamUnlimited':
case 'pro':
case 'proUnlimited':
case 'starter':
case 'plus':
case 'business':
switch (workspacePlan.status) {
case 'cancelationScheduled':
case 'valid':
case 'paymentFailed':
throw new WorkspacePaidPlanActiveError()
case 'canceled':
case 'trial':
case 'expired':
break
default:
throwUncoveredError(workspacePlan)
@@ -624,9 +710,6 @@ export = FF_WORKSPACES_MODULE_ENABLED
case 'free':
case 'unlimited':
case 'academia':
case 'starterInvoiced':
case 'plusInvoiced':
case 'businessInvoiced':
case 'proUnlimitedInvoiced':
case 'teamUnlimitedInvoiced':
break
@@ -729,37 +812,35 @@ export = FF_WORKSPACES_MODULE_ENABLED
})
if (!role) {
// this is currently not working with the command factory
// TODO: include the onWorkspaceRoleDeletedFactory listener service
await withOperationLogging(
async () =>
await withTransaction(
async ({ db: trx }) => {
const deleteWorkspaceRole = deleteWorkspaceRoleFactory({
deleteWorkspaceRole: repoDeleteWorkspaceRoleFactory({ db: trx }),
getWorkspaceRoles: getWorkspaceRolesFactory({ db: trx }),
emitWorkspaceEvent: getEventBus().emit
})
await asOperation(
async ({ db, emit }) => {
const deleteWorkspaceRole = deleteWorkspaceRoleFactory({
deleteWorkspaceRole: repoDeleteWorkspaceRoleFactory({ db }),
getWorkspaceRoles: getWorkspaceRolesFactory({ db }),
emitWorkspaceEvent: emit
})
return await deleteWorkspaceRole({ workspaceId, userId })
},
{ db }
),
return await deleteWorkspaceRole({
workspaceId,
userId,
deletedByUserId: context.userId!
})
},
{
logger,
operationName: 'deleteWorkspaceRole',
operationDescription: 'Delete workspace role'
name: 'deleteWorkspaceRole',
description: 'Delete workspace role',
transaction: true
}
)
} else {
if (!isWorkspaceRole(role)) {
throw new WorkspaceInvalidRoleError()
}
const updateWorkspaceRole = commandFactory({
db,
eventBus,
operationFactory: ({ trx, emit }) =>
updateWorkspaceRoleFactory({
await asOperation(
async ({ db: trx, emit }) => {
const updateWorkspaceRole = addOrUpdateWorkspaceRoleFactory({
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db: trx }),
getWorkspaceWithDomains: getWorkspaceWithDomainsFactory({ db: trx }),
findVerifiedEmailsByUserId: findVerifiedEmailsByUserIdFactory({
@@ -773,23 +854,25 @@ export = FF_WORKSPACES_MODULE_ENABLED
eventEmit: emit
})
})
})
await withOperationLogging(
async () =>
await updateWorkspaceRole({
return await updateWorkspaceRole({
userId,
workspaceId,
role,
updatedByUserId: context.userId!
}),
})
},
{
logger,
operationName: 'updateWorkspaceRole',
operationDescription: 'Update workspace role'
name: 'updateWorkspaceRole',
description: 'Update workspace role',
transaction: true
}
)
}
context.clearCache()
return await getWorkspaceFactory({ db })({
workspaceId: args.input.workspaceId,
userId: context.userId
@@ -904,71 +987,36 @@ export = FF_WORKSPACES_MODULE_ENABLED
return true
},
async join(_parent, args, context) {
if (!context.userId) throw new WorkspaceJoinNotAllowedError()
const workspaceId = args.input.workspaceId
const logger = context.log.child({
workspaceId
})
const joinWorkspace = joinWorkspaceFactory({
getUserEmails: findEmailsByUserIdFactory({ db }),
getWorkspaceWithDomains: getWorkspaceWithDomainsFactory({ db }),
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db }),
emitWorkspaceEvent: getEventBus().emit,
ensureValidWorkspaceRoleSeat: ensureValidWorkspaceRoleSeatFactory({
createWorkspaceSeat: createWorkspaceSeatFactory({ db }),
getWorkspaceUserSeat: getWorkspaceUserSeatFactory({ db }),
eventEmit: getEventBus().emit
})
})
await withOperationLogging(
async () => await joinWorkspace({ userId: context.userId!, workspaceId }),
{
logger,
operationName: 'joinWorkspace',
operationDescription: 'Join workspace'
}
)
return await getWorkspaceFactory({ db })({
workspaceId,
userId: context.userId
})
},
leave: async (_parent, args, context) => {
const workspaceId = args.id
const logger = context.log.child({
workspaceId
})
// this is currently not working with the command factory
// TODO: include the onWorkspaceRoleDeletedFactory listener service
await withOperationLogging(
async () =>
await withTransaction(
async ({ db: trx }) => {
const deleteWorkspaceRole = deleteWorkspaceRoleFactory({
deleteWorkspaceRole: repoDeleteWorkspaceRoleFactory({ db: trx }),
getWorkspaceRoles: getWorkspaceRolesFactory({ db: trx }),
emitWorkspaceEvent: getEventBus().emit
})
await asOperation(
async ({ db, emit }) => {
const deleteWorkspaceRole = deleteWorkspaceRoleFactory({
deleteWorkspaceRole: repoDeleteWorkspaceRoleFactory({ db }),
getWorkspaceRoles: getWorkspaceRolesFactory({ db }),
emitWorkspaceEvent: emit
})
return await deleteWorkspaceRole({
workspaceId,
userId: context.userId!
})
},
{ db }
),
return await deleteWorkspaceRole({
workspaceId,
userId: context.userId!,
deletedByUserId: context.userId!
})
},
{
logger,
operationName: 'leaveWorkspace',
operationDescription: 'Leave workspace'
name: 'leaveWorkspace',
description: 'Leave workspace',
transaction: true
}
)
context.clearCache()
return true
},
updateCreationState: async (_parent, args, context) => {
@@ -1099,8 +1147,7 @@ export = FF_WORKSPACES_MODULE_ENABLED
}),
findUserByTarget: findUserByTargetFactory({ db }),
findInvite: findInviteFactory({
db,
filterQuery: workspaceInviteValidityFilter
db
}),
markInviteUpdated: markInviteUpdatedFactory({ db }),
getUser,
@@ -1170,9 +1217,9 @@ export = FF_WORKSPACES_MODULE_ENABLED
const { workspaceId } = args
const inviteCount = args.input.length
if (inviteCount > 10 && ctx.role !== Roles.Server.Admin) {
if (inviteCount > WorkspaceInvitesLimit && ctx.role !== Roles.Server.Admin) {
throw new InviteCreateValidationError(
'Maximum 10 invites can be sent at once by non admins'
`Maximum ${WorkspaceInvitesLimit} invites can be sent at once by non admins`
)
}
@@ -1229,52 +1276,7 @@ export = FF_WORKSPACES_MODULE_ENABLED
use: async (_parent, args, ctx) => {
const logger = ctx.log
const finalizeInvite = finalizeResourceInviteFactory({
findInvite: findInviteFactory({
db,
filterQuery: workspaceInviteValidityFilter
}),
deleteInvitesByTarget: deleteInvitesByTargetFactory({ db }),
insertInviteAndDeleteOld: insertInviteAndDeleteOldFactory({ db }),
emitEvent: ({ eventName, payload }) =>
getEventBus().emit({
eventName,
payload
}),
validateInvite: validateWorkspaceInviteBeforeFinalizationFactory({
getWorkspace: getWorkspaceFactory({ db })
}),
processInvite: processFinalizedWorkspaceInviteFactory({
getWorkspace: getWorkspaceFactory({ db }),
updateWorkspaceRole: updateWorkspaceRoleFactory({
getWorkspaceWithDomains: getWorkspaceWithDomainsFactory({ db }),
findVerifiedEmailsByUserId: findVerifiedEmailsByUserIdFactory({ db }),
getWorkspaceRoles: getWorkspaceRolesFactory({ db }),
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db }),
emitWorkspaceEvent: getEventBus().emit,
ensureValidWorkspaceRoleSeat: ensureValidWorkspaceRoleSeatFactory({
createWorkspaceSeat: createWorkspaceSeatFactory({ db }),
getWorkspaceUserSeat: getWorkspaceUserSeatFactory({ db }),
eventEmit: getEventBus().emit
})
})
}),
findEmail: findEmailFactory({ db }),
validateAndCreateUserEmail: validateAndCreateUserEmailFactory({
createUserEmail: createUserEmailFactory({ db }),
ensureNoPrimaryEmailForUser: ensureNoPrimaryEmailForUserFactory({ db }),
findEmail: findEmailFactory({ db }),
updateEmailInvites: finalizeInvitedServerRegistrationFactory({
deleteServerOnlyInvites: deleteServerOnlyInvitesFactory({ db }),
updateAllInviteTargets: updateAllInviteTargetsFactory({ db })
}),
requestNewEmailVerification
}),
collectAndValidateResourceTargets: buildCollectAndValidateResourceTargets(),
getUser,
getServerInfo
})
const finalizeInvite = buildFinalizeWorkspaceInvite()
await withOperationLogging(
async () =>
await finalizeInvite({
@@ -1282,7 +1284,6 @@ export = FF_WORKSPACES_MODULE_ENABLED
finalizerResourceAccessLimits: ctx.resourceAccessRules,
token: args.input.token,
accept: args.input.accept,
resourceType: WorkspaceInviteResourceType,
allowAttachingNewEmail: args.input.addNewEmail ?? undefined
}),
{
@@ -1318,12 +1319,15 @@ export = FF_WORKSPACES_MODULE_ENABLED
const cancelInvite = cancelResourceInviteFactory({
findInvite: findInviteFactory({
db,
filterQuery: workspaceInviteValidityFilter
db
}),
deleteInvite: deleteInviteFactory({ db }),
validateResourceAccess: validateWorkspaceInviteBeforeFinalizationFactory({
getWorkspace: getWorkspaceFactory({ db })
getWorkspace: getWorkspaceFactory({ db }),
validateProjectInviteBeforeFinalization:
validateProjectInviteBeforeFinalizationFactory({
getProject: getStream
})
}),
emitEvent: getEventBus().emit
})
@@ -1331,10 +1335,8 @@ export = FF_WORKSPACES_MODULE_ENABLED
await withOperationLogging(
async () =>
await cancelInvite({
resourceId: args.workspaceId,
inviteId,
cancelerId: ctx.userId!,
resourceType: WorkspaceInviteResourceType,
cancelerResourceAccessLimits: ctx.resourceAccessRules
}),
{
@@ -1392,7 +1394,7 @@ export = FF_WORKSPACES_MODULE_ENABLED
projectId,
streamId: projectId //legacy
})
return await withOperationLogging(
const ret = await withOperationLogging(
async () =>
await updateStreamRoleAndNotify(
args.input,
@@ -1405,6 +1407,10 @@ export = FF_WORKSPACES_MODULE_ENABLED
operationDescription: 'Update workspace project role'
}
)
context.clearCache()
return ret
},
moveToWorkspace: async (_parent, args, context) => {
const { projectId, workspaceId } = args
@@ -1436,7 +1442,7 @@ export = FF_WORKSPACES_MODULE_ENABLED
updateProjectRole: updateStreamRoleAndNotify,
getProjectCollaborators: getStreamCollaboratorsFactory({ db }),
getWorkspaceRolesAndSeats: getWorkspaceRolesAndSeatsFactory({ db }),
updateWorkspaceRole: updateWorkspaceRoleFactory({
updateWorkspaceRole: addOrUpdateWorkspaceRoleFactory({
getWorkspaceRoles: getWorkspaceRolesFactory({ db }),
getWorkspaceWithDomains: getWorkspaceWithDomainsFactory({ db }),
findVerifiedEmailsByUserId: findVerifiedEmailsByUserIdFactory({
@@ -1562,8 +1568,7 @@ export = FF_WORKSPACES_MODULE_ENABLED
invitedTeam: async (parent, args) => {
const getPendingTeam = getPendingWorkspaceCollaboratorsFactory({
queryAllResourceInvites: queryAllResourceInvitesFactory({
db,
filterQuery: workspaceInviteValidityFilter
db
}),
getInvitationTargetUsers: getInvitationTargetUsersFactory({ getUsers })
})
@@ -1693,6 +1698,11 @@ export = FF_WORKSPACES_MODULE_ENABLED
}))
}
},
LimitedWorkspaceCollaborator: {
user: async (parent) => {
return parent
}
},
ProjectRole: {
project: async (parent, _args, ctx) => {
return await ctx.loaders.streams.getStream.load(parent.projectId)
@@ -1817,8 +1827,7 @@ export = FF_WORKSPACES_MODULE_ENABLED
const getInvites = getUserPendingWorkspaceInvitesFactory({
getUser,
getUserResourceInvites: queryAllUserResourceInvitesFactory({
db,
filterQuery: workspaceInviteValidityFilter
db
})
})