fix(server): project role updates after workspace role/seat changes (#4599)
* fix(workspaces): workspace role sync * role changes fixed + validated * seat changes validated * fix tests --------- Co-authored-by: Charles Driesler <chuck@speckle.systems>
This commit is contained in:
committed by
GitHub
parent
02be5652d3
commit
cf833a7719
@@ -118,6 +118,7 @@ generates:
|
||||
documents:
|
||||
- 'test/graphql/*.{js,ts}'
|
||||
- 'modules/**/tests/helpers/graphql.ts'
|
||||
- 'modules/**/tests/helpers/*Graphql.ts'
|
||||
config:
|
||||
enumsAsConst: true
|
||||
scalars:
|
||||
|
||||
@@ -1144,7 +1144,7 @@ export const grantStreamPermissionsFactory =
|
||||
.count()
|
||||
if (parseInt(countObj.count as string) === 1)
|
||||
throw new StreamAccessUpdateError(
|
||||
'Could not revoke permissions for last admin',
|
||||
'A project needs at least one project owner',
|
||||
{
|
||||
info: { streamId, userId }
|
||||
}
|
||||
@@ -1222,7 +1222,7 @@ export const revokeStreamPermissionsFactory =
|
||||
.count()
|
||||
if (parseInt(countObj.count as string) === 1)
|
||||
throw new StreamAccessUpdateError(
|
||||
'Could not revoke permissions for last admin',
|
||||
'A project needs at least one project owner',
|
||||
{
|
||||
info: { streamId, userId }
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ export function isEmailEnabled() {
|
||||
}
|
||||
|
||||
export function postgresMaxConnections() {
|
||||
return getIntFromEnv('POSTGRES_MAX_CONNECTIONS_SERVER', '4')
|
||||
return getIntFromEnv('POSTGRES_MAX_CONNECTIONS_SERVER', '8')
|
||||
}
|
||||
|
||||
export function postgresConnectionAcquireTimeoutMillis() {
|
||||
|
||||
@@ -124,6 +124,10 @@ export type GetWorkspaceCollaboratorsArgs = {
|
||||
*/
|
||||
search?: string
|
||||
seatType?: WorkspaceSeatType
|
||||
/**
|
||||
* Optionally filter by user id
|
||||
*/
|
||||
excludeUserIds?: string[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
deleteProjectRoleFactory,
|
||||
getStreamFactory,
|
||||
getStreamsCollaboratorCountsFactory,
|
||||
grantStreamPermissionsFactory,
|
||||
@@ -11,6 +10,7 @@ import {
|
||||
CountWorkspaceRoleWithOptionalProjectRole,
|
||||
GetDefaultRegion,
|
||||
GetWorkspace,
|
||||
GetWorkspaceCollaborators,
|
||||
GetWorkspaceRoleForUser,
|
||||
GetWorkspaceRoleToDefaultProjectRoleMapping,
|
||||
GetWorkspaceSeatTypeToProjectRoleMapping,
|
||||
@@ -29,15 +29,18 @@ import { logger, moduleLogger } from '@/observability/logging'
|
||||
import { updateWorkspaceRoleFactory } from '@/modules/workspaces/services/management'
|
||||
import { EventPayload, getEventBus } from '@/modules/shared/services/eventBus'
|
||||
import { WorkspaceInviteResourceType } from '@/modules/workspacesCore/domain/constants'
|
||||
import { Roles, throwUncoveredError, WorkspaceRoles } from '@speckle/shared'
|
||||
import {
|
||||
DeleteProjectRole,
|
||||
UpsertProjectRole
|
||||
} from '@/modules/core/domain/projects/operations'
|
||||
Roles,
|
||||
StreamRoles,
|
||||
throwUncoveredError,
|
||||
WorkspaceRoles
|
||||
} from '@speckle/shared'
|
||||
import { UpsertProjectRole } from '@/modules/core/domain/projects/operations'
|
||||
import { WorkspaceEvents } from '@/modules/workspacesCore/domain/events'
|
||||
import { Knex } from 'knex'
|
||||
import {
|
||||
countWorkspaceRoleWithOptionalProjectRoleFactory,
|
||||
getWorkspaceCollaboratorsFactory,
|
||||
getWorkspaceFactory,
|
||||
getWorkspaceRoleForUserFactory,
|
||||
getWorkspaceRolesFactory,
|
||||
@@ -86,7 +89,7 @@ import {
|
||||
GetWorkspaceWithPlan
|
||||
} from '@/modules/gatekeeper/domain/billing'
|
||||
import { getWorkspacePlanProductId } from '@/modules/gatekeeper/stripe'
|
||||
import { Workspace } from '@/modules/workspacesCore/domain/types'
|
||||
import { Workspace, WorkspaceSeatType } from '@/modules/workspacesCore/domain/types'
|
||||
import { FindEmailsByUserId } from '@/modules/core/domain/userEmails/operations'
|
||||
import { getDefaultRegionFactory } from '@/modules/workspaces/repositories/regions'
|
||||
import {
|
||||
@@ -103,7 +106,10 @@ import {
|
||||
getWorkspaceRolesAndSeatsFactory,
|
||||
getWorkspaceUserSeatFactory
|
||||
} from '@/modules/gatekeeper/repositories/workspaceSeat'
|
||||
import { DeleteWorkspaceSeat } from '@/modules/gatekeeper/domain/operations'
|
||||
import {
|
||||
DeleteWorkspaceSeat,
|
||||
GetWorkspaceUserSeat
|
||||
} from '@/modules/gatekeeper/domain/operations'
|
||||
import {
|
||||
isStreamCollaboratorFactory,
|
||||
setStreamCollaboratorFactory,
|
||||
@@ -202,9 +208,9 @@ export const onInviteFinalizedFactory =
|
||||
role: workspaceRole,
|
||||
userId: targetUserId,
|
||||
workspaceId: project.workspaceId,
|
||||
skipProjectRoleUpdatesFor: [project.id],
|
||||
preventRoleDowngrade: true,
|
||||
updatedByUserId: invite.inviterId
|
||||
updatedByUserId: invite.inviterId,
|
||||
skipProjectRoleUpdatesFor: [project.id]
|
||||
})
|
||||
|
||||
// Automatically promote user to project owner if workspace admin
|
||||
@@ -256,29 +262,73 @@ export const onWorkspaceAuthorizedFactory =
|
||||
}
|
||||
|
||||
export const onWorkspaceRoleDeletedFactory =
|
||||
({
|
||||
queryAllWorkspaceProjects,
|
||||
deleteProjectRole,
|
||||
deleteWorkspaceSeat
|
||||
}: {
|
||||
(deps: {
|
||||
queryAllWorkspaceProjects: QueryAllWorkspaceProjects
|
||||
deleteProjectRole: DeleteProjectRole
|
||||
deleteWorkspaceSeat: DeleteWorkspaceSeat
|
||||
getStreamsCollaboratorCounts: GetStreamsCollaboratorCounts
|
||||
getWorkspaceCollaborators: GetWorkspaceCollaborators
|
||||
setStreamCollaborator: SetStreamCollaborator
|
||||
}) =>
|
||||
async ({ userId, workspaceId }: { userId: string; workspaceId: string }) => {
|
||||
async ({
|
||||
acl: { userId, workspaceId },
|
||||
updatedByUserId
|
||||
}: {
|
||||
acl: { userId: string; workspaceId: string }
|
||||
updatedByUserId: string
|
||||
}) => {
|
||||
// Resolve a fallback admin
|
||||
const [admin] = await deps.getWorkspaceCollaborators({
|
||||
workspaceId,
|
||||
limit: 1,
|
||||
filter: {
|
||||
roles: [Roles.Workspace.Admin],
|
||||
excludeUserIds: [userId]
|
||||
}
|
||||
})
|
||||
|
||||
// Delete roles for all workspace projects
|
||||
for await (const projectsPage of queryAllWorkspaceProjects({
|
||||
workspaceId
|
||||
for await (const projectsPage of deps.queryAllWorkspaceProjects({
|
||||
workspaceId,
|
||||
userId
|
||||
})) {
|
||||
const projectsOldOwnerCounts = await deps.getStreamsCollaboratorCounts({
|
||||
streamIds: projectsPage.map((p) => p.id),
|
||||
type: Roles.Stream.Owner
|
||||
})
|
||||
await Promise.all(
|
||||
projectsPage.map(({ id: projectId }) =>
|
||||
deleteProjectRole({ projectId, userId })
|
||||
)
|
||||
projectsPage.map(async ({ id: projectId, role: originalProjectRole }) => {
|
||||
// If downgraded from owner & last owner, transfer ownership to a workspace admin
|
||||
const isNoLongerOwner = originalProjectRole === Roles.Stream.Owner
|
||||
const wasLastOwner =
|
||||
projectsOldOwnerCounts[projectId]?.[Roles.Stream.Owner] === 1
|
||||
if (isNoLongerOwner && wasLastOwner) {
|
||||
await deps.setStreamCollaborator(
|
||||
{
|
||||
streamId: projectId,
|
||||
userId: admin.id,
|
||||
role: Roles.Stream.Owner,
|
||||
setByUserId: updatedByUserId
|
||||
},
|
||||
{ trackProjectUpdate: false, skipAuthorization: true }
|
||||
)
|
||||
}
|
||||
|
||||
// Do actual role change for changed user
|
||||
await deps.setStreamCollaborator(
|
||||
{
|
||||
streamId: projectId,
|
||||
userId,
|
||||
role: null,
|
||||
setByUserId: updatedByUserId
|
||||
},
|
||||
{ trackProjectUpdate: false, skipAuthorization: true }
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
// Delete seat
|
||||
await deleteWorkspaceSeat({ userId, workspaceId })
|
||||
await deps.deleteWorkspaceSeat({ userId, workspaceId })
|
||||
}
|
||||
|
||||
export const onWorkspaceSeatUpdatedFactory =
|
||||
@@ -288,6 +338,8 @@ export const onWorkspaceSeatUpdatedFactory =
|
||||
setStreamCollaborator: SetStreamCollaborator
|
||||
getWorkspaceWithPlan: GetWorkspaceWithPlan
|
||||
getWorkspaceRoleForUser: GetWorkspaceRoleForUser
|
||||
getStreamsCollaboratorCounts: GetStreamsCollaboratorCounts
|
||||
getWorkspaceCollaborators: GetWorkspaceCollaborators
|
||||
}) =>
|
||||
async (params: EventPayload<typeof WorkspaceEvents.SeatUpdated>) => {
|
||||
const { seat, updatedByUserId } = params.payload
|
||||
@@ -310,11 +362,25 @@ export const onWorkspaceSeatUpdatedFactory =
|
||||
workspaceId
|
||||
})
|
||||
|
||||
// Resolve a fallback admin
|
||||
const [admin] = await deps.getWorkspaceCollaborators({
|
||||
workspaceId,
|
||||
limit: 1,
|
||||
filter: {
|
||||
roles: [Roles.Workspace.Admin],
|
||||
excludeUserIds: [userId]
|
||||
}
|
||||
})
|
||||
|
||||
// Ensure project roles are valid on seat type switch
|
||||
for await (const projectsPage of deps.queryAllWorkspaceProjects({
|
||||
workspaceId,
|
||||
userId
|
||||
})) {
|
||||
const projectsOldOwnerCounts = await deps.getStreamsCollaboratorCounts({
|
||||
streamIds: projectsPage.map((p) => p.id),
|
||||
type: Roles.Stream.Owner
|
||||
})
|
||||
await Promise.all(
|
||||
projectsPage.map(async ({ id: projectId, role: originalProjectRole }) => {
|
||||
const disallowedProjectRole =
|
||||
@@ -322,12 +388,32 @@ export const onWorkspaceSeatUpdatedFactory =
|
||||
!allowedProjectRoles[seatType].includes(originalProjectRole)
|
||||
if (!disallowedProjectRole) return
|
||||
|
||||
const newRole = defaultProjectRoles[seatType]
|
||||
const nextUserRole = defaultProjectRoles[seatType]
|
||||
|
||||
// If downgraded from owner & last owner, transfer ownership to a workspace admin
|
||||
const isNoLongerOwner =
|
||||
originalProjectRole === Roles.Stream.Owner &&
|
||||
nextUserRole !== Roles.Stream.Owner
|
||||
const wasLastOwner =
|
||||
projectsOldOwnerCounts[projectId]?.[Roles.Stream.Owner] === 1
|
||||
if (isNoLongerOwner && wasLastOwner) {
|
||||
await deps.setStreamCollaborator(
|
||||
{
|
||||
streamId: projectId,
|
||||
userId: admin.id,
|
||||
role: Roles.Stream.Owner,
|
||||
setByUserId: updatedByUserId
|
||||
},
|
||||
{ trackProjectUpdate: false, skipAuthorization: true }
|
||||
)
|
||||
}
|
||||
|
||||
// Do actual role change for changed user
|
||||
await deps.setStreamCollaborator(
|
||||
{
|
||||
streamId: projectId,
|
||||
userId,
|
||||
role: newRole,
|
||||
role: nextUserRole,
|
||||
setByUserId: updatedByUserId
|
||||
},
|
||||
{ trackProjectUpdate: false, skipAuthorization: true }
|
||||
@@ -342,13 +428,15 @@ export const onWorkspaceRoleUpdatedFactory =
|
||||
getWorkspaceRoleToDefaultProjectRoleMapping: GetWorkspaceRoleToDefaultProjectRoleMapping
|
||||
queryAllWorkspaceProjects: QueryAllWorkspaceProjects
|
||||
setStreamCollaborator: SetStreamCollaborator
|
||||
getWorkspaceUserSeat: GetWorkspaceUserSeat
|
||||
getStreamsCollaboratorCounts: GetStreamsCollaboratorCounts
|
||||
getWorkspaceCollaborators: GetWorkspaceCollaborators
|
||||
getWorkspaceWithPlan: GetWorkspaceWithPlan
|
||||
}) =>
|
||||
async ({
|
||||
acl,
|
||||
flags,
|
||||
updatedByUserId
|
||||
updatedByUserId,
|
||||
flags
|
||||
}: {
|
||||
acl: { userId: string; role: WorkspaceRoles; workspaceId: string }
|
||||
flags?: {
|
||||
@@ -357,23 +445,31 @@ export const onWorkspaceRoleUpdatedFactory =
|
||||
updatedByUserId: string
|
||||
}) => {
|
||||
const { userId, role, workspaceId } = acl
|
||||
|
||||
const workspace = await deps.getWorkspaceWithPlan({ workspaceId })
|
||||
if (!workspace) return
|
||||
|
||||
// New plans don't do automatic project role assignment
|
||||
const isNewPlan = workspace.plan && isNewPlanType(workspace.plan.name)
|
||||
if (isNewPlan) {
|
||||
return
|
||||
}
|
||||
|
||||
// Until we kill old plan code, we need to do full project role assignment for them
|
||||
const isOldPlan = !workspace.plan || !isNewPlanType(workspace.plan.name)
|
||||
const { default: defaultProjectRoles } =
|
||||
await deps.getWorkspaceRoleToDefaultProjectRoleMapping({
|
||||
workspaceId
|
||||
})
|
||||
|
||||
const nextUserRole = defaultProjectRoles[role]
|
||||
const seatType = await deps.getWorkspaceUserSeat({ workspaceId, userId })
|
||||
if (!seatType) return
|
||||
|
||||
// Keep user's project roles in sync with their workspace role
|
||||
// Resolve a fallback admin
|
||||
const [admin] = await deps.getWorkspaceCollaborators({
|
||||
workspaceId,
|
||||
limit: 1,
|
||||
filter: {
|
||||
roles: [Roles.Workspace.Admin],
|
||||
excludeUserIds: [userId]
|
||||
}
|
||||
})
|
||||
|
||||
// Enforce project roles based on workspace role and seat type, if project role exists
|
||||
for await (const projectsPage of deps.queryAllWorkspaceProjects({
|
||||
workspaceId,
|
||||
userId
|
||||
@@ -382,26 +478,64 @@ export const onWorkspaceRoleUpdatedFactory =
|
||||
streamIds: projectsPage.map((p) => p.id),
|
||||
type: Roles.Stream.Owner
|
||||
})
|
||||
|
||||
await Promise.all(
|
||||
projectsPage.map(async ({ id: projectId, role: originalProjectRole }) => {
|
||||
if (flags?.skipProjectRoleUpdatesFor.includes(projectId)) {
|
||||
if (isOldPlan && flags?.skipProjectRoleUpdatesFor.includes(projectId)) {
|
||||
// Skip assignment (used during invite flow)
|
||||
// TODO: Can we refactor this special case away?
|
||||
return
|
||||
}
|
||||
|
||||
// If downgraded from owner & last owner, transfer ownership to admin causing the role update (updatedByUserId)
|
||||
if (!originalProjectRole && !isOldPlan) {
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* We cant really throw here, because by this point the workspace role has already
|
||||
* been written to DB. So we must ensure the updates we make here are valid
|
||||
*/
|
||||
|
||||
let nextUserRole: StreamRoles | null
|
||||
if (isOldPlan) {
|
||||
nextUserRole = defaultProjectRoles[role]
|
||||
} else {
|
||||
switch (role) {
|
||||
case Roles.Workspace.Admin: {
|
||||
// Set workspace owner as project owner
|
||||
nextUserRole = Roles.Stream.Owner
|
||||
break
|
||||
}
|
||||
case Roles.Workspace.Guest: {
|
||||
// If workspace guest is project owner
|
||||
if (originalProjectRole !== Roles.Stream.Owner) {
|
||||
return
|
||||
}
|
||||
|
||||
// If workspace guest has an editor seat
|
||||
if (seatType.type !== WorkspaceSeatType.Editor) {
|
||||
return
|
||||
}
|
||||
|
||||
// Demote to contributor
|
||||
nextUserRole = Roles.Stream.Contributor
|
||||
break
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// If downgraded from owner & last owner, transfer ownership to a workspace admin
|
||||
const isNoLongerOwner =
|
||||
originalProjectRole === Roles.Stream.Owner &&
|
||||
(!nextUserRole || nextUserRole !== Roles.Stream.Owner)
|
||||
nextUserRole !== Roles.Stream.Owner
|
||||
const wasLastOwner =
|
||||
projectsOldOwnerCounts[projectId]?.[Roles.Stream.Owner] === 1
|
||||
if (isNoLongerOwner && wasLastOwner) {
|
||||
await deps.setStreamCollaborator(
|
||||
{
|
||||
streamId: projectId,
|
||||
userId: updatedByUserId,
|
||||
userId: admin.id,
|
||||
role: Roles.Stream.Owner,
|
||||
setByUserId: updatedByUserId
|
||||
},
|
||||
@@ -409,7 +543,7 @@ export const onWorkspaceRoleUpdatedFactory =
|
||||
)
|
||||
}
|
||||
|
||||
// Finally change target role
|
||||
// Do actual role change for changed user
|
||||
await deps.setStreamCollaborator(
|
||||
{
|
||||
streamId: projectId,
|
||||
@@ -735,11 +869,28 @@ export const initializeEventListenersFactory =
|
||||
queryAllWorkspaceProjects: queryAllWorkspaceProjectsFactory({
|
||||
getStreams
|
||||
}),
|
||||
deleteProjectRole: deleteProjectRoleFactory({ db: trx }),
|
||||
deleteWorkspaceSeat: deleteWorkspaceSeatFactory({ db: trx })
|
||||
deleteWorkspaceSeat: deleteWorkspaceSeatFactory({ db: trx }),
|
||||
getStreamsCollaboratorCounts: getStreamsCollaboratorCountsFactory({ db }),
|
||||
getWorkspaceCollaborators: getWorkspaceCollaboratorsFactory({ db }),
|
||||
setStreamCollaborator: setStreamCollaboratorFactory({
|
||||
getUser: getUserFactory({ db }),
|
||||
validateStreamAccess: validateStreamAccessFactory({
|
||||
authorizeResolver
|
||||
}),
|
||||
emitEvent: eventBus.emit,
|
||||
grantStreamPermissions: grantStreamPermissionsFactory({
|
||||
db: trx
|
||||
}),
|
||||
isStreamCollaborator: isStreamCollaboratorFactory({
|
||||
getStream: getStreamFactory({ db })
|
||||
}),
|
||||
revokeStreamPermissions: revokeStreamPermissionsFactory({
|
||||
db: trx
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return await onWorkspaceRoleDeleted(payload.acl)
|
||||
return await onWorkspaceRoleDeleted(payload)
|
||||
},
|
||||
{ db }
|
||||
)
|
||||
@@ -748,11 +899,6 @@ export const initializeEventListenersFactory =
|
||||
await withTransaction(
|
||||
async ({ db: trx }) => {
|
||||
const onWorkspaceRoleUpdated = onWorkspaceRoleUpdatedFactory({
|
||||
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db }),
|
||||
getWorkspaceRoleToDefaultProjectRoleMapping:
|
||||
getWorkspaceRoleToDefaultProjectRoleMappingFactory({
|
||||
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db })
|
||||
}),
|
||||
queryAllWorkspaceProjects: queryAllWorkspaceProjectsFactory({
|
||||
getStreams
|
||||
}),
|
||||
@@ -772,7 +918,14 @@ export const initializeEventListenersFactory =
|
||||
db: trx
|
||||
})
|
||||
}),
|
||||
getStreamsCollaboratorCounts: getStreamsCollaboratorCountsFactory({ db })
|
||||
getWorkspaceUserSeat: getWorkspaceUserSeatFactory({ db }),
|
||||
getStreamsCollaboratorCounts: getStreamsCollaboratorCountsFactory({ db }),
|
||||
getWorkspaceCollaborators: getWorkspaceCollaboratorsFactory({ db }),
|
||||
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db }),
|
||||
getWorkspaceRoleToDefaultProjectRoleMapping:
|
||||
getWorkspaceRoleToDefaultProjectRoleMappingFactory({
|
||||
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db })
|
||||
})
|
||||
})
|
||||
return await onWorkspaceRoleUpdated(payload)
|
||||
},
|
||||
@@ -803,7 +956,9 @@ export const initializeEventListenersFactory =
|
||||
getWorkspaceSeatTypeToProjectRoleMapping:
|
||||
getWorkspaceSeatTypeToProjectRoleMappingFactory({
|
||||
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db })
|
||||
})
|
||||
}),
|
||||
getStreamsCollaboratorCounts: getStreamsCollaboratorCountsFactory({ db }),
|
||||
getWorkspaceCollaborators: getWorkspaceCollaboratorsFactory({ db })
|
||||
})
|
||||
|
||||
return await onWorkspaceSeatUpdated(payload)
|
||||
|
||||
@@ -148,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 {
|
||||
getRateLimitResult,
|
||||
isRateLimitBreached
|
||||
@@ -728,37 +727,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 = updateWorkspaceRoleFactory({
|
||||
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db: trx }),
|
||||
getWorkspaceWithDomains: getWorkspaceWithDomainsFactory({ db: trx }),
|
||||
findVerifiedEmailsByUserId: findVerifiedEmailsByUserIdFactory({
|
||||
@@ -772,23 +769,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
|
||||
@@ -943,31 +942,30 @@ export = FF_WORKSPACES_MODULE_ENABLED
|
||||
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) => {
|
||||
@@ -1394,7 +1392,7 @@ export = FF_WORKSPACES_MODULE_ENABLED
|
||||
projectId,
|
||||
streamId: projectId //legacy
|
||||
})
|
||||
return await withOperationLogging(
|
||||
const ret = await withOperationLogging(
|
||||
async () =>
|
||||
await updateStreamRoleAndNotify(
|
||||
args.input,
|
||||
@@ -1407,6 +1405,10 @@ export = FF_WORKSPACES_MODULE_ENABLED
|
||||
operationDescription: 'Update workspace project role'
|
||||
}
|
||||
)
|
||||
|
||||
context.clearCache()
|
||||
|
||||
return ret
|
||||
},
|
||||
moveToWorkspace: async (_parent, args, context) => {
|
||||
const { projectId, workspaceId } = args
|
||||
|
||||
@@ -364,7 +364,7 @@ export const getWorkspaceCollaboratorsFactory =
|
||||
.where(DbWorkspaceAcl.col.workspaceId, workspaceId)
|
||||
.orderBy('workspaceRoleCreatedAt', 'desc')
|
||||
|
||||
const { search, roles, seatType } = filter || {}
|
||||
const { search, roles, seatType, excludeUserIds } = filter || {}
|
||||
|
||||
if (seatType) {
|
||||
query
|
||||
@@ -387,6 +387,12 @@ export const getWorkspaceCollaboratorsFactory =
|
||||
})
|
||||
}
|
||||
|
||||
if (excludeUserIds?.length) {
|
||||
query.andWhere((w) => {
|
||||
w.whereNotIn(Users.col.id, excludeUserIds)
|
||||
})
|
||||
}
|
||||
|
||||
if (cursor) {
|
||||
query.andWhere(DbWorkspaceAcl.col.createdAt, '<', cursor)
|
||||
}
|
||||
|
||||
@@ -349,6 +349,7 @@ export const deleteWorkspaceFactory =
|
||||
type WorkspaceRoleDeleteArgs = {
|
||||
userId: string
|
||||
workspaceId: string
|
||||
deletedByUserId: string
|
||||
}
|
||||
|
||||
export const deleteWorkspaceRoleFactory =
|
||||
@@ -363,7 +364,8 @@ export const deleteWorkspaceRoleFactory =
|
||||
}) =>
|
||||
async ({
|
||||
workspaceId,
|
||||
userId
|
||||
userId,
|
||||
deletedByUserId
|
||||
}: WorkspaceRoleDeleteArgs): Promise<WorkspaceAcl | null> => {
|
||||
// Protect against removing last admin
|
||||
const workspaceRoles = await getWorkspaceRoles({ workspaceId })
|
||||
@@ -380,7 +382,7 @@ export const deleteWorkspaceRoleFactory =
|
||||
// Emit deleted role
|
||||
await emitWorkspaceEvent({
|
||||
eventName: WorkspaceEvents.RoleDeleted,
|
||||
payload: { acl: deletedRole }
|
||||
payload: { acl: deletedRole, updatedByUserId: deletedByUserId }
|
||||
})
|
||||
|
||||
return deletedRole
|
||||
@@ -420,9 +422,9 @@ export const updateWorkspaceRoleFactory =
|
||||
workspaceId,
|
||||
userId,
|
||||
role: nextWorkspaceRole,
|
||||
skipProjectRoleUpdatesFor,
|
||||
preventRoleDowngrade,
|
||||
updatedByUserId
|
||||
updatedByUserId,
|
||||
skipProjectRoleUpdatesFor
|
||||
}): Promise<void> => {
|
||||
const workspaceRoles = await getWorkspaceRoles({ workspaceId })
|
||||
|
||||
@@ -493,10 +495,10 @@ export const updateWorkspaceRoleFactory =
|
||||
workspaceId,
|
||||
role: nextWorkspaceRole
|
||||
},
|
||||
updatedByUserId,
|
||||
flags: {
|
||||
skipProjectRoleUpdatesFor: skipProjectRoleUpdatesFor ?? []
|
||||
},
|
||||
updatedByUserId
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -356,7 +356,7 @@ export const validateWorkspaceMemberProjectRoleFactory =
|
||||
// User's workspace role does not allow the requested project role
|
||||
throw new WorkspaceInvalidRoleError(
|
||||
isNewPlan
|
||||
? `User's workspace seat type '${seatType}' does not allow project role '${projectRole}'.`
|
||||
? `User's workspace seat type '${seatType}' and workspace role '${workspaceRole}' does not allow project role '${projectRole}'.`
|
||||
: `User's workspace role '${workspaceRole}' does not allow project role '${projectRole}'.`
|
||||
)
|
||||
}
|
||||
|
||||
@@ -339,7 +339,8 @@ export const unassignFromWorkspace = async (
|
||||
|
||||
await deleteWorkspaceRole({
|
||||
userId: user.id,
|
||||
workspaceId: workspace.id
|
||||
workspaceId: workspace.id,
|
||||
deletedByUserId: workspace.ownerId
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
import { basicWorkspaceFragment } from '@/modules/workspaces/tests/helpers/graphql'
|
||||
import { ProjectImplicitRoleCheckFragment } from '@/test/graphql/generated/graphql'
|
||||
import { MaybeNullOrUndefined, Roles } from '@speckle/shared'
|
||||
import { gql } from 'graphql-tag'
|
||||
|
||||
export const fullPermissionCheckResultFragment = gql(`
|
||||
fragment FullPermissionCheckResult on PermissionCheckResult {
|
||||
authorized
|
||||
code
|
||||
message
|
||||
payload
|
||||
}
|
||||
`)
|
||||
|
||||
export const projectImplicitRoleCheckFragment = gql`
|
||||
fragment ProjectImplicitRoleCheck on Project {
|
||||
id
|
||||
role
|
||||
permissions {
|
||||
# general access check
|
||||
canRead {
|
||||
...FullPermissionCheckResult
|
||||
}
|
||||
# implicit reviewer check
|
||||
canReadSettings {
|
||||
...FullPermissionCheckResult
|
||||
}
|
||||
# implicit owner check
|
||||
canReadWebhooks {
|
||||
...FullPermissionCheckResult
|
||||
}
|
||||
# implicit contributor check
|
||||
canCreateModel {
|
||||
...FullPermissionCheckResult
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${fullPermissionCheckResultFragment}
|
||||
`
|
||||
|
||||
export const getUserWorkspaceAccessQuery = gql`
|
||||
query GetUserWorkspaceAccess($id: String!) {
|
||||
workspace(id: $id) {
|
||||
id
|
||||
role
|
||||
seatType
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const getUserWorkspaceProjectsWithAccessChecksQuery = gql`
|
||||
query GetUserWorkspaceProjectsWithAccessChecks(
|
||||
$id: String!
|
||||
$limit: Int
|
||||
$cursor: String
|
||||
$filter: WorkspaceProjectsFilter
|
||||
) {
|
||||
workspace(id: $id) {
|
||||
...BasicWorkspace
|
||||
role
|
||||
seatType
|
||||
projects(limit: $limit, cursor: $cursor, filter: $filter) {
|
||||
items {
|
||||
...ProjectImplicitRoleCheck
|
||||
}
|
||||
cursor
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${basicWorkspaceFragment}
|
||||
${projectImplicitRoleCheckFragment}
|
||||
`
|
||||
|
||||
export const getUserProjectsWithAccessChecksQuery = gql`
|
||||
query GetUserProjectsWithAccessChecks(
|
||||
$limit: Int
|
||||
$cursor: String
|
||||
$filter: UserProjectsFilter
|
||||
) {
|
||||
activeUser {
|
||||
id
|
||||
projects(limit: $limit, cursor: $cursor, filter: $filter) {
|
||||
items {
|
||||
...ProjectImplicitRoleCheck
|
||||
}
|
||||
cursor
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
${projectImplicitRoleCheckFragment}
|
||||
`
|
||||
|
||||
export const projectImplicitRoleCheck = (
|
||||
project: MaybeNullOrUndefined<ProjectImplicitRoleCheckFragment>
|
||||
) => {
|
||||
return {
|
||||
hasAccess: !!project?.permissions?.canRead.authorized,
|
||||
isReviewer: !!project?.permissions?.canReadSettings.authorized,
|
||||
isContributor: !!project?.permissions?.canCreateModel.authorized,
|
||||
isOwner: !!project?.permissions?.canReadWebhooks.authorized,
|
||||
isExplicitOwner: project?.role === Roles.Stream.Owner,
|
||||
isExplicitContributor: project?.role === Roles.Stream.Contributor,
|
||||
isExplicitReviewer: project?.role === Roles.Stream.Reviewer,
|
||||
hasExplicitRole: !!project?.role
|
||||
}
|
||||
}
|
||||
|
||||
export type ProjectImplicitRoleCheck = ReturnType<typeof projectImplicitRoleCheck>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,9 @@
|
||||
import cryptoRandomString from 'crypto-random-string'
|
||||
import { Workspace, WorkspaceAcl } from '@/modules/workspacesCore/domain/types'
|
||||
import { Roles, StreamRoles } from '@speckle/shared'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { StreamAclRecord, StreamRecord } from '@/modules/core/helpers/types'
|
||||
import {
|
||||
onProjectCreatedFactory,
|
||||
onWorkspaceRoleUpdatedFactory
|
||||
} from '@/modules/workspaces/events/eventListener'
|
||||
import { onProjectCreatedFactory } from '@/modules/workspaces/events/eventListener'
|
||||
import { expect } from 'chai'
|
||||
import { chunk } from 'lodash'
|
||||
import { GetWorkspaceRolesAndSeats } from '@/modules/gatekeeper/domain/billing'
|
||||
|
||||
describe('Event handlers', () => {
|
||||
@@ -89,132 +85,4 @@ describe('Event handlers', () => {
|
||||
expect(projectRoles.length).to.equal(2)
|
||||
})
|
||||
})
|
||||
describe('onWorkspaceRoleUpdatedFactory creates a function, that', () => {
|
||||
it('assigns no project roles if the role mapping returns null', async () => {
|
||||
let isDeleteCalled = false
|
||||
const fakeProject = { id: 'test' } as StreamRecord
|
||||
|
||||
await onWorkspaceRoleUpdatedFactory({
|
||||
getWorkspaceWithPlan: async () =>
|
||||
({
|
||||
id: 'fake'
|
||||
} as Workspace & { plan: null }),
|
||||
getWorkspaceRoleToDefaultProjectRoleMapping: async () => ({
|
||||
default: {
|
||||
[Roles.Workspace.Admin]: Roles.Stream.Owner,
|
||||
[Roles.Workspace.Member]: Roles.Stream.Contributor,
|
||||
[Roles.Workspace.Guest]: null
|
||||
},
|
||||
allowed: {
|
||||
[Roles.Workspace.Admin]: [
|
||||
Roles.Stream.Owner,
|
||||
Roles.Stream.Contributor,
|
||||
Roles.Stream.Reviewer
|
||||
],
|
||||
[Roles.Workspace.Member]: [
|
||||
Roles.Stream.Owner,
|
||||
Roles.Stream.Contributor,
|
||||
Roles.Stream.Reviewer
|
||||
],
|
||||
[Roles.Workspace.Guest]: [Roles.Stream.Reviewer, Roles.Stream.Contributor]
|
||||
}
|
||||
}),
|
||||
async *queryAllWorkspaceProjects() {
|
||||
yield [fakeProject as StreamRecord]
|
||||
},
|
||||
getStreamsCollaboratorCounts: async () => {
|
||||
return {}
|
||||
},
|
||||
setStreamCollaborator: async ({ role }) => {
|
||||
if (!role) {
|
||||
isDeleteCalled = true
|
||||
} else {
|
||||
expect.fail()
|
||||
}
|
||||
|
||||
return fakeProject
|
||||
}
|
||||
})({
|
||||
acl: {
|
||||
role: Roles.Workspace.Guest,
|
||||
userId: cryptoRandomString({ length: 10 }),
|
||||
workspaceId: cryptoRandomString({ length: 10 })
|
||||
},
|
||||
updatedByUserId: cryptoRandomString({ length: 10 })
|
||||
})
|
||||
|
||||
expect(isDeleteCalled).to.be.true
|
||||
})
|
||||
it('assigns the mapped projects roles to all queried project', async () => {
|
||||
const projectIds = [
|
||||
cryptoRandomString({ length: 10 }),
|
||||
cryptoRandomString({ length: 10 }),
|
||||
cryptoRandomString({ length: 10 }),
|
||||
cryptoRandomString({ length: 10 })
|
||||
]
|
||||
const userId = cryptoRandomString({ length: 10 })
|
||||
const projectRole = Roles.Stream.Reviewer
|
||||
|
||||
const storedRoles: { userId: string; role: StreamRoles; projectId: string }[] = []
|
||||
let trackProjectUpdate: boolean | undefined = false
|
||||
await onWorkspaceRoleUpdatedFactory({
|
||||
getWorkspaceWithPlan: async () =>
|
||||
({
|
||||
id: 'fake'
|
||||
} as Workspace & { plan: null }),
|
||||
getWorkspaceRoleToDefaultProjectRoleMapping: async () => ({
|
||||
default: {
|
||||
[Roles.Workspace.Admin]: Roles.Stream.Owner,
|
||||
[Roles.Workspace.Member]: projectRole,
|
||||
[Roles.Workspace.Guest]: null
|
||||
},
|
||||
allowed: {
|
||||
[Roles.Workspace.Admin]: [
|
||||
Roles.Stream.Owner,
|
||||
Roles.Stream.Contributor,
|
||||
Roles.Stream.Reviewer
|
||||
],
|
||||
[Roles.Workspace.Member]: [
|
||||
Roles.Stream.Owner,
|
||||
Roles.Stream.Contributor,
|
||||
Roles.Stream.Reviewer
|
||||
],
|
||||
[Roles.Workspace.Guest]: [Roles.Stream.Reviewer, Roles.Stream.Contributor]
|
||||
}
|
||||
}),
|
||||
async *queryAllWorkspaceProjects() {
|
||||
for (const projIds of chunk(projectIds, 3)) {
|
||||
yield projIds.map((projId) => ({ id: projId } as unknown as StreamRecord))
|
||||
}
|
||||
},
|
||||
getStreamsCollaboratorCounts: async () => {
|
||||
return {}
|
||||
},
|
||||
setStreamCollaborator: async (params, options) => {
|
||||
if (!params.role) {
|
||||
return expect.fail()
|
||||
} else {
|
||||
storedRoles.push({
|
||||
userId: params.userId,
|
||||
role: params.role,
|
||||
projectId: params.streamId
|
||||
})
|
||||
trackProjectUpdate = trackProjectUpdate || options?.trackProjectUpdate
|
||||
return {} as StreamRecord
|
||||
}
|
||||
}
|
||||
})({
|
||||
acl: {
|
||||
role: Roles.Workspace.Member,
|
||||
userId,
|
||||
workspaceId: cryptoRandomString({ length: 10 })
|
||||
},
|
||||
updatedByUserId: cryptoRandomString({ length: 10 })
|
||||
})
|
||||
expect(storedRoles).deep.equals(
|
||||
projectIds.map((projectId) => ({ projectId, role: projectRole, userId }))
|
||||
)
|
||||
expect(trackProjectUpdate).to.not.be.true
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -693,7 +693,11 @@ describe('Workspace role services', () => {
|
||||
workspaceRoles: [role]
|
||||
})
|
||||
|
||||
const deletedRole = await deleteWorkspaceRole({ userId, workspaceId })
|
||||
const deletedRole = await deleteWorkspaceRole({
|
||||
userId,
|
||||
workspaceId,
|
||||
deletedByUserId: cryptoRandomString({ length: 10 })
|
||||
})
|
||||
|
||||
expect(context.workspaceRoles.length).to.equal(0)
|
||||
expect(deletedRole).to.deep.equal(role)
|
||||
@@ -713,11 +717,19 @@ describe('Workspace role services', () => {
|
||||
workspaceRoles: [role]
|
||||
})
|
||||
|
||||
await deleteWorkspaceRole({ userId, workspaceId })
|
||||
const deletedByUserId = cryptoRandomString({ length: 10 })
|
||||
await deleteWorkspaceRole({
|
||||
userId,
|
||||
workspaceId,
|
||||
deletedByUserId
|
||||
})
|
||||
|
||||
expect(context.eventData.isCalled).to.be.true
|
||||
expect(context.eventData.eventName).to.equal(WorkspaceEvents.RoleDeleted)
|
||||
expect(context.eventData.payload).to.deep.equal({ acl: role })
|
||||
expect(context.eventData.payload).to.deep.equal({
|
||||
acl: role,
|
||||
updatedByUserId: deletedByUserId
|
||||
})
|
||||
})
|
||||
it('throws if attempting to delete the last admin from a workspace', async () => {
|
||||
const userId = cryptoRandomString({ length: 10 })
|
||||
@@ -734,7 +746,13 @@ describe('Workspace role services', () => {
|
||||
workspaceRoles: [role]
|
||||
})
|
||||
|
||||
await expectToThrow(() => deleteWorkspaceRole({ userId, workspaceId }))
|
||||
await expectToThrow(() =>
|
||||
deleteWorkspaceRole({
|
||||
userId,
|
||||
workspaceId,
|
||||
deletedByUserId: cryptoRandomString({ length: 10 })
|
||||
})
|
||||
)
|
||||
})
|
||||
it('deletes workspace project roles', async () => {
|
||||
const userId = cryptoRandomString({ length: 10 })
|
||||
@@ -757,7 +775,11 @@ describe('Workspace role services', () => {
|
||||
]
|
||||
})
|
||||
|
||||
await deleteWorkspaceRole({ userId, workspaceId })
|
||||
await deleteWorkspaceRole({
|
||||
userId,
|
||||
workspaceId,
|
||||
deletedByUserId: cryptoRandomString({ length: 10 })
|
||||
})
|
||||
|
||||
expect(context.workspaceProjectRoles.length).to.equal(0)
|
||||
})
|
||||
@@ -807,13 +829,15 @@ describe('Workspace role services', () => {
|
||||
...(context.eventData
|
||||
.payload as WorkspaceEventsPayloads[typeof WorkspaceEvents.RoleUpdated])
|
||||
}
|
||||
delete payload.flags
|
||||
|
||||
expect(context.eventData.isCalled).to.be.true
|
||||
expect(context.eventData.eventName).to.equal(WorkspaceEvents.RoleUpdated)
|
||||
expect(payload).to.deep.equal({
|
||||
acl: role,
|
||||
updatedByUserId: workspaceOwnerId
|
||||
updatedByUserId: workspaceOwnerId,
|
||||
flags: {
|
||||
skipProjectRoleUpdatesFor: []
|
||||
}
|
||||
})
|
||||
})
|
||||
it('throws if attempting to remove the last admin in a workspace', async () => {
|
||||
|
||||
@@ -30,11 +30,12 @@ type WorkspaceCreatedPayload = {
|
||||
type WorkspaceUpdatedPayload = { workspace: Workspace }
|
||||
type WorkspaceRoleDeletedPayload = {
|
||||
acl: Pick<WorkspaceAcl, 'userId' | 'workspaceId' | 'role'>
|
||||
updatedByUserId: string
|
||||
}
|
||||
type WorkspaceRoleUpdatedPayload = {
|
||||
acl: Pick<WorkspaceAcl, 'userId' | 'workspaceId' | 'role'>
|
||||
flags?: { skipProjectRoleUpdatesFor: string[] }
|
||||
updatedByUserId: string
|
||||
flags?: { skipProjectRoleUpdatesFor: string[] }
|
||||
}
|
||||
type WorkspaceSeatUpdatedPayload = {
|
||||
seat: WorkspaceSeat
|
||||
|
||||
@@ -5490,6 +5490,36 @@ export type GetProjectInvitableCollaboratorsQueryVariables = Exact<{
|
||||
|
||||
export type GetProjectInvitableCollaboratorsQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, name: string, invitableCollaborators: { __typename?: 'WorkspaceCollaboratorCollection', totalCount: number, items: Array<{ __typename?: 'WorkspaceCollaborator', id: string, user: { __typename?: 'LimitedUser', name: string } }> } } };
|
||||
|
||||
export type FullPermissionCheckResultFragment = { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null };
|
||||
|
||||
export type ProjectImplicitRoleCheckFragment = { __typename?: 'Project', id: string, role?: string | null, permissions: { __typename?: 'ProjectPermissionChecks', canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null }, canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null } } };
|
||||
|
||||
export type GetUserWorkspaceAccessQueryVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type GetUserWorkspaceAccessQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, role?: string | null, seatType?: WorkspaceSeatType | null } };
|
||||
|
||||
export type GetUserWorkspaceProjectsWithAccessChecksQueryVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
limit?: InputMaybe<Scalars['Int']['input']>;
|
||||
cursor?: InputMaybe<Scalars['String']['input']>;
|
||||
filter?: InputMaybe<WorkspaceProjectsFilter>;
|
||||
}>;
|
||||
|
||||
|
||||
export type GetUserWorkspaceProjectsWithAccessChecksQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', role?: string | null, seatType?: WorkspaceSeatType | null, id: string, name: string, slug: string, updatedAt: string, createdAt: string, readOnly: boolean, projects: { __typename?: 'ProjectCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Project', id: string, role?: string | null, permissions: { __typename?: 'ProjectPermissionChecks', canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null }, canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null } } }> } } };
|
||||
|
||||
export type GetUserProjectsWithAccessChecksQueryVariables = Exact<{
|
||||
limit?: InputMaybe<Scalars['Int']['input']>;
|
||||
cursor?: InputMaybe<Scalars['String']['input']>;
|
||||
filter?: InputMaybe<UserProjectsFilter>;
|
||||
}>;
|
||||
|
||||
|
||||
export type GetUserProjectsWithAccessChecksQuery = { __typename?: 'Query', activeUser?: { __typename?: 'User', id: string, projects: { __typename?: 'UserProjectCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Project', id: string, role?: string | null, permissions: { __typename?: 'ProjectPermissionChecks', canRead: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null }, canReadSettings: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null }, canReadWebhooks: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null }, canCreateModel: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string, payload?: Record<string, unknown> | null } } }> } } | null };
|
||||
|
||||
export type BasicStreamAccessRequestFieldsFragment = { __typename?: 'StreamAccessRequest', id: string, requesterId: string, streamId: string, createdAt: string, requester: { __typename?: 'LimitedUser', id: string, name: string } };
|
||||
|
||||
export type CreateStreamAccessRequestMutationVariables = Exact<{
|
||||
@@ -6264,6 +6294,8 @@ export type MoveProjectToWorkspaceMutation = { __typename?: 'Mutation', workspac
|
||||
export const BasicWorkspaceFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}}]} as unknown as DocumentNode<BasicWorkspaceFragment, unknown>;
|
||||
export const BasicPendingWorkspaceCollaboratorFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicPendingWorkspaceCollaborator"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PendingWorkspaceCollaborator"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"inviteId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceName"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"invitedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"token"}}]}}]} as unknown as DocumentNode<BasicPendingWorkspaceCollaboratorFragment, unknown>;
|
||||
export const WorkspaceProjectsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkspaceProjects"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProjectCollection"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]} as unknown as DocumentNode<WorkspaceProjectsFragment, unknown>;
|
||||
export const FullPermissionCheckResultFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}}]} as unknown as DocumentNode<FullPermissionCheckResultFragment, unknown>;
|
||||
export const ProjectImplicitRoleCheckFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectImplicitRoleCheck"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canRead"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canReadSettings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canReadWebhooks"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canCreateModel"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}}]} as unknown as DocumentNode<ProjectImplicitRoleCheckFragment, unknown>;
|
||||
export const BasicStreamAccessRequestFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicStreamAccessRequestFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StreamAccessRequest"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"requester"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"requesterId"}},{"kind":"Field","name":{"kind":"Name","value":"streamId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode<BasicStreamAccessRequestFieldsFragment, unknown>;
|
||||
export const TestAutomateFunctionFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestAutomateFunction"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AutomateFunction"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"repo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"owner"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}},{"kind":"Field","name":{"kind":"Name","value":"releases"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"versionTag"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"inputSchema"}},{"kind":"Field","name":{"kind":"Name","value":"commitId"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"supportedSourceApps"}},{"kind":"Field","name":{"kind":"Name","value":"tags"}}]}}]} as unknown as DocumentNode<TestAutomateFunctionFragment, unknown>;
|
||||
export const TestAutomationFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestAutomation"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Automation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"runs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"trigger"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"VersionCreatedTrigger"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"version"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"model"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"functionRuns"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"statusMessage"}},{"kind":"Field","name":{"kind":"Name","value":"contextView"}},{"kind":"Field","name":{"kind":"Name","value":"function"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"elapsed"}},{"kind":"Field","name":{"kind":"Name","value":"results"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"currentRevision"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"triggerDefinitions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"VersionCreatedTriggerDefinition"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"model"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"functions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"parameters"}},{"kind":"Field","name":{"kind":"Name","value":"release"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"function"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"versionTag"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"inputSchema"}},{"kind":"Field","name":{"kind":"Name","value":"commitId"}}]}}]}}]}}]}}]} as unknown as DocumentNode<TestAutomationFragment, unknown>;
|
||||
@@ -6332,6 +6364,9 @@ export const GetWorkspaceWithMembersByRoleDocument = {"kind":"Document","definit
|
||||
export const UpdateWorkspaceProjectRoleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateWorkspaceProjectRole"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ProjectUpdateRoleInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projects"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateRole"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicProjectFields"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicProjectFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"allowPublicComments"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<UpdateWorkspaceProjectRoleMutation, UpdateWorkspaceProjectRoleMutationVariables>;
|
||||
export const UpdateWorkspaceSeatTypeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateWorkspaceSeatType"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceUpdateSeatTypeInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateSeatType"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"seatType"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode<UpdateWorkspaceSeatTypeMutation, UpdateWorkspaceSeatTypeMutationVariables>;
|
||||
export const GetProjectInvitableCollaboratorsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProjectInvitableCollaborators"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"invitableCollaborators"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"search"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetProjectInvitableCollaboratorsQuery, GetProjectInvitableCollaboratorsQueryVariables>;
|
||||
export const GetUserWorkspaceAccessDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetUserWorkspaceAccess"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"seatType"}}]}}]}}]} as unknown as DocumentNode<GetUserWorkspaceAccessQuery, GetUserWorkspaceAccessQueryVariables>;
|
||||
export const GetUserWorkspaceProjectsWithAccessChecksDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetUserWorkspaceProjectsWithAccessChecks"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceProjectsFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicWorkspace"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"seatType"}},{"kind":"Field","name":{"kind":"Name","value":"projects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"cursor"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectImplicitRoleCheck"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicWorkspace"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Workspace"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"readOnly"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectImplicitRoleCheck"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canRead"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canReadSettings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canReadWebhooks"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canCreateModel"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}}]} as unknown as DocumentNode<GetUserWorkspaceProjectsWithAccessChecksQuery, GetUserWorkspaceProjectsWithAccessChecksQueryVariables>;
|
||||
export const GetUserProjectsWithAccessChecksDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetUserProjectsWithAccessChecks"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UserProjectsFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"projects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"cursor"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectImplicitRoleCheck"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullPermissionCheckResult"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PermissionCheckResult"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"payload"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectImplicitRoleCheck"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canRead"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canReadSettings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canReadWebhooks"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canCreateModel"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullPermissionCheckResult"}}]}}]}}]}}]} as unknown as DocumentNode<GetUserProjectsWithAccessChecksQuery, GetUserProjectsWithAccessChecksQueryVariables>;
|
||||
export const CreateStreamAccessRequestDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateStreamAccessRequest"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"streamId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"streamAccessRequestCreate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"streamId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"streamId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicStreamAccessRequestFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicStreamAccessRequestFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StreamAccessRequest"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"requester"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"requesterId"}},{"kind":"Field","name":{"kind":"Name","value":"streamId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode<CreateStreamAccessRequestMutation, CreateStreamAccessRequestMutationVariables>;
|
||||
export const GetStreamAccessRequestDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetStreamAccessRequest"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"streamId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"streamAccessRequest"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"streamId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"streamId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicStreamAccessRequestFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicStreamAccessRequestFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StreamAccessRequest"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"requester"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"requesterId"}},{"kind":"Field","name":{"kind":"Name","value":"streamId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode<GetStreamAccessRequestQuery, GetStreamAccessRequestQueryVariables>;
|
||||
export const GetFullStreamAccessRequestDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetFullStreamAccessRequest"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"streamId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"streamAccessRequest"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"streamId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"streamId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicStreamAccessRequestFields"}},{"kind":"Field","name":{"kind":"Name","value":"stream"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicStreamAccessRequestFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StreamAccessRequest"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"requester"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"requesterId"}},{"kind":"Field","name":{"kind":"Name","value":"streamId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode<GetFullStreamAccessRequestQuery, GetFullStreamAccessRequestQueryVariables>;
|
||||
|
||||
@@ -244,7 +244,7 @@
|
||||
"maxConnectionsServer": {
|
||||
"type": "number",
|
||||
"description": "The number of connections to the Postgres database to provide in the connection pool",
|
||||
"default": 4
|
||||
"default": 8
|
||||
},
|
||||
"certificate": {
|
||||
"type": "string",
|
||||
|
||||
@@ -191,7 +191,7 @@ db:
|
||||
useCertificate: false
|
||||
## @param db.maxConnectionsServer The number of connections to the Postgres database to provide in the connection pool
|
||||
##
|
||||
maxConnectionsServer: 4
|
||||
maxConnectionsServer: 8
|
||||
## @param db.certificate The x509 public certificate for SSL connections to the Postgres database. Use of this certificate requires db.useCertificate to be enabled and an appropriate value for db.PGSSLMODE provided.
|
||||
## The value must be formatted as a multi-line string. We recommend using the pipe-symbol and taking care to
|
||||
## indent all lines of the value correctly.
|
||||
|
||||
Reference in New Issue
Block a user