Merge branch 'main' of github.com:specklesystems/speckle-server into alessandro/web-1767-guest-table-should-show-what-they-have-access-to
This commit is contained in:
@@ -1,21 +1,15 @@
|
||||
import { db } from '@/db/knex'
|
||||
import {
|
||||
deleteProjectRoleFactory,
|
||||
getStream,
|
||||
upsertProjectRoleFactory
|
||||
} from '@/modules/core/repositories/streams'
|
||||
import { getStream } from '@/modules/core/repositories/streams'
|
||||
import {
|
||||
findEmailsByUserIdFactory,
|
||||
findVerifiedEmailsByUserIdFactory
|
||||
} from '@/modules/core/repositories/userEmails'
|
||||
import { getStreams } from '@/modules/core/services/streams'
|
||||
import {
|
||||
findUserByTargetFactory,
|
||||
insertInviteAndDeleteOldFactory
|
||||
} from '@/modules/serverinvites/repositories/serverInvites'
|
||||
import { createAndSendInviteFactory } from '@/modules/serverinvites/services/creation'
|
||||
import { getEventBus } from '@/modules/shared/services/eventBus'
|
||||
import { mapWorkspaceRoleToInitialProjectRole } from '@/modules/workspaces/domain/logic'
|
||||
import {
|
||||
getWorkspaceRolesFactory,
|
||||
upsertWorkspaceFactory,
|
||||
@@ -38,7 +32,6 @@ import {
|
||||
updateWorkspaceFactory,
|
||||
addDomainToWorkspaceFactory
|
||||
} from '@/modules/workspaces/services/management'
|
||||
import { queryAllWorkspaceProjectsFactory } from '@/modules/workspaces/services/projects'
|
||||
import { BasicTestUser } from '@/test/authHelper'
|
||||
import { CreateWorkspaceInviteMutationVariables } from '@/test/graphql/generated/graphql'
|
||||
import { MaybeNullOrUndefined, Roles, WorkspaceRoles } from '@speckle/shared'
|
||||
@@ -138,10 +131,6 @@ export const assignToWorkspace = async (
|
||||
findVerifiedEmailsByUserId: findVerifiedEmailsByUserIdFactory({ db }),
|
||||
getWorkspaceRoles: getWorkspaceRolesFactory({ db }),
|
||||
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db }),
|
||||
getDefaultWorkspaceProjectRoleMapping: mapWorkspaceRoleToInitialProjectRole,
|
||||
upsertProjectRole: upsertProjectRoleFactory({ db }),
|
||||
deleteProjectRole: deleteProjectRoleFactory({ db }),
|
||||
queryAllWorkspaceProjects: queryAllWorkspaceProjectsFactory({ getStreams }),
|
||||
emitWorkspaceEvent: (...args) => getEventBus().emit(...args)
|
||||
})
|
||||
|
||||
@@ -159,8 +148,6 @@ export const unassignFromWorkspace = async (
|
||||
const deleteWorkspaceRole = deleteWorkspaceRoleFactory({
|
||||
getWorkspaceRoles: getWorkspaceRolesFactory({ db }),
|
||||
deleteWorkspaceRole: dbDeleteWorkspaceRoleFactory({ db }),
|
||||
deleteProjectRole: deleteProjectRoleFactory({ db }),
|
||||
queryAllWorkspaceProjects: queryAllWorkspaceProjectsFactory({ getStreams }),
|
||||
emitWorkspaceEvent: (...args) => getEventBus().emit(...args)
|
||||
})
|
||||
|
||||
|
||||
@@ -565,11 +565,9 @@ describe('Workspaces GQL CRUD', () => {
|
||||
|
||||
// first 10 users
|
||||
await createTestUsers(freeGuests)
|
||||
await Promise.all(
|
||||
freeGuests.map((guest) =>
|
||||
assignToWorkspace(workspace, guest, Roles.Workspace.Guest)
|
||||
)
|
||||
)
|
||||
for (const guest of freeGuests) {
|
||||
await assignToWorkspace(workspace, guest, Roles.Workspace.Guest)
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
createTestUser(member),
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Roles, StreamRoles } from '@speckle/shared'
|
||||
import { StreamAclRecord, StreamRecord } from '@/modules/core/helpers/types'
|
||||
import {
|
||||
onProjectCreatedFactory,
|
||||
onWorkspaceJoinedFactory
|
||||
onWorkspaceRoleUpdatedFactory
|
||||
} from '@/modules/workspaces/events/eventListener'
|
||||
import { expect } from 'chai'
|
||||
import { mapWorkspaceRoleToInitialProjectRole } from '@/modules/workspaces/domain/logic'
|
||||
@@ -61,16 +61,22 @@ describe('Event handlers', () => {
|
||||
expect(projectRoles.length).to.equal(2)
|
||||
})
|
||||
})
|
||||
describe('onWorkspaceJoinedFactory creates a function, that', () => {
|
||||
describe('onWorkspaceRoleUpdatedFactory creates a function, that', () => {
|
||||
it('assigns no project roles if the role mapping returns null', async () => {
|
||||
await onWorkspaceJoinedFactory({
|
||||
let isDeleteCalled = false
|
||||
|
||||
await onWorkspaceRoleUpdatedFactory({
|
||||
getDefaultWorkspaceProjectRoleMapping: async () => ({
|
||||
[Roles.Workspace.Admin]: Roles.Stream.Owner,
|
||||
[Roles.Workspace.Member]: Roles.Stream.Contributor,
|
||||
[Roles.Workspace.Guest]: null
|
||||
}),
|
||||
async *queryAllWorkspaceProjects() {
|
||||
expect.fail()
|
||||
yield [{ id: 'test' } as StreamRecord]
|
||||
},
|
||||
deleteProjectRole: async () => {
|
||||
isDeleteCalled = true
|
||||
return undefined
|
||||
},
|
||||
upsertProjectRole: async () => {
|
||||
expect.fail()
|
||||
@@ -80,6 +86,8 @@ describe('Event handlers', () => {
|
||||
userId: cryptoRandomString({ length: 10 }),
|
||||
workspaceId: cryptoRandomString({ length: 10 })
|
||||
})
|
||||
|
||||
expect(isDeleteCalled).to.be.true
|
||||
})
|
||||
it('assigns the mapped projects roles to all queried project', async () => {
|
||||
const projectIds = [
|
||||
@@ -92,7 +100,7 @@ describe('Event handlers', () => {
|
||||
const projectRole = Roles.Stream.Reviewer
|
||||
|
||||
const storedRoles: { userId: string; role: StreamRoles; projectId: string }[] = []
|
||||
await onWorkspaceJoinedFactory({
|
||||
await onWorkspaceRoleUpdatedFactory({
|
||||
getDefaultWorkspaceProjectRoleMapping: async () => ({
|
||||
[Roles.Workspace.Admin]: Roles.Stream.Owner,
|
||||
[Roles.Workspace.Member]: projectRole,
|
||||
@@ -103,6 +111,9 @@ describe('Event handlers', () => {
|
||||
yield projIds.map((projId) => ({ id: projId } as unknown as StreamRecord))
|
||||
}
|
||||
},
|
||||
deleteProjectRole: async () => {
|
||||
expect.fail()
|
||||
},
|
||||
upsertProjectRole: async (args) => {
|
||||
storedRoles.push(args)
|
||||
return {} as StreamRecord
|
||||
|
||||
@@ -14,7 +14,10 @@ import {
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { expect } from 'chai'
|
||||
import cryptoRandomString from 'crypto-random-string'
|
||||
import { WorkspaceEvents } from '@/modules/workspacesCore/domain/events'
|
||||
import {
|
||||
WorkspaceEvents,
|
||||
WorkspaceEventsPayloads
|
||||
} from '@/modules/workspacesCore/domain/events'
|
||||
import { StreamAclRecord, StreamRecord } from '@/modules/core/helpers/types'
|
||||
import { expectToThrow } from '@/test/assertionHelper'
|
||||
import { createRandomPassword } from '@/modules/core/helpers/testHelpers'
|
||||
@@ -386,17 +389,21 @@ const buildDeleteWorkspaceRoleAndTestContext = (
|
||||
context.eventData.eventName = eventName
|
||||
context.eventData.payload = payload
|
||||
|
||||
switch (eventName) {
|
||||
case 'workspace.role-deleted': {
|
||||
const { userId } =
|
||||
payload as WorkspaceEventsPayloads['workspace.role-deleted']
|
||||
for (const project of context.workspaceProjects) {
|
||||
context.workspaceProjectRoles = context.workspaceProjectRoles.filter(
|
||||
(role) => role.resourceId !== project.id && role.userId !== userId
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return []
|
||||
},
|
||||
async *queryAllWorkspaceProjects() {
|
||||
yield context.workspaceProjects
|
||||
},
|
||||
deleteProjectRole: async ({ projectId, userId }) => {
|
||||
context.workspaceProjectRoles = context.workspaceProjectRoles.filter(
|
||||
(role) => role.resourceId !== projectId && role.userId !== userId
|
||||
)
|
||||
return {} as StreamRecord
|
||||
},
|
||||
...dependencyOverrides
|
||||
}
|
||||
|
||||
@@ -430,32 +437,47 @@ const buildUpdateWorkspaceRoleAndTestContext = (
|
||||
context.eventData.eventName = eventName
|
||||
context.eventData.payload = payload
|
||||
|
||||
return []
|
||||
},
|
||||
async *queryAllWorkspaceProjects() {
|
||||
yield context.workspaceProjects
|
||||
},
|
||||
getDefaultWorkspaceProjectRoleMapping: mapWorkspaceRoleToInitialProjectRole,
|
||||
upsertProjectRole: async (role) => {
|
||||
const streamAcl: StreamAclRecord = {
|
||||
userId: role.userId,
|
||||
role: role.role,
|
||||
resourceId: role.projectId
|
||||
switch (eventName) {
|
||||
case 'workspace.role-deleted': {
|
||||
const { userId } =
|
||||
payload as WorkspaceEventsPayloads['workspace.role-deleted']
|
||||
for (const project of context.workspaceProjects) {
|
||||
context.workspaceProjectRoles = context.workspaceProjectRoles.filter(
|
||||
(role) => role.resourceId !== project.id && role.userId !== userId
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'workspace.role-updated': {
|
||||
const workspaceRole =
|
||||
payload as WorkspaceEventsPayloads['workspace.role-updated']
|
||||
const mapping = await mapWorkspaceRoleToInitialProjectRole({
|
||||
workspaceId: workspaceRole.workspaceId
|
||||
})
|
||||
|
||||
for (const project of context.workspaceProjects) {
|
||||
const projectRole = mapping[workspaceRole.role]
|
||||
|
||||
if (!projectRole) {
|
||||
continue
|
||||
}
|
||||
|
||||
const streamAcl: StreamAclRecord = {
|
||||
userId: workspaceRole.userId,
|
||||
role: projectRole,
|
||||
resourceId: project.id
|
||||
}
|
||||
|
||||
context.workspaceProjectRoles = context.workspaceProjectRoles.filter(
|
||||
(acl) => acl.userId !== workspaceRole.userId
|
||||
)
|
||||
context.workspaceProjectRoles.push(streamAcl)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
context.workspaceProjectRoles = context.workspaceProjectRoles.filter(
|
||||
(acl) => acl.userId !== role.userId
|
||||
)
|
||||
context.workspaceProjectRoles.push(streamAcl)
|
||||
|
||||
return {} as StreamRecord
|
||||
},
|
||||
deleteProjectRole: async ({ userId }) => {
|
||||
context.workspaceProjectRoles = context.workspaceProjectRoles.filter(
|
||||
(acl) => acl.userId !== userId
|
||||
)
|
||||
|
||||
return {} as StreamRecord
|
||||
return []
|
||||
},
|
||||
...dependencyOverrides
|
||||
}
|
||||
@@ -589,9 +611,15 @@ describe('Workspace role services', () => {
|
||||
|
||||
await updateWorkspaceRole(role)
|
||||
|
||||
const payload = {
|
||||
...(context.eventData
|
||||
.payload as WorkspaceEventsPayloads['workspace.role-updated'])
|
||||
}
|
||||
delete payload.flags
|
||||
|
||||
expect(context.eventData.isCalled).to.be.true
|
||||
expect(context.eventData.eventName).to.equal(WorkspaceEvents.RoleUpdated)
|
||||
expect(context.eventData.payload).to.deep.equal(role)
|
||||
expect(payload).to.deep.equal(role)
|
||||
})
|
||||
it('throws if attempting to remove the last admin in a workspace', async () => {
|
||||
const userId = cryptoRandomString({ length: 10 })
|
||||
|
||||
Reference in New Issue
Block a user