feat(workspaces): cru(d) resolvers (#2521)
* feat(workspaces): drop createdByUserId from the dataschema * feat(workspaces): repositories WIP * merge * protect against removing last admin in workspace * quick impl and stub tests * add tests * services * unit tests for role services * feat(workspaces): authorize project creation if workspace specified * feat(workspaces): emit project created event * feat(workspaces): assign roles on project create in workspace * feat(workspaces): update project roles when user added to workspace * feat(workspaces): stencil gql resolvers * fix(workspaces): lol lmao * fix(workspaces): perform automatic project role update in service function * fix(workspaces): also delete roles * fix(workspaces): broke tests again oops * fix(workspaces): update `onProjectCreated` listener to use new repo method * fix(workspaces): use service function in event listener * fix(workspaces): get workspace projects via existing stream repo functions * fix(workspaces): roles mapping in domain, use enum * feat(workspaces): stencil gql api and resolvers * fix(workspaces): repair type reference in tests * fix(workspaces): consolidate files, use different existing stream-getter * fix(workspaces): more specific error * fix(workspaces): roles and scopes * fix(workspaces): yield per page * fix(workspaces): some test dry * fix(workspaces): superdry * fix(workspaces): add scopes * fix(workspaces): classic * feat(workspaces): create workspace mutation * feat(workspaces): I'm sure everything will be fine * fix(workspaces): yep * fix(workspaces): successful gql e2e test * feat(workspaces): update workspace resolver * chore(workspaces): update resolver test * feat(workspaces): some retrieval resolvers * chore(workspaces): tests for query resolvers * fix(chore): revert temp test command change * fix(workspaces): test structure and gql types * fix(workspaces): validate user authz to perform some operations * fix(workspaces): use existing test infrastructure * fix(workspaces): stop `isPublic` check if authorizing a workspace resource * fix(workspaces): better test hygiene --------- Co-authored-by: Gergő Jedlicska <gergo@jedlicska.com>
This commit is contained in:
Родитель
56a04440a8
Коммит
6eaf3c8c92
|
@ -1,5 +1,7 @@
|
|||
extend type Query {
|
||||
workspace(id: String!): Workspace! @hasScope(scope: "workspace:read")
|
||||
workspace(id: String!): Workspace!
|
||||
@hasServerRole(role: SERVER_USER)
|
||||
@hasScope(scope: "workspace:read")
|
||||
}
|
||||
|
||||
input WorkspaceCreateInput {
|
||||
|
@ -31,7 +33,9 @@ extend type Mutation {
|
|||
}
|
||||
|
||||
type WorkspaceMutations {
|
||||
create(input: WorkspaceCreateInput!): Workspace! @hasScope(scope: "workspace:create")
|
||||
create(input: WorkspaceCreateInput!): Workspace!
|
||||
@hasServerRole(role: SERVER_ADMIN)
|
||||
@hasScope(scope: "workspace:create")
|
||||
delete(workspaceId: String!): Workspace! @hasScope(scope: "workspace:delete")
|
||||
update(input: WorkspaceUpdateInput!): Workspace! @hasScope(scope: "workspace:update")
|
||||
"""
|
||||
|
|
|
@ -51,6 +51,8 @@ generates:
|
|||
ProjectTriggeredAutomationsStatusUpdatedMessage: '@/modules/automate/helpers/graphTypes#ProjectTriggeredAutomationsStatusUpdatedMessageGraphQLReturn'
|
||||
ProjectAutomationsUpdatedMessage: '@/modules/automate/helpers/graphTypes#ProjectAutomationsUpdatedMessageGraphQLReturn'
|
||||
UserAutomateInfo: '@/modules/automate/helpers/graphTypes#UserAutomateInfoGraphQLReturn'
|
||||
Workspace: '@/modules/workspacesCore/helpers/graphTypes#WorkspaceGraphQLReturn'
|
||||
WorkspaceMutations: '@/modules/core/helpers/graphTypes#MutationsObjectGraphQLReturn'
|
||||
modules/cross-server-sync/graph/generated/graphql.ts:
|
||||
plugins:
|
||||
- 'typescript'
|
||||
|
|
|
@ -5,6 +5,7 @@ import { CommentReplyAuthorCollectionGraphQLReturn, CommentGraphQLReturn } from
|
|||
import { PendingStreamCollaboratorGraphQLReturn } from '@/modules/serverinvites/helpers/graphTypes';
|
||||
import { FileUploadGraphQLReturn } from '@/modules/fileuploads/helpers/types';
|
||||
import { AutomateFunctionGraphQLReturn, AutomateFunctionReleaseGraphQLReturn, AutomationGraphQLReturn, AutomationRevisionGraphQLReturn, AutomationRevisionFunctionGraphQLReturn, AutomateRunGraphQLReturn, AutomationRunTriggerGraphQLReturn, AutomationRevisionTriggerDefinitionGraphQLReturn, AutomateFunctionRunGraphQLReturn, TriggeredAutomationsStatusGraphQLReturn, ProjectAutomationMutationsGraphQLReturn, ProjectTriggeredAutomationsStatusUpdatedMessageGraphQLReturn, ProjectAutomationsUpdatedMessageGraphQLReturn, UserAutomateInfoGraphQLReturn } from '@/modules/automate/helpers/graphTypes';
|
||||
import { WorkspaceGraphQLReturn } from '@/modules/workspacesCore/helpers/graphTypes';
|
||||
import { GraphQLContext } from '@/modules/shared/helpers/typeHelper';
|
||||
export type Maybe<T> = T | null;
|
||||
export type InputMaybe<T> = Maybe<T>;
|
||||
|
@ -3813,6 +3814,7 @@ export type WorkspaceMutations = {
|
|||
deleteRole: Scalars['Boolean']['output'];
|
||||
invites: WorkspaceInviteMutations;
|
||||
update: Workspace;
|
||||
/** TODO: `@hasWorkspaceRole(role: WORKSPACE_ADMIN)` for role changes */
|
||||
updateRole: Scalars['Boolean']['output'];
|
||||
};
|
||||
|
||||
|
@ -4156,14 +4158,14 @@ export type ResolversTypes = {
|
|||
WebhookEvent: ResolverTypeWrapper<WebhookEvent>;
|
||||
WebhookEventCollection: ResolverTypeWrapper<WebhookEventCollection>;
|
||||
WebhookUpdateInput: WebhookUpdateInput;
|
||||
Workspace: ResolverTypeWrapper<Omit<Workspace, 'invitedTeam' | 'projects' | 'team'> & { invitedTeam?: Maybe<Array<ResolversTypes['PendingWorkspaceCollaborator']>>, projects: ResolversTypes['ProjectCollection'], team: Array<ResolversTypes['WorkspaceCollaborator']> }>;
|
||||
Workspace: ResolverTypeWrapper<WorkspaceGraphQLReturn>;
|
||||
WorkspaceCollaborator: ResolverTypeWrapper<Omit<WorkspaceCollaborator, 'user'> & { user: ResolversTypes['LimitedUser'] }>;
|
||||
WorkspaceCollection: ResolverTypeWrapper<Omit<WorkspaceCollection, 'items'> & { items: Array<ResolversTypes['Workspace']> }>;
|
||||
WorkspaceCreateInput: WorkspaceCreateInput;
|
||||
WorkspaceInviteCreateInput: WorkspaceInviteCreateInput;
|
||||
WorkspaceInviteMutations: ResolverTypeWrapper<Omit<WorkspaceInviteMutations, 'batchCreate' | 'cancel' | 'create'> & { batchCreate: ResolversTypes['Workspace'], cancel: ResolversTypes['Workspace'], create: ResolversTypes['Workspace'] }>;
|
||||
WorkspaceInviteUseInput: WorkspaceInviteUseInput;
|
||||
WorkspaceMutations: ResolverTypeWrapper<Omit<WorkspaceMutations, 'create' | 'delete' | 'invites' | 'update'> & { create: ResolversTypes['Workspace'], delete: ResolversTypes['Workspace'], invites: ResolversTypes['WorkspaceInviteMutations'], update: ResolversTypes['Workspace'] }>;
|
||||
WorkspaceMutations: ResolverTypeWrapper<MutationsObjectGraphQLReturn>;
|
||||
WorkspaceRole: WorkspaceRole;
|
||||
WorkspaceRoleDeleteInput: WorkspaceRoleDeleteInput;
|
||||
WorkspaceRoleUpdateInput: WorkspaceRoleUpdateInput;
|
||||
|
@ -4371,14 +4373,14 @@ export type ResolversParentTypes = {
|
|||
WebhookEvent: WebhookEvent;
|
||||
WebhookEventCollection: WebhookEventCollection;
|
||||
WebhookUpdateInput: WebhookUpdateInput;
|
||||
Workspace: Omit<Workspace, 'invitedTeam' | 'projects' | 'team'> & { invitedTeam?: Maybe<Array<ResolversParentTypes['PendingWorkspaceCollaborator']>>, projects: ResolversParentTypes['ProjectCollection'], team: Array<ResolversParentTypes['WorkspaceCollaborator']> };
|
||||
Workspace: WorkspaceGraphQLReturn;
|
||||
WorkspaceCollaborator: Omit<WorkspaceCollaborator, 'user'> & { user: ResolversParentTypes['LimitedUser'] };
|
||||
WorkspaceCollection: Omit<WorkspaceCollection, 'items'> & { items: Array<ResolversParentTypes['Workspace']> };
|
||||
WorkspaceCreateInput: WorkspaceCreateInput;
|
||||
WorkspaceInviteCreateInput: WorkspaceInviteCreateInput;
|
||||
WorkspaceInviteMutations: Omit<WorkspaceInviteMutations, 'batchCreate' | 'cancel' | 'create'> & { batchCreate: ResolversParentTypes['Workspace'], cancel: ResolversParentTypes['Workspace'], create: ResolversParentTypes['Workspace'] };
|
||||
WorkspaceInviteUseInput: WorkspaceInviteUseInput;
|
||||
WorkspaceMutations: Omit<WorkspaceMutations, 'create' | 'delete' | 'invites' | 'update'> & { create: ResolversParentTypes['Workspace'], delete: ResolversParentTypes['Workspace'], invites: ResolversParentTypes['WorkspaceInviteMutations'], update: ResolversParentTypes['Workspace'] };
|
||||
WorkspaceMutations: MutationsObjectGraphQLReturn;
|
||||
WorkspaceRoleDeleteInput: WorkspaceRoleDeleteInput;
|
||||
WorkspaceRoleUpdateInput: WorkspaceRoleUpdateInput;
|
||||
WorkspaceUpdateInput: WorkspaceUpdateInput;
|
||||
|
|
|
@ -3803,6 +3803,7 @@ export type WorkspaceMutations = {
|
|||
deleteRole: Scalars['Boolean']['output'];
|
||||
invites: WorkspaceInviteMutations;
|
||||
update: Workspace;
|
||||
/** TODO: `@hasWorkspaceRole(role: WORKSPACE_ADMIN)` for role changes */
|
||||
updateRole: Scalars['Boolean']['output'];
|
||||
};
|
||||
|
||||
|
|
|
@ -100,11 +100,13 @@ async function authorizeResolver(
|
|||
}
|
||||
|
||||
try {
|
||||
const { isPublic } = await knex(role.resourceTarget)
|
||||
.select('isPublic')
|
||||
.where({ id: resourceId })
|
||||
.first()
|
||||
if (isPublic && role.weight < 200) return true
|
||||
if (role.resourceTarget !== 'workspace') {
|
||||
const { isPublic } = await knex(role.resourceTarget)
|
||||
.select('isPublic')
|
||||
.where({ id: resourceId })
|
||||
.first()
|
||||
if (isPublic && role.weight < 200) return true
|
||||
}
|
||||
} catch {
|
||||
throw new ForbiddenError(
|
||||
`Resource of type ${role.resourceTarget} with ${resourceId} not found`
|
||||
|
|
|
@ -116,7 +116,7 @@ export function initializeEventBus() {
|
|||
}
|
||||
}
|
||||
|
||||
type EventBus = ReturnType<typeof initializeEventBus>
|
||||
export type EventBus = ReturnType<typeof initializeEventBus>
|
||||
|
||||
let eventBus: EventBus
|
||||
|
||||
|
|
|
@ -11,11 +11,23 @@ export class WorkspaceInvalidRoleError extends BaseError {
|
|||
static code = 'WORKSPACE_INVALID_ROLE_ERROR'
|
||||
}
|
||||
|
||||
export class WorkspaceNotFoundError extends BaseError {
|
||||
static defaultMessage = 'Workspace not found'
|
||||
static code = 'WORKSAPCE_NOT_FOUND_ERROR'
|
||||
static statusCode = 404
|
||||
}
|
||||
|
||||
export class WorkspaceQueryError extends BaseError {
|
||||
static defaultMessage = 'Unexpected error during query operation'
|
||||
static code = 'WORKSPACE_QUERY_ERROR'
|
||||
}
|
||||
|
||||
export class WorkspacesNotAuthorizedError extends BaseError {
|
||||
static defaultMessage = 'You are not authorized'
|
||||
static code = 'WORKSPACES_NOT_AUTHORIZED_ERROR'
|
||||
static statusCode = 401
|
||||
}
|
||||
|
||||
export class WorkspacesNotYetImplementedError extends BaseError {
|
||||
static defaultMessage = 'Not yet implemented'
|
||||
static code = 'WORKSPACES_NOT_YET_IMPLEMENTED_ERROR'
|
||||
|
|
|
@ -1,26 +1,101 @@
|
|||
import { Resolvers } from '@/modules/core/graph/generated/graphql'
|
||||
import { getFeatureFlags } from '@/modules/shared/helpers/envHelper'
|
||||
import { WorkspacesNotYetImplementedError } from '@/modules/workspaces/errors/workspace'
|
||||
import {
|
||||
WorkspaceNotFoundError,
|
||||
WorkspacesNotAuthorizedError,
|
||||
WorkspacesNotYetImplementedError
|
||||
} from '@/modules/workspaces/errors/workspace'
|
||||
import {
|
||||
getWorkspaceFactory,
|
||||
getWorkspaceRolesForUserFactory,
|
||||
upsertWorkspaceFactory,
|
||||
upsertWorkspaceRoleFactory
|
||||
} from '@/modules/workspaces/repositories/workspaces'
|
||||
import {
|
||||
createWorkspaceFactory,
|
||||
updateWorkspaceFactory
|
||||
} from '@/modules/workspaces/services/management'
|
||||
import db from '@/db/knex'
|
||||
import { getEventBus } from '@/modules/shared/services/eventBus'
|
||||
import { getWorkspacesForUserFactory } from '@/modules/workspaces/services/retrieval'
|
||||
|
||||
const { FF_WORKSPACES_MODULE_ENABLED } = getFeatureFlags()
|
||||
|
||||
export = FF_WORKSPACES_MODULE_ENABLED
|
||||
? ({
|
||||
Query: {
|
||||
workspace: async () => {
|
||||
// Get workspace by id
|
||||
throw new WorkspacesNotYetImplementedError()
|
||||
workspace: async (_parent, args) => {
|
||||
const { id: workspaceId } = args
|
||||
|
||||
// TODO: Use dataloader
|
||||
const workspace = await getWorkspaceFactory({ db })({ workspaceId })
|
||||
|
||||
if (!workspace) {
|
||||
throw new WorkspaceNotFoundError()
|
||||
}
|
||||
|
||||
return workspace
|
||||
}
|
||||
},
|
||||
Mutation: {
|
||||
workspaceMutations: () => ({})
|
||||
},
|
||||
WorkspaceMutations: {
|
||||
create: async () => {
|
||||
throw new WorkspacesNotYetImplementedError()
|
||||
create: async (_parent, args, context) => {
|
||||
const { name, description, logoUrl } = args.input
|
||||
|
||||
const { emit: emitWorkspaceEvent } = getEventBus()
|
||||
|
||||
const upsertWorkspace = upsertWorkspaceFactory({ db })
|
||||
const upsertWorkspaceRole = upsertWorkspaceRoleFactory({ db })
|
||||
// TODO: Integrate with blobstorage
|
||||
const storeBlob = async () => ''
|
||||
|
||||
const createWorkspace = createWorkspaceFactory({
|
||||
upsertWorkspace,
|
||||
upsertWorkspaceRole,
|
||||
emitWorkspaceEvent,
|
||||
storeBlob
|
||||
})
|
||||
|
||||
const workspace = await createWorkspace({
|
||||
userId: context.userId!,
|
||||
workspaceInput: {
|
||||
name,
|
||||
description: description ?? null,
|
||||
logoUrl: logoUrl ?? null
|
||||
}
|
||||
})
|
||||
|
||||
return workspace
|
||||
},
|
||||
delete: async () => {
|
||||
throw new WorkspacesNotYetImplementedError()
|
||||
},
|
||||
update: async () => {
|
||||
throw new WorkspacesNotYetImplementedError()
|
||||
update: async (_parent, args, context) => {
|
||||
const { id: workspaceId, ...workspaceInput } = args.input
|
||||
|
||||
const { emit: emitWorkspaceEvent } = getEventBus()
|
||||
|
||||
const getWorkspace = getWorkspaceFactory({ db })
|
||||
const upsertWorkspace = upsertWorkspaceFactory({ db })
|
||||
// TODO: Integrate with blobstorage
|
||||
const storeBlob = async () => ''
|
||||
|
||||
const updateWorkspace = updateWorkspaceFactory({
|
||||
getWorkspace,
|
||||
upsertWorkspace,
|
||||
emitWorkspaceEvent,
|
||||
storeBlob
|
||||
})
|
||||
|
||||
const workspace = await updateWorkspace({
|
||||
workspaceId,
|
||||
workspaceInput,
|
||||
workspaceUpdaterId: context.userId!
|
||||
})
|
||||
|
||||
return workspace
|
||||
},
|
||||
updateRole: async () => {
|
||||
throw new WorkspacesNotYetImplementedError()
|
||||
|
@ -62,9 +137,26 @@ export = FF_WORKSPACES_MODULE_ENABLED
|
|||
}
|
||||
},
|
||||
User: {
|
||||
workspaces: async () => {
|
||||
// Get roles for user, get workspaces
|
||||
throw new WorkspacesNotYetImplementedError()
|
||||
workspaces: async (_parent, _args, context) => {
|
||||
if (!context.userId) {
|
||||
throw new WorkspacesNotAuthorizedError()
|
||||
}
|
||||
|
||||
const getWorkspace = getWorkspaceFactory({ db })
|
||||
const getWorkspaceRolesForUser = getWorkspaceRolesForUserFactory({ db })
|
||||
|
||||
const getWorkspacesForUser = getWorkspacesForUserFactory({
|
||||
getWorkspace,
|
||||
getWorkspaceRolesForUser
|
||||
})
|
||||
|
||||
const workspaces = await getWorkspacesForUser({ userId: context.userId })
|
||||
|
||||
// TODO: Pagination
|
||||
return {
|
||||
items: workspaces,
|
||||
totalCount: workspaces.length
|
||||
}
|
||||
}
|
||||
},
|
||||
Project: {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { WorkspaceEvents } from '@/modules/workspacesCore/domain/events'
|
||||
import {
|
||||
EmitWorkspaceEvent,
|
||||
GetWorkspace,
|
||||
StoreBlob,
|
||||
UpsertWorkspace,
|
||||
UpsertWorkspaceRole
|
||||
|
@ -18,14 +19,34 @@ import {
|
|||
GetWorkspaceRoleForUser,
|
||||
GetWorkspaceRoles
|
||||
} from '@/modules/workspaces/domain/operations'
|
||||
import { WorkspaceAdminRequiredError } from '@/modules/workspaces/errors/workspace'
|
||||
import {
|
||||
WorkspaceAdminRequiredError,
|
||||
WorkspaceNotFoundError
|
||||
} from '@/modules/workspaces/errors/workspace'
|
||||
import { isUserLastWorkspaceAdmin } from '@/modules/workspaces/utils/roles'
|
||||
import { mapWorkspaceRoleToProjectRole } from '@/modules/workspaces/domain/roles'
|
||||
import { queryAllWorkspaceProjectsFactory } from '@/modules/workspaces/services/projects'
|
||||
import { EventBus } from '@/modules/shared/services/eventBus'
|
||||
import { removeNullOrUndefinedKeys } from '@speckle/shared'
|
||||
import { authorizeResolver } from '@/modules/shared'
|
||||
|
||||
const tryStoreBlobFactory =
|
||||
(storeBlob: StoreBlob) =>
|
||||
async (blob?: string | null): Promise<string | null> => {
|
||||
let logoUrl: string | null = null
|
||||
if (blob) {
|
||||
logoUrl = await storeBlob(blob)
|
||||
}
|
||||
return logoUrl
|
||||
}
|
||||
|
||||
type WorkspaceCreateArgs = {
|
||||
workspaceInput: { name: string; description: string | null; logo: string | null }
|
||||
userId: string
|
||||
workspaceInput: {
|
||||
name: string
|
||||
description: string | null
|
||||
logoUrl: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export const createWorkspaceFactory =
|
||||
|
@ -37,14 +58,11 @@ export const createWorkspaceFactory =
|
|||
}: {
|
||||
upsertWorkspace: UpsertWorkspace
|
||||
upsertWorkspaceRole: UpsertWorkspaceRole
|
||||
emitWorkspaceEvent: EventBus['emit']
|
||||
storeBlob: StoreBlob
|
||||
emitWorkspaceEvent: EmitWorkspaceEvent
|
||||
}) =>
|
||||
async ({ userId, workspaceInput }: WorkspaceCreateArgs): Promise<Workspace> => {
|
||||
let logoUrl: string | null = null
|
||||
if (workspaceInput.logo) {
|
||||
logoUrl = await storeBlob(workspaceInput.logo)
|
||||
}
|
||||
const logoUrl = await tryStoreBlobFactory(storeBlob)(workspaceInput.logoUrl)
|
||||
|
||||
const workspace = {
|
||||
...workspaceInput,
|
||||
|
@ -70,6 +88,57 @@ export const createWorkspaceFactory =
|
|||
return workspace
|
||||
}
|
||||
|
||||
type WorkspaceUpdateArgs = {
|
||||
/** Id of user performing the operation */
|
||||
workspaceUpdaterId: string
|
||||
workspaceId: string
|
||||
workspaceInput: {
|
||||
name?: string | null
|
||||
description?: string | null
|
||||
logoUrl?: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export const updateWorkspaceFactory =
|
||||
({
|
||||
getWorkspace,
|
||||
upsertWorkspace,
|
||||
emitWorkspaceEvent,
|
||||
storeBlob
|
||||
}: {
|
||||
getWorkspace: GetWorkspace
|
||||
upsertWorkspace: UpsertWorkspace
|
||||
emitWorkspaceEvent: EventBus['emit']
|
||||
storeBlob: StoreBlob
|
||||
}) =>
|
||||
async ({
|
||||
workspaceUpdaterId,
|
||||
workspaceId,
|
||||
workspaceInput
|
||||
}: WorkspaceUpdateArgs): Promise<Workspace> => {
|
||||
await authorizeResolver(workspaceUpdaterId, workspaceId, Roles.Workspace.Admin)
|
||||
|
||||
const currentWorkspace = await getWorkspace({ workspaceId })
|
||||
|
||||
if (!currentWorkspace) {
|
||||
throw new WorkspaceNotFoundError()
|
||||
}
|
||||
|
||||
const logoUrl = await tryStoreBlobFactory(storeBlob)(workspaceInput.logoUrl)
|
||||
|
||||
const workspace = {
|
||||
...currentWorkspace,
|
||||
...removeNullOrUndefinedKeys(workspaceInput),
|
||||
updatedAt: new Date(),
|
||||
logoUrl
|
||||
}
|
||||
|
||||
await upsertWorkspace({ workspace })
|
||||
await emitWorkspaceEvent({ eventName: WorkspaceEvents.Updated, payload: workspace })
|
||||
|
||||
return workspace
|
||||
}
|
||||
|
||||
type WorkspaceRoleDeleteArgs = {
|
||||
userId: string
|
||||
workspaceId: string
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import {
|
||||
GetWorkspace,
|
||||
GetWorkspaceRolesForUser
|
||||
} from '@/modules/workspaces/domain/operations'
|
||||
import { Workspace } from '@/modules/workspacesCore/domain/types'
|
||||
import { chunk, isNull } from 'lodash'
|
||||
|
||||
type GetWorkspacesForUserArgs = {
|
||||
userId: string
|
||||
}
|
||||
|
||||
export const getWorkspacesForUserFactory =
|
||||
({
|
||||
getWorkspace,
|
||||
getWorkspaceRolesForUser
|
||||
}: {
|
||||
getWorkspace: GetWorkspace
|
||||
getWorkspaceRolesForUser: GetWorkspaceRolesForUser
|
||||
}) =>
|
||||
async ({ userId }: GetWorkspacesForUserArgs): Promise<Workspace[]> => {
|
||||
const workspaceRoles = await getWorkspaceRolesForUser({ userId })
|
||||
|
||||
const workspaces: Workspace[] = []
|
||||
|
||||
for (const workspaceRoleBatch of chunk(workspaceRoles, 20)) {
|
||||
// TODO: Use `getWorkspaces`, which I saw Fabians already wrote in another PR
|
||||
const workspacesBatch = await Promise.all(
|
||||
workspaceRoleBatch.map(({ workspaceId }) => getWorkspace({ workspaceId }))
|
||||
)
|
||||
workspaces.push(
|
||||
...workspacesBatch.filter(
|
||||
(workspace): workspace is Workspace => !isNull(workspace)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return workspaces
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
import { expect } from 'chai'
|
||||
import cryptoRandomString from 'crypto-random-string'
|
||||
import {
|
||||
createTestContext,
|
||||
testApolloServer,
|
||||
TestApolloServer
|
||||
} from '@/test/graphqlHelper'
|
||||
import {
|
||||
BasicTestUser,
|
||||
createAuthTokenForUser,
|
||||
createTestUser
|
||||
} from '@/test/authHelper'
|
||||
import { AllScopes, Roles } from '@speckle/shared'
|
||||
import {
|
||||
CreateWorkspaceDocument,
|
||||
GetActiveUserWorkspacesDocument,
|
||||
GetWorkspaceDocument,
|
||||
UpdateWorkspaceDocument
|
||||
} from '@/test/graphql/generated/graphql'
|
||||
import { Workspace } from '@/modules/workspacesCore/domain/types'
|
||||
|
||||
describe('workspaces module gql operations', () => {
|
||||
let apollo: TestApolloServer
|
||||
|
||||
const testUser: BasicTestUser = {
|
||||
id: '',
|
||||
name: 'John Speckle',
|
||||
email: 'john-speckle@example.org',
|
||||
role: Roles.Server.Admin
|
||||
}
|
||||
|
||||
before(async () => {
|
||||
await createTestUser(testUser)
|
||||
const token = await createAuthTokenForUser(testUser.id, AllScopes)
|
||||
apollo = await testApolloServer({
|
||||
context: createTestContext({
|
||||
auth: true,
|
||||
userId: testUser.id,
|
||||
token,
|
||||
role: testUser.role,
|
||||
scopes: AllScopes
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('retrieval operations', () => {
|
||||
const workspaceIds: string[] = []
|
||||
|
||||
before(async () => {
|
||||
const workspaces: Pick<Workspace, 'name'>[] = [
|
||||
{ name: 'Workspace A' },
|
||||
{ name: 'Workspace B' }
|
||||
]
|
||||
|
||||
const results = await Promise.all(
|
||||
workspaces.map((workspace) =>
|
||||
apollo.execute(CreateWorkspaceDocument, { input: workspace })
|
||||
)
|
||||
)
|
||||
|
||||
for (const result of results) {
|
||||
workspaceIds.push(result.data!.workspaceMutations.create.id)
|
||||
}
|
||||
})
|
||||
|
||||
describe('query workspace', () => {
|
||||
it('should return a workspace that exists', async () => {
|
||||
const res = await apollo.execute(GetWorkspaceDocument, {
|
||||
workspaceId: workspaceIds[0]
|
||||
})
|
||||
|
||||
expect(res).to.not.haveGraphQLErrors()
|
||||
expect(res.data?.workspace).to.exist
|
||||
})
|
||||
|
||||
it('throw a not found error if the workspace does not exist', async () => {
|
||||
const res = await apollo.execute(GetWorkspaceDocument, {
|
||||
workspaceId: cryptoRandomString({ length: 6 })
|
||||
})
|
||||
expect(res).to.haveGraphQLErrors('not found')
|
||||
})
|
||||
})
|
||||
|
||||
describe('query activeUser.workspaces', () => {
|
||||
it('should return all workspaces for a user', async () => {
|
||||
const res = await apollo.execute(GetActiveUserWorkspacesDocument, {})
|
||||
|
||||
expect(res).to.not.haveGraphQLErrors()
|
||||
expect(res.data?.activeUser?.workspaces?.items?.length).to.above(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('management operations', () => {
|
||||
describe('mutation workspaceMutations.create', () => {
|
||||
it('should create a workspace', async () => {
|
||||
const workspaceName = cryptoRandomString({ length: 6 })
|
||||
|
||||
const createRes = await apollo.execute(CreateWorkspaceDocument, {
|
||||
input: { name: workspaceName }
|
||||
})
|
||||
const getRes = await apollo.execute(GetWorkspaceDocument, {
|
||||
workspaceId: createRes.data!.workspaceMutations.create.id
|
||||
})
|
||||
|
||||
expect(createRes).to.not.haveGraphQLErrors()
|
||||
expect(getRes).to.not.haveGraphQLErrors()
|
||||
expect(getRes.data?.workspace).to.exist
|
||||
expect(getRes.data?.workspace?.name).to.equal(workspaceName)
|
||||
})
|
||||
})
|
||||
|
||||
describe('mutation workspaceMutations.update', () => {
|
||||
it('should update a workspace', async () => {
|
||||
const createRes = await apollo.execute(CreateWorkspaceDocument, {
|
||||
input: { name: cryptoRandomString({ length: 6 }) }
|
||||
})
|
||||
|
||||
const workspaceName = cryptoRandomString({ length: 6 })
|
||||
|
||||
await apollo.execute(UpdateWorkspaceDocument, {
|
||||
input: {
|
||||
id: createRes.data!.workspaceMutations.create.id,
|
||||
name: workspaceName
|
||||
}
|
||||
})
|
||||
|
||||
const getRes = await apollo.execute(GetWorkspaceDocument, {
|
||||
workspaceId: createRes.data!.workspaceMutations.create.id
|
||||
})
|
||||
|
||||
expect(createRes).to.not.haveGraphQLErrors()
|
||||
expect(getRes).to.not.haveGraphQLErrors()
|
||||
expect(getRes.data?.workspace.name).to.equal(workspaceName)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -61,7 +61,7 @@ const getCreateWorkspaceInput = () => {
|
|||
userId: cryptoRandomString({ length: 10 }),
|
||||
workspaceInput: {
|
||||
description: 'foobar',
|
||||
logo: null,
|
||||
logoUrl: null,
|
||||
name: cryptoRandomString({ length: 6 })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ const workspaceEventPrefix = `${workspaceEventNamespace}.` as const
|
|||
|
||||
export const WorkspaceEvents = {
|
||||
Created: `${workspaceEventPrefix}created`,
|
||||
Updated: `${workspaceEventPrefix}updated`,
|
||||
RoleDeleted: `${workspaceEventPrefix}role-deleted`,
|
||||
RoleUpdated: `${workspaceEventPrefix}role-updated`
|
||||
} as const
|
||||
|
@ -15,11 +16,13 @@ export type WorkspaceEvents = (typeof WorkspaceEvents)[keyof typeof WorkspaceEve
|
|||
type WorkspaceCreatedPayload = Workspace & {
|
||||
createdByUserId: string
|
||||
}
|
||||
type WorkspaceUpdatedPayload = Workspace
|
||||
type WorkspaceRoleDeletedPayload = WorkspaceAcl
|
||||
type WorkspaceRoleUpdatedPayload = WorkspaceAcl
|
||||
|
||||
export type WorkspaceEventsPayloads = {
|
||||
[WorkspaceEvents.Created]: WorkspaceCreatedPayload
|
||||
[WorkspaceEvents.Updated]: WorkspaceUpdatedPayload
|
||||
[WorkspaceEvents.RoleDeleted]: WorkspaceRoleDeletedPayload
|
||||
[WorkspaceEvents.RoleUpdated]: WorkspaceRoleUpdatedPayload
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import { Workspace } from '@/modules/workspacesCore/domain/types'
|
||||
|
||||
export type WorkspaceGraphQLReturn = Workspace
|
|
@ -3804,6 +3804,7 @@ export type WorkspaceMutations = {
|
|||
deleteRole: Scalars['Boolean']['output'];
|
||||
invites: WorkspaceInviteMutations;
|
||||
update: Workspace;
|
||||
/** TODO: `@hasWorkspaceRole(role: WORKSPACE_ADMIN)` for role changes */
|
||||
updateRole: Scalars['Boolean']['output'];
|
||||
};
|
||||
|
||||
|
@ -4314,6 +4315,34 @@ export type MarkProjectVersionReceivedMutationVariables = Exact<{
|
|||
|
||||
export type MarkProjectVersionReceivedMutation = { __typename?: 'Mutation', versionMutations: { __typename?: 'VersionMutations', markReceived: boolean } };
|
||||
|
||||
export type TestWorkspaceFragment = { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string };
|
||||
|
||||
export type CreateWorkspaceMutationVariables = Exact<{
|
||||
input: WorkspaceCreateInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateWorkspaceMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', create: { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string } } };
|
||||
|
||||
export type GetWorkspaceQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type GetWorkspaceQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type UpdateWorkspaceMutationVariables = Exact<{
|
||||
input: WorkspaceUpdateInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateWorkspaceMutation = { __typename?: 'Mutation', workspaceMutations: { __typename?: 'WorkspaceMutations', update: { __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string } } };
|
||||
|
||||
export type GetActiveUserWorkspacesQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type GetActiveUserWorkspacesQuery = { __typename?: 'Query', activeUser?: { __typename?: 'User', workspaces: { __typename?: 'WorkspaceCollection', items: Array<{ __typename?: 'Workspace', id: string, name: string, description?: string | null, createdAt: string, updatedAt: string }> } } | null };
|
||||
|
||||
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":"automationCount"}},{"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>;
|
||||
|
@ -4325,6 +4354,7 @@ export const StreamInviteDataFragmentDoc = {"kind":"Document","definitions":[{"k
|
|||
export const BasicStreamFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BasicStreamFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Stream"}},"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":"isPublic"}},{"kind":"Field","name":{"kind":"Name","value":"isDiscoverable"}},{"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<BasicStreamFieldsFragment, unknown>;
|
||||
export const BaseUserFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BaseUserFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"bio"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"verified"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]} as unknown as DocumentNode<BaseUserFieldsFragment, unknown>;
|
||||
export const BaseLimitedUserFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BaseLimitedUserFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedUser"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"bio"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"verified"}}]}}]} as unknown as DocumentNode<BaseLimitedUserFieldsFragment, unknown>;
|
||||
export const TestWorkspaceFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"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":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<TestWorkspaceFragment, unknown>;
|
||||
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>;
|
||||
|
@ -4383,4 +4413,8 @@ export const GetAdminUsersDocument = {"kind":"Document","definitions":[{"kind":"
|
|||
export const GetPendingEmailVerificationStatusDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPendingEmailVerificationStatus"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"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":"hasPendingVerification"}}]}}]}}]} as unknown as DocumentNode<GetPendingEmailVerificationStatusQuery, GetPendingEmailVerificationStatusQueryVariables>;
|
||||
export const RequestVerificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RequestVerification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"requestVerification"}}]}}]} as unknown as DocumentNode<RequestVerificationMutation, RequestVerificationMutationVariables>;
|
||||
export const CreateProjectVersionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateProjectVersion"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateVersionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"versionMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create"},"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":"message"}},{"kind":"Field","name":{"kind":"Name","value":"sourceApplication"}},{"kind":"Field","name":{"kind":"Name","value":"model"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"referencedObject"}}]}}]}}]}}]} as unknown as DocumentNode<CreateProjectVersionMutation, CreateProjectVersionMutationVariables>;
|
||||
export const MarkProjectVersionReceivedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MarkProjectVersionReceived"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MarkReceivedVersionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"versionMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"markReceived"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]}}]} as unknown as DocumentNode<MarkProjectVersionReceivedMutation, MarkProjectVersionReceivedMutationVariables>;
|
||||
export const MarkProjectVersionReceivedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MarkProjectVersionReceived"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MarkReceivedVersionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"versionMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"markReceived"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]}}]} as unknown as DocumentNode<MarkProjectVersionReceivedMutation, MarkProjectVersionReceivedMutationVariables>;
|
||||
export const CreateWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceCreateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create"},"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":"TestWorkspace"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"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":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<CreateWorkspaceMutation, CreateWorkspaceMutationVariables>;
|
||||
export const GetWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"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":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspace"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"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":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<GetWorkspaceQuery, GetWorkspaceQueryVariables>;
|
||||
export const UpdateWorkspaceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateWorkspace"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"WorkspaceUpdateInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"update"},"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":"TestWorkspace"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"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":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<UpdateWorkspaceMutation, UpdateWorkspaceMutationVariables>;
|
||||
export const GetActiveUserWorkspacesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetActiveUserWorkspaces"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaces"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TestWorkspace"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TestWorkspace"},"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":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<GetActiveUserWorkspacesQuery, GetActiveUserWorkspacesQueryVariables>;
|
|
@ -0,0 +1,55 @@
|
|||
import { gql } from 'apollo-server-express'
|
||||
|
||||
export const workspaceFragment = gql`
|
||||
fragment TestWorkspace on Workspace {
|
||||
id
|
||||
name
|
||||
description
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
`
|
||||
|
||||
export const createWorkspaceQuery = gql`
|
||||
mutation CreateWorkspace($input: WorkspaceCreateInput!) {
|
||||
workspaceMutations {
|
||||
create(input: $input) {
|
||||
...TestWorkspace
|
||||
}
|
||||
}
|
||||
}
|
||||
${workspaceFragment}
|
||||
`
|
||||
|
||||
export const getWorkspaceQuery = gql`
|
||||
query GetWorkspace($workspaceId: String!) {
|
||||
workspace(id: $workspaceId) {
|
||||
...TestWorkspace
|
||||
}
|
||||
}
|
||||
${workspaceFragment}
|
||||
`
|
||||
|
||||
export const updateWorkspaceQuery = gql`
|
||||
mutation UpdateWorkspace($input: WorkspaceUpdateInput!) {
|
||||
workspaceMutations {
|
||||
update(input: $input) {
|
||||
...TestWorkspace
|
||||
}
|
||||
}
|
||||
}
|
||||
${workspaceFragment}
|
||||
`
|
||||
|
||||
export const getActiveUserWorkspacesQuery = gql`
|
||||
query GetActiveUserWorkspaces {
|
||||
activeUser {
|
||||
workspaces {
|
||||
items {
|
||||
...TestWorkspace
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${workspaceFragment}
|
||||
`
|
Загрузка…
Ссылка в новой задаче