Merge branch 'main' of github.com:specklesystems/speckle-server into gergo/web-1968-add-features-list

This commit is contained in:
Gergő Jedlicska
2024-10-20 14:53:52 +02:00
354 changed files with 14449 additions and 7284 deletions
@@ -1,5 +1,4 @@
import { db } from '@/db/knex'
import { getStream } from '@/modules/core/repositories/streams'
import {
findEmailsByUserIdFactory,
findVerifiedEmailsByUserIdFactory
@@ -45,6 +44,9 @@ import {
StreamRoles,
WorkspaceRoles
} from '@speckle/shared'
import { getStreamFactory } from '@/modules/core/repositories/streams'
import { getUserFactory } from '@/modules/core/repositories/users'
import { getServerInfoFactory } from '@/modules/core/repositories/server'
export type BasicTestWorkspace = {
/**
@@ -207,8 +209,11 @@ export const createWorkspaceInviteDirectly = async (
args: CreateWorkspaceInviteMutationVariables,
inviterId: string
) => {
const getServerInfo = getServerInfoFactory({ db })
const getStream = getStreamFactory({ db })
const getUser = getUserFactory({ db })
const createAndSendInvite = createAndSendInviteFactory({
findUserByTarget: findUserByTargetFactory(),
findUserByTarget: findUserByTargetFactory({ db }),
insertInviteAndDeleteOld: insertInviteAndDeleteOldFactory({ db }),
collectAndValidateResourceTargets: collectAndValidateWorkspaceTargetsFactory({
getStream,
@@ -224,7 +229,9 @@ export const createWorkspaceInviteDirectly = async (
getEventBus().emit({
eventName,
payload
})
}),
getUser,
getServerInfo
})
const createInvite = createWorkspaceInviteFactory({
@@ -65,7 +65,6 @@ import {
import type { Express } from 'express'
import { AllScopes } from '@/modules/core/helpers/mainConstants'
import { getWorkspaceFactory } from '@/modules/workspaces/repositories/workspaces'
import { getStream } from '@/modules/core/repositories/streams'
import {
createUserEmailFactory,
deleteUserEmailFactory,
@@ -75,10 +74,25 @@ import {
} from '@/modules/core/repositories/userEmails'
import { markUserEmailAsVerifiedFactory } from '@/modules/core/services/users/emailVerification'
import { createRandomPassword } from '@/modules/core/helpers/testHelpers'
import { addOrUpdateStreamCollaborator } from '@/modules/core/services/streams/streamAccessService'
import { WorkspaceProtectedError } from '@/modules/workspaces/errors/workspace'
import { ForbiddenError } from '@/modules/shared/errors'
import cryptoRandomString from 'crypto-random-string'
import {
getStreamFactory,
grantStreamPermissionsFactory
} from '@/modules/core/repositories/streams'
import { saveActivityFactory } from '@/modules/activitystream/repositories'
import {
addOrUpdateStreamCollaboratorFactory,
validateStreamAccessFactory
} from '@/modules/core/services/streams/access'
import { authorizeResolver } from '@/modules/shared'
import {
addStreamInviteAcceptedActivityFactory,
addStreamPermissionsAddedActivityFactory
} from '@/modules/activitystream/services/streamActivity'
import { publish } from '@/modules/shared/utils/subscriptions'
import { getUserFactory } from '@/modules/core/repositories/users'
enum InviteByTarget {
Email = 'email',
@@ -87,6 +101,25 @@ enum InviteByTarget {
type TestGraphQLOperations = ReturnType<typeof buildGraphqlOperations>
const getStream = getStreamFactory({ db })
const saveActivity = saveActivityFactory({ db })
const validateStreamAccess = validateStreamAccessFactory({ authorizeResolver })
const getUser = getUserFactory({ db })
const addOrUpdateStreamCollaborator = addOrUpdateStreamCollaboratorFactory({
validateStreamAccess,
getUser,
grantStreamPermissions: grantStreamPermissionsFactory({ db }),
addStreamInviteAcceptedActivity: addStreamInviteAcceptedActivityFactory({
saveActivity,
publish
}),
addStreamPermissionsAddedActivity: addStreamPermissionsAddedActivityFactory({
saveActivity,
publish
})
})
const buildGraphqlOperations = (deps: { apollo: TestApolloServer }) => {
const { apollo } = deps
@@ -1,5 +1,6 @@
import { db } from '@/db/knex'
import { AllScopes } from '@/modules/core/helpers/mainConstants'
import { grantStreamPermissions } from '@/modules/core/repositories/streams'
import { grantStreamPermissionsFactory } from '@/modules/core/repositories/streams'
import {
BasicTestWorkspace,
createTestWorkspace
@@ -27,6 +28,8 @@ import { Roles } from '@speckle/shared'
import { expect } from 'chai'
import cryptoRandomString from 'crypto-random-string'
const grantStreamPermissions = grantStreamPermissionsFactory({ db })
describe('Workspace project GQL CRUD', () => {
let apollo: TestApolloServer
@@ -38,7 +38,7 @@ import {
import { truncateTables } from '@/test/hooks'
import { createTestStream } from '@/test/speckle-helpers/streamHelper'
import {
grantStreamPermissions,
grantStreamPermissionsFactory,
upsertProjectRoleFactory
} from '@/modules/core/repositories/streams'
import { omit } from 'lodash'
@@ -58,6 +58,7 @@ const createUserEmail = createUserEmailFactory({ db })
const updateUserEmail = updateUserEmailFactory({ db })
const getUserDiscoverableWorkspaces = getUserDiscoverableWorkspacesFactory({ db })
const upsertProjectRole = upsertProjectRoleFactory({ db })
const grantStreamPermissions = grantStreamPermissionsFactory({ db })
const upsertWorkspace = upsertWorkspaceFactory({ db })
const createAndStoreTestWorkspace = createAndStoreTestWorkspaceFactory({
@@ -1,5 +1,6 @@
import { db } from '@/db/knex'
import { AllScopes } from '@/modules/core/helpers/mainConstants'
import { grantStreamPermissions } from '@/modules/core/repositories/streams'
import { grantStreamPermissionsFactory } from '@/modules/core/repositories/streams'
import {
assignToWorkspace,
BasicTestWorkspace,
@@ -29,6 +30,8 @@ import { expect } from 'chai'
import cryptoRandomString from 'crypto-random-string'
import { isUndefined } from 'lodash'
const grantStreamPermissions = grantStreamPermissionsFactory({ db })
describe('Workspaces Roles GQL', () => {
let apollo: TestApolloServer
@@ -49,8 +49,10 @@ import {
createRandomString
} from '@/modules/core/helpers/testHelpers'
import { getBranchesByStreamId } from '@/modules/core/services/branches'
import { grantStreamPermissions } from '@/modules/core/repositories/streams'
import { getWorkspaceFactory } from '@/modules/workspaces/repositories/workspaces'
import { grantStreamPermissionsFactory } from '@/modules/core/repositories/streams'
const grantStreamPermissions = grantStreamPermissionsFactory({ db })
const createProjectWithVersions =
({ apollo }: { apollo: TestApolloServer }) =>
@@ -325,11 +327,11 @@ describe('Workspaces GQL CRUD', () => {
expect(res.data?.workspace.team.items[0].user.name).to.equal('John C Speckle')
})
it('should respect role filters', async () => {
it('should respect role filters with one value', async () => {
const res = await largeWorkspaceApollo.execute(GetWorkspaceTeamDocument, {
workspaceId: largeWorkspace.id,
filter: {
role: 'workspace:member'
roles: ['workspace:member']
}
})
@@ -337,6 +339,18 @@ describe('Workspaces GQL CRUD', () => {
expect(res.data?.workspace.team.items.length).to.equal(2)
})
it('should respect role filters with multiple values', async () => {
const res = await largeWorkspaceApollo.execute(GetWorkspaceTeamDocument, {
workspaceId: largeWorkspace.id,
filter: {
roles: ['workspace:admin', 'workspace:member']
}
})
expect(res).to.not.haveGraphQLErrors()
expect(res.data?.workspace.team.items.length).to.equal(4)
})
it('should respect search limits', async () => {
const res = await largeWorkspaceApollo.execute(GetWorkspaceTeamDocument, {
workspaceId: largeWorkspace.id,
@@ -1,13 +1,15 @@
import { ProjectTeamMember } from '@/modules/core/domain/projects/types'
import { Stream } from '@/modules/core/domain/streams/types'
import { StreamAclRecord, StreamRecord } from '@/modules/core/helpers/types'
import {
moveProjectToWorkspaceFactory,
queryAllWorkspaceProjectsFactory
queryAllWorkspaceProjectsFactory,
updateWorkspaceProjectRoleFactory
} from '@/modules/workspaces/services/projects'
import { WorkspaceAcl } from '@/modules/workspacesCore/domain/types'
import { expectToThrow } from '@/test/assertionHelper'
import { Roles } from '@speckle/shared'
import { expect } from 'chai'
import { assert, expect } from 'chai'
import cryptoRandomString from 'crypto-random-string'
const getWorkspaceRoleToDefaultProjectRoleMapping = async () => ({
@@ -393,4 +395,33 @@ describe('Project management services', () => {
expect(updatedRoles[0].role).to.equal(Roles.Stream.Owner)
})
})
describe('updateWorkspaceProjectRoleFactory returns a function, that', () => {
it('should throw when attempting to promote a workspace guest to project owner', async () => {
const workspaceId = cryptoRandomString({ length: 9 })
const projectId = cryptoRandomString({ length: 9 })
const userId = cryptoRandomString({ length: 9 })
const updateWorkspaceProjectRole = updateWorkspaceProjectRoleFactory({
getStream: async () => {
return { workspaceId } as Stream
},
getWorkspaceRoleForUser: async () => ({
workspaceId,
userId,
role: Roles.Workspace.Guest,
createdAt: new Date()
}),
updateStreamRoleAndNotify: async () => {
assert.fail()
}
})
await expectToThrow(() =>
updateWorkspaceProjectRole({
role: { userId, projectId, role: Roles.Stream.Owner },
updater: { userId: '', resourceAccessRules: [] }
})
)
})
})
})