Alessandro/web 1659 workspace limits (#2733)
* chore(workspaces): billing version limit graphql schema * chore(workspaces): billing member role required * chore(core): test helper for random string * chore(core): test helpers * chore(workspaces): workspaces billing version resolver * chore(workspaces): rename version to versionsCount
This commit is contained in:
committed by
GitHub
parent
131918b428
commit
0ac36af93e
@@ -146,3 +146,9 @@ export type EmitWorkspaceEvent = <TEvent extends WorkspaceEvents>(args: {
|
||||
eventName: TEvent
|
||||
payload: EventBusPayloads[TEvent]
|
||||
}) => Promise<unknown[]>
|
||||
|
||||
export type CountProjectsVersionsByWorkspaceId = ({
|
||||
workspaceId
|
||||
}: {
|
||||
workspaceId: string
|
||||
}) => Promise<number>
|
||||
|
||||
@@ -61,7 +61,8 @@ import {
|
||||
deleteWorkspaceDomainFactory,
|
||||
getWorkspaceDomainsFactory,
|
||||
getUserDiscoverableWorkspacesFactory,
|
||||
getWorkspaceWithDomainsFactory
|
||||
getWorkspaceWithDomainsFactory,
|
||||
countProjectsVersionsByWorkspaceIdFactory
|
||||
} from '@/modules/workspaces/repositories/workspaces'
|
||||
import {
|
||||
buildWorkspaceInviteEmailContentsFactory,
|
||||
@@ -102,6 +103,8 @@ 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'
|
||||
|
||||
const buildCreateAndSendServerOrProjectInvite = () =>
|
||||
createAndSendInviteFactory({
|
||||
@@ -611,6 +614,17 @@ export = FF_WORKSPACES_MODULE_ENABLED
|
||||
},
|
||||
domains: async (parent) => {
|
||||
return await getWorkspaceDomainsFactory({ db })({ workspaceIds: [parent.id] })
|
||||
},
|
||||
billing: (parent) => ({ parent })
|
||||
},
|
||||
WorkspaceBilling: {
|
||||
versionsCount: async (parent) => {
|
||||
return {
|
||||
current: await countProjectsVersionsByWorkspaceIdFactory({ db })({
|
||||
workspaceId: (parent as { parent: Workspace }).parent.id
|
||||
}),
|
||||
max: WORKSPACE_MAX_PROJECTS_VERSIONS
|
||||
}
|
||||
}
|
||||
},
|
||||
WorkspaceCollaborator: {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
WorkspaceWithOptionalRole
|
||||
} from '@/modules/workspacesCore/domain/types'
|
||||
import {
|
||||
CountProjectsVersionsByWorkspaceId,
|
||||
DeleteWorkspace,
|
||||
DeleteWorkspaceDomain,
|
||||
DeleteWorkspaceRole,
|
||||
@@ -30,7 +31,14 @@ import {
|
||||
WorkspaceDomains,
|
||||
Workspaces
|
||||
} from '@/modules/workspaces/helpers/db'
|
||||
import { knex, ServerAcl, ServerInvites, Users } from '@/modules/core/dbSchema'
|
||||
import {
|
||||
knex,
|
||||
ServerAcl,
|
||||
ServerInvites,
|
||||
StreamCommits,
|
||||
Streams,
|
||||
Users
|
||||
} from '@/modules/core/dbSchema'
|
||||
import { UserWithRole } from '@/modules/core/repositories/users'
|
||||
import { removePrivateFields } from '@/modules/core/helpers/userHelper'
|
||||
import {
|
||||
@@ -302,3 +310,15 @@ export const getWorkspaceWithDomainsFactory =
|
||||
)
|
||||
} as Workspace & { domains: WorkspaceDomain[] }
|
||||
}
|
||||
|
||||
export const countProjectsVersionsByWorkspaceIdFactory =
|
||||
({ db }: { db: Knex }): CountProjectsVersionsByWorkspaceId =>
|
||||
async ({ workspaceId }) => {
|
||||
const [res] = await tables
|
||||
.streams(db)
|
||||
.join(StreamCommits.name, StreamCommits.col.streamId, Streams.col.id)
|
||||
.where({ workspaceId })
|
||||
.count(StreamCommits.col.commitId)
|
||||
|
||||
return parseInt(res.count.toString())
|
||||
}
|
||||
|
||||
@@ -30,6 +30,17 @@ export const basicPendingWorkspaceCollaboratorFragment = gql`
|
||||
}
|
||||
`
|
||||
|
||||
export const workspaceBillingFragment = gql`
|
||||
fragment WorkspaceBilling on Workspace {
|
||||
billing {
|
||||
versionsCount {
|
||||
current
|
||||
max
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const createWorkspaceInviteQuery = gql`
|
||||
mutation CreateWorkspaceInvite(
|
||||
$workspaceId: String!
|
||||
@@ -86,6 +97,18 @@ export const getWorkspaceWithTeamQuery = gql`
|
||||
${basicPendingWorkspaceCollaboratorFragment}
|
||||
`
|
||||
|
||||
export const getWorkspaceWithBillingQuery = gql`
|
||||
query GetWorkspaceWithBilling($workspaceId: String!) {
|
||||
workspace(id: $workspaceId) {
|
||||
...BasicWorkspace
|
||||
...WorkspaceBilling
|
||||
}
|
||||
}
|
||||
|
||||
${basicWorkspaceFragment}
|
||||
${workspaceBillingFragment}
|
||||
`
|
||||
|
||||
export const cancelInviteMutation = gql`
|
||||
mutation CancelWorkspaceInvite($workspaceId: String!, $inviteId: String!) {
|
||||
workspaceMutations {
|
||||
|
||||
@@ -20,7 +20,11 @@ import {
|
||||
GetWorkspaceTeamDocument,
|
||||
UpdateWorkspaceDocument,
|
||||
UpdateWorkspaceRoleDocument,
|
||||
ActiveUserLeaveWorkspaceDocument
|
||||
ActiveUserLeaveWorkspaceDocument,
|
||||
GetWorkspaceWithBillingDocument,
|
||||
CreateProjectDocument,
|
||||
CreateObjectDocument,
|
||||
CreateProjectVersionDocument
|
||||
} from '@/test/graphql/generated/graphql'
|
||||
import { beforeEachContext } from '@/test/hooks'
|
||||
import { AllScopes } from '@/modules/core/helpers/mainConstants'
|
||||
@@ -33,7 +37,57 @@ import {
|
||||
import { BasicTestCommit, createTestCommit } from '@/test/speckle-helpers/commitHelper'
|
||||
import { BasicTestStream, createTestStream } from '@/test/speckle-helpers/streamHelper'
|
||||
import knex from '@/db/knex'
|
||||
import { createRandomPassword } from '@/modules/core/helpers/testHelpers'
|
||||
import { getBranchesByStreamId } from '@/modules/core/services/branches'
|
||||
|
||||
const createProjectWithVersions =
|
||||
({ apollo }: { apollo: TestApolloServer }) =>
|
||||
async ({
|
||||
workspaceId,
|
||||
versionsCount
|
||||
}: {
|
||||
workspaceId?: string
|
||||
versionsCount: number
|
||||
}) => {
|
||||
const resProject1 = await apollo.execute(CreateProjectDocument, {
|
||||
input: {
|
||||
name: createRandomPassword(),
|
||||
workspaceId
|
||||
}
|
||||
})
|
||||
expect(resProject1).to.not.haveGraphQLErrors()
|
||||
const project1Id = resProject1.data!.projectMutations.create.id
|
||||
|
||||
const {
|
||||
items: [model1]
|
||||
} = await getBranchesByStreamId({
|
||||
streamId: project1Id,
|
||||
limit: 1,
|
||||
cursor: null
|
||||
})
|
||||
expect(model1).to.exist
|
||||
|
||||
const resObj1 = await apollo.execute(CreateObjectDocument, {
|
||||
input: {
|
||||
streamId: project1Id,
|
||||
objects: [{ some: 'obj' }]
|
||||
}
|
||||
})
|
||||
expect(resObj1).to.not.haveGraphQLErrors()
|
||||
|
||||
await Promise.all(
|
||||
new Array(versionsCount).fill(0).map(async () => {
|
||||
const res = await apollo.execute(CreateProjectVersionDocument, {
|
||||
input: {
|
||||
projectId: project1Id,
|
||||
modelId: model1.id,
|
||||
objectId: resObj1.data!.objectCreate[0]
|
||||
}
|
||||
})
|
||||
expect(res).to.not.haveGraphQLErrors()
|
||||
})
|
||||
)
|
||||
}
|
||||
describe('Workspaces GQL CRUD', () => {
|
||||
let apollo: TestApolloServer
|
||||
|
||||
@@ -150,6 +204,29 @@ describe('Workspaces GQL CRUD', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('query workspace.billing', () => {
|
||||
it('should return workspace version limits', async () => {
|
||||
await createProjectWithVersions({ apollo })({
|
||||
workspaceId: workspace.id,
|
||||
versionsCount: 3
|
||||
})
|
||||
await createProjectWithVersions({ apollo })({
|
||||
workspaceId: workspace.id,
|
||||
versionsCount: 2
|
||||
})
|
||||
|
||||
const res = await apollo.execute(GetWorkspaceWithBillingDocument, {
|
||||
workspaceId: workspace.id
|
||||
})
|
||||
|
||||
expect(res).to.not.haveGraphQLErrors()
|
||||
expect(res.data?.workspace.billing.versionsCount).to.deep.equal({
|
||||
current: 5,
|
||||
max: 500
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('query activeUser.workspaces', () => {
|
||||
it('should return all workspaces for a user', async () => {
|
||||
const res = await apollo.execute(GetActiveUserWorkspacesDocument, {})
|
||||
|
||||
Reference in New Issue
Block a user