e703bb7415
* feat(workspaces): drop createdByUserId from the dataschema * feat(workspaces): repositories WIP * merge * protect against removing last admin in workspace * quick impl and stub tests * add tests * services * unit tests for role services * fix(workspaces): maybe tests work like this * fix(workspaces): dry * fix(workspaces): initialize tests better * fix(workspaces): so true * fix(workspaces): right * fix(workspaces): self nit * fix(workspaces): better repository structure * fix(workspaces): repair tests, use `example.org` * fix(workspaces): add tests for new repo functions, repair other tests * fix(workspaces): better distinction between service-level guarantees and repo-level guarantees * fix(workspaces): review comments and stencil tests * fix(workspaces): add tests * fix(workspaces): tests work --------- Co-authored-by: Gergő Jedlicska <gergo@jedlicska.com>
254 lines
8.4 KiB
TypeScript
254 lines
8.4 KiB
TypeScript
import {
|
|
deleteWorkspaceRoleFactory,
|
|
getWorkspaceRoleForUserFactory,
|
|
getWorkspaceFactory,
|
|
upsertWorkspaceFactory,
|
|
upsertWorkspaceRoleFactory,
|
|
getWorkspaceRolesFactory,
|
|
getWorkspaceRolesForUserFactory
|
|
} from '@/modules/workspaces/repositories/workspaces'
|
|
import db from '@/db/knex'
|
|
import cryptoRandomString from 'crypto-random-string'
|
|
import { expect } from 'chai'
|
|
import { Workspace, WorkspaceAcl } from '@/modules/workspaces/domain/types'
|
|
import { expectToThrow } from '@/test/assertionHelper'
|
|
import { BasicTestUser, createTestUser } from '@/test/authHelper'
|
|
|
|
const getWorkspace = getWorkspaceFactory({ db })
|
|
const upsertWorkspace = upsertWorkspaceFactory({ db })
|
|
const deleteWorkspaceRole = deleteWorkspaceRoleFactory({ db })
|
|
const getWorkspaceRoles = getWorkspaceRolesFactory({ db })
|
|
const getWorkspaceRoleForUser = getWorkspaceRoleForUserFactory({ db })
|
|
const getWorkspaceRolesForUser = getWorkspaceRolesForUserFactory({ db })
|
|
const upsertWorkspaceRole = upsertWorkspaceRoleFactory({ db })
|
|
|
|
const createAndStoreTestUser = async (): Promise<BasicTestUser> => {
|
|
const testId = cryptoRandomString({ length: 6 })
|
|
|
|
const userRecord: BasicTestUser = {
|
|
name: `test-user-${testId}`,
|
|
email: `test-user-${testId}@example.org`,
|
|
password: '',
|
|
id: '',
|
|
role: 'server:user'
|
|
}
|
|
|
|
await createTestUser(userRecord)
|
|
|
|
return userRecord
|
|
}
|
|
|
|
const createAndStoreTestWorkspace = async (): Promise<Workspace> => {
|
|
const workspace: Workspace = {
|
|
id: cryptoRandomString({ length: 10 }),
|
|
name: cryptoRandomString({ length: 10 }),
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
description: null,
|
|
logoUrl: null
|
|
}
|
|
|
|
await upsertWorkspace({ workspace })
|
|
|
|
return workspace
|
|
}
|
|
|
|
describe('Workspace repositories', () => {
|
|
describe('getWorkspaceFactory creates a function, that', () => {
|
|
it('returns null if the workspace is not found', async () => {
|
|
const workspace = await getWorkspace({
|
|
workspaceId: cryptoRandomString({ length: 10 })
|
|
})
|
|
expect(workspace).to.be.null
|
|
})
|
|
// not testing get here, we're going to use that for testing upsert
|
|
})
|
|
|
|
describe('upsertWorkspaceFactory creates a function, that', () => {
|
|
it('upserts the workspace', async () => {
|
|
const testWorkspace = await createAndStoreTestWorkspace()
|
|
const storedWorkspace = await getWorkspace({ workspaceId: testWorkspace.id })
|
|
expect(storedWorkspace).to.deep.equal(testWorkspace)
|
|
|
|
const modifiedTestWorkspace: Workspace = {
|
|
...testWorkspace,
|
|
description: 'now im adding a description to the workspace'
|
|
}
|
|
|
|
await upsertWorkspace({ workspace: modifiedTestWorkspace })
|
|
|
|
const modifiedStoredWorkspace = await getWorkspace({
|
|
workspaceId: testWorkspace.id
|
|
})
|
|
|
|
expect(modifiedStoredWorkspace).to.deep.equal(modifiedTestWorkspace)
|
|
})
|
|
it('updates only relevant workspace fields', async () => {
|
|
const testWorkspace = await createAndStoreTestWorkspace()
|
|
const storedWorkspace = await getWorkspace({ workspaceId: testWorkspace.id })
|
|
expect(storedWorkspace).to.deep.equal(testWorkspace)
|
|
|
|
await upsertWorkspace({
|
|
workspace: {
|
|
...testWorkspace,
|
|
id: cryptoRandomString({ length: 13 }),
|
|
createdAt: new Date()
|
|
}
|
|
})
|
|
|
|
const modifiedStoredWorkspace = await getWorkspace({
|
|
workspaceId: testWorkspace.id
|
|
})
|
|
|
|
expect(modifiedStoredWorkspace).to.deep.equal(testWorkspace)
|
|
})
|
|
})
|
|
|
|
describe('deleteWorkspaceRoleFactory creates a function, that', () => {
|
|
it('deletes specified workspace role', async () => {
|
|
const { id: userId } = await createAndStoreTestUser()
|
|
const { id: workspaceId } = await createAndStoreTestWorkspace()
|
|
|
|
await upsertWorkspaceRole({ userId, workspaceId, role: 'workspace:member' })
|
|
await deleteWorkspaceRole({ userId, workspaceId })
|
|
|
|
const role = await getWorkspaceRoleForUser({ userId, workspaceId })
|
|
|
|
expect(role).to.be.null
|
|
})
|
|
it('returns deleted workspace role', async () => {
|
|
const { id: userId } = await createAndStoreTestUser()
|
|
const { id: workspaceId } = await createAndStoreTestWorkspace()
|
|
|
|
const createdRole: WorkspaceAcl = {
|
|
userId,
|
|
workspaceId,
|
|
role: 'workspace:member'
|
|
}
|
|
await upsertWorkspaceRole(createdRole)
|
|
const deletedRole = await deleteWorkspaceRole({ userId, workspaceId })
|
|
|
|
expect(deletedRole).to.deep.equal(createdRole)
|
|
})
|
|
it('return null if role does not exist', async () => {
|
|
const deletedRole = await deleteWorkspaceRole({ userId: '', workspaceId: '' })
|
|
|
|
expect(deletedRole).to.be.null
|
|
})
|
|
})
|
|
|
|
describe('getWorkspaceRolesFactory creates a function, that', () => {
|
|
it('returns all roles in a given workspace', async () => {
|
|
const { id: workspaceId } = await createAndStoreTestWorkspace()
|
|
|
|
const { id: userIdA } = await createAndStoreTestUser()
|
|
const { id: userIdB } = await createAndStoreTestUser()
|
|
|
|
await upsertWorkspaceRole({
|
|
workspaceId,
|
|
userId: userIdA,
|
|
role: 'workspace:admin'
|
|
})
|
|
await upsertWorkspaceRole({
|
|
workspaceId,
|
|
userId: userIdB,
|
|
role: 'workspace:admin'
|
|
})
|
|
|
|
const workspaceRoles = await getWorkspaceRoles({ workspaceId })
|
|
|
|
expect(workspaceRoles.length).to.equal(2)
|
|
expect(workspaceRoles.some(({ userId }) => userId === userIdA)).to.be.true
|
|
expect(workspaceRoles.some(({ userId }) => userId === userIdB)).to.be.true
|
|
})
|
|
})
|
|
|
|
describe('getWorkspaceRoleForUserFactory creates a function, that', () => {
|
|
it('returns the current role for a given user in a given workspace', async () => {
|
|
const { id: userId } = await createAndStoreTestUser()
|
|
const { id: workspaceId } = await createAndStoreTestWorkspace()
|
|
|
|
await upsertWorkspaceRole({ workspaceId, userId, role: 'workspace:admin' })
|
|
|
|
const workspaceRole = await getWorkspaceRoleForUser({ userId, workspaceId })
|
|
|
|
expect(workspaceRole).to.not.be.null
|
|
expect(workspaceRole?.userId).to.equal(userId)
|
|
})
|
|
it('returns `null` if the given user does not have a role in the given workspace', async () => {
|
|
const workspaceRole = await getWorkspaceRoleForUser({
|
|
userId: 'invalid-user-id',
|
|
workspaceId: 'invalid-workspace-id'
|
|
})
|
|
|
|
expect(workspaceRole).to.be.null
|
|
})
|
|
})
|
|
|
|
describe('getWorkspaceRolesForUserFactory creates a function, that', () => {
|
|
it('returns the current role for a given user across all workspaces', async () => {
|
|
const { id: userId } = await createAndStoreTestUser()
|
|
|
|
const { id: workspaceIdA } = await createAndStoreTestWorkspace()
|
|
const { id: workspaceIdB } = await createAndStoreTestWorkspace()
|
|
|
|
await upsertWorkspaceRole({
|
|
workspaceId: workspaceIdA,
|
|
userId,
|
|
role: 'workspace:admin'
|
|
})
|
|
await upsertWorkspaceRole({
|
|
workspaceId: workspaceIdB,
|
|
userId,
|
|
role: 'workspace:admin'
|
|
})
|
|
|
|
const workspaceRoles = await getWorkspaceRolesForUser({ userId })
|
|
|
|
expect(workspaceRoles.length).to.equal(2)
|
|
expect(workspaceRoles.some(({ workspaceId }) => workspaceId === workspaceIdA)).to
|
|
.be.true
|
|
expect(workspaceRoles.some(({ workspaceId }) => workspaceId === workspaceIdB)).to
|
|
.be.true
|
|
})
|
|
it('returns the current role for workspaces specified by the workspace id filter, if provided', async () => {
|
|
const { id: userId } = await createAndStoreTestUser()
|
|
|
|
const { id: workspaceIdA } = await createAndStoreTestWorkspace()
|
|
const { id: workspaceIdB } = await createAndStoreTestWorkspace()
|
|
|
|
await upsertWorkspaceRole({
|
|
workspaceId: workspaceIdA,
|
|
userId,
|
|
role: 'workspace:admin'
|
|
})
|
|
await upsertWorkspaceRole({
|
|
workspaceId: workspaceIdB,
|
|
userId,
|
|
role: 'workspace:admin'
|
|
})
|
|
|
|
const workspaceRoles = await getWorkspaceRolesForUser(
|
|
{ userId },
|
|
{ workspaceIdFilter: [workspaceIdA] }
|
|
)
|
|
|
|
expect(workspaceRoles.length).to.equal(1)
|
|
expect(workspaceRoles[0].workspaceId).to.equal(workspaceIdA)
|
|
})
|
|
})
|
|
|
|
describe('upsertWorkspaceRoleFactory creates a function, that', () => {
|
|
it('throws if an unknown role is provided', async () => {
|
|
const role: WorkspaceAcl = {
|
|
// @ts-expect-error type asserts valid values for `role`
|
|
role: 'fake-role',
|
|
userId: '',
|
|
workspaceId: ''
|
|
}
|
|
|
|
await expectToThrow(() => upsertWorkspaceRole(role))
|
|
})
|
|
})
|
|
})
|