From 39c34b1b78227c55e5dbf092f8ca96aec7e639b2 Mon Sep 17 00:00:00 2001 From: Chuck Driesler Date: Mon, 2 Sep 2024 15:23:27 +0100 Subject: [PATCH] fix(workspaces): safer billing query for guests (#2844) * fix(workspaces): safer billing query for guests * chore(workspaces): comment * chore(workspaces): lint * chore(workspaces): ope --- .../components/settings/workspaces/Billing.vue | 16 +++++++++++++--- .../components/workspace/ProjectList.vue | 2 +- .../components/workspace/header/Header.vue | 5 ++++- .../lib/common/generated/gql/graphql.ts | 10 +++++----- .../workspacesCore/typedefs/workspaces.graphql | 2 +- packages/server/codegen.yml | 1 + .../modules/core/graph/generated/graphql.ts | 10 +++++----- .../graph/generated/graphql.ts | 2 +- .../workspaces/graph/resolvers/workspaces.ts | 18 ++++++------------ .../tests/integration/workspaces.graph.spec.ts | 4 ++-- .../workspacesCore/helpers/graphTypes.ts | 1 + .../server/test/graphql/generated/graphql.ts | 6 +++--- 12 files changed, 43 insertions(+), 34 deletions(-) diff --git a/packages/frontend-2/components/settings/workspaces/Billing.vue b/packages/frontend-2/components/settings/workspaces/Billing.vue index ccccc8547..dae720d2f 100644 --- a/packages/frontend-2/components/settings/workspaces/Billing.vue +++ b/packages/frontend-2/components/settings/workspaces/Billing.vue @@ -59,6 +59,7 @@ import { graphql } from '~/lib/common/generated/gql' import { useQuery } from '@vue/apollo-composable' import { settingsWorkspaceBillingQuery } from '~/lib/settings/graphql/queries' +import { skipLoggingErrorsIfOneFieldError } from '~/lib/common/helpers/graphql' graphql(` fragment SettingsWorkspacesBilling_Workspace on Workspace { @@ -80,9 +81,18 @@ const props = defineProps<{ workspaceId: string }>() -const { result } = useQuery(settingsWorkspaceBillingQuery, () => ({ - workspaceId: props.workspaceId -})) +const { result } = useQuery( + settingsWorkspaceBillingQuery, + () => ({ + workspaceId: props.workspaceId + }), + () => ({ + errorPolicy: 'all', + context: { + skipLoggingErrors: skipLoggingErrorsIfOneFieldError('billing') + } + }) +) const billing = computed(() => result.value?.workspace.billing) const versionCount = computed(() => billing.value?.versionsCount) diff --git a/packages/frontend-2/components/workspace/ProjectList.vue b/packages/frontend-2/components/workspace/ProjectList.vue index 164adbe50..f2de9f8ee 100644 --- a/packages/frontend-2/components/workspace/ProjectList.vue +++ b/packages/frontend-2/components/workspace/ProjectList.vue @@ -114,7 +114,7 @@ const { result: initialQueryResult } = useQuery( // doesn't kill the entire query errorPolicy: 'all', context: { - skipLoggingErrors: skipLoggingErrorsIfOneFieldError('invitedTeam') + skipLoggingErrors: skipLoggingErrorsIfOneFieldError(['invitedTeam', 'billing']) } }) ) diff --git a/packages/frontend-2/components/workspace/header/Header.vue b/packages/frontend-2/components/workspace/header/Header.vue index 41ab9610f..c14185861 100644 --- a/packages/frontend-2/components/workspace/header/Header.vue +++ b/packages/frontend-2/components/workspace/header/Header.vue @@ -40,7 +40,10 @@
-
+
diff --git a/packages/frontend-2/lib/common/generated/gql/graphql.ts b/packages/frontend-2/lib/common/generated/gql/graphql.ts index da423f6b8..fb5578c41 100644 --- a/packages/frontend-2/lib/common/generated/gql/graphql.ts +++ b/packages/frontend-2/lib/common/generated/gql/graphql.ts @@ -3857,7 +3857,7 @@ export type WebhookUpdateInput = { export type Workspace = { __typename?: 'Workspace'; /** Billing data for Workspaces beta */ - billing: WorkspaceBilling; + billing?: Maybe; createdAt: Scalars['DateTime']['output']; /** Selected fallback when `logo` not set */ defaultLogoIndex: Scalars['Int']['output']; @@ -4364,7 +4364,7 @@ export type SettingsUserProfileDetails_UserFragment = { __typename?: 'User', id: export type UserProfileEditDialogAvatar_UserFragment = { __typename?: 'User', id: string, avatar?: string | null, name: string }; -export type SettingsWorkspacesBilling_WorkspaceFragment = { __typename?: 'Workspace', billing: { __typename?: 'WorkspaceBilling', cost: { __typename?: 'WorkspaceCost', subTotal: number, total: number, items: Array<{ __typename?: 'WorkspaceCostItem', cost: number, count: number, name: string }>, discount?: { __typename?: 'WorkspaceCostDiscount', amount: number, name: string } | null }, versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number } } }; +export type SettingsWorkspacesBilling_WorkspaceFragment = { __typename?: 'Workspace', billing?: { __typename?: 'WorkspaceBilling', cost: { __typename?: 'WorkspaceCost', subTotal: number, total: number, items: Array<{ __typename?: 'WorkspaceCostItem', cost: number, count: number, name: string }>, discount?: { __typename?: 'WorkspaceCostDiscount', amount: number, name: string } | null }, versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number } } | null }; export type SettingsWorkspacesGeneral_WorkspaceFragment = { __typename?: 'Workspace', id: string, name: string, description?: string | null, logo?: string | null, role?: string | null, defaultLogoIndex: number }; @@ -4412,7 +4412,7 @@ export type WorkspaceInviteDialog_WorkspaceFragment = { __typename?: 'Workspace' export type WorkspaceProjectList_ProjectCollectionFragment = { __typename?: 'ProjectCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null }> }, workspace?: { __typename?: 'Workspace', id: string, name: string, logo?: string | null, defaultLogoIndex: number } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }> }> }; -export type WorkspaceHeader_WorkspaceFragment = { __typename?: 'Workspace', id: string, role?: string | null, name: string, logo?: string | null, description?: string | null, defaultLogoIndex: number, domainBasedMembershipProtectionEnabled: boolean, totalProjects: { __typename?: 'ProjectCollection', totalCount: number }, billing: { __typename?: 'WorkspaceBilling', versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number } }, team: { __typename?: 'WorkspaceCollaboratorCollection', items: Array<{ __typename?: 'WorkspaceCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }> }, domains: Array<{ __typename?: 'WorkspaceDomain', domain: string, id: string }>, invitedTeam?: Array<{ __typename?: 'PendingWorkspaceCollaborator', title: string, user?: { __typename?: 'LimitedUser', id: string } | null }> | null }; +export type WorkspaceHeader_WorkspaceFragment = { __typename?: 'Workspace', id: string, role?: string | null, name: string, logo?: string | null, description?: string | null, defaultLogoIndex: number, domainBasedMembershipProtectionEnabled: boolean, totalProjects: { __typename?: 'ProjectCollection', totalCount: number }, billing?: { __typename?: 'WorkspaceBilling', versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number } } | null, team: { __typename?: 'WorkspaceCollaboratorCollection', items: Array<{ __typename?: 'WorkspaceCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }> }, domains: Array<{ __typename?: 'WorkspaceDomain', domain: string, id: string }>, invitedTeam?: Array<{ __typename?: 'PendingWorkspaceCollaborator', title: string, user?: { __typename?: 'LimitedUser', id: string } | null }> | null }; export type WorkspaceInviteBanner_PendingWorkspaceCollaboratorFragment = { __typename?: 'PendingWorkspaceCollaborator', id: string, workspaceId: string, workspaceName: string, token?: string | null, invitedBy: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null }, user?: { __typename?: 'LimitedUser', id: string } | null }; @@ -5318,7 +5318,7 @@ export type SettingsWorkspaceBillingQueryVariables = Exact<{ }>; -export type SettingsWorkspaceBillingQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, billing: { __typename?: 'WorkspaceBilling', cost: { __typename?: 'WorkspaceCost', subTotal: number, total: number, items: Array<{ __typename?: 'WorkspaceCostItem', cost: number, count: number, name: string }>, discount?: { __typename?: 'WorkspaceCostDiscount', amount: number, name: string } | null }, versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number } } } }; +export type SettingsWorkspaceBillingQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, billing?: { __typename?: 'WorkspaceBilling', cost: { __typename?: 'WorkspaceCost', subTotal: number, total: number, items: Array<{ __typename?: 'WorkspaceCostItem', cost: number, count: number, name: string }>, discount?: { __typename?: 'WorkspaceCostDiscount', amount: number, name: string } | null }, versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number } } | null } }; export type SettingsWorkspacesMembersQueryVariables = Exact<{ workspaceId: Scalars['String']['input']; @@ -5560,7 +5560,7 @@ export type WorkspacePageQueryQueryVariables = Exact<{ }>; -export type WorkspacePageQueryQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, role?: string | null, name: string, logo?: string | null, description?: string | null, defaultLogoIndex: number, domainBasedMembershipProtectionEnabled: boolean, projects: { __typename?: 'ProjectCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null }> }, workspace?: { __typename?: 'Workspace', id: string, name: string, logo?: string | null, defaultLogoIndex: number } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }> }> }, totalProjects: { __typename?: 'ProjectCollection', totalCount: number }, billing: { __typename?: 'WorkspaceBilling', versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number } }, team: { __typename?: 'WorkspaceCollaboratorCollection', items: Array<{ __typename?: 'WorkspaceCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }> }, domains: Array<{ __typename?: 'WorkspaceDomain', domain: string, id: string }>, invitedTeam?: Array<{ __typename?: 'PendingWorkspaceCollaborator', title: string, user?: { __typename?: 'LimitedUser', id: string } | null }> | null }, workspaceInvite?: { __typename?: 'PendingWorkspaceCollaborator', id: string, workspaceId: string, workspaceName: string, token?: string | null, title: string, email?: string | null, invitedBy: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null }, user?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null } | null }; +export type WorkspacePageQueryQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, role?: string | null, name: string, logo?: string | null, description?: string | null, defaultLogoIndex: number, domainBasedMembershipProtectionEnabled: boolean, projects: { __typename?: 'ProjectCollection', totalCount: number, cursor?: string | null, items: Array<{ __typename?: 'Project', id: string, name: string, createdAt: string, updatedAt: string, role?: string | null, visibility: ProjectVisibility, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, description?: string | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, automationsStatus?: { __typename?: 'TriggeredAutomationsStatus', id: string, automationRuns: Array<{ __typename?: 'AutomateRun', id: string, functionRuns: Array<{ __typename?: 'AutomateFunctionRun', id: string, updatedAt: string, status: AutomateRunStatus, results?: {} | null, statusMessage?: string | null, contextView?: string | null, createdAt: string, function?: { __typename?: 'AutomateFunction', id: string, logo?: string | null, name: string } | null }>, automation: { __typename?: 'Automation', id: string, name: string } }> } | null }> }, workspace?: { __typename?: 'Workspace', id: string, name: string, logo?: string | null, defaultLogoIndex: number } | null, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }> }> }, totalProjects: { __typename?: 'ProjectCollection', totalCount: number }, billing?: { __typename?: 'WorkspaceBilling', versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number } } | null, team: { __typename?: 'WorkspaceCollaboratorCollection', items: Array<{ __typename?: 'WorkspaceCollaborator', id: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }> }, domains: Array<{ __typename?: 'WorkspaceDomain', domain: string, id: string }>, invitedTeam?: Array<{ __typename?: 'PendingWorkspaceCollaborator', title: string, user?: { __typename?: 'LimitedUser', id: string } | null }> | null }, workspaceInvite?: { __typename?: 'PendingWorkspaceCollaborator', id: string, workspaceId: string, workspaceName: string, token?: string | null, title: string, email?: string | null, invitedBy: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null }, user?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null } | null }; export type WorkspaceProjectsQueryQueryVariables = Exact<{ workspaceId: Scalars['String']['input']; diff --git a/packages/server/assets/workspacesCore/typedefs/workspaces.graphql b/packages/server/assets/workspacesCore/typedefs/workspaces.graphql index eab6591e4..e0494da2d 100644 --- a/packages/server/assets/workspacesCore/typedefs/workspaces.graphql +++ b/packages/server/assets/workspacesCore/typedefs/workspaces.graphql @@ -276,7 +276,7 @@ type Workspace { """ Billing data for Workspaces beta """ - billing: WorkspaceBilling! @hasWorkspaceRole(role: MEMBER) + billing: WorkspaceBilling @hasWorkspaceRole(role: MEMBER) """ Enable/Disable restriction to invite users to workspace as Guests only """ diff --git a/packages/server/codegen.yml b/packages/server/codegen.yml index b45ba1466..033746dce 100644 --- a/packages/server/codegen.yml +++ b/packages/server/codegen.yml @@ -56,6 +56,7 @@ generates: ProjectAutomationsUpdatedMessage: '@/modules/automate/helpers/graphTypes#ProjectAutomationsUpdatedMessageGraphQLReturn' UserAutomateInfo: '@/modules/automate/helpers/graphTypes#UserAutomateInfoGraphQLReturn' Workspace: '@/modules/workspacesCore/helpers/graphTypes#WorkspaceGraphQLReturn' + WorkspaceBilling: '@/modules/workspacesCore/helpers/graphTypes#WorkspaceBillingGraphQLReturn' WorkspaceMutations: '@/modules/workspacesCore/helpers/graphTypes#WorkspaceMutationsGraphQLReturn' WorkspaceInviteMutations: '@/modules/workspacesCore/helpers/graphTypes#WorkspaceInviteMutationsGraphQLReturn' PendingWorkspaceCollaborator: '@/modules/workspacesCore/helpers/graphTypes#PendingWorkspaceCollaboratorGraphQLReturn' diff --git a/packages/server/modules/core/graph/generated/graphql.ts b/packages/server/modules/core/graph/generated/graphql.ts index e1ff5e392..2347d1811 100644 --- a/packages/server/modules/core/graph/generated/graphql.ts +++ b/packages/server/modules/core/graph/generated/graphql.ts @@ -5,7 +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, WorkspaceMutationsGraphQLReturn, WorkspaceInviteMutationsGraphQLReturn, PendingWorkspaceCollaboratorGraphQLReturn, WorkspaceCollaboratorGraphQLReturn } from '@/modules/workspacesCore/helpers/graphTypes'; +import { WorkspaceGraphQLReturn, WorkspaceBillingGraphQLReturn, WorkspaceMutationsGraphQLReturn, WorkspaceInviteMutationsGraphQLReturn, PendingWorkspaceCollaboratorGraphQLReturn, WorkspaceCollaboratorGraphQLReturn } from '@/modules/workspacesCore/helpers/graphTypes'; import { GraphQLContext } from '@/modules/shared/helpers/typeHelper'; export type Maybe = T | null; export type InputMaybe = Maybe; @@ -3871,7 +3871,7 @@ export type WebhookUpdateInput = { export type Workspace = { __typename?: 'Workspace'; /** Billing data for Workspaces beta */ - billing: WorkspaceBilling; + billing?: Maybe; createdAt: Scalars['DateTime']['output']; /** Selected fallback when `logo` not set */ defaultLogoIndex: Scalars['Int']['output']; @@ -4469,7 +4469,7 @@ export type ResolversTypes = { WebhookEventCollection: ResolverTypeWrapper; WebhookUpdateInput: WebhookUpdateInput; Workspace: ResolverTypeWrapper; - WorkspaceBilling: ResolverTypeWrapper; + WorkspaceBilling: ResolverTypeWrapper; WorkspaceCollaborator: ResolverTypeWrapper; WorkspaceCollaboratorCollection: ResolverTypeWrapper & { items: Array }>; WorkspaceCollection: ResolverTypeWrapper & { items: Array }>; @@ -4707,7 +4707,7 @@ export type ResolversParentTypes = { WebhookEventCollection: WebhookEventCollection; WebhookUpdateInput: WebhookUpdateInput; Workspace: WorkspaceGraphQLReturn; - WorkspaceBilling: WorkspaceBilling; + WorkspaceBilling: WorkspaceBillingGraphQLReturn; WorkspaceCollaborator: WorkspaceCollaboratorGraphQLReturn; WorkspaceCollaboratorCollection: Omit & { items: Array }; WorkspaceCollection: Omit & { items: Array }; @@ -6067,7 +6067,7 @@ export type WebhookEventCollectionResolvers = { - billing?: Resolver; + billing?: Resolver, ParentType, ContextType>; createdAt?: Resolver; defaultLogoIndex?: Resolver; description?: Resolver, ParentType, ContextType>; diff --git a/packages/server/modules/cross-server-sync/graph/generated/graphql.ts b/packages/server/modules/cross-server-sync/graph/generated/graphql.ts index 3f8b2c995..d0b6ec14d 100644 --- a/packages/server/modules/cross-server-sync/graph/generated/graphql.ts +++ b/packages/server/modules/cross-server-sync/graph/generated/graphql.ts @@ -3860,7 +3860,7 @@ export type WebhookUpdateInput = { export type Workspace = { __typename?: 'Workspace'; /** Billing data for Workspaces beta */ - billing: WorkspaceBilling; + billing?: Maybe; createdAt: Scalars['DateTime']['output']; /** Selected fallback when `logo` not set */ defaultLogoIndex: Scalars['Int']['output']; diff --git a/packages/server/modules/workspaces/graph/resolvers/workspaces.ts b/packages/server/modules/workspaces/graph/resolvers/workspaces.ts index 57b95c2e8..614f170ee 100644 --- a/packages/server/modules/workspaces/graph/resolvers/workspaces.ts +++ b/packages/server/modules/workspaces/graph/resolvers/workspaces.ts @@ -1,9 +1,5 @@ import { db } from '@/db/knex' -import { - ResolverTypeWrapper, - Resolvers, - WorkspaceBilling -} from '@/modules/core/graph/generated/graphql' +import { Resolvers } from '@/modules/core/graph/generated/graphql' import { removePrivateFields } from '@/modules/core/helpers/userHelper' import { getStream, @@ -116,7 +112,6 @@ import { import { joinWorkspaceFactory } from '@/modules/workspaces/services/join' import { validateAndCreateUserEmailFactory } from '@/modules/core/services/userEmails' import { requestNewEmailVerification } from '@/modules/emails/services/verification/request' -import { Workspace } from '@/modules/workspacesCore/domain/types' import { WORKSPACE_MAX_PROJECTS_VERSIONS } from '@/modules/gatekeeper/domain/constants' import { getWorkspaceCostFactory, @@ -681,12 +676,11 @@ export = FF_WORKSPACES_MODULE_ENABLED domains: async (parent) => { return await getWorkspaceDomainsFactory({ db })({ workspaceIds: [parent.id] }) }, - billing: (parent) => - ({ parent } as { parent: Workspace } & ResolverTypeWrapper) + billing: (parent) => ({ parent }) }, WorkspaceBilling: { - versionsCount: async (parent) => { - const workspaceId = (parent as unknown as { parent: Workspace }).parent.id + versionsCount: async ({ parent }) => { + const workspaceId = parent.id return { current: await countProjectsVersionsByWorkspaceIdFactory({ db })({ workspaceId @@ -694,8 +688,8 @@ export = FF_WORKSPACES_MODULE_ENABLED max: WORKSPACE_MAX_PROJECTS_VERSIONS } }, - cost: async (parent) => { - const workspaceId = (parent as unknown as { parent: Workspace }).parent.id + cost: async ({ parent }) => { + const workspaceId = parent.id return getWorkspaceCostFactory({ getWorkspaceCostItems: getWorkspaceCostItemsFactory({ countRole: countWorkspaceRoleWithOptionalProjectRoleFactory({ db }), diff --git a/packages/server/modules/workspaces/tests/integration/workspaces.graph.spec.ts b/packages/server/modules/workspaces/tests/integration/workspaces.graph.spec.ts index 68083d227..a4cc62a85 100644 --- a/packages/server/modules/workspaces/tests/integration/workspaces.graph.spec.ts +++ b/packages/server/modules/workspaces/tests/integration/workspaces.graph.spec.ts @@ -386,7 +386,7 @@ describe('Workspaces GQL CRUD', () => { }) expect(res).to.not.haveGraphQLErrors() - expect(res.data?.workspace.billing.versionsCount).to.deep.equal({ + expect(res.data?.workspace.billing?.versionsCount).to.deep.equal({ current: 5, max: 500 }) @@ -483,7 +483,7 @@ describe('Workspaces GQL CRUD', () => { expect(res).to.not.haveGraphQLErrors() const { subTotal, currency, items, total, discount } = - res.data!.workspace.billing.cost + res.data?.workspace.billing?.cost || {} expect(subTotal).to.equal(49 + 49 + 15 + 2 * 5) expect(currency).to.equal('GBP') expect(items).to.deep.equal([ diff --git a/packages/server/modules/workspacesCore/helpers/graphTypes.ts b/packages/server/modules/workspacesCore/helpers/graphTypes.ts index 65a93b3c1..2a7199734 100644 --- a/packages/server/modules/workspacesCore/helpers/graphTypes.ts +++ b/packages/server/modules/workspacesCore/helpers/graphTypes.ts @@ -5,6 +5,7 @@ import { Workspace } from '@/modules/workspacesCore/domain/types' import { WorkspaceRoles } from '@speckle/shared' export type WorkspaceGraphQLReturn = Workspace +export type WorkspaceBillingGraphQLReturn = { parent: Workspace } export type WorkspaceMutationsGraphQLReturn = MutationsObjectGraphQLReturn export type WorkspaceInviteMutationsGraphQLReturn = MutationsObjectGraphQLReturn diff --git a/packages/server/test/graphql/generated/graphql.ts b/packages/server/test/graphql/generated/graphql.ts index 488172fbd..8d043305e 100644 --- a/packages/server/test/graphql/generated/graphql.ts +++ b/packages/server/test/graphql/generated/graphql.ts @@ -3861,7 +3861,7 @@ export type WebhookUpdateInput = { export type Workspace = { __typename?: 'Workspace'; /** Billing data for Workspaces beta */ - billing: WorkspaceBilling; + billing?: Maybe; createdAt: Scalars['DateTime']['output']; /** Selected fallback when `logo` not set */ defaultLogoIndex: Scalars['Int']['output']; @@ -4166,7 +4166,7 @@ export type BasicWorkspaceFragment = { __typename?: 'Workspace', id: string, nam export type BasicPendingWorkspaceCollaboratorFragment = { __typename?: 'PendingWorkspaceCollaborator', id: string, inviteId: string, workspaceId: string, workspaceName: string, title: string, role: string, token?: string | null, invitedBy: { __typename?: 'LimitedUser', id: string, name: string }, user?: { __typename?: 'LimitedUser', id: string, name: string } | null }; -export type WorkspaceBillingFragment = { __typename?: 'Workspace', billing: { __typename?: 'WorkspaceBilling', versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number }, cost: { __typename?: 'WorkspaceCost', subTotal: number, currency: Currency, total: number, items: Array<{ __typename?: 'WorkspaceCostItem', count: number, name: string, cost: number }>, discount?: { __typename?: 'WorkspaceCostDiscount', name: string, amount: number } | null } } }; +export type WorkspaceBillingFragment = { __typename?: 'Workspace', billing?: { __typename?: 'WorkspaceBilling', versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number }, cost: { __typename?: 'WorkspaceCost', subTotal: number, currency: Currency, total: number, items: Array<{ __typename?: 'WorkspaceCostItem', count: number, name: string, cost: number }>, discount?: { __typename?: 'WorkspaceCostDiscount', name: string, amount: number } | null } } | null }; export type WorkspaceProjectsFragment = { __typename?: 'ProjectCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Project', id: string }> }; @@ -4198,7 +4198,7 @@ export type GetWorkspaceWithBillingQueryVariables = Exact<{ }>; -export type GetWorkspaceWithBillingQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, name: string, updatedAt: string, createdAt: string, role?: string | null, billing: { __typename?: 'WorkspaceBilling', versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number }, cost: { __typename?: 'WorkspaceCost', subTotal: number, currency: Currency, total: number, items: Array<{ __typename?: 'WorkspaceCostItem', count: number, name: string, cost: number }>, discount?: { __typename?: 'WorkspaceCostDiscount', name: string, amount: number } | null } } } }; +export type GetWorkspaceWithBillingQuery = { __typename?: 'Query', workspace: { __typename?: 'Workspace', id: string, name: string, updatedAt: string, createdAt: string, role?: string | null, billing?: { __typename?: 'WorkspaceBilling', versionsCount: { __typename?: 'WorkspaceVersionsCount', current: number, max: number }, cost: { __typename?: 'WorkspaceCost', subTotal: number, currency: Currency, total: number, items: Array<{ __typename?: 'WorkspaceCostItem', count: number, name: string, cost: number }>, discount?: { __typename?: 'WorkspaceCostDiscount', name: string, amount: number } | null } } | null } }; export type GetWorkspaceWithProjectsQueryVariables = Exact<{ workspaceId: Scalars['String']['input'];