From f74227067b7151cb63a54e815e57f81984467bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20S=C3=B3jko?= Date: Tue, 11 Oct 2022 11:49:54 +0200 Subject: [PATCH] feat(workspace): add invite access level --- .../src/Domain/Workspace/WorkspaceAccessLevel.ts | 0 packages/common/src/Domain/index.ts | 1 + .../1665481699781-add-invite-access-level.ts | 13 +++++++++++++ .../src/Controller/WorkspacesController.spec.ts | 3 ++- .../src/Controller/WorkspacesController.ts | 3 ++- .../workspace/src/Domain/Invite/WorkspaceInvite.ts | 8 ++++++++ .../AcceptInvitation/AcceptInvitation.spec.ts | 7 +++++++ .../UseCase/AcceptInvitation/AcceptInvitation.ts | 1 + .../UseCase/CreateWorkspace/CreateWorkspace.ts | 2 +- .../InviteToWorkspace/InviteToWorkspace.spec.ts | 3 +++ .../UseCase/InviteToWorkspace/InviteToWorkspace.ts | 1 + .../InviteToWorkspace/InviteToWorkspaceDTO.ts | 3 ++- .../workspace/src/Domain/Workspace/WorkspaceUser.ts | 3 ++- 13 files changed, 43 insertions(+), 5 deletions(-) rename packages/{workspace => common}/src/Domain/Workspace/WorkspaceAccessLevel.ts (100%) create mode 100644 packages/workspace/migrations/1665481699781-add-invite-access-level.ts diff --git a/packages/workspace/src/Domain/Workspace/WorkspaceAccessLevel.ts b/packages/common/src/Domain/Workspace/WorkspaceAccessLevel.ts similarity index 100% rename from packages/workspace/src/Domain/Workspace/WorkspaceAccessLevel.ts rename to packages/common/src/Domain/Workspace/WorkspaceAccessLevel.ts diff --git a/packages/common/src/Domain/index.ts b/packages/common/src/Domain/index.ts index a0c2abe90..8779f81eb 100644 --- a/packages/common/src/Domain/index.ts +++ b/packages/common/src/Domain/index.ts @@ -24,4 +24,5 @@ export * from './Type/Either' export * from './Type/Only' export * from './Validator/UuidValidator' export * from './Validator/ValidatorInterface' +export * from './Workspace/WorkspaceAccessLevel' export * from './Workspace/WorkspaceType' diff --git a/packages/workspace/migrations/1665481699781-add-invite-access-level.ts b/packages/workspace/migrations/1665481699781-add-invite-access-level.ts new file mode 100644 index 000000000..998be58ec --- /dev/null +++ b/packages/workspace/migrations/1665481699781-add-invite-access-level.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from 'typeorm' + +export class addInviteAccessLevel1665481699781 implements MigrationInterface { + name = 'addInviteAccessLevel1665481699781' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `workspace_invites` ADD `access_level` varchar(64) NOT NULL') + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('ALTER TABLE `workspace_invites` DROP COLUMN `access_level`') + } +} diff --git a/packages/workspace/src/Controller/WorkspacesController.spec.ts b/packages/workspace/src/Controller/WorkspacesController.spec.ts index 0f90df225..b8ca9d3ce 100644 --- a/packages/workspace/src/Controller/WorkspacesController.spec.ts +++ b/packages/workspace/src/Controller/WorkspacesController.spec.ts @@ -1,4 +1,4 @@ -import { WorkspaceType } from '@standardnotes/common' +import { WorkspaceAccessLevel, WorkspaceType } from '@standardnotes/common' import 'reflect-metadata' import { CreateWorkspace } from '../Domain/UseCase/CreateWorkspace/CreateWorkspace' @@ -42,6 +42,7 @@ describe('WorkspacesController', () => { const result = await createController().inviteToWorkspace({ inviteeEmail: 'test@test.te', workspaceUuid: 'w-1-2-3', + accessLevel: WorkspaceAccessLevel.ReadOnly, }) expect(result).toEqual({ diff --git a/packages/workspace/src/Controller/WorkspacesController.ts b/packages/workspace/src/Controller/WorkspacesController.ts index b577f3ab1..ddd25edaf 100644 --- a/packages/workspace/src/Controller/WorkspacesController.ts +++ b/packages/workspace/src/Controller/WorkspacesController.ts @@ -7,7 +7,7 @@ import { WorkspaceInvitationResponse, WorkspaceServerInterface, } from '@standardnotes/api' -import { Uuid, WorkspaceType } from '@standardnotes/common' +import { Uuid, WorkspaceAccessLevel, WorkspaceType } from '@standardnotes/common' import TYPES from '../Bootstrap/Types' import { CreateWorkspace } from '../Domain/UseCase/CreateWorkspace/CreateWorkspace' @@ -25,6 +25,7 @@ export class WorkspacesController implements WorkspaceServerInterface { inviteeEmail: params.inviteeEmail, workspaceUuid: params.workspaceUuid, inviterUuid: params.inviterUuid as Uuid, + accessLevel: params.accessLevel as WorkspaceAccessLevel, }) return { diff --git a/packages/workspace/src/Domain/Invite/WorkspaceInvite.ts b/packages/workspace/src/Domain/Invite/WorkspaceInvite.ts index 03005769b..93eaf7493 100644 --- a/packages/workspace/src/Domain/Invite/WorkspaceInvite.ts +++ b/packages/workspace/src/Domain/Invite/WorkspaceInvite.ts @@ -1,4 +1,6 @@ +import { WorkspaceAccessLevel } from '@standardnotes/common' import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' + import { Workspace } from '../Workspace/Workspace' import { WorkspaceInviteStatus } from './WorkspaceInviteStatus' @@ -40,6 +42,12 @@ export class WorkspaceInvite { }) declare workspaceUuid: string + @Column({ + name: 'access_level', + length: 64, + }) + declare accessLevel: WorkspaceAccessLevel + @Column({ name: 'created_at', type: 'bigint', diff --git a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.spec.ts b/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.spec.ts index 145549ba7..ba2e10db0 100644 --- a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.spec.ts +++ b/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.spec.ts @@ -6,6 +6,7 @@ import { WorkspaceInviteRepositoryInterface } from '../../Invite/WorkspaceInvite import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' import { AcceptInvitation } from './AcceptInvitation' +import { WorkspaceAccessLevel } from '@standardnotes/common' describe('AcceptInvitation', () => { let workspaceInviteRepository: WorkspaceInviteRepositoryInterface @@ -19,6 +20,8 @@ describe('AcceptInvitation', () => { invite = { uuid: 'i-1-2-3', workspaceUuid: 'w-1-2-3', + inviteeEmail: 'test@test.te', + accessLevel: WorkspaceAccessLevel.WriteAndRead, } as jest.Mocked workspaceInviteRepository = {} as jest.Mocked workspaceInviteRepository.findOneByUuid = jest.fn().mockReturnValue(invite) @@ -45,6 +48,8 @@ describe('AcceptInvitation', () => { updatedAt: 1, uuid: 'i-1-2-3', workspaceUuid: 'w-1-2-3', + inviteeEmail: 'test@test.te', + accessLevel: 'write-and-read', }) expect(workspaceUserRepository.save).toHaveBeenCalledWith({ encryptedPrivateKey: 'foo', @@ -52,6 +57,8 @@ describe('AcceptInvitation', () => { status: 'pending-keyshare', userUuid: 'u-1-2-3', workspaceUuid: 'w-1-2-3', + accessLevel: 'write-and-read', + userDisplayName: 'test@test.te', }) }) diff --git a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.ts b/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.ts index 4b3ec3a16..01ca793df 100644 --- a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.ts +++ b/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.ts @@ -40,6 +40,7 @@ export class AcceptInvitation implements UseCaseInterface { workspaceUser.workspaceUuid = invite.workspaceUuid workspaceUser.publicKey = dto.publicKey workspaceUser.encryptedPrivateKey = dto.encryptedPrivateKey + workspaceUser.accessLevel = invite.accessLevel workspaceUser.status = WorkspaceUserStatus.PendingKeyshare await this.workspaceUserRepository.save(workspaceUser) diff --git a/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspace.ts b/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspace.ts index 932e38583..08442ddf3 100644 --- a/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspace.ts +++ b/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspace.ts @@ -1,9 +1,9 @@ import { TimerInterface } from '@standardnotes/time' +import { WorkspaceAccessLevel } from '@standardnotes/common' import { inject, injectable } from 'inversify' import TYPES from '../../../Bootstrap/Types' import { Workspace } from '../../Workspace/Workspace' -import { WorkspaceAccessLevel } from '../../Workspace/WorkspaceAccessLevel' import { WorkspaceRepositoryInterface } from '../../Workspace/WorkspaceRepositoryInterface' import { WorkspaceUser } from '../../Workspace/WorkspaceUser' import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' diff --git a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.spec.ts b/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.spec.ts index 8e2955519..f6c2cd674 100644 --- a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.spec.ts +++ b/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.spec.ts @@ -6,6 +6,7 @@ import { WorkspaceInviteRepositoryInterface } from '../../Invite/WorkspaceInvite import { InviteToWorkspace } from './InviteToWorkspace' import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface' import { DomainEventPublisherInterface, WorkspaceInviteCreatedEvent } from '@standardnotes/domain-events' +import { WorkspaceAccessLevel } from '@standardnotes/common' describe('InviteToWorkspace', () => { let workspaceInviteRepository: WorkspaceInviteRepositoryInterface @@ -42,6 +43,7 @@ describe('InviteToWorkspace', () => { inviteeEmail: 'test@test.te', inviterUuid: 'u-1-2-3', workspaceUuid: 'w-1-2-3', + accessLevel: WorkspaceAccessLevel.WriteAndRead, }) expect(result).toEqual({ @@ -51,6 +53,7 @@ describe('InviteToWorkspace', () => { inviteeEmail: 'test@test.te', workspaceUuid: 'w-1-2-3', status: 'created', + accessLevel: 'write-and-read', createdAt: 1, updatedAt: 1, }, diff --git a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.ts b/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.ts index 7f1940591..b6a873215 100644 --- a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.ts +++ b/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.ts @@ -26,6 +26,7 @@ export class InviteToWorkspace implements UseCaseInterface { invite.inviterUuid = dto.inviterUuid invite.inviteeEmail = dto.inviteeEmail invite.workspaceUuid = dto.workspaceUuid + invite.accessLevel = dto.accessLevel invite.status = WorkspaceInviteStatus.Created const timestamp = this.timer.getTimestampInMicroseconds() diff --git a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspaceDTO.ts b/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspaceDTO.ts index 0c52df4d4..d1639f820 100644 --- a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspaceDTO.ts +++ b/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspaceDTO.ts @@ -1,7 +1,8 @@ -import { Uuid } from '@standardnotes/common' +import { Uuid, WorkspaceAccessLevel } from '@standardnotes/common' export type InviteToWorkspaceDTO = { workspaceUuid: Uuid inviterUuid: Uuid inviteeEmail: string + accessLevel: WorkspaceAccessLevel } diff --git a/packages/workspace/src/Domain/Workspace/WorkspaceUser.ts b/packages/workspace/src/Domain/Workspace/WorkspaceUser.ts index 6fecb4bc1..646ca671b 100644 --- a/packages/workspace/src/Domain/Workspace/WorkspaceUser.ts +++ b/packages/workspace/src/Domain/Workspace/WorkspaceUser.ts @@ -1,5 +1,6 @@ +import { WorkspaceAccessLevel } from '@standardnotes/common' import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm' -import { WorkspaceAccessLevel } from './WorkspaceAccessLevel' + import { WorkspaceUserStatus } from './WorkspaceUserStatus' @Entity({ name: 'workspace_users' })