55f91d2cdf
* fix(workspace): auto approval * fix(scopes): access scopes across the server * fix(hasAccessRole): establish for all mutations * feat(token): scoping does not require the token to exist * chore(scopes): added additional roles * fix: replaced UNAUTHORIZED_ACCESS_ERROR with UNAUTHORIZED * fix(email): user list scopes
356 lines
11 KiB
TypeScript
356 lines
11 KiB
TypeScript
import { createRandomString } from '@/modules/core/helpers/testHelpers'
|
|
import type { BasicTestWorkspace } from '@/modules/workspaces/tests/helpers/creation'
|
|
import { createTestWorkspace } from '@/modules/workspaces/tests/helpers/creation'
|
|
import type { BasicTestUser } from '@/test/authHelper'
|
|
import { createTestUser, login } from '@/test/authHelper'
|
|
import {
|
|
ApproveJoinRequestDocument,
|
|
DenyJoinRequestDocument,
|
|
DismissWorkspaceDocument,
|
|
GetActiveUserWithWorkspaceJoinRequestsDocument,
|
|
GetWorkspaceTeamDocument,
|
|
GetWorkspaceWithJoinRequestsDocument,
|
|
RequestToJoinWorkspaceDocument
|
|
} from '@/modules/core/graph/generated/graphql'
|
|
import { beforeEachContext } from '@/test/hooks'
|
|
import { Roles } from '@speckle/shared'
|
|
import { expect } from 'chai'
|
|
|
|
describe('WorkspaceJoinRequests GQL', () => {
|
|
let admin: BasicTestUser
|
|
let user1: BasicTestUser
|
|
let user2: BasicTestUser
|
|
let user3: BasicTestUser
|
|
let workspace1: BasicTestWorkspace
|
|
let workspace2: BasicTestWorkspace
|
|
let dismissedWorkspace: BasicTestWorkspace
|
|
let workspaceAutoJoin: BasicTestWorkspace
|
|
|
|
before(async () => {
|
|
await beforeEachContext()
|
|
;[admin, user1, user2, user3] = await Promise.all([
|
|
createTestUser({
|
|
name: 'admin user',
|
|
role: Roles.Server.User,
|
|
email: `${createRandomString()}@example.org`,
|
|
verified: true
|
|
}),
|
|
createTestUser({
|
|
name: 'user 1',
|
|
role: Roles.Server.User,
|
|
email: `${createRandomString()}@example.org`,
|
|
verified: true
|
|
}),
|
|
createTestUser({
|
|
name: 'user 2',
|
|
role: Roles.Server.User,
|
|
email: `${createRandomString()}@example.org`,
|
|
verified: true
|
|
}),
|
|
createTestUser({
|
|
name: 'user 3',
|
|
role: Roles.Server.User,
|
|
email: `${createRandomString()}@example.org`,
|
|
verified: true
|
|
})
|
|
])
|
|
;[workspace1, dismissedWorkspace, workspace2, workspaceAutoJoin] =
|
|
await Promise.all([
|
|
await createTestWorkspace(
|
|
{
|
|
id: createRandomString(),
|
|
name: 'Workspace 1',
|
|
ownerId: admin.id,
|
|
description: '',
|
|
discoverabilityEnabled: true
|
|
},
|
|
admin,
|
|
{ domain: 'example.org' }
|
|
),
|
|
await createTestWorkspace(
|
|
{
|
|
id: createRandomString(),
|
|
name: 'should not be visible',
|
|
ownerId: admin.id,
|
|
description: '',
|
|
discoverabilityEnabled: true
|
|
},
|
|
admin,
|
|
{
|
|
domain: 'example.org'
|
|
}
|
|
),
|
|
await createTestWorkspace(
|
|
{
|
|
id: createRandomString(),
|
|
name: 'Workspace 2',
|
|
ownerId: admin.id,
|
|
description: '',
|
|
discoverabilityEnabled: true
|
|
},
|
|
admin,
|
|
{ domain: 'example.org' }
|
|
),
|
|
await createTestWorkspace(
|
|
{
|
|
id: createRandomString(),
|
|
name: 'Worksapce autojoin',
|
|
ownerId: admin.id,
|
|
description: '',
|
|
discoverabilityEnabled: true,
|
|
discoverabilityAutoJoinEnabled: true
|
|
},
|
|
admin,
|
|
{
|
|
domain: 'example.org'
|
|
}
|
|
)
|
|
])
|
|
})
|
|
|
|
describe('Workspace.adminWorkspacesJoinRequests', () => {
|
|
it('allows users to request joining a workspace', async () => {
|
|
// User1 requests to join workspace1
|
|
const sessionUser1 = await login(user1)
|
|
await sessionUser1.execute(
|
|
RequestToJoinWorkspaceDocument,
|
|
{ input: { workspaceId: workspace1.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
// admin logs in
|
|
const sessionAdmin = await login(admin)
|
|
const workspace1Res = await sessionAdmin.execute(
|
|
GetWorkspaceWithJoinRequestsDocument,
|
|
{ workspaceId: workspace1.id },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
// has one join request
|
|
const { items: items, totalCount: totalCount } =
|
|
workspace1Res.data!.workspace!.adminWorkspacesJoinRequests!
|
|
|
|
expect(totalCount).to.equal(1)
|
|
expect(items).to.have.length(1)
|
|
expect(items[0].status).to.equal('pending')
|
|
expect(items[0].workspace.id).to.equal(workspace1.id)
|
|
expect(items[0].user.id).to.equal(user1.id)
|
|
})
|
|
|
|
it('has the ability to dismiss a join request', async () => {
|
|
// User2 requests to join dismissedWorkspace
|
|
const sessionUser2 = await login(user2)
|
|
await sessionUser2.execute(
|
|
RequestToJoinWorkspaceDocument,
|
|
{ input: { workspaceId: dismissedWorkspace.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
// admins sees a request
|
|
const sessionAdmin = await login(admin)
|
|
const joinRequests = await sessionAdmin.execute(
|
|
GetWorkspaceWithJoinRequestsDocument,
|
|
{ workspaceId: dismissedWorkspace.id },
|
|
{ assertNoErrors: true }
|
|
)
|
|
const { workspace: joinsWorkspace2 } = joinRequests.data!
|
|
expect(joinsWorkspace2!.adminWorkspacesJoinRequests!.totalCount).to.equal(1)
|
|
|
|
// user2 cancels the request
|
|
await sessionUser2.execute(
|
|
DismissWorkspaceDocument,
|
|
{ input: { workspaceId: dismissedWorkspace.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
// no request for admin
|
|
const workspaceDismissedRes = await sessionAdmin.execute(
|
|
GetWorkspaceWithJoinRequestsDocument,
|
|
{ workspaceId: dismissedWorkspace.id },
|
|
{ assertNoErrors: true }
|
|
)
|
|
const { workspace } = workspaceDismissedRes.data!
|
|
expect(workspace.adminWorkspacesJoinRequests!.items).to.have.lengthOf(0)
|
|
expect(workspace.adminWorkspacesJoinRequests!.totalCount).to.eql(0)
|
|
})
|
|
})
|
|
|
|
describe('User.workspaceJoinRequests', () => {
|
|
it('should return the workspace join requests for the user', async () => {
|
|
// User requests to join workspace1 and 2
|
|
const sessionUser = await login(user1)
|
|
await sessionUser.execute(
|
|
RequestToJoinWorkspaceDocument,
|
|
{ input: { workspaceId: workspace1.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
await sessionUser.execute(
|
|
RequestToJoinWorkspaceDocument,
|
|
{ input: { workspaceId: workspace2.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
const res = await sessionUser.execute(
|
|
GetActiveUserWithWorkspaceJoinRequestsDocument,
|
|
{},
|
|
{ assertNoErrors: true }
|
|
)
|
|
const { items, totalCount } = res.data!.activeUser!.workspaceJoinRequests!
|
|
|
|
expect(totalCount).to.equal(2)
|
|
expect(items).to.have.length(2)
|
|
expect(items[0].status).to.equal('pending')
|
|
expect(items[0].workspace.id).to.equal(workspace2.id)
|
|
expect(items[0].user.id).to.equal(user1.id)
|
|
expect(items[1].status).to.equal('pending')
|
|
expect(items[1].workspace.id).to.equal(workspace1.id)
|
|
expect(items[1].user.id).to.equal(user1.id)
|
|
})
|
|
|
|
it('does not show request that were dissmissed for the user', async () => {
|
|
// User requests to join workspaceDismissed
|
|
const sessionUser = await login(user2)
|
|
await sessionUser.execute(
|
|
RequestToJoinWorkspaceDocument,
|
|
{ input: { workspaceId: dismissedWorkspace.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
// dismisses it
|
|
await sessionUser.execute(
|
|
DismissWorkspaceDocument,
|
|
{ input: { workspaceId: dismissedWorkspace.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
const res = await sessionUser.execute(
|
|
GetActiveUserWithWorkspaceJoinRequestsDocument,
|
|
{},
|
|
{ assertNoErrors: true }
|
|
)
|
|
const { items, totalCount } = res.data!.activeUser!.workspaceJoinRequests!
|
|
|
|
expect(totalCount).to.equal(0)
|
|
expect(items).to.have.length(0)
|
|
})
|
|
})
|
|
|
|
describe('joining a workspace', () => {
|
|
it('allows admin accepting a join request to a workspace', async () => {
|
|
const sessionAdmin = await login(admin)
|
|
const sessionUser = await login(user1)
|
|
|
|
// User requests to join workspace1
|
|
await sessionUser.execute(
|
|
RequestToJoinWorkspaceDocument,
|
|
{ input: { workspaceId: workspace1.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
await sessionAdmin.execute(
|
|
ApproveJoinRequestDocument,
|
|
{ input: { workspaceId: workspace1.id, userId: user1.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
const res = await sessionAdmin.execute(GetWorkspaceTeamDocument, {
|
|
workspaceId: workspace1.id
|
|
})
|
|
|
|
const { items, totalCount } = res.data!.workspace.team
|
|
|
|
expect(totalCount).to.equal(2)
|
|
expect(items).to.have.length(2)
|
|
expect(items[0].id).to.equal(user1.id)
|
|
})
|
|
|
|
it('allows admin denying a join request to a workspace', async () => {
|
|
const sessionAdmin = await login(admin)
|
|
const sessionUser = await login(user2)
|
|
|
|
// User requests to join workspace1
|
|
await sessionUser.execute(
|
|
RequestToJoinWorkspaceDocument,
|
|
{ input: { workspaceId: workspace2.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
await sessionAdmin.execute(
|
|
DenyJoinRequestDocument,
|
|
{ input: { workspaceId: workspace2.id, userId: user2.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
const res = await sessionAdmin.execute(GetWorkspaceTeamDocument, {
|
|
workspaceId: workspace2.id
|
|
})
|
|
|
|
const { items, totalCount } = res.data!.workspace.team
|
|
|
|
expect(totalCount).to.equal(1)
|
|
expect(items).to.have.length(1)
|
|
})
|
|
|
|
it('doesnt allow the joiner user to hack around their way into a workspace', async () => {
|
|
const sessionAdmin = await login(admin)
|
|
const sessionUser = await login(user3)
|
|
|
|
// User requests to join workspace1
|
|
await sessionUser.execute(
|
|
RequestToJoinWorkspaceDocument,
|
|
{ input: { workspaceId: workspace2.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
// Accepts himself
|
|
const autoAcceptAttempt = await sessionUser.execute(
|
|
ApproveJoinRequestDocument,
|
|
{ input: { workspaceId: workspace2.id, userId: user3.id } },
|
|
{ assertNoErrors: false }
|
|
)
|
|
|
|
const autoDenyAttempt = await sessionUser.execute(
|
|
DenyJoinRequestDocument,
|
|
{ input: { workspaceId: workspace2.id, userId: user3.id } },
|
|
{ assertNoErrors: false }
|
|
)
|
|
|
|
const res = await sessionAdmin.execute(GetWorkspaceTeamDocument, {
|
|
workspaceId: workspace2.id
|
|
})
|
|
|
|
const { items, totalCount } = res.data!.workspace.team
|
|
|
|
const AUTH_ERROR = 'You are not authorized to access this resource.'
|
|
expect(autoAcceptAttempt).to.haveGraphQLErrors()
|
|
expect(autoAcceptAttempt.errors![0].message).to.contain(AUTH_ERROR)
|
|
expect(autoDenyAttempt).to.haveGraphQLErrors()
|
|
expect(autoDenyAttempt.errors![0].message).to.contain(AUTH_ERROR)
|
|
expect(totalCount).to.equal(1)
|
|
expect(items).to.have.length(1)
|
|
})
|
|
|
|
it('can auto join if admin had previously preconfigured it', async () => {
|
|
const sessionAdmin = await login(admin)
|
|
const sessionUser = await login(user3)
|
|
|
|
// User requests to join workspace1
|
|
await sessionUser.execute(
|
|
RequestToJoinWorkspaceDocument,
|
|
{ input: { workspaceId: workspaceAutoJoin.id } },
|
|
{ assertNoErrors: true }
|
|
)
|
|
|
|
const res = await sessionAdmin.execute(GetWorkspaceTeamDocument, {
|
|
workspaceId: workspaceAutoJoin.id
|
|
})
|
|
|
|
const { items, totalCount } = res.data!.workspace.team
|
|
|
|
expect(totalCount).to.equal(2)
|
|
expect(items).to.have.length(2)
|
|
expect(items[0].id).to.equal(user3.id)
|
|
})
|
|
})
|
|
})
|