diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 53655528f..85fb2a6b3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -95,11 +95,6 @@ updates: schedule: interval: "daily" - - package-ecosystem: "npm" - directory: "/packages/workspace" - schedule: - interval: "daily" - - package-ecosystem: "github-actions" directory: "/" schedule: diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml deleted file mode 100644 index 914604b75..000000000 --- a/.github/workflows/workspace.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Workspace Server - -concurrency: - group: workspace - cancel-in-progress: true - -on: - push: - tags: - - '*standardnotes/workspace-server*' - workflow_dispatch: - -jobs: - call_server_application_workflow: - name: Server Application - uses: standardnotes/server/.github/workflows/common-server-application.yml@main - with: - service_name: workspace - workspace_name: "@standardnotes/workspace-server" - package_path: packages/workspace - secrets: inherit - - newrelic: - needs: call_server_application_workflow - - runs-on: ubuntu-latest - steps: - - - name: Create New Relic deployment marker for Web - uses: newrelic/deployment-marker-action@v1 - with: - accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }} - apiKey: ${{ secrets.NEW_RELIC_API_KEY }} - applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_WORKSPACE_WEB_PROD }} - revision: "${{ github.sha }}" - description: "Automated Deployment via Github Actions" - user: "${{ github.actor }}" - - - name: Create New Relic deployment marker for Worker - uses: newrelic/deployment-marker-action@v1 - with: - accountId: ${{ secrets.NEW_RELIC_ACCOUNT_ID }} - apiKey: ${{ secrets.NEW_RELIC_API_KEY }} - applicationId: ${{ secrets.NEW_RELIC_APPLICATION_ID_WORKSPACE_WORKER_PROD }} - revision: "${{ github.sha }}" - description: "Automated Deployment via Github Actions" - user: "${{ github.actor }}" diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index d27f7bbe4..f41810c18 100755 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -349,7 +349,6 @@ export API_GATEWAY_NEW_RELIC_NO_CONFIG_FILE=true export API_GATEWAY_SYNCING_SERVER_JS_URL=http://localhost:$SYNCING_SERVER_PORT export API_GATEWAY_AUTH_SERVER_URL=http://localhost:$AUTH_SERVER_PORT -export API_GATEWAY_WORKSPACE_SERVER_URL=http://localhost:3004 export API_GATEWAY_REVISIONS_SERVER_URL=http://localhost:3005 if [ -z "$PUBLIC_FILES_SERVER_URL" ]; then export PUBLIC_FILES_SERVER_URL=http://localhost:3125 diff --git a/docker/localstack_bootstrap.sh b/docker/localstack_bootstrap.sh index 74d8f25cf..79202ed34 100755 --- a/docker/localstack_bootstrap.sh +++ b/docker/localstack_bootstrap.sh @@ -91,13 +91,6 @@ TOPIC_CREATED_RESULT=$(create_topic ${SCHEDULER_TOPIC_NAME}) echo "created topic: $TOPIC_CREATED_RESULT" SCHEDULER_TOPIC_ARN=$(get_topic_arn_from_name $SCHEDULER_TOPIC_NAME) -WORKSPACE_TOPIC_NAME="workspace-local-topic" - -echo "creating topic $WORKSPACE_TOPIC_NAME" -TOPIC_CREATED_RESULT=$(create_topic ${WORKSPACE_TOPIC_NAME}) -echo "created topic: $TOPIC_CREATED_RESULT" -WORKSPACE_TOPIC_ARN=$(get_topic_arn_from_name $WORKSPACE_TOPIC_NAME) - QUEUE_NAME="analytics-local-queue" echo "creating queue $QUEUE_NAME" @@ -182,13 +175,6 @@ QUEUE_URL=$(create_queue ${QUEUE_NAME}) echo "created queue: $QUEUE_URL" SCHEDULER_QUEUE_ARN=$(get_queue_arn_from_name $QUEUE_NAME) -QUEUE_NAME="workspace-local-queue" - -echo "creating queue $QUEUE_NAME" -QUEUE_URL=$(create_queue ${QUEUE_NAME}) -echo "created queue: $QUEUE_URL" -WORKSPACE_QUEUE_ARN=$(get_queue_arn_from_name $QUEUE_NAME) - echo "all topics are:" echo "$(get_all_topics)" diff --git a/packages/api-gateway/.env.sample b/packages/api-gateway/.env.sample index 2959c2a60..ca02ce5bc 100644 --- a/packages/api-gateway/.env.sample +++ b/packages/api-gateway/.env.sample @@ -6,7 +6,6 @@ PORT=3000 SYNCING_SERVER_JS_URL=http://syncing_server_js:3000 AUTH_SERVER_URL=http://auth:3000 -WORKSPACE_SERVER_URL=http://workspace:3000 WEB_SOCKET_SERVER_URL=http://websockets:3000 PAYMENTS_SERVER_URL=http://payments:3000 FILES_SERVER_URL=http://files:3000 diff --git a/packages/api-gateway/bin/server.ts b/packages/api-gateway/bin/server.ts index e0e415db6..d415839f8 100644 --- a/packages/api-gateway/bin/server.ts +++ b/packages/api-gateway/bin/server.ts @@ -19,7 +19,6 @@ import '../src/Controller/v1/TokensController' import '../src/Controller/v1/OfflineController' import '../src/Controller/v1/FilesController' import '../src/Controller/v1/SubscriptionInvitesController' -import '../src/Controller/v1/WorkspacesController' import '../src/Controller/v1/InvitesController' import '../src/Controller/v1/AuthenticatorsController' import '../src/Controller/v1/ProxyController' diff --git a/packages/api-gateway/src/Bootstrap/Container.ts b/packages/api-gateway/src/Bootstrap/Container.ts index 259a458bf..90c00acf4 100644 --- a/packages/api-gateway/src/Bootstrap/Container.ts +++ b/packages/api-gateway/src/Bootstrap/Container.ts @@ -59,7 +59,6 @@ export class ContainerConfigLoader { container.bind(TYPES.PAYMENTS_SERVER_URL).toConstantValue(env.get('PAYMENTS_SERVER_URL', true)) container.bind(TYPES.FILES_SERVER_URL).toConstantValue(env.get('FILES_SERVER_URL', true)) container.bind(TYPES.AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET')) - container.bind(TYPES.WORKSPACE_SERVER_URL).toConstantValue(env.get('WORKSPACE_SERVER_URL', true)) container.bind(TYPES.WEB_SOCKET_SERVER_URL).toConstantValue(env.get('WEB_SOCKET_SERVER_URL', true)) container.bind(TYPES.PROXY_SERVER_URL).toConstantValue(env.get('PROXY_SERVER_URL', true)) container diff --git a/packages/api-gateway/src/Bootstrap/Types.ts b/packages/api-gateway/src/Bootstrap/Types.ts index 3c3b2a778..3feb800bd 100644 --- a/packages/api-gateway/src/Bootstrap/Types.ts +++ b/packages/api-gateway/src/Bootstrap/Types.ts @@ -9,7 +9,6 @@ const TYPES = { FILES_SERVER_URL: Symbol.for('FILES_SERVER_URL'), REVISIONS_SERVER_URL: Symbol.for('REVISIONS_SERVER_URL'), EMAIL_SERVER_URL: Symbol.for('EMAIL_SERVER_URL'), - WORKSPACE_SERVER_URL: Symbol.for('WORKSPACE_SERVER_URL'), WEB_SOCKET_SERVER_URL: Symbol.for('WEB_SOCKET_SERVER_URL'), PROXY_SERVER_URL: Symbol.for('PROXY_SERVER_URL'), AUTH_JWT_SECRET: Symbol.for('AUTH_JWT_SECRET'), diff --git a/packages/api-gateway/src/Controller/v1/InvitesController.ts b/packages/api-gateway/src/Controller/v1/InvitesController.ts deleted file mode 100644 index 69cec3fb6..000000000 --- a/packages/api-gateway/src/Controller/v1/InvitesController.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { inject } from 'inversify' -import { Request, Response } from 'express' -import { controller, BaseHttpController, httpPost } from 'inversify-express-utils' - -import TYPES from '../../Bootstrap/Types' -import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface' - -@controller('/v1/invites', TYPES.AuthMiddleware) -export class InvitesController extends BaseHttpController { - constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) { - super() - } - - @httpPost('/:inviteUuid/accept') - async accept(request: Request, response: Response): Promise { - await this.httpService.callWorkspaceServer( - request, - response, - `invites/${request.params.inviteUuid}/accept`, - request.body, - ) - } -} diff --git a/packages/api-gateway/src/Controller/v1/WorkspacesController.ts b/packages/api-gateway/src/Controller/v1/WorkspacesController.ts deleted file mode 100644 index 5f3ab8567..000000000 --- a/packages/api-gateway/src/Controller/v1/WorkspacesController.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { inject } from 'inversify' -import { Request, Response } from 'express' -import { controller, BaseHttpController, httpPost, httpGet } from 'inversify-express-utils' - -import TYPES from '../../Bootstrap/Types' -import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface' - -@controller('/v1/workspaces', TYPES.AuthMiddleware) -export class WorkspacesController extends BaseHttpController { - constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) { - super() - } - - @httpPost('/') - async create(request: Request, response: Response): Promise { - await this.httpService.callWorkspaceServer(request, response, 'workspaces', request.body) - } - - @httpGet('/:workspaceUuid/users') - async listWorkspaceUsers(request: Request, response: Response): Promise { - await this.httpService.callWorkspaceServer( - request, - response, - `workspaces/${request.params.workspaceUuid}/users`, - request.body, - ) - } - - @httpPost('/:workspaceUuid/users/:userUuid/keyshare') - async initiateKeyshare(request: Request, response: Response): Promise { - await this.httpService.callWorkspaceServer( - request, - response, - `workspaces/${request.params.workspaceUuid}/users/${request.params.userUuid}/keyshare`, - request.body, - ) - } - - @httpGet('/') - async listWorkspaces(request: Request, response: Response): Promise { - await this.httpService.callWorkspaceServer(request, response, 'workspaces', request.body) - } - - @httpPost('/:workspaceUuid/invites') - async invite(request: Request, response: Response): Promise { - await this.httpService.callWorkspaceServer( - request, - response, - `workspaces/${request.params.workspaceUuid}/invites`, - request.body, - ) - } -} diff --git a/packages/api-gateway/src/Service/Http/HttpService.ts b/packages/api-gateway/src/Service/Http/HttpService.ts index 2e3a8fe7e..b8f7ea966 100644 --- a/packages/api-gateway/src/Service/Http/HttpService.ts +++ b/packages/api-gateway/src/Service/Http/HttpService.ts @@ -16,7 +16,6 @@ export class HttpService implements HttpServiceInterface { @inject(TYPES.SYNCING_SERVER_JS_URL) private syncingServerJsUrl: string, @inject(TYPES.PAYMENTS_SERVER_URL) private paymentsServerUrl: string, @inject(TYPES.FILES_SERVER_URL) private filesServerUrl: string, - @inject(TYPES.WORKSPACE_SERVER_URL) private workspaceServerUrl: string, @inject(TYPES.WEB_SOCKET_SERVER_URL) private webSocketServerUrl: string, @inject(TYPES.REVISIONS_SERVER_URL) private revisionsServerUrl: string, @inject(TYPES.EMAIL_SERVER_URL) private emailServerUrl: string, @@ -82,21 +81,6 @@ export class HttpService implements HttpServiceInterface { await this.callServer(this.emailServerUrl, request, response, endpoint, payload) } - async callWorkspaceServer( - request: Request, - response: Response, - endpoint: string, - payload?: Record | string, - ): Promise { - if (!this.workspaceServerUrl) { - response.status(400).send({ message: 'Workspace Server not configured' }) - - return - } - - await this.callServer(this.workspaceServerUrl, request, response, endpoint, payload) - } - async callWebSocketServer( request: Request, response: Response, diff --git a/packages/api-gateway/src/Service/Http/HttpServiceInterface.ts b/packages/api-gateway/src/Service/Http/HttpServiceInterface.ts index df6209a56..249f35c34 100644 --- a/packages/api-gateway/src/Service/Http/HttpServiceInterface.ts +++ b/packages/api-gateway/src/Service/Http/HttpServiceInterface.ts @@ -43,12 +43,6 @@ export interface HttpServiceInterface { endpoint: string, payload?: Record | string, ): Promise - callWorkspaceServer( - request: Request, - response: Response, - endpoint: string, - payload?: Record | string, - ): Promise callWebSocketServer( request: Request, response: Response, diff --git a/packages/common/src/Domain/Email/EmailMessageIdentifier.ts b/packages/common/src/Domain/Email/EmailMessageIdentifier.ts index 63e663657..a68392255 100644 --- a/packages/common/src/Domain/Email/EmailMessageIdentifier.ts +++ b/packages/common/src/Domain/Email/EmailMessageIdentifier.ts @@ -26,7 +26,6 @@ export enum EmailMessageIdentifier { REFUND_NOTICE = 'REFUND_NOTICE', REFUND_REQUESTED = 'REFUND_REQUESTED', RATE_ADJUSTMENT_NOTICE = 'RATE_ADJUSTMENT_NOTICE', - WORKSPACE_INVITE_CREATED = 'WORKSPACE_INVITE_CREATED', EXIT_DISCOUNT = 'EXIT_DISCOUNT', SUBSCRIPTION_CANCELLED = 'SUBSCRIPTION_CANCELLED', } diff --git a/packages/common/src/Domain/Workspace/WorkspaceAccessLevel.ts b/packages/common/src/Domain/Workspace/WorkspaceAccessLevel.ts deleted file mode 100644 index f4a33b619..000000000 --- a/packages/common/src/Domain/Workspace/WorkspaceAccessLevel.ts +++ /dev/null @@ -1,6 +0,0 @@ -export enum WorkspaceAccessLevel { - Owner = 'owner', - Admin = 'admin', - ReadOnly = 'read-only', - WriteAndRead = 'write-and-read', -} diff --git a/packages/common/src/Domain/Workspace/WorkspaceType.ts b/packages/common/src/Domain/Workspace/WorkspaceType.ts deleted file mode 100644 index 06af2d065..000000000 --- a/packages/common/src/Domain/Workspace/WorkspaceType.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum WorkspaceType { - Root = 'root', - Team = 'team', - Private = 'private', -} diff --git a/packages/common/src/Domain/Workspace/WorkspaceUserStatus.ts b/packages/common/src/Domain/Workspace/WorkspaceUserStatus.ts deleted file mode 100644 index 10627642a..000000000 --- a/packages/common/src/Domain/Workspace/WorkspaceUserStatus.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum WorkspaceUserStatus { - Active = 'active', - PendingKeyshare = 'pending-keyshare', -} diff --git a/packages/common/src/Domain/index.ts b/packages/common/src/Domain/index.ts index f08da9379..bff742891 100644 --- a/packages/common/src/Domain/index.ts +++ b/packages/common/src/Domain/index.ts @@ -20,6 +20,3 @@ export * from './Subscription/SubscriptionName' export * from './Type/Either' export * from './Type/Only' export * from './User/UserRequestType' -export * from './Workspace/WorkspaceAccessLevel' -export * from './Workspace/WorkspaceType' -export * from './Workspace/WorkspaceUserStatus' diff --git a/packages/domain-events/src/Domain/Event/DomainEventService.ts b/packages/domain-events/src/Domain/Event/DomainEventService.ts index 49c9a7d18..b27454027 100644 --- a/packages/domain-events/src/Domain/Event/DomainEventService.ts +++ b/packages/domain-events/src/Domain/Event/DomainEventService.ts @@ -8,7 +8,6 @@ export enum DomainEventService { ApiGateway = 'api-gateway', Files = 'files', Scheduler = 'scheduler', - Workspace = 'workspace', Analytics = 'analytics', Revisions = 'revisions', Email = 'email', diff --git a/packages/domain-events/src/Domain/Event/WorkspaceInviteAcceptedEvent.ts b/packages/domain-events/src/Domain/Event/WorkspaceInviteAcceptedEvent.ts deleted file mode 100644 index aa131055a..000000000 --- a/packages/domain-events/src/Domain/Event/WorkspaceInviteAcceptedEvent.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { DomainEventInterface } from './DomainEventInterface' -import { WorkspaceInviteAcceptedEventPayload } from './WorkspaceInviteAcceptedEventPayload' - -export interface WorkspaceInviteAcceptedEvent extends DomainEventInterface { - type: 'WORKSPACE_INVITE_ACCEPTED' - payload: WorkspaceInviteAcceptedEventPayload -} diff --git a/packages/domain-events/src/Domain/Event/WorkspaceInviteAcceptedEventPayload.ts b/packages/domain-events/src/Domain/Event/WorkspaceInviteAcceptedEventPayload.ts deleted file mode 100644 index 5d68cd121..000000000 --- a/packages/domain-events/src/Domain/Event/WorkspaceInviteAcceptedEventPayload.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface WorkspaceInviteAcceptedEventPayload { - inviterUuid: string - inviteeUuid: string - workspaceUuid: string -} diff --git a/packages/domain-events/src/Domain/index.ts b/packages/domain-events/src/Domain/index.ts index 3bdeb0aeb..5b35dab76 100644 --- a/packages/domain-events/src/Domain/index.ts +++ b/packages/domain-events/src/Domain/index.ts @@ -92,8 +92,6 @@ export * from './Event/UserRolesChangedEvent' export * from './Event/UserRolesChangedEventPayload' export * from './Event/WebSocketMessageRequestedEvent' export * from './Event/WebSocketMessageRequestedEventPayload' -export * from './Event/WorkspaceInviteAcceptedEvent' -export * from './Event/WorkspaceInviteAcceptedEventPayload' export * from './Handler/DomainEventHandlerInterface' export * from './Handler/DomainEventMessageHandlerInterface' diff --git a/packages/workspace/.env.sample b/packages/workspace/.env.sample deleted file mode 100644 index fb2268eb1..000000000 --- a/packages/workspace/.env.sample +++ /dev/null @@ -1,32 +0,0 @@ -LOG_LEVEL=debug -NODE_ENV=development -VERSION=development - -AUTH_JWT_SECRET=auth_jwt_secret - -PORT=3000 - -DB_HOST=127.0.0.1 -DB_REPLICA_HOST=127.0.0.1 -DB_PORT=3306 -DB_USERNAME=workspace -DB_PASSWORD=changeme123 -DB_DATABASE=workspace -DB_DEBUG_LEVEL=all # "all" | "query" | "schema" | "error" | "warn" | "info" | "log" | "migration" -DB_MIGRATIONS_PATH=dist/migrations/*.js - -REDIS_URL=redis://cache - -SNS_TOPIC_ARN= -SNS_AWS_REGION= -SQS_QUEUE_URL= -SQS_AWS_REGION= - -# (Optional) New Relic Setup -NEW_RELIC_ENABLED=false -NEW_RELIC_APP_NAME=Workspace -NEW_RELIC_LICENSE_KEY= -NEW_RELIC_NO_CONFIG_FILE=true -NEW_RELIC_DISTRIBUTED_TRACING_ENABLED=false -NEW_RELIC_LOG_ENABLED=false -NEW_RELIC_LOG_LEVEL=info diff --git a/packages/workspace/.eslintignore b/packages/workspace/.eslintignore deleted file mode 100644 index 4186e3d19..000000000 --- a/packages/workspace/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -dist -test-setup.ts -data diff --git a/packages/workspace/.eslintrc b/packages/workspace/.eslintrc deleted file mode 100644 index cb7136174..000000000 --- a/packages/workspace/.eslintrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "../../.eslintrc", - "parserOptions": { - "project": "./linter.tsconfig.json" - } -} diff --git a/packages/workspace/CHANGELOG.md b/packages/workspace/CHANGELOG.md deleted file mode 100644 index d66d0da87..000000000 --- a/packages/workspace/CHANGELOG.md +++ /dev/null @@ -1,558 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [1.20.4](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.20.3...@standardnotes/workspace-server@1.20.4) (2023-02-23) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.20.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.20.2...@standardnotes/workspace-server@1.20.3) (2023-02-21) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.20.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.20.1...@standardnotes/workspace-server@1.20.2) (2023-02-20) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.20.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.20.0...@standardnotes/workspace-server@1.20.1) (2023-02-15) - -**Note:** Version bump only for package @standardnotes/workspace-server - -# [1.20.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.23...@standardnotes/workspace-server@1.20.0) (2023-02-15) - -### Features - -* optimize memory on server utilities ([881a696](https://github.com/standardnotes/server/commit/881a6967aca57d68795af0792114f848ddddf120)) - -## [1.19.23](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.22...@standardnotes/workspace-server@1.19.23) (2023-02-06) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.22](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.21...@standardnotes/workspace-server@1.19.22) (2023-01-30) - -### Bug Fixes - -* sqs configuration for aws sdk v3 ([b54c331](https://github.com/standardnotes/server/commit/b54c331bef0d4ad1ba1111700dc9f1bf64c1ea51)) - -## [1.19.21](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.20...@standardnotes/workspace-server@1.19.21) (2023-01-25) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.20](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.19...@standardnotes/workspace-server@1.19.20) (2023-01-24) - -### Bug Fixes - -* **auth:** add pseudo u2f params on non existing accounts ([e4c65ca](https://github.com/standardnotes/server/commit/e4c65ca631938d8b1d635a40e463d5544051e4a1)) - -## [1.19.19](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.18...@standardnotes/workspace-server@1.19.19) (2023-01-24) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.18](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.17...@standardnotes/workspace-server@1.19.18) (2023-01-23) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.17](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.16...@standardnotes/workspace-server@1.19.17) (2023-01-20) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.16](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.15...@standardnotes/workspace-server@1.19.16) (2023-01-20) - -### Bug Fixes - -* dependency issues ([589f8e6](https://github.com/standardnotes/server/commit/589f8e62f4753b9c6fab21bd675114d373d89f2d)) - -## [1.19.15](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.14...@standardnotes/workspace-server@1.19.15) (2023-01-20) - -### Reverts - -* Revert "chore: upgrade @standardnotes/* dependencies" ([5bf3ecd](https://github.com/standardnotes/server/commit/5bf3ecdf42e1e5b9cb538cad08a18fb6e4054129)) - -## [1.19.14](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.13...@standardnotes/workspace-server@1.19.14) (2023-01-20) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.13](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.12...@standardnotes/workspace-server@1.19.13) (2023-01-19) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.12](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.11...@standardnotes/workspace-server@1.19.12) (2023-01-19) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.11](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.10...@standardnotes/workspace-server@1.19.11) (2023-01-19) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.10](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.9...@standardnotes/workspace-server@1.19.10) (2023-01-19) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.9](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.8...@standardnotes/workspace-server@1.19.9) (2023-01-18) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.8](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.7...@standardnotes/workspace-server@1.19.8) (2023-01-17) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.7](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.6...@standardnotes/workspace-server@1.19.7) (2023-01-17) - -### Bug Fixes - -* allow to run typeorm in non-replica mode ([f73129c](https://github.com/standardnotes/server/commit/f73129cd7e7d6a9b8a63e5c80284467597557982)) - -## [1.19.6](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.5...@standardnotes/workspace-server@1.19.6) (2023-01-16) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.5](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.4...@standardnotes/workspace-server@1.19.5) (2023-01-13) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.4](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.3...@standardnotes/workspace-server@1.19.4) (2022-12-28) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.2...@standardnotes/workspace-server@1.19.3) (2022-12-20) - -### Bug Fixes - -* **workspace:** specs ([c8203cf](https://github.com/standardnotes/server/commit/c8203cf04cb93cc65d30b69f10fb275f5e6be449)) - -## [1.19.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.1...@standardnotes/workspace-server@1.19.2) (2022-12-20) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.19.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.0...@standardnotes/workspace-server@1.19.1) (2022-12-19) - -**Note:** Version bump only for package @standardnotes/workspace-server - -# [1.19.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.18.6...@standardnotes/workspace-server@1.19.0) (2022-12-19) - -### Features - -* **auth:** add session traces ([8bcb552](https://github.com/standardnotes/server/commit/8bcb552783b2d12f3296b3195752168482790bc8)) - -## [1.18.6](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.18.5...@standardnotes/workspace-server@1.18.6) (2022-12-15) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.18.5](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.18.4...@standardnotes/workspace-server@1.18.5) (2022-12-15) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.18.4](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.18.3...@standardnotes/workspace-server@1.18.4) (2022-12-12) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.18.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.18.2...@standardnotes/workspace-server@1.18.3) (2022-12-12) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.18.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.18.1...@standardnotes/workspace-server@1.18.2) (2022-12-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.18.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.18.0...@standardnotes/workspace-server@1.18.1) (2022-12-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -# [1.18.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.47...@standardnotes/workspace-server@1.18.0) (2022-12-09) - -### Features - -* **workspace:** replace workspace invite created event with email requested ([61c1cff](https://github.com/standardnotes/server/commit/61c1cfff4bcee09e1f933cb3e085412b6f07cc42)) - -## [1.17.47](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.46...@standardnotes/workspace-server@1.17.47) (2022-12-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.46](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.45...@standardnotes/workspace-server@1.17.46) (2022-12-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.45](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.44...@standardnotes/workspace-server@1.17.45) (2022-12-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.44](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.43...@standardnotes/workspace-server@1.17.44) (2022-12-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.43](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.42...@standardnotes/workspace-server@1.17.43) (2022-12-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.42](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.41...@standardnotes/workspace-server@1.17.42) (2022-12-08) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.41](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.40...@standardnotes/workspace-server@1.17.41) (2022-12-08) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.40](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.39...@standardnotes/workspace-server@1.17.40) (2022-12-08) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.39](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.38...@standardnotes/workspace-server@1.17.39) (2022-12-08) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.38](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.37...@standardnotes/workspace-server@1.17.38) (2022-12-08) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.37](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.36...@standardnotes/workspace-server@1.17.37) (2022-12-07) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.36](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.35...@standardnotes/workspace-server@1.17.36) (2022-12-07) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.35](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.34...@standardnotes/workspace-server@1.17.35) (2022-12-07) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.34](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.33...@standardnotes/workspace-server@1.17.34) (2022-12-06) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.33](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.32...@standardnotes/workspace-server@1.17.33) (2022-12-05) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.32](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.31...@standardnotes/workspace-server@1.17.32) (2022-11-30) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.31](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.30...@standardnotes/workspace-server@1.17.31) (2022-11-28) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.30](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.29...@standardnotes/workspace-server@1.17.30) (2022-11-25) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.29](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.28...@standardnotes/workspace-server@1.17.29) (2022-11-24) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.28](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.27...@standardnotes/workspace-server@1.17.28) (2022-11-23) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.27](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.26...@standardnotes/workspace-server@1.17.27) (2022-11-23) - -### Bug Fixes - -* binding of sns and sqs with additional config ([74bc791](https://github.com/standardnotes/server/commit/74bc79116bc50d9a5af1a558db1b7108dcda6d0e)) - -## [1.17.26](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.25...@standardnotes/workspace-server@1.17.26) (2022-11-22) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.25](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.24...@standardnotes/workspace-server@1.17.25) (2022-11-21) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.24](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.23...@standardnotes/workspace-server@1.17.24) (2022-11-18) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.23](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.22...@standardnotes/workspace-server@1.17.23) (2022-11-16) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.22](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.21...@standardnotes/workspace-server@1.17.22) (2022-11-14) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.21](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.18...@standardnotes/workspace-server@1.17.21) (2022-11-14) - -### Bug Fixes - -* versioning issue ([7ca377f](https://github.com/standardnotes/server/commit/7ca377f1b889379e6a43a66c0134bf266763516d)) - -## [1.17.18](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.17...@standardnotes/workspace-server@1.17.18) (2022-11-14) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.17](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.16...@standardnotes/workspace-server@1.17.17) (2022-11-11) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.16](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.15...@standardnotes/workspace-server@1.17.16) (2022-11-11) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.15](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.14...@standardnotes/workspace-server@1.17.15) (2022-11-10) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.14](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.13...@standardnotes/workspace-server@1.17.14) (2022-11-10) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.13](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.12...@standardnotes/workspace-server@1.17.13) (2022-11-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.12](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.11...@standardnotes/workspace-server@1.17.12) (2022-11-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.11](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.10...@standardnotes/workspace-server@1.17.11) (2022-11-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.10](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.9...@standardnotes/workspace-server@1.17.10) (2022-11-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.9](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.8...@standardnotes/workspace-server@1.17.9) (2022-11-09) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.8](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.7...@standardnotes/workspace-server@1.17.8) (2022-11-07) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.7](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.6...@standardnotes/workspace-server@1.17.7) (2022-11-07) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.6](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.5...@standardnotes/workspace-server@1.17.6) (2022-11-07) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.5](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.4...@standardnotes/workspace-server@1.17.5) (2022-11-07) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.4](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.3...@standardnotes/workspace-server@1.17.4) (2022-11-04) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.2...@standardnotes/workspace-server@1.17.3) (2022-11-04) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.1...@standardnotes/workspace-server@1.17.2) (2022-11-04) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.17.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.17.0...@standardnotes/workspace-server@1.17.1) (2022-11-03) - -**Note:** Version bump only for package @standardnotes/workspace-server - -# [1.17.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.16.6...@standardnotes/workspace-server@1.17.0) (2022-11-02) - -### Features - -* **auth:** add processing user requests ([2255f85](https://github.com/standardnotes/server/commit/2255f856f928e855ac94f8aca4e1fb81047f58f7)) - -## [1.16.6](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.16.5...@standardnotes/workspace-server@1.16.6) (2022-11-02) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.16.5](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.16.4...@standardnotes/workspace-server@1.16.5) (2022-11-01) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.16.4](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.16.3...@standardnotes/workspace-server@1.16.4) (2022-11-01) - -### Bug Fixes - -* force utf8mb4 charset on typeorm ([5160cc3](https://github.com/standardnotes/server/commit/5160cc36ddc9e30551d5ad40a9e210d87091eec3)) - -## [1.16.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.16.2...@standardnotes/workspace-server@1.16.3) (2022-10-31) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.16.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.16.1...@standardnotes/workspace-server@1.16.2) (2022-10-31) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.16.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.16.0...@standardnotes/workspace-server@1.16.1) (2022-10-26) - -**Note:** Version bump only for package @standardnotes/workspace-server - -# [1.16.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.15.0...@standardnotes/workspace-server@1.16.0) (2022-10-24) - -### Features - -* **auth:** change accepting invitations to be an authorized endpoint ([771a555](https://github.com/standardnotes/server/commit/771a555b4f33452311cd5bf0b8cfcbc4f2f1c4dd)) - -# [1.15.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.14.6...@standardnotes/workspace-server@1.15.0) (2022-10-19) - -### Features - -* building server applications in ARM64 architecture for Docker ([fd92866](https://github.com/standardnotes/server/commit/fd92866ba1a86b22769b23cc4c8387a83f87979a)) - -## [1.14.6](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.14.5...@standardnotes/workspace-server@1.14.6) (2022-10-17) - -### Bug Fixes - -* **workspaces:** accepting invitations ([b6f3954](https://github.com/standardnotes/server/commit/b6f3954e24794d6ab97ab61f39c4d91c39e5f558)) - -## [1.14.5](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.14.4...@standardnotes/workspace-server@1.14.5) (2022-10-17) - -### Bug Fixes - -* **workspaces:** allow type of workspace to come from parameters ([6af8ff7](https://github.com/standardnotes/server/commit/6af8ff700ea795252d5f8d3a955f27eef9240ae2)) - -## [1.14.4](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.14.3...@standardnotes/workspace-server@1.14.4) (2022-10-17) - -### Bug Fixes - -* **workspaces:** listing workspace uuids ([365d316](https://github.com/standardnotes/server/commit/365d316878d8d76256efc102e53ff9868789cbc8)) - -## [1.14.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.14.2...@standardnotes/workspace-server@1.14.3) (2022-10-17) - -### Bug Fixes - -* **workspaces:** add debug logs for listing workspaces ([d232e71](https://github.com/standardnotes/server/commit/d232e71683d553ddaa41dd2f75716cdf8e62a19f)) - -## [1.14.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.14.1...@standardnotes/workspace-server@1.14.2) (2022-10-14) - -### Bug Fixes - -* **workspace:** fetching users workspaces list ([0cacc8e](https://github.com/standardnotes/server/commit/0cacc8efa06d6dde0e8cc4486c303082a5ee4211)) - -## [1.14.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.14.0...@standardnotes/workspace-server@1.14.1) (2022-10-14) - -### Bug Fixes - -* **workspaces:** reading response locals when listing workspaces ([d2fcc76](https://github.com/standardnotes/server/commit/d2fcc761ad30786c7245f379ded996da383c5cfe)) - -# [1.14.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.13.2...@standardnotes/workspace-server@1.14.0) (2022-10-13) - -### Features - -* publish workspace invite accepted event for websockets ([86379eb](https://github.com/standardnotes/server/commit/86379eb96d7231d6a76ee91350accef2d44a941d)) - -## [1.13.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.13.1...@standardnotes/workspace-server@1.13.2) (2022-10-13) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.13.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.13.0...@standardnotes/workspace-server@1.13.1) (2022-10-12) - -### Bug Fixes - -* **workspace:** add workspace to workspace user foreign keys ([4f6a2a8](https://github.com/standardnotes/server/commit/4f6a2a83d3d7b57d176e169f33780730eeae6919)) - -# [1.13.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.12.0...@standardnotes/workspace-server@1.13.0) (2022-10-12) - -### Features - -* **workspace:** add endpoints for initiating keyshare in a workspace ([0c1a779](https://github.com/standardnotes/server/commit/0c1a779ef03819928e7e791a6843d90eb9fed964)) - -# [1.12.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.11.0...@standardnotes/workspace-server@1.12.0) (2022-10-12) - -### Features - -* **workspace:** add initiating key share ([cea9021](https://github.com/standardnotes/server/commit/cea9021c164588969890370a2332f11749ac820e)) - -# [1.11.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.10.0...@standardnotes/workspace-server@1.11.0) (2022-10-11) - -### Features - -* add listin worspaces and workspace users ([095d13f](https://github.com/standardnotes/server/commit/095d13f8bbfe543fcf086840e1a985447a6c51ef)) - -# [1.10.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.9.0...@standardnotes/workspace-server@1.10.0) (2022-10-11) - -### Features - -* **workspace:** extract workspace user status to common ([8bc9261](https://github.com/standardnotes/server/commit/8bc92616d2fbeb833c3fcbef6b87538745fc7f3e)) - -# [1.9.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.8.0...@standardnotes/workspace-server@1.9.0) (2022-10-11) - -### Features - -* **workspace:** add invite access level ([f742270](https://github.com/standardnotes/server/commit/f74227067b7151cb63a54e815e57f81984467bfe)) - -# [1.8.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.7.0...@standardnotes/workspace-server@1.8.0) (2022-10-11) - -### Features - -* **workspace:** add workspace user display name ([ba9d3bf](https://github.com/standardnotes/server/commit/ba9d3bfe4632d5001b8c967860df086f103e2e35)) - -# [1.7.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.6.0...@standardnotes/workspace-server@1.7.0) (2022-10-11) - -### Features - -* **workspace:** accepting invitation ([ace2b69](https://github.com/standardnotes/server/commit/ace2b6936a104f3cfcad8f15d846e845917aa678)) - -# [1.6.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.5.1...@standardnotes/workspace-server@1.6.0) (2022-10-11) - -### Features - -* **workspace:** add invite to workspace endpoints ([266adda](https://github.com/standardnotes/server/commit/266adda45bd3ad84bc6605824b6be1dd912f3f9a)) - -## [1.5.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.5.0...@standardnotes/workspace-server@1.5.1) (2022-10-10) - -**Note:** Version bump only for package @standardnotes/workspace-server - -# [1.5.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.4.1...@standardnotes/workspace-server@1.5.0) (2022-10-10) - -### Features - -* **workspace:** add publishing workspace invite created ([6f9683c](https://github.com/standardnotes/server/commit/6f9683c41a1135489832d9a854a114c82825a647)) - -## [1.4.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.4.0...@standardnotes/workspace-server@1.4.1) (2022-10-10) - -**Note:** Version bump only for package @standardnotes/workspace-server - -# [1.4.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.3.0...@standardnotes/workspace-server@1.4.0) (2022-10-10) - -### Features - -* **workspace:** add inviting to workspace ([e06cc3b](https://github.com/standardnotes/server/commit/e06cc3ba80fd3bbf8a5fb0e176bc76b4318a36e9)) - -# [1.3.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.2.3...@standardnotes/workspace-server@1.3.0) (2022-10-10) - -### Features - -* **workspace:** add creating root workspace upon user registration ([3f61d31](https://github.com/standardnotes/server/commit/3f61d3163ef91b3b94056208a41bb4858c0df259)) - -## [1.2.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.2.2...@standardnotes/workspace-server@1.2.3) (2022-10-10) - -### Bug Fixes - -* **workspace:** add optional parameters to creating workspace ([0ce4185](https://github.com/standardnotes/server/commit/0ce4185379d921cf69eb27c94d63933b8cabc2e7)) - -## [1.2.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.2.1...@standardnotes/workspace-server@1.2.2) (2022-10-10) - -### Bug Fixes - -* **workspace:** extract workspace type to common types ([0ea88ad](https://github.com/standardnotes/server/commit/0ea88ad202d54de79d1433183c1706823639da93)) - -## [1.2.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.2.0...@standardnotes/workspace-server@1.2.1) (2022-10-10) - -### Bug Fixes - -* **workspace:** rename private key to encrypted private key ([447d600](https://github.com/standardnotes/server/commit/447d600dbe0ee101a7579409adc9da6cd3e309de)) - -# [1.2.0](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.1.2...@standardnotes/workspace-server@1.2.0) (2022-10-07) - -### Features - -* add workspaces creation ([156ab65](https://github.com/standardnotes/server/commit/156ab6527265351b13797394cbd34da037ab5a38)) - -## [1.1.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.1.1...@standardnotes/workspace-server@1.1.2) (2022-10-07) - -**Note:** Version bump only for package @standardnotes/workspace-server - -## [1.1.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.1.0...@standardnotes/workspace-server@1.1.1) (2022-10-06) - -**Note:** Version bump only for package @standardnotes/workspace-server - -# 1.1.0 (2022-10-06) - -### Features - -* add workspace microservice ([44a9ade](https://github.com/standardnotes/server/commit/44a9ade3fc0935d24733327c6b2de05b52496b1c)) diff --git a/packages/workspace/Dockerfile b/packages/workspace/Dockerfile deleted file mode 100644 index 5f304f3aa..000000000 --- a/packages/workspace/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM node:18.13.0-alpine - -RUN apk add --update \ - curl \ - && rm -rf /var/cache/apk/* - -ENV NODE_ENV production - -RUN corepack enable - -COPY ./ /workspace - -WORKDIR /workspace/packages/workspace - -ENTRYPOINT [ "/workspace/packages/workspace/docker/entrypoint.sh" ] - -CMD [ "start-web" ] diff --git a/packages/workspace/bin/server.ts b/packages/workspace/bin/server.ts deleted file mode 100644 index e1b25b03a..000000000 --- a/packages/workspace/bin/server.ts +++ /dev/null @@ -1,71 +0,0 @@ -import 'reflect-metadata' - -import 'newrelic' - -import * as Sentry from '@sentry/node' - -import '../src/Infra/InversifyExpressUtils/InversifyExpressHealthCheckController' -import '../src/Infra/InversifyExpressUtils/InversifyExpressInvitesController' -import '../src/Infra/InversifyExpressUtils/InversifyExpressWorkspacesController' - -import * as cors from 'cors' -import { urlencoded, json, Request, Response, NextFunction, RequestHandler, ErrorRequestHandler } from 'express' -import * as winston from 'winston' - -import { InversifyExpressServer } from 'inversify-express-utils' -import { ContainerConfigLoader } from '../src/Bootstrap/Container' -import TYPES from '../src/Bootstrap/Types' -import { Env } from '../src/Bootstrap/Env' - -const container = new ContainerConfigLoader() -void container.load().then((container) => { - const env: Env = new Env() - env.load() - - const server = new InversifyExpressServer(container) - - server.setConfig((app) => { - app.use((_request: Request, response: Response, next: NextFunction) => { - response.setHeader('X-Auth-Version', container.get(TYPES.VERSION)) - next() - }) - app.use(json()) - app.use(urlencoded({ extended: true })) - app.use(cors()) - - if (env.get('SENTRY_DSN', true)) { - Sentry.init({ - dsn: env.get('SENTRY_DSN'), - integrations: [new Sentry.Integrations.Http({ tracing: false, breadcrumbs: true })], - tracesSampleRate: 0, - }) - - app.use(Sentry.Handlers.requestHandler() as RequestHandler) - } - }) - - const logger: winston.Logger = container.get(TYPES.Logger) - - server.setErrorConfig((app) => { - if (env.get('SENTRY_DSN', true)) { - app.use(Sentry.Handlers.errorHandler() as ErrorRequestHandler) - } - - app.use((error: Record, _request: Request, response: Response, _next: NextFunction) => { - logger.error(error.stack) - - response.status(500).send({ - error: { - message: - "Unfortunately, we couldn't handle your request. Please try again or contact our support if the error persists.", - }, - }) - }) - }) - - const serverInstance = server.build() - - serverInstance.listen(env.get('PORT')) - - logger.info(`Server started on port ${process.env.PORT}`) -}) diff --git a/packages/workspace/bin/worker.ts b/packages/workspace/bin/worker.ts deleted file mode 100644 index 23fe62631..000000000 --- a/packages/workspace/bin/worker.ts +++ /dev/null @@ -1,25 +0,0 @@ -import 'reflect-metadata' - -import 'newrelic' - -import { Logger } from 'winston' - -import { ContainerConfigLoader } from '../src/Bootstrap/Container' -import TYPES from '../src/Bootstrap/Types' -import { Env } from '../src/Bootstrap/Env' -import { DomainEventSubscriberFactoryInterface } from '@standardnotes/domain-events' - -const container = new ContainerConfigLoader() -void container.load().then((container) => { - const env: Env = new Env() - env.load() - - const logger: Logger = container.get(TYPES.Logger) - - logger.info('Starting worker...') - - const subscriberFactory: DomainEventSubscriberFactoryInterface = container.get(TYPES.DomainEventSubscriberFactory) - subscriberFactory.create().start() - - setInterval(() => logger.info('Alive and kicking!'), 20 * 60 * 1000) -}) diff --git a/packages/workspace/docker/entrypoint-server.js b/packages/workspace/docker/entrypoint-server.js deleted file mode 100644 index a59fe3a6d..000000000 --- a/packages/workspace/docker/entrypoint-server.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict' - -const path = require('path') - -const pnp = require(path.normalize(path.resolve(__dirname, '../../..', '.pnp.cjs'))).setup() - -const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/server.js'))) - -Object.defineProperty(exports, '__esModule', { value: true }) - -exports.default = index diff --git a/packages/workspace/docker/entrypoint-worker.js b/packages/workspace/docker/entrypoint-worker.js deleted file mode 100644 index daf3cf9da..000000000 --- a/packages/workspace/docker/entrypoint-worker.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict' - -const path = require('path') - -const pnp = require(path.normalize(path.resolve(__dirname, '../../..', '.pnp.cjs'))).setup() - -const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/worker.js'))) - -Object.defineProperty(exports, '__esModule', { value: true }) - -exports.default = index diff --git a/packages/workspace/docker/entrypoint.sh b/packages/workspace/docker/entrypoint.sh deleted file mode 100755 index f4c9b15f9..000000000 --- a/packages/workspace/docker/entrypoint.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -set -e - -COMMAND=$1 && shift 1 - -case "$COMMAND" in - 'start-web' ) - echo "Starting Web..." - node docker/entrypoint-server.js - ;; - - 'start-worker' ) - echo "Starting Worker..." - node docker/entrypoint-worker.js - ;; - - * ) - echo "Unknown command" - ;; -esac - -exec "$@" diff --git a/packages/workspace/jest.config.js b/packages/workspace/jest.config.js deleted file mode 100644 index 9710ef095..000000000 --- a/packages/workspace/jest.config.js +++ /dev/null @@ -1,12 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires -const base = require('../../jest.config') -const { defaults: tsjPreset } = require('ts-jest/presets') - -module.exports = { - ...base, - transform: { - ...tsjPreset.transform, - }, - coveragePathIgnorePatterns: ['/Bootstrap/', '/InversifyExpressUtils/', '/Domain/Email/', '/Domain/Event'], - setupFilesAfterEnv: ['./test-setup.ts'], -} diff --git a/packages/workspace/linter.tsconfig.json b/packages/workspace/linter.tsconfig.json deleted file mode 100644 index 67d92b038..000000000 --- a/packages/workspace/linter.tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["dist", "test-setup.ts"] -} diff --git a/packages/workspace/migrations/1665049971623-initial.ts b/packages/workspace/migrations/1665049971623-initial.ts deleted file mode 100644 index 1e1f43c11..000000000 --- a/packages/workspace/migrations/1665049971623-initial.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class initial1665049971623 implements MigrationInterface { - name = 'initial1665049971623' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'CREATE TABLE `workspaces` (`uuid` varchar(36) NOT NULL, `type` varchar(64) NOT NULL, `name` varchar(255) NULL, `key_rotation_index` int NOT NULL DEFAULT 0, PRIMARY KEY (`uuid`)) ENGINE=InnoDB', - ) - await queryRunner.query( - 'CREATE TABLE `workspace_users` (`uuid` varchar(36) NOT NULL, `access_level` varchar(64) NOT NULL, `user_uuid` varchar(36) NOT NULL, `workspace_uuid` varchar(36) NOT NULL, `encrypted_workspace_key` varchar(255) NULL, `public_key` varchar(255) NOT NULL, `private_key` varchar(255) NOT NULL, `status` varchar(64) NOT NULL, `key_rotation_index` int NOT NULL DEFAULT 0, UNIQUE INDEX `index_workspace_users_on_workspace_and_user` (`user_uuid`, `workspace_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB', - ) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DROP INDEX `index_workspace_users_on_workspace_and_user` ON `workspace_users`') - await queryRunner.query('DROP TABLE `workspace_users`') - await queryRunner.query('DROP TABLE `workspaces`') - } -} diff --git a/packages/workspace/migrations/1665389240189-rename-private-key.ts b/packages/workspace/migrations/1665389240189-rename-private-key.ts deleted file mode 100644 index 843597747..000000000 --- a/packages/workspace/migrations/1665389240189-rename-private-key.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class renamePrivateKey1665389240189 implements MigrationInterface { - name = 'renamePrivateKey1665389240189' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'ALTER TABLE `workspace_users` CHANGE `private_key` `encrypted_private_key` varchar(255) NOT NULL', - ) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'ALTER TABLE `workspace_users` CHANGE `encrypted_private_key` `private_key` varchar(255) NOT NULL', - ) - } -} diff --git a/packages/workspace/migrations/1665390489236-optional-keys.ts b/packages/workspace/migrations/1665390489236-optional-keys.ts deleted file mode 100644 index 77caf0bd6..000000000 --- a/packages/workspace/migrations/1665390489236-optional-keys.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class optionalKeys1665390489236 implements MigrationInterface { - name = 'optionalKeys1665390489236' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE `workspace_users` CHANGE `public_key` `public_key` varchar(255) NULL') - await queryRunner.query( - 'ALTER TABLE `workspace_users` CHANGE `encrypted_private_key` `encrypted_private_key` varchar(255) NULL', - ) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'ALTER TABLE `workspace_users` CHANGE `encrypted_private_key` `encrypted_private_key` varchar(255) NOT NULL', - ) - await queryRunner.query('ALTER TABLE `workspace_users` CHANGE `public_key` `public_key` varchar(255) NOT NULL') - } -} diff --git a/packages/workspace/migrations/1665394559520-add-invites.ts b/packages/workspace/migrations/1665394559520-add-invites.ts deleted file mode 100644 index 4b0268525..000000000 --- a/packages/workspace/migrations/1665394559520-add-invites.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class addInvites1665394559520 implements MigrationInterface { - name = 'addInvites1665394559520' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'CREATE TABLE `workspace_invites` (`uuid` varchar(36) NOT NULL, `inviter_uuid` varchar(36) NOT NULL, `invitee_email` varchar(255) NOT NULL, `status` varchar(64) NOT NULL, `accepting_user_uuid` varchar(36) NULL, `workspace_uuid` varchar(36) NOT NULL, `created_at` bigint NOT NULL, `updated_at` bigint NOT NULL, PRIMARY KEY (`uuid`)) ENGINE=InnoDB', - ) - await queryRunner.query('ALTER TABLE `workspaces` ADD `created_at` bigint NOT NULL') - await queryRunner.query('ALTER TABLE `workspaces` ADD `updated_at` bigint NOT NULL') - await queryRunner.query('ALTER TABLE `workspace_users` ADD `created_at` bigint NOT NULL') - await queryRunner.query('ALTER TABLE `workspace_users` ADD `updated_at` bigint NOT NULL') - await queryRunner.query( - 'ALTER TABLE `workspace_invites` ADD CONSTRAINT `FK_782df40d03151dd3998acd0a6ba` FOREIGN KEY (`workspace_uuid`) REFERENCES `workspaces`(`uuid`) ON DELETE CASCADE ON UPDATE NO ACTION', - ) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE `workspace_invites` DROP FOREIGN KEY `FK_782df40d03151dd3998acd0a6ba`') - await queryRunner.query('ALTER TABLE `workspace_users` DROP COLUMN `updated_at`') - await queryRunner.query('ALTER TABLE `workspace_users` DROP COLUMN `created_at`') - await queryRunner.query('ALTER TABLE `workspaces` DROP COLUMN `updated_at`') - await queryRunner.query('ALTER TABLE `workspaces` DROP COLUMN `created_at`') - await queryRunner.query('DROP TABLE `workspace_invites`') - } -} diff --git a/packages/workspace/migrations/1665480537103-add-user-display-name.ts b/packages/workspace/migrations/1665480537103-add-user-display-name.ts deleted file mode 100644 index e29cc86d7..000000000 --- a/packages/workspace/migrations/1665480537103-add-user-display-name.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class addUserDisplayName1665480537103 implements MigrationInterface { - name = 'addUserDisplayName1665480537103' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE `workspace_users` ADD `user_display_name` varchar(255) NULL') - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE `workspace_users` DROP COLUMN `user_display_name`') - } -} diff --git a/packages/workspace/migrations/1665481699781-add-invite-access-level.ts b/packages/workspace/migrations/1665481699781-add-invite-access-level.ts deleted file mode 100644 index 998be58ec..000000000 --- a/packages/workspace/migrations/1665481699781-add-invite-access-level.ts +++ /dev/null @@ -1,13 +0,0 @@ -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/migrations/1665580464598-add-workspace-user-foreign-key.ts b/packages/workspace/migrations/1665580464598-add-workspace-user-foreign-key.ts deleted file mode 100644 index 845e02aba..000000000 --- a/packages/workspace/migrations/1665580464598-add-workspace-user-foreign-key.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm' - -export class addWorkspaceUserForeignKey1665580464598 implements MigrationInterface { - name = 'addWorkspaceUserForeignKey1665580464598' - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - 'ALTER TABLE `workspace_users` ADD CONSTRAINT `FK_cd407e5f2c4f3156ad2015aed41` FOREIGN KEY (`workspace_uuid`) REFERENCES `workspaces`(`uuid`) ON DELETE CASCADE ON UPDATE NO ACTION', - ) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('ALTER TABLE `workspace_users` DROP FOREIGN KEY `FK_cd407e5f2c4f3156ad2015aed41`') - } -} diff --git a/packages/workspace/package.json b/packages/workspace/package.json deleted file mode 100644 index b8032bcc0..000000000 --- a/packages/workspace/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "@standardnotes/workspace-server", - "version": "1.20.4", - "engines": { - "node": ">=18.0.0 <19.0.0" - }, - "private": true, - "description": "Workspace Server", - "main": "dist/src/index.js", - "typings": "dist/src/index.d.ts", - "author": "Karol Sójko ", - "license": "AGPL-3.0-or-later", - "scripts": { - "clean": "rm -fr dist", - "setup:env": "cp .env.sample .env", - "build": "tsc --build", - "lint": "eslint . --ext .ts", - "pretest": "yarn lint && yarn build", - "test": "jest --coverage --config=./jest.config.js --maxWorkers=50%", - "start": "yarn node dist/bin/server.js", - "worker": "yarn node dist/bin/worker.js", - "typeorm": "typeorm-ts-node-commonjs" - }, - "dependencies": { - "@aws-sdk/client-sns": "^3.259.0", - "@aws-sdk/client-sqs": "^3.259.0", - "@newrelic/winston-enricher": "^4.0.0", - "@sentry/node": "^7.28.1", - "@standardnotes/api": "^1.24.10", - "@standardnotes/common": "workspace:*", - "@standardnotes/domain-core": "workspace:^", - "@standardnotes/domain-events": "workspace:^", - "@standardnotes/domain-events-infra": "workspace:^", - "@standardnotes/models": "^1.42.11", - "@standardnotes/security": "workspace:*", - "@standardnotes/time": "workspace:^", - "cors": "2.8.5", - "dotenv": "^16.0.1", - "express": "^4.18.2", - "inversify": "^6.0.1", - "inversify-express-utils": "^6.4.3", - "ioredis": "^5.2.4", - "mysql2": "^3.0.1", - "newrelic": "^9.8.0", - "reflect-metadata": "0.1.13", - "typeorm": "^0.3.10", - "winston": "^3.8.1" - }, - "devDependencies": { - "@types/cors": "^2.8.9", - "@types/express": "^4.17.14", - "@types/ioredis": "^5.0.0", - "@types/jest": "^29.1.1", - "@types/newrelic": "^9.4.0", - "@typescript-eslint/eslint-plugin": "^5.48.2", - "eslint": "^8.32.0", - "eslint-plugin-prettier": "^4.0.0", - "jest": "^29.1.2", - "ts-jest": "^29.0.3", - "typescript": "^4.8.4" - } -} diff --git a/packages/workspace/src/Bootstrap/Container.ts b/packages/workspace/src/Bootstrap/Container.ts deleted file mode 100644 index 6a93b26dd..000000000 --- a/packages/workspace/src/Bootstrap/Container.ts +++ /dev/null @@ -1,195 +0,0 @@ -import * as winston from 'winston' -import Redis from 'ioredis' -import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns' -import { SQSClient, SQSClientConfig } from '@aws-sdk/client-sqs' -import { Container } from 'inversify' -import { - DomainEventHandlerInterface, - DomainEventMessageHandlerInterface, - DomainEventSubscriberFactoryInterface, -} from '@standardnotes/domain-events' -import { TimerInterface, Timer } from '@standardnotes/time' -import { Env } from './Env' -import TYPES from './Types' -import { AppDataSource } from './DataSource' -import { - SNSDomainEventPublisher, - SQSDomainEventSubscriberFactory, - SQSEventMessageHandler, - SQSNewRelicEventMessageHandler, -} from '@standardnotes/domain-events-infra' -import { ApiGatewayAuthMiddleware } from '../Controller/ApiGatewayAuthMiddleware' -import { CrossServiceTokenData, TokenDecoder, TokenDecoderInterface } from '@standardnotes/security' -import { WorkspaceRepositoryInterface } from '../Domain/Workspace/WorkspaceRepositoryInterface' -import { MySQLWorkspaceRepository } from '../Infra/MySQL/MySQLWorkspaceRepository' -import { WorkspaceUserRepositoryInterface } from '../Domain/Workspace/WorkspaceUserRepositoryInterface' -import { MySQLWorkspaceUserRepository } from '../Infra/MySQL/MySQLWorkspaceUserRepository' -import { Repository } from 'typeorm' -import { Workspace } from '../Domain/Workspace/Workspace' -import { WorkspaceUser } from '../Domain/Workspace/WorkspaceUser' -import { CreateWorkspace } from '../Domain/UseCase/CreateWorkspace/CreateWorkspace' -import { WorkspacesController } from '../Controller/WorkspacesController' -import { UserRegisteredEventHandler } from '../Domain/Handler/UserRegisteredEventHandler' -import { WorkspaceInviteRepositoryInterface } from '../Domain/Invite/WorkspaceInviteRepositoryInterface' -import { MySQLWorkspaceInviteRepository } from '../Infra/MySQL/MySQLWorkspaceInviteRepository' -import { WorkspaceInvite } from '../Domain/Invite/WorkspaceInvite' -import { InviteToWorkspace } from '../Domain/UseCase/InviteToWorkspace/InviteToWorkspace' -import { DomainEventFactory } from '../Domain/Event/DomainEventFactory' -import { DomainEventFactoryInterface } from '../Domain/Event/DomainEventFactoryInterface' -import { WorkspaceProjection } from '../Domain/Projection/WorkspaceProjection' -import { WorkspaceProjector } from '../Domain/Projection/WorkspaceProjector' -import { ProjectorInterface } from '../Domain/Projection/ProjectorInterface' -import { WorkspaceUserProjection } from '../Domain/Projection/WorkspaceUserProjection' -import { WorkspaceUserProjector } from '../Domain/Projection/WorkspaceUserProjector' -import { AcceptInvitation } from '../Domain/UseCase/AcceptInvitation/AcceptInvitation' -import { ListWorkspaces } from '../Domain/UseCase/ListWorkspaces/ListWorkspaces' -import { ListWorkspaceUsers } from '../Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsers' -import { InitiateKeyShare } from '../Domain/UseCase/InitiateKeyShare/InitiateKeyShare' - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const newrelicFormatter = require('@newrelic/winston-enricher') - -export class ContainerConfigLoader { - async load(): Promise { - const env: Env = new Env() - env.load() - - const container = new Container() - - await AppDataSource.initialize() - - const redisUrl = env.get('REDIS_URL') - const isRedisInClusterMode = redisUrl.indexOf(',') > 0 - let redis - if (isRedisInClusterMode) { - redis = new Redis.Cluster(redisUrl.split(',')) - } else { - redis = new Redis(redisUrl) - } - - container.bind(TYPES.Redis).toConstantValue(redis) - - const newrelicWinstonFormatter = newrelicFormatter(winston) - const winstonFormatters = [winston.format.splat(), winston.format.json()] - if (env.get('NEW_RELIC_ENABLED', true) === 'true') { - winstonFormatters.push(newrelicWinstonFormatter()) - } - - const logger = winston.createLogger({ - level: env.get('LOG_LEVEL') || 'info', - format: winston.format.combine(...winstonFormatters), - transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL') || 'info' })], - }) - container.bind(TYPES.Logger).toConstantValue(logger) - - if (env.get('SNS_TOPIC_ARN', true)) { - const snsConfig: SNSClientConfig = { - apiVersion: 'latest', - region: env.get('SNS_AWS_REGION', true), - } - if (env.get('SNS_ENDPOINT', true)) { - snsConfig.endpoint = env.get('SNS_ENDPOINT', true) - } - if (env.get('SNS_ACCESS_KEY_ID', true) && env.get('SNS_SECRET_ACCESS_KEY', true)) { - snsConfig.credentials = { - accessKeyId: env.get('SNS_ACCESS_KEY_ID', true), - secretAccessKey: env.get('SNS_SECRET_ACCESS_KEY', true), - } - } - container.bind(TYPES.SNS).toConstantValue(new SNSClient(snsConfig)) - } - - if (env.get('SQS_QUEUE_URL', true)) { - const sqsConfig: SQSClientConfig = { - region: env.get('SQS_AWS_REGION', true), - } - if (env.get('SQS_ENDPOINT', true)) { - sqsConfig.endpoint = env.get('SQS_ENDPOINT', true) - } - if (env.get('SQS_ACCESS_KEY_ID', true) && env.get('SQS_SECRET_ACCESS_KEY', true)) { - sqsConfig.credentials = { - accessKeyId: env.get('SQS_ACCESS_KEY_ID', true), - secretAccessKey: env.get('SQS_SECRET_ACCESS_KEY', true), - } - } - container.bind(TYPES.SQS).toConstantValue(new SQSClient(sqsConfig)) - } - - // Controller - container.bind(TYPES.WorkspacesController).to(WorkspacesController) - // Repositories - container.bind(TYPES.WorkspaceRepository).to(MySQLWorkspaceRepository) - container.bind(TYPES.WorkspaceUserRepository).to(MySQLWorkspaceUserRepository) - container - .bind(TYPES.WorkspaceInviteRepository) - .to(MySQLWorkspaceInviteRepository) - // ORM - container - .bind>(TYPES.ORMWorkspaceRepository) - .toConstantValue(AppDataSource.getRepository(Workspace)) - container - .bind>(TYPES.ORMWorkspaceUserRepository) - .toConstantValue(AppDataSource.getRepository(WorkspaceUser)) - container - .bind>(TYPES.ORMWorkspaceInviteRepository) - .toConstantValue(AppDataSource.getRepository(WorkspaceInvite)) - // Middleware - container.bind(TYPES.ApiGatewayAuthMiddleware).to(ApiGatewayAuthMiddleware) - // env vars - container.bind(TYPES.AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET')) - container.bind(TYPES.REDIS_URL).toConstantValue(env.get('REDIS_URL')) - container.bind(TYPES.SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN')) - container.bind(TYPES.SNS_AWS_REGION).toConstantValue(env.get('SNS_AWS_REGION', true)) - container.bind(TYPES.SQS_QUEUE_URL).toConstantValue(env.get('SQS_QUEUE_URL')) - container.bind(TYPES.NEW_RELIC_ENABLED).toConstantValue(env.get('NEW_RELIC_ENABLED', true)) - container.bind(TYPES.VERSION).toConstantValue(env.get('VERSION')) - - // use cases - container.bind(TYPES.CreateWorkspace).to(CreateWorkspace) - container.bind(TYPES.InviteToWorkspace).to(InviteToWorkspace) - container.bind(TYPES.AcceptInvitation).to(AcceptInvitation) - container.bind(TYPES.ListWorkspaces).to(ListWorkspaces) - container.bind(TYPES.ListWorkspaceUsers).to(ListWorkspaceUsers) - container.bind(TYPES.InitiateKeyShare).to(InitiateKeyShare) - // Handlers - container.bind(TYPES.UserRegisteredEventHandler).to(UserRegisteredEventHandler) - // Projection - container.bind>(TYPES.WorkspaceProjector).to(WorkspaceProjector) - container - .bind>(TYPES.WorkspaceUserProjector) - .to(WorkspaceUserProjector) - // Services - container.bind(TYPES.DomainEventFactory).to(DomainEventFactory) - container.bind(TYPES.Timer).toConstantValue(new Timer()) - container - .bind>(TYPES.CrossServiceTokenDecoder) - .toConstantValue(new TokenDecoder(container.get(TYPES.AUTH_JWT_SECRET))) - - container - .bind(TYPES.DomainEventPublisher) - .toConstantValue(new SNSDomainEventPublisher(container.get(TYPES.SNS), container.get(TYPES.SNS_TOPIC_ARN))) - - const eventHandlers: Map = new Map([ - ['USER_REGISTERED', container.get(TYPES.UserRegisteredEventHandler)], - ]) - - container - .bind(TYPES.DomainEventMessageHandler) - .toConstantValue( - env.get('NEW_RELIC_ENABLED', true) === 'true' - ? new SQSNewRelicEventMessageHandler(eventHandlers, container.get(TYPES.Logger)) - : new SQSEventMessageHandler(eventHandlers, container.get(TYPES.Logger)), - ) - container - .bind(TYPES.DomainEventSubscriberFactory) - .toConstantValue( - new SQSDomainEventSubscriberFactory( - container.get(TYPES.SQS), - container.get(TYPES.SQS_QUEUE_URL), - container.get(TYPES.DomainEventMessageHandler), - ), - ) - - return container - } -} diff --git a/packages/workspace/src/Bootstrap/DataSource.ts b/packages/workspace/src/Bootstrap/DataSource.ts deleted file mode 100644 index 4747bce30..000000000 --- a/packages/workspace/src/Bootstrap/DataSource.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { DataSource, LoggerOptions } from 'typeorm' -import { WorkspaceInvite } from '../Domain/Invite/WorkspaceInvite' -import { Workspace } from '../Domain/Workspace/Workspace' -import { WorkspaceUser } from '../Domain/Workspace/WorkspaceUser' -import { Env } from './Env' - -const env: Env = new Env() -env.load() - -const maxQueryExecutionTime = env.get('DB_MAX_QUERY_EXECUTION_TIME', true) - ? +env.get('DB_MAX_QUERY_EXECUTION_TIME', true) - : 45_000 - -const inReplicaMode = env.get('DB_REPLICA_HOST', true) ? true : false - -const replicationConfig = { - master: { - host: env.get('DB_HOST'), - port: parseInt(env.get('DB_PORT')), - username: env.get('DB_USERNAME'), - password: env.get('DB_PASSWORD'), - database: env.get('DB_DATABASE'), - }, - slaves: [ - { - host: env.get('DB_REPLICA_HOST', true), - port: parseInt(env.get('DB_PORT')), - username: env.get('DB_USERNAME'), - password: env.get('DB_PASSWORD'), - database: env.get('DB_DATABASE'), - }, - ], - removeNodeErrorCount: 10, - restoreNodeTimeout: 5, -} - -export const AppDataSource = new DataSource({ - type: 'mysql', - charset: 'utf8mb4', - supportBigNumbers: true, - bigNumberStrings: false, - maxQueryExecutionTime, - replication: inReplicaMode ? replicationConfig : undefined, - host: inReplicaMode ? undefined : env.get('DB_HOST'), - port: inReplicaMode ? undefined : parseInt(env.get('DB_PORT')), - username: inReplicaMode ? undefined : env.get('DB_USERNAME'), - password: inReplicaMode ? undefined : env.get('DB_PASSWORD'), - database: inReplicaMode ? undefined : env.get('DB_DATABASE'), - entities: [Workspace, WorkspaceUser, WorkspaceInvite], - migrations: [env.get('DB_MIGRATIONS_PATH', true) ?? 'dist/migrations/*.js'], - migrationsRun: true, - logging: env.get('DB_DEBUG_LEVEL'), -}) diff --git a/packages/workspace/src/Bootstrap/Env.ts b/packages/workspace/src/Bootstrap/Env.ts deleted file mode 100644 index b26b07aca..000000000 --- a/packages/workspace/src/Bootstrap/Env.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { config, DotenvParseOutput } from 'dotenv' -import { injectable } from 'inversify' - -@injectable() -export class Env { - private env?: DotenvParseOutput - - public load(): void { - const output = config() - this.env = output.parsed - } - - public get(key: string, optional = false): string { - if (!this.env) { - this.load() - } - - if (!process.env[key] && !optional) { - throw new Error(`Environment variable ${key} not set`) - } - - return process.env[key] - } -} diff --git a/packages/workspace/src/Bootstrap/Types.ts b/packages/workspace/src/Bootstrap/Types.ts deleted file mode 100644 index 8bcd87b0f..000000000 --- a/packages/workspace/src/Bootstrap/Types.ts +++ /dev/null @@ -1,48 +0,0 @@ -const TYPES = { - Logger: Symbol.for('Logger'), - Redis: Symbol.for('Redis'), - SNS: Symbol.for('SNS'), - SQS: Symbol.for('SQS'), - // Controller - WorkspacesController: Symbol.for('WorkspacesController'), - // Repositories - WorkspaceRepository: Symbol.for('WorkspaceRepository'), - WorkspaceUserRepository: Symbol.for('WorkspaceUserRepository'), - WorkspaceInviteRepository: Symbol.for('WorkspaceInviteRepository'), - // ORM - ORMWorkspaceRepository: Symbol.for('ORMWorkspaceRepository'), - ORMWorkspaceUserRepository: Symbol.for('ORMWorkspaceUserRepository'), - ORMWorkspaceInviteRepository: Symbol.for('ORMWorkspaceInviteRepository'), - // Middleware - ApiGatewayAuthMiddleware: Symbol.for('ApiGatewayAuthMiddleware'), - // env vars - AUTH_JWT_SECRET: Symbol.for('AUTH_JWT_SECRET'), - REDIS_URL: Symbol.for('REDIS_URL'), - SNS_TOPIC_ARN: Symbol.for('SNS_TOPIC_ARN'), - SNS_AWS_REGION: Symbol.for('SNS_AWS_REGION'), - SQS_QUEUE_URL: Symbol.for('SQS_QUEUE_URL'), - SQS_AWS_REGION: Symbol.for('SQS_AWS_REGION'), - NEW_RELIC_ENABLED: Symbol.for('NEW_RELIC_ENABLED'), - VERSION: Symbol.for('VERSION'), - // use cases - CreateWorkspace: Symbol.for('CreateWorkspace'), - InviteToWorkspace: Symbol.for('InviteToWorkspace'), - AcceptInvitation: Symbol.for('AcceptInvitation'), - ListWorkspaces: Symbol.for('ListWorkspaces'), - ListWorkspaceUsers: Symbol.for('ListWorkspaceUsers'), - InitiateKeyShare: Symbol.for('InitiateKeyShare'), - // Handlers - UserRegisteredEventHandler: Symbol.for('UserRegisteredEventHandler'), - // Projection - WorkspaceProjector: Symbol.for('WorkspaceProjector'), - WorkspaceUserProjector: Symbol.for('WorkspaceUserProjector'), - // Services - Timer: Symbol.for('Timer'), - CrossServiceTokenDecoder: Symbol.for('CrossServiceTokenDecoder'), - DomainEventPublisher: Symbol.for('DomainEventPublisher'), - DomainEventSubscriberFactory: Symbol.for('DomainEventSubscriberFactory'), - DomainEventMessageHandler: Symbol.for('DomainEventMessageHandler'), - DomainEventFactory: Symbol.for('DomainEventFactory'), -} - -export default TYPES diff --git a/packages/workspace/src/Controller/ApiGatewayAuthMiddleware.spec.ts b/packages/workspace/src/Controller/ApiGatewayAuthMiddleware.spec.ts deleted file mode 100644 index 0b50305bf..000000000 --- a/packages/workspace/src/Controller/ApiGatewayAuthMiddleware.spec.ts +++ /dev/null @@ -1,99 +0,0 @@ -import 'reflect-metadata' - -import { ApiGatewayAuthMiddleware } from './ApiGatewayAuthMiddleware' -import { NextFunction, Request, Response } from 'express' -import { Logger } from 'winston' -import { CrossServiceTokenData, TokenDecoderInterface } from '@standardnotes/security' -import { RoleName } from '@standardnotes/domain-core' - -describe('ApiGatewayAuthMiddleware', () => { - let tokenDecoder: TokenDecoderInterface - let request: Request - let response: Response - let next: NextFunction - - const logger = { - debug: jest.fn(), - } as unknown as jest.Mocked - - const createMiddleware = () => new ApiGatewayAuthMiddleware(tokenDecoder, logger) - - beforeEach(() => { - tokenDecoder = {} as jest.Mocked> - tokenDecoder.decodeToken = jest.fn().mockReturnValue({ - user: { - uuid: '1-2-3', - email: 'test@test.te', - }, - roles: [ - { - uuid: 'a-b-c', - name: RoleName.NAMES.CoreUser, - }, - ], - }) - - request = { - headers: {}, - } as jest.Mocked - response = { - locals: {}, - } as jest.Mocked - response.status = jest.fn().mockReturnThis() - response.send = jest.fn() - next = jest.fn() - }) - - it('should authorize user', async () => { - request.headers['x-auth-token'] = 'auth-jwt-token' - - await createMiddleware().handler(request, response, next) - - expect(response.locals.user).toEqual({ - uuid: '1-2-3', - email: 'test@test.te', - }) - expect(response.locals.roles).toEqual([ - { - uuid: 'a-b-c', - name: RoleName.NAMES.CoreUser, - }, - ]) - - expect(next).toHaveBeenCalled() - }) - - it('should not authorize if request is missing auth jwt token in headers', async () => { - await createMiddleware().handler(request, response, next) - - expect(response.status).toHaveBeenCalledWith(401) - expect(next).not.toHaveBeenCalled() - }) - - it('should not authorize if auth jwt token is malformed', async () => { - request.headers['x-auth-token'] = 'auth-jwt-token' - - tokenDecoder.decodeToken = jest.fn().mockReturnValue(undefined) - - await createMiddleware().handler(request, response, next) - - expect(response.status).toHaveBeenCalledWith(401) - expect(next).not.toHaveBeenCalled() - }) - - it('should pass the error to next middleware if one occurres', async () => { - request.headers['x-auth-token'] = 'auth-jwt-token' - - const error = new Error('Ooops') - - tokenDecoder.decodeToken = jest.fn().mockImplementation(() => { - throw error - }) - - await createMiddleware().handler(request, response, next) - - expect(response.status).not.toHaveBeenCalled() - - expect(next).toHaveBeenCalledWith(error) - }) -}) diff --git a/packages/workspace/src/Controller/ApiGatewayAuthMiddleware.ts b/packages/workspace/src/Controller/ApiGatewayAuthMiddleware.ts deleted file mode 100644 index 2665df1c3..000000000 --- a/packages/workspace/src/Controller/ApiGatewayAuthMiddleware.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { CrossServiceTokenData, TokenDecoderInterface } from '@standardnotes/security' -import { NextFunction, Request, Response } from 'express' -import { inject, injectable } from 'inversify' -import { BaseMiddleware } from 'inversify-express-utils' -import { Logger } from 'winston' -import TYPES from '../Bootstrap/Types' - -@injectable() -export class ApiGatewayAuthMiddleware extends BaseMiddleware { - constructor( - @inject(TYPES.CrossServiceTokenDecoder) private tokenDecoder: TokenDecoderInterface, - @inject(TYPES.Logger) private logger: Logger, - ) { - super() - } - - async handler(request: Request, response: Response, next: NextFunction): Promise { - try { - if (!request.headers['x-auth-token']) { - this.logger.debug('ApiGatewayAuthMiddleware missing x-auth-token header.') - - response.status(401).send({ - error: { - tag: 'invalid-auth', - message: 'Invalid login credentials.', - }, - }) - - return - } - - const token: CrossServiceTokenData | undefined = this.tokenDecoder.decodeToken( - request.headers['x-auth-token'] as string, - ) - - if (token === undefined) { - this.logger.debug('ApiGatewayAuthMiddleware authentication failure.') - - response.status(401).send({ - error: { - tag: 'invalid-auth', - message: 'Invalid login credentials.', - }, - }) - - return - } - - response.locals.user = token.user - response.locals.roles = token.roles - response.locals.session = token.session - response.locals.readOnlyAccess = token.session?.readonly_access ?? false - - return next() - } catch (error) { - return next(error) - } - } -} diff --git a/packages/workspace/src/Controller/WorkspacesController.spec.ts b/packages/workspace/src/Controller/WorkspacesController.spec.ts deleted file mode 100644 index 41fd8ee0c..000000000 --- a/packages/workspace/src/Controller/WorkspacesController.spec.ts +++ /dev/null @@ -1,204 +0,0 @@ -import 'reflect-metadata' -import { WorkspaceAccessLevel, WorkspaceType } from '@standardnotes/common' - -import { ProjectorInterface } from '../Domain/Projection/ProjectorInterface' -import { WorkspaceProjection } from '../Domain/Projection/WorkspaceProjection' -import { WorkspaceUserProjection } from '../Domain/Projection/WorkspaceUserProjection' -import { AcceptInvitation } from '../Domain/UseCase/AcceptInvitation/AcceptInvitation' - -import { CreateWorkspace } from '../Domain/UseCase/CreateWorkspace/CreateWorkspace' -import { InitiateKeyShare } from '../Domain/UseCase/InitiateKeyShare/InitiateKeyShare' -import { InviteToWorkspace } from '../Domain/UseCase/InviteToWorkspace/InviteToWorkspace' -import { ListWorkspaces } from '../Domain/UseCase/ListWorkspaces/ListWorkspaces' -import { ListWorkspaceUsers } from '../Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsers' -import { Workspace } from '../Domain/Workspace/Workspace' -import { WorkspaceUser } from '../Domain/Workspace/WorkspaceUser' - -import { WorkspacesController } from './WorkspacesController' - -describe('WorkspacesController', () => { - let doCreateWorkspace: CreateWorkspace - let doInviteToWorkspace: InviteToWorkspace - let doAcceptInvitation: AcceptInvitation - let doListWorkspaces: ListWorkspaces - let doListWorkspaceUsers: ListWorkspaceUsers - let doInitiateKeyshare: InitiateKeyShare - let workspacesProject: ProjectorInterface - let workspaceUsersProjector: ProjectorInterface - let workspace1: Workspace - let workspace2: Workspace - let workspaceUser1: WorkspaceUser - let workspaceUser2: WorkspaceUser - - const createController = () => - new WorkspacesController( - doCreateWorkspace, - doInviteToWorkspace, - doListWorkspaces, - doListWorkspaceUsers, - doAcceptInvitation, - doInitiateKeyshare, - workspacesProject, - workspaceUsersProjector, - ) - - beforeEach(() => { - doCreateWorkspace = {} as jest.Mocked - doCreateWorkspace.execute = jest.fn().mockReturnValue({ workspace: { uuid: 'w-1-2-3' } }) - - doInviteToWorkspace = {} as jest.Mocked - doInviteToWorkspace.execute = jest.fn().mockReturnValue({ invite: { uuid: 'i-1-2-3' } }) - - doListWorkspaces = {} as jest.Mocked - doListWorkspaces.execute = jest - .fn() - .mockReturnValue({ ownedWorkspaces: [workspace1], joinedWorkspaces: [workspace2] }) - - doListWorkspaceUsers = {} as jest.Mocked - doListWorkspaceUsers.execute = jest.fn().mockReturnValue({ workspaceUsers: [workspaceUser1, workspaceUser2] }) - - doAcceptInvitation = {} as jest.Mocked - doAcceptInvitation.execute = jest.fn().mockReturnValue({ success: true }) - - doInitiateKeyshare = {} as jest.Mocked - doInitiateKeyshare.execute = jest.fn().mockReturnValue({ success: true }) - - workspacesProject = {} as jest.Mocked> - workspacesProject.project = jest.fn().mockReturnValue({ foo: 'bar' }) - - workspaceUsersProjector = {} as jest.Mocked> - workspaceUsersProjector.project = jest.fn().mockReturnValue({ bar: 'buzz' }) - }) - - it('should create a workspace', async () => { - const result = await createController().createWorkspace({ - encryptedPrivateKey: 'foo', - encryptedWorkspaceKey: 'bar', - publicKey: 'buzz', - workspaceName: 'A Team', - ownerUuid: 'u-1-2-3', - workspaceType: WorkspaceType.Private, - }) - - expect(result).toEqual({ - data: { - uuid: 'w-1-2-3', - }, - status: 200, - }) - }) - - it('should invite to a workspace', async () => { - const result = await createController().inviteToWorkspace({ - inviteeEmail: 'test@test.te', - workspaceUuid: 'w-1-2-3', - accessLevel: WorkspaceAccessLevel.ReadOnly, - }) - - expect(result).toEqual({ - data: { - uuid: 'i-1-2-3', - }, - status: 200, - }) - }) - - it('should accept an invite', async () => { - const result = await createController().acceptInvite({ - userUuid: '1-2-3', - encryptedPrivateKey: 'foo', - inviteUuid: 'i-1-2-3', - publicKey: 'bar', - }) - - expect(result).toEqual({ - data: { - success: true, - }, - status: 200, - }) - }) - - it('should not accept an invite if it fails', async () => { - doAcceptInvitation.execute = jest.fn().mockReturnValue({ success: false }) - const result = await createController().acceptInvite({ - userUuid: '1-2-3', - encryptedPrivateKey: 'foo', - inviteUuid: 'i-1-2-3', - publicKey: 'bar', - }) - - expect(result).toEqual({ - data: { - error: { - message: 'Could not accept invite', - }, - }, - status: 400, - }) - }) - - it('should list workspaces', async () => { - const result = await createController().listWorkspaces({ - userUuid: '1-2-3', - }) - - expect(result).toEqual({ - data: { - ownedWorkspaces: [{ foo: 'bar' }], - joinedWorkspaces: [{ foo: 'bar' }], - }, - status: 200, - }) - }) - - it('should list workspace users', async () => { - const result = await createController().listWorkspaceUsers({ - userUuid: '1-2-3', - workspaceUuid: 'w-1-2-3', - }) - - expect(result).toEqual({ - data: { - users: [{ bar: 'buzz' }, { bar: 'buzz' }], - }, - status: 200, - }) - }) - - it('should initiate keyshare', async () => { - const result = await createController().initiateKeyshare({ - userUuid: 'u-1-2-3', - encryptedWorkspaceKey: 'foo', - workspaceUuid: 'w-1-2-3', - performingUserUuid: 'p-1-2-3', - }) - - expect(result).toEqual({ - data: { - success: true, - }, - status: 200, - }) - }) - - it('should not initiate keyshare if it fails', async () => { - doInitiateKeyshare.execute = jest.fn().mockReturnValue({ success: false }) - - const result = await createController().initiateKeyshare({ - userUuid: 'u-1-2-3', - encryptedWorkspaceKey: 'foo', - workspaceUuid: 'w-1-2-3', - performingUserUuid: 'p-1-2-3', - }) - - expect(result).toEqual({ - data: { - error: { - message: 'Could not initiate keyshare.', - }, - }, - status: 400, - }) - }) -}) diff --git a/packages/workspace/src/Controller/WorkspacesController.ts b/packages/workspace/src/Controller/WorkspacesController.ts deleted file mode 100644 index 3d17604db..000000000 --- a/packages/workspace/src/Controller/WorkspacesController.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { inject, injectable } from 'inversify' -import { - HttpStatusCode, - WorkspaceCreationRequestParams, - WorkspaceCreationResponse, - WorkspaceInvitationRequestParams, - WorkspaceInvitationResponse, - WorkspaceServerInterface, - WorkspaceListRequestParams, - WorkspaceListResponse, - WorkspaceInvitationAcceptingRequestParams, - WorkspaceInvitationAcceptingResponse, - WorkspaceUserListRequestParams, - WorkspaceKeyshareInitiatingRequestParams, - WorkspaceKeyshareInitiatingResponse, -} from '@standardnotes/api' -import { WorkspaceAccessLevel } from '@standardnotes/common' - -import TYPES from '../Bootstrap/Types' -import { CreateWorkspace } from '../Domain/UseCase/CreateWorkspace/CreateWorkspace' -import { InviteToWorkspace } from '../Domain/UseCase/InviteToWorkspace/InviteToWorkspace' -import { ProjectorInterface } from '../Domain/Projection/ProjectorInterface' -import { WorkspaceProjection } from '../Domain/Projection/WorkspaceProjection' -import { Workspace } from '../Domain/Workspace/Workspace' -import { ListWorkspaces } from '../Domain/UseCase/ListWorkspaces/ListWorkspaces' -import { WorkspaceUserListResponse } from '@standardnotes/api/dist/Domain/Response/Workspace/WorkspaceUserListResponse' -import { AcceptInvitation } from '../Domain/UseCase/AcceptInvitation/AcceptInvitation' -import { WorkspaceUser } from '../Domain/Workspace/WorkspaceUser' -import { WorkspaceUserProjection } from '../Domain/Projection/WorkspaceUserProjection' -import { ListWorkspaceUsers } from '../Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsers' -import { InitiateKeyShare } from '../Domain/UseCase/InitiateKeyShare/InitiateKeyShare' - -@injectable() -export class WorkspacesController implements WorkspaceServerInterface { - constructor( - @inject(TYPES.CreateWorkspace) private doCreateWorkspace: CreateWorkspace, - @inject(TYPES.InviteToWorkspace) private doInviteToWorkspace: InviteToWorkspace, - @inject(TYPES.ListWorkspaces) private doListWorkspaces: ListWorkspaces, - @inject(TYPES.ListWorkspaceUsers) private doListWorkspaceUsers: ListWorkspaceUsers, - @inject(TYPES.AcceptInvitation) private doAcceptInvite: AcceptInvitation, - @inject(TYPES.InitiateKeyShare) private doInitiateKeyshare: InitiateKeyShare, - @inject(TYPES.WorkspaceProjector) private workspaceProjector: ProjectorInterface, - @inject(TYPES.WorkspaceUserProjector) - private workspaceUserProjector: ProjectorInterface, - ) {} - - async initiateKeyshare( - params: WorkspaceKeyshareInitiatingRequestParams, - ): Promise { - const result = await this.doInitiateKeyshare.execute({ - userUuid: params.userUuid, - workspaceUuid: params.workspaceUuid, - encryptedWorkspaceKey: params.encryptedWorkspaceKey, - performingUserUuid: params.performingUserUuid as string, - }) - - if (!result.success) { - return { - status: HttpStatusCode.BadRequest, - data: { - error: { - message: 'Could not initiate keyshare.', - }, - }, - } - } - - return { - status: HttpStatusCode.Success, - data: { - success: true, - }, - } - } - - async inviteToWorkspace(params: WorkspaceInvitationRequestParams): Promise { - const { invite } = await this.doInviteToWorkspace.execute({ - inviteeEmail: params.inviteeEmail, - workspaceUuid: params.workspaceUuid, - inviterUuid: params.inviterUuid as string, - accessLevel: params.accessLevel as WorkspaceAccessLevel, - }) - - return { - status: HttpStatusCode.Success, - data: { uuid: invite.uuid }, - } - } - - async createWorkspace(params: WorkspaceCreationRequestParams): Promise { - const { workspace } = await this.doCreateWorkspace.execute({ - encryptedPrivateKey: params.encryptedPrivateKey, - encryptedWorkspaceKey: params.encryptedWorkspaceKey, - publicKey: params.publicKey, - name: params.workspaceName, - type: params.workspaceType, - ownerUuid: params.ownerUuid as string, - }) - - return { - status: HttpStatusCode.Success, - data: { uuid: workspace.uuid }, - } - } - - async listWorkspaces(params: WorkspaceListRequestParams): Promise { - const { ownedWorkspaces, joinedWorkspaces } = await this.doListWorkspaces.execute({ - userUuid: params.userUuid as string, - }) - - const ownedWorkspacesProjections = [] - for (const ownedWorkspace of ownedWorkspaces) { - ownedWorkspacesProjections.push(await this.workspaceProjector.project(ownedWorkspace)) - } - - const joinedWorkspacesProjections = [] - for (const joinedWorkspace of joinedWorkspaces) { - joinedWorkspacesProjections.push(await this.workspaceProjector.project(joinedWorkspace)) - } - - return { - status: HttpStatusCode.Success, - data: { ownedWorkspaces: ownedWorkspacesProjections, joinedWorkspaces: joinedWorkspacesProjections }, - } - } - - async listWorkspaceUsers(params: WorkspaceUserListRequestParams): Promise { - const { workspaceUsers } = await this.doListWorkspaceUsers.execute({ - userUuid: params.userUuid as string, - workspaceUuid: params.workspaceUuid, - }) - - const workspaceUserProjections = [] - for (const workspaceUser of workspaceUsers) { - workspaceUserProjections.push(await this.workspaceUserProjector.project(workspaceUser)) - } - - return { - status: HttpStatusCode.Success, - data: { users: workspaceUserProjections }, - } - } - - async acceptInvite(params: WorkspaceInvitationAcceptingRequestParams): Promise { - const result = await this.doAcceptInvite.execute({ - acceptingUserUuid: params.userUuid, - encryptedPrivateKey: params.encryptedPrivateKey, - invitationUuid: params.inviteUuid, - publicKey: params.publicKey, - }) - - if (!result.success) { - return { - status: HttpStatusCode.BadRequest, - data: { - error: { - message: 'Could not accept invite', - }, - }, - } - } - - return { - status: HttpStatusCode.Success, - data: { - success: true, - }, - } - } -} diff --git a/packages/workspace/src/Domain/Email/WorkspaceInviteCreated.ts b/packages/workspace/src/Domain/Email/WorkspaceInviteCreated.ts deleted file mode 100644 index beded6260..000000000 --- a/packages/workspace/src/Domain/Email/WorkspaceInviteCreated.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { html } from './workspace-invite-created.html' - -export function getSubject(): string { - return 'You have been invited to a Standard Notes workspace' -} - -export function getBody(inviteUuid: string): string { - return html(inviteUuid) -} diff --git a/packages/workspace/src/Domain/Email/workspace-invite-created.html.ts b/packages/workspace/src/Domain/Email/workspace-invite-created.html.ts deleted file mode 100644 index 6e768ece8..000000000 --- a/packages/workspace/src/Domain/Email/workspace-invite-created.html.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const html = (inviteUuid: string) => `

Hello,

-

We are happy to inform that you have been invited to a shared workspace in Standard Notes.

-

- Please - accept the invitation - to see the shared content. -

-

- Thanks, -
SN
-

` diff --git a/packages/workspace/src/Domain/Event/DomainEventFactory.ts b/packages/workspace/src/Domain/Event/DomainEventFactory.ts deleted file mode 100644 index 97e072181..000000000 --- a/packages/workspace/src/Domain/Event/DomainEventFactory.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { - DomainEventService, - EmailRequestedEvent, - WebSocketMessageRequestedEvent, - WorkspaceInviteAcceptedEvent, -} from '@standardnotes/domain-events' -import { TimerInterface } from '@standardnotes/time' -import { inject, injectable } from 'inversify' - -import TYPES from '../../Bootstrap/Types' - -import { DomainEventFactoryInterface } from './DomainEventFactoryInterface' - -@injectable() -export class DomainEventFactory implements DomainEventFactoryInterface { - constructor(@inject(TYPES.Timer) private timer: TimerInterface) {} - - createWorkspaceInviteAcceptedEvent(dto: { - inviterUuid: string - inviteeUuid: string - workspaceUuid: string - }): WorkspaceInviteAcceptedEvent { - return { - type: 'WORKSPACE_INVITE_ACCEPTED', - createdAt: this.timer.getUTCDate(), - meta: { - correlation: { - userIdentifier: dto.inviteeUuid, - userIdentifierType: 'uuid', - }, - origin: DomainEventService.Workspace, - }, - payload: dto, - } - } - - createWebSocketMessageRequestedEvent(dto: { userUuid: string; message: string }): WebSocketMessageRequestedEvent { - return { - type: 'WEB_SOCKET_MESSAGE_REQUESTED', - createdAt: this.timer.getUTCDate(), - meta: { - correlation: { - userIdentifier: dto.userUuid, - userIdentifierType: 'uuid', - }, - origin: DomainEventService.Workspace, - }, - payload: dto, - } - } - - createEmailRequestedEvent(dto: { - userEmail: string - messageIdentifier: string - level: string - body: string - subject: string - }): EmailRequestedEvent { - return { - type: 'EMAIL_REQUESTED', - createdAt: this.timer.getUTCDate(), - meta: { - correlation: { - userIdentifier: dto.userEmail, - userIdentifierType: 'email', - }, - origin: DomainEventService.Auth, - }, - payload: dto, - } - } -} diff --git a/packages/workspace/src/Domain/Event/DomainEventFactoryInterface.ts b/packages/workspace/src/Domain/Event/DomainEventFactoryInterface.ts deleted file mode 100644 index c5cfdbf64..000000000 --- a/packages/workspace/src/Domain/Event/DomainEventFactoryInterface.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { JSONString } from '@standardnotes/common' -import { - EmailRequestedEvent, - WebSocketMessageRequestedEvent, - WorkspaceInviteAcceptedEvent, -} from '@standardnotes/domain-events' - -export interface DomainEventFactoryInterface { - createEmailRequestedEvent(dto: { - userEmail: string - messageIdentifier: string - level: string - body: string - subject: string - }): EmailRequestedEvent - createWorkspaceInviteAcceptedEvent(dto: { - inviterUuid: string - inviteeUuid: string - workspaceUuid: string - }): WorkspaceInviteAcceptedEvent - createWebSocketMessageRequestedEvent(dto: { userUuid: string; message: JSONString }): WebSocketMessageRequestedEvent -} diff --git a/packages/workspace/src/Domain/Handler/UserRegisteredEventHandler.spec.ts b/packages/workspace/src/Domain/Handler/UserRegisteredEventHandler.spec.ts deleted file mode 100644 index e86c5c6ae..000000000 --- a/packages/workspace/src/Domain/Handler/UserRegisteredEventHandler.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import 'reflect-metadata' - -import { UserRegisteredEvent } from '@standardnotes/domain-events' - -import { UserRegisteredEventHandler } from './UserRegisteredEventHandler' -import { CreateWorkspace } from '../UseCase/CreateWorkspace/CreateWorkspace' -import { ProtocolVersion } from '@standardnotes/common' - -describe('UserRegisteredEventHandler', () => { - let createWorkspace: CreateWorkspace - let event: UserRegisteredEvent - - const createHandler = () => new UserRegisteredEventHandler(createWorkspace) - - beforeEach(() => { - createWorkspace = {} as jest.Mocked - createWorkspace.execute = jest.fn() - - event = {} as jest.Mocked - event.createdAt = new Date(1) - event.payload = { - userUuid: '1-2-3', - email: 'test@test.te', - protocolVersion: ProtocolVersion.V005, - } - }) - - it('should create a root workspace for newly registered user', async () => { - await createHandler().handle(event) - - expect(createWorkspace.execute).toHaveBeenCalledWith({ - ownerUuid: '1-2-3', - type: 'root', - }) - }) - - it('should not create a root workspace for newly registered user on legacy protocols', async () => { - event.payload.protocolVersion = ProtocolVersion.V004 - - await createHandler().handle(event) - - expect(createWorkspace.execute).not.toHaveBeenCalled() - }) -}) diff --git a/packages/workspace/src/Domain/Handler/UserRegisteredEventHandler.ts b/packages/workspace/src/Domain/Handler/UserRegisteredEventHandler.ts deleted file mode 100644 index 825fe5536..000000000 --- a/packages/workspace/src/Domain/Handler/UserRegisteredEventHandler.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ProtocolVersion, WorkspaceType } from '@standardnotes/common' -import { DomainEventHandlerInterface, UserRegisteredEvent } from '@standardnotes/domain-events' -import { inject, injectable } from 'inversify' - -import TYPES from '../../Bootstrap/Types' -import { CreateWorkspace } from '../UseCase/CreateWorkspace/CreateWorkspace' - -@injectable() -export class UserRegisteredEventHandler implements DomainEventHandlerInterface { - constructor(@inject(TYPES.CreateWorkspace) private createWorkspace: CreateWorkspace) {} - - async handle(event: UserRegisteredEvent): Promise { - if (event.payload.protocolVersion !== ProtocolVersion.V005) { - return - } - - await this.createWorkspace.execute({ - ownerUuid: event.payload.userUuid, - type: WorkspaceType.Root, - }) - } -} diff --git a/packages/workspace/src/Domain/Invite/WorkspaceInvite.ts b/packages/workspace/src/Domain/Invite/WorkspaceInvite.ts deleted file mode 100644 index 93eaf7493..000000000 --- a/packages/workspace/src/Domain/Invite/WorkspaceInvite.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { WorkspaceAccessLevel } from '@standardnotes/common' -import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' - -import { Workspace } from '../Workspace/Workspace' -import { WorkspaceInviteStatus } from './WorkspaceInviteStatus' - -@Entity({ name: 'workspace_invites' }) -export class WorkspaceInvite { - @PrimaryGeneratedColumn('uuid') - declare uuid: string - - @Column({ - name: 'inviter_uuid', - length: 36, - }) - declare inviterUuid: string - - @Column({ - name: 'invitee_email', - length: 255, - }) - declare inviteeEmail: string - - @Column({ - name: 'status', - type: 'varchar', - length: 64, - }) - declare status: WorkspaceInviteStatus - - @Column({ - name: 'accepting_user_uuid', - type: 'varchar', - length: 36, - nullable: true, - }) - declare acceptingUserUuid: string | null - - @Column({ - name: 'workspace_uuid', - length: 36, - }) - declare workspaceUuid: string - - @Column({ - name: 'access_level', - length: 64, - }) - declare accessLevel: WorkspaceAccessLevel - - @Column({ - name: 'created_at', - type: 'bigint', - }) - declare createdAt: number - - @Column({ - name: 'updated_at', - type: 'bigint', - }) - declare updatedAt: number - - @ManyToOne( - /* istanbul ignore next */ - () => Workspace, - /* istanbul ignore next */ - (workspace) => workspace.invites, - /* istanbul ignore next */ - { onDelete: 'CASCADE' }, - ) - @JoinColumn( - /* istanbul ignore next */ - { name: 'workspace_uuid' }, - ) - declare workspace: Promise -} diff --git a/packages/workspace/src/Domain/Invite/WorkspaceInviteRepositoryInterface.ts b/packages/workspace/src/Domain/Invite/WorkspaceInviteRepositoryInterface.ts deleted file mode 100644 index 4989e9538..000000000 --- a/packages/workspace/src/Domain/Invite/WorkspaceInviteRepositoryInterface.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { WorkspaceInvite } from './WorkspaceInvite' - -export interface WorkspaceInviteRepositoryInterface { - findOneByUuid(uuid: string): Promise - save(workspace: WorkspaceInvite): Promise -} diff --git a/packages/workspace/src/Domain/Invite/WorkspaceInviteStatus.ts b/packages/workspace/src/Domain/Invite/WorkspaceInviteStatus.ts deleted file mode 100644 index fb9fbc79e..000000000 --- a/packages/workspace/src/Domain/Invite/WorkspaceInviteStatus.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum WorkspaceInviteStatus { - Created = 'created', - Accepted = 'accepted', -} diff --git a/packages/workspace/src/Domain/Projection/ProjectorInterface.ts b/packages/workspace/src/Domain/Projection/ProjectorInterface.ts deleted file mode 100644 index a987e78be..000000000 --- a/packages/workspace/src/Domain/Projection/ProjectorInterface.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface ProjectorInterface { - project(object: T): Promise -} diff --git a/packages/workspace/src/Domain/Projection/WorkspaceProjection.ts b/packages/workspace/src/Domain/Projection/WorkspaceProjection.ts deleted file mode 100644 index 09d309f7c..000000000 --- a/packages/workspace/src/Domain/Projection/WorkspaceProjection.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Workspace } from '@standardnotes/api' - -export type WorkspaceProjection = Workspace diff --git a/packages/workspace/src/Domain/Projection/WorkspaceProjector.spec.ts b/packages/workspace/src/Domain/Projection/WorkspaceProjector.spec.ts deleted file mode 100644 index 103c95406..000000000 --- a/packages/workspace/src/Domain/Projection/WorkspaceProjector.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import 'reflect-metadata' - -import { WorkspaceType } from '@standardnotes/common' -import { Workspace } from '../Workspace/Workspace' - -import { WorkspaceProjector } from './WorkspaceProjector' - -describe('WorkspaceProjector', () => { - const createProjector = () => new WorkspaceProjector() - - it('should project a workspace', async () => { - expect( - await createProjector().project({ - uuid: 'w-1-2-3', - type: WorkspaceType.Private, - name: 'test', - keyRotationIndex: 0, - createdAt: 1, - updatedAt: 2, - } as jest.Mocked), - ).toEqual({ - uuid: 'w-1-2-3', - type: 'private', - name: 'test', - keyRotationIndex: 0, - createdAt: 1, - updatedAt: 2, - }) - }) -}) diff --git a/packages/workspace/src/Domain/Projection/WorkspaceProjector.ts b/packages/workspace/src/Domain/Projection/WorkspaceProjector.ts deleted file mode 100644 index 2d798b360..000000000 --- a/packages/workspace/src/Domain/Projection/WorkspaceProjector.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { injectable } from 'inversify' -import { ProjectorInterface } from './ProjectorInterface' - -import { WorkspaceProjection } from './WorkspaceProjection' -import { Workspace } from '../Workspace/Workspace' - -@injectable() -export class WorkspaceProjector implements ProjectorInterface { - async project(workspace: Workspace): Promise { - return { - uuid: workspace.uuid, - type: workspace.type, - name: workspace.name, - keyRotationIndex: workspace.keyRotationIndex, - createdAt: workspace.createdAt, - updatedAt: workspace.updatedAt, - } - } -} diff --git a/packages/workspace/src/Domain/Projection/WorkspaceUserProjection.ts b/packages/workspace/src/Domain/Projection/WorkspaceUserProjection.ts deleted file mode 100644 index 989d54683..000000000 --- a/packages/workspace/src/Domain/Projection/WorkspaceUserProjection.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { WorkspaceUser } from '@standardnotes/api' - -export type WorkspaceUserProjection = WorkspaceUser diff --git a/packages/workspace/src/Domain/Projection/WorkspaceUserProjector.spec.ts b/packages/workspace/src/Domain/Projection/WorkspaceUserProjector.spec.ts deleted file mode 100644 index 35a54b4c6..000000000 --- a/packages/workspace/src/Domain/Projection/WorkspaceUserProjector.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import 'reflect-metadata' - -import { WorkspaceAccessLevel, WorkspaceUserStatus } from '@standardnotes/common' -import { WorkspaceUser } from '../Workspace/WorkspaceUser' - -import { WorkspaceUserProjector } from './WorkspaceUserProjector' - -describe('WorkspaceUserProjector', () => { - const createProjector = () => new WorkspaceUserProjector() - - it('should project a workspace user', async () => { - expect( - await createProjector().project({ - uuid: '1-2-3', - accessLevel: WorkspaceAccessLevel.Owner, - userUuid: 'u-1-2-3', - userDisplayName: 'foobar', - workspaceUuid: 'w-1-2-3', - encryptedWorkspaceKey: 'foo', - publicKey: 'bar', - encryptedPrivateKey: 'buzz', - status: WorkspaceUserStatus.PendingKeyshare, - keyRotationIndex: 0, - createdAt: 1, - updatedAt: 2, - } as jest.Mocked), - ).toEqual({ - uuid: '1-2-3', - accessLevel: 'owner', - userUuid: 'u-1-2-3', - userDisplayName: 'foobar', - workspaceUuid: 'w-1-2-3', - encryptedWorkspaceKey: 'foo', - publicKey: 'bar', - encryptedPrivateKey: 'buzz', - status: 'pending-keyshare', - keyRotationIndex: 0, - createdAt: 1, - updatedAt: 2, - }) - }) -}) diff --git a/packages/workspace/src/Domain/Projection/WorkspaceUserProjector.ts b/packages/workspace/src/Domain/Projection/WorkspaceUserProjector.ts deleted file mode 100644 index 613b88160..000000000 --- a/packages/workspace/src/Domain/Projection/WorkspaceUserProjector.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { injectable } from 'inversify' -import { ProjectorInterface } from './ProjectorInterface' - -import { WorkspaceUserProjection } from './WorkspaceUserProjection' -import { WorkspaceUser } from '../Workspace/WorkspaceUser' - -@injectable() -export class WorkspaceUserProjector implements ProjectorInterface { - async project(workspaceUser: WorkspaceUser): Promise { - return { - uuid: workspaceUser.uuid, - accessLevel: workspaceUser.accessLevel, - userUuid: workspaceUser.userUuid, - userDisplayName: workspaceUser.userDisplayName, - workspaceUuid: workspaceUser.workspaceUuid, - encryptedWorkspaceKey: workspaceUser.encryptedWorkspaceKey, - publicKey: workspaceUser.publicKey, - encryptedPrivateKey: workspaceUser.encryptedPrivateKey, - status: workspaceUser.status, - keyRotationIndex: workspaceUser.keyRotationIndex, - createdAt: workspaceUser.createdAt, - updatedAt: workspaceUser.updatedAt, - } - } -} diff --git a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.spec.ts b/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.spec.ts deleted file mode 100644 index 584a4f6ad..000000000 --- a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.spec.ts +++ /dev/null @@ -1,106 +0,0 @@ -import 'reflect-metadata' -import { TimerInterface } from '@standardnotes/time' - -import { WorkspaceInvite } from '../../Invite/WorkspaceInvite' -import { WorkspaceInviteRepositoryInterface } from '../../Invite/WorkspaceInviteRepositoryInterface' -import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' - -import { AcceptInvitation } from './AcceptInvitation' -import { WorkspaceAccessLevel } from '@standardnotes/common' -import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface' -import { - DomainEventPublisherInterface, - WebSocketMessageRequestedEvent, - WorkspaceInviteAcceptedEvent, -} from '@standardnotes/domain-events' - -describe('AcceptInvitation', () => { - let workspaceInviteRepository: WorkspaceInviteRepositoryInterface - let workspaceUserRepository: WorkspaceUserRepositoryInterface - let domainEventFactory: DomainEventFactoryInterface - let domainEventPublisher: DomainEventPublisherInterface - let timer: TimerInterface - let invite: WorkspaceInvite - - const createUseCase = () => - new AcceptInvitation( - workspaceInviteRepository, - workspaceUserRepository, - domainEventFactory, - domainEventPublisher, - timer, - ) - - beforeEach(() => { - 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) - workspaceInviteRepository.save = jest.fn() - - workspaceUserRepository = {} as jest.Mocked - workspaceUserRepository.save = jest.fn() - - timer = {} as jest.Mocked - timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(1) - - domainEventFactory = {} as jest.Mocked - domainEventFactory.createWebSocketMessageRequestedEvent = jest - .fn() - .mockReturnValue({} as jest.Mocked) - domainEventFactory.createWorkspaceInviteAcceptedEvent = jest - .fn() - .mockReturnValue({} as jest.Mocked) - - domainEventPublisher = {} as jest.Mocked - domainEventPublisher.publish = jest.fn() - }) - - it('should accept an invite and assign user to workspace', async () => { - await createUseCase().execute({ - acceptingUserUuid: 'u-1-2-3', - encryptedPrivateKey: 'foo', - publicKey: 'bar', - invitationUuid: 'i-1-2-3', - }) - - expect(workspaceInviteRepository.save).toHaveBeenCalledWith({ - acceptingUserUuid: 'u-1-2-3', - status: 'accepted', - 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', - publicKey: 'bar', - status: 'pending-keyshare', - userUuid: 'u-1-2-3', - workspaceUuid: 'w-1-2-3', - accessLevel: 'write-and-read', - userDisplayName: 'test@test.te', - createdAt: 1, - updatedAt: 1, - }) - }) - - it('should not accept an invite if it does not exist', async () => { - workspaceInviteRepository.findOneByUuid = jest.fn().mockReturnValue(null) - - await createUseCase().execute({ - acceptingUserUuid: 'u-1-2-3', - encryptedPrivateKey: 'foo', - publicKey: 'bar', - invitationUuid: 'i-1-2-3', - }) - - expect(workspaceInviteRepository.save).not.toHaveBeenCalled() - expect(workspaceUserRepository.save).not.toHaveBeenCalled() - }) -}) diff --git a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.ts b/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.ts deleted file mode 100644 index 36d07722b..000000000 --- a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitation.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { TimerInterface } from '@standardnotes/time' -import { WorkspaceUserStatus } from '@standardnotes/common' -import { inject, injectable } from 'inversify' - -import TYPES from '../../../Bootstrap/Types' -import { WorkspaceInviteRepositoryInterface } from '../../Invite/WorkspaceInviteRepositoryInterface' -import { WorkspaceInviteStatus } from '../../Invite/WorkspaceInviteStatus' -import { WorkspaceUser } from '../../Workspace/WorkspaceUser' -import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' -import { UseCaseInterface } from '../UseCaseInterface' - -import { AcceptInvitationDTO } from './AcceptInvitationDTO' -import { AcceptInvitationResponse } from './AcceptInvitationResponse' -import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface' -import { DomainEventPublisherInterface } from '@standardnotes/domain-events' - -@injectable() -export class AcceptInvitation implements UseCaseInterface { - constructor( - @inject(TYPES.WorkspaceInviteRepository) private workspaceInviteRepository: WorkspaceInviteRepositoryInterface, - @inject(TYPES.WorkspaceUserRepository) private workspaceUserRepository: WorkspaceUserRepositoryInterface, - @inject(TYPES.DomainEventFactory) private domainEventFactory: DomainEventFactoryInterface, - @inject(TYPES.DomainEventPublisher) private domainEventPublisher: DomainEventPublisherInterface, - @inject(TYPES.Timer) private timer: TimerInterface, - ) {} - - async execute(dto: AcceptInvitationDTO): Promise { - const invite = await this.workspaceInviteRepository.findOneByUuid(dto.invitationUuid) - if (invite === null) { - return { - success: false, - } - } - - const timestamp = this.timer.getTimestampInMicroseconds() - invite.acceptingUserUuid = dto.acceptingUserUuid - invite.updatedAt = timestamp - invite.status = WorkspaceInviteStatus.Accepted - - await this.workspaceInviteRepository.save(invite) - - const workspaceUser = new WorkspaceUser() - workspaceUser.userUuid = dto.acceptingUserUuid - workspaceUser.userDisplayName = invite.inviteeEmail - workspaceUser.workspaceUuid = invite.workspaceUuid - workspaceUser.publicKey = dto.publicKey - workspaceUser.encryptedPrivateKey = dto.encryptedPrivateKey - workspaceUser.accessLevel = invite.accessLevel - workspaceUser.status = WorkspaceUserStatus.PendingKeyshare - workspaceUser.createdAt = timestamp - workspaceUser.updatedAt = timestamp - - await this.workspaceUserRepository.save(workspaceUser) - - const event = this.domainEventFactory.createWorkspaceInviteAcceptedEvent({ - inviteeUuid: invite.acceptingUserUuid, - inviterUuid: invite.inviterUuid, - workspaceUuid: invite.workspaceUuid, - }) - - await this.domainEventPublisher.publish( - this.domainEventFactory.createWebSocketMessageRequestedEvent({ - userUuid: invite.inviterUuid, - message: JSON.stringify(event), - }), - ) - - return { - success: true, - } - } -} diff --git a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitationDTO.ts b/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitationDTO.ts deleted file mode 100644 index 893d2111b..000000000 --- a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitationDTO.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type AcceptInvitationDTO = { - invitationUuid: string - acceptingUserUuid: string - publicKey: string - encryptedPrivateKey: string -} diff --git a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitationResponse.ts b/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitationResponse.ts deleted file mode 100644 index adf77d586..000000000 --- a/packages/workspace/src/Domain/UseCase/AcceptInvitation/AcceptInvitationResponse.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type AcceptInvitationResponse = { - success: boolean -} diff --git a/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspace.spec.ts b/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspace.spec.ts deleted file mode 100644 index a10adbcb1..000000000 --- a/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspace.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import 'reflect-metadata' - -import { WorkspaceType } from '@standardnotes/common' - -import { WorkspaceRepositoryInterface } from '../../Workspace/WorkspaceRepositoryInterface' -import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' - -import { CreateWorkspace } from './CreateWorkspace' -import { TimerInterface } from '@standardnotes/time' - -describe('CreateWorkspace', () => { - let workspaceRepository: WorkspaceRepositoryInterface - let workspaceUserRepository: WorkspaceUserRepositoryInterface - let timer: TimerInterface - - const createUseCase = () => new CreateWorkspace(workspaceRepository, workspaceUserRepository, timer) - - beforeEach(() => { - timer = {} as jest.Mocked - timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(1) - - workspaceRepository = {} as jest.Mocked - workspaceRepository.save = jest.fn().mockImplementation((workspace) => { - return { - ...workspace, - uuid: 'w-1-2-3', - } - }) - - workspaceUserRepository = {} as jest.Mocked - workspaceUserRepository.save = jest.fn() - }) - - it('should create a workspace and owner association with it', async () => { - await createUseCase().execute({ - encryptedPrivateKey: 'foo', - encryptedWorkspaceKey: 'bar', - publicKey: 'buzz', - name: 'A Team', - ownerUuid: '1-2-3', - type: WorkspaceType.Root, - }) - - expect(workspaceRepository.save).toHaveBeenCalledWith({ - name: 'A Team', - type: 'root', - createdAt: 1, - updatedAt: 1, - }) - expect(workspaceUserRepository.save).toHaveBeenCalledWith({ - accessLevel: 'owner', - encryptedWorkspaceKey: 'bar', - encryptedPrivateKey: 'foo', - publicKey: 'buzz', - status: 'active', - userUuid: '1-2-3', - workspaceUuid: 'w-1-2-3', - createdAt: 1, - updatedAt: 1, - }) - }) - - it('should create a workspace without optional parameters', async () => { - await createUseCase().execute({ - ownerUuid: '1-2-3', - type: WorkspaceType.Private, - }) - - expect(workspaceRepository.save).toHaveBeenCalledWith({ - type: 'private', - createdAt: 1, - updatedAt: 1, - }) - expect(workspaceUserRepository.save).toHaveBeenCalledWith({ - accessLevel: 'owner', - status: 'active', - userUuid: '1-2-3', - workspaceUuid: 'w-1-2-3', - createdAt: 1, - updatedAt: 1, - }) - }) -}) diff --git a/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspace.ts b/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspace.ts deleted file mode 100644 index bf0193f74..000000000 --- a/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspace.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { TimerInterface } from '@standardnotes/time' -import { WorkspaceAccessLevel, WorkspaceUserStatus } from '@standardnotes/common' -import { inject, injectable } from 'inversify' - -import TYPES from '../../../Bootstrap/Types' -import { Workspace } from '../../Workspace/Workspace' -import { WorkspaceRepositoryInterface } from '../../Workspace/WorkspaceRepositoryInterface' -import { WorkspaceUser } from '../../Workspace/WorkspaceUser' -import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' -import { UseCaseInterface } from '../UseCaseInterface' - -import { CreateWorkspaceDTO } from './CreateWorkspaceDTO' -import { CreateWorkspaceResponse } from './CreateWorkspaceResponse' - -@injectable() -export class CreateWorkspace implements UseCaseInterface { - constructor( - @inject(TYPES.WorkspaceRepository) private workspaceRepository: WorkspaceRepositoryInterface, - @inject(TYPES.WorkspaceUserRepository) private workspaceUserRepository: WorkspaceUserRepositoryInterface, - @inject(TYPES.Timer) private timer: TimerInterface, - ) {} - - async execute(dto: CreateWorkspaceDTO): Promise { - let workspace = new Workspace() - if (dto.name !== undefined) { - workspace.name = dto.name - } - workspace.type = dto.type - const timestamp = this.timer.getTimestampInMicroseconds() - workspace.createdAt = timestamp - workspace.updatedAt = timestamp - - workspace = await this.workspaceRepository.save(workspace) - - const ownerAssociation = new WorkspaceUser() - ownerAssociation.accessLevel = WorkspaceAccessLevel.Owner - if (dto.encryptedWorkspaceKey !== undefined) { - ownerAssociation.encryptedWorkspaceKey = dto.encryptedWorkspaceKey - } - if (dto.encryptedPrivateKey !== undefined) { - ownerAssociation.encryptedPrivateKey = dto.encryptedPrivateKey - } - if (dto.publicKey !== undefined) { - ownerAssociation.publicKey = dto.publicKey - } - ownerAssociation.status = WorkspaceUserStatus.Active - ownerAssociation.userUuid = dto.ownerUuid - ownerAssociation.workspaceUuid = workspace.uuid - ownerAssociation.createdAt = timestamp - ownerAssociation.updatedAt = timestamp - - await this.workspaceUserRepository.save(ownerAssociation) - - return { workspace } - } -} diff --git a/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspaceDTO.ts b/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspaceDTO.ts deleted file mode 100644 index cdefccae8..000000000 --- a/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspaceDTO.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { WorkspaceType } from '@standardnotes/common' - -export type CreateWorkspaceDTO = { - ownerUuid: string - type: WorkspaceType - encryptedWorkspaceKey?: string - encryptedPrivateKey?: string - publicKey?: string - name?: string -} diff --git a/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspaceResponse.ts b/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspaceResponse.ts deleted file mode 100644 index 08f2bc5bd..000000000 --- a/packages/workspace/src/Domain/UseCase/CreateWorkspace/CreateWorkspaceResponse.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Workspace } from '../../Workspace/Workspace' - -export type CreateWorkspaceResponse = { - workspace: Workspace -} diff --git a/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShare.spec.ts b/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShare.spec.ts deleted file mode 100644 index 1911ffbfa..000000000 --- a/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShare.spec.ts +++ /dev/null @@ -1,100 +0,0 @@ -import 'reflect-metadata' - -import { TimerInterface } from '@standardnotes/time' - -import { WorkspaceUser } from '../../Workspace/WorkspaceUser' -import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' - -import { InitiateKeyShare } from './InitiateKeyShare' -import { WorkspaceAccessLevel } from '@standardnotes/common' - -describe('InitiateKeyShare', () => { - let workspaceUserRepository: WorkspaceUserRepositoryInterface - let timer: TimerInterface - let workspaceUser: WorkspaceUser - let workspaceOwner: WorkspaceUser - - const createUseCase = () => new InitiateKeyShare(workspaceUserRepository, timer) - - beforeEach(() => { - workspaceOwner = { - accessLevel: WorkspaceAccessLevel.Owner, - } as jest.Mocked - workspaceUser = {} as jest.Mocked - - workspaceUserRepository = {} as jest.Mocked - workspaceUserRepository.findOneByUserUuidAndWorkspaceUuid = jest - .fn() - .mockReturnValueOnce(workspaceOwner) - .mockReturnValueOnce(workspaceUser) - workspaceUserRepository.save = jest.fn().mockImplementation((user: WorkspaceUser) => user) - - timer = {} as jest.Mocked - timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(1) - }) - - it('should update the workspace user with a workspace key and mark as active', async () => { - await createUseCase().execute({ - workspaceUuid: 'w-1-2-3', - userUuid: 'u-1-2-3', - encryptedWorkspaceKey: 'foobar', - performingUserUuid: 'o-1-2-3', - }) - - expect(workspaceUserRepository.save).toHaveBeenCalledWith({ - encryptedWorkspaceKey: 'foobar', - status: 'active', - updatedAt: 1, - }) - }) - - it('should not initiate key share if workspace is not found', async () => { - workspaceUserRepository.findOneByUserUuidAndWorkspaceUuid = jest - .fn() - .mockReturnValueOnce(workspaceOwner) - .mockReturnValueOnce(null) - - await createUseCase().execute({ - workspaceUuid: 'w-1-2-3', - userUuid: 'u-1-2-3', - encryptedWorkspaceKey: 'foobar', - performingUserUuid: 'o-1-2-3', - }) - - expect(workspaceUserRepository.save).not.toHaveBeenCalled() - }) - - it('should not initiate key share if workspace performing user is not the owner or admin', async () => { - workspaceOwner.accessLevel = WorkspaceAccessLevel.ReadOnly - workspaceUserRepository.findOneByUserUuidAndWorkspaceUuid = jest - .fn() - .mockReturnValueOnce(workspaceOwner) - .mockReturnValueOnce(workspaceUser) - - await createUseCase().execute({ - workspaceUuid: 'w-1-2-3', - userUuid: 'u-1-2-3', - encryptedWorkspaceKey: 'foobar', - performingUserUuid: 'o-1-2-3', - }) - - expect(workspaceUserRepository.save).not.toHaveBeenCalled() - }) - - it('should not initiate key share if workspace performing user is found in workspace', async () => { - workspaceOwner.accessLevel = WorkspaceAccessLevel.ReadOnly - workspaceUserRepository.findOneByUserUuidAndWorkspaceUuid = jest - .fn() - .mockReturnValueOnce(null) - .mockReturnValueOnce(workspaceUser) - - await createUseCase().execute({ - workspaceUuid: 'w-1-2-3', - userUuid: 'u-1-2-3', - encryptedWorkspaceKey: 'foobar', - performingUserUuid: 'o-1-2-3', - }) - - expect(workspaceUserRepository.save).not.toHaveBeenCalled() - }) -}) diff --git a/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShare.ts b/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShare.ts deleted file mode 100644 index 36a3a2600..000000000 --- a/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShare.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { WorkspaceAccessLevel, WorkspaceUserStatus } from '@standardnotes/common' -import { TimerInterface } from '@standardnotes/time' -import { inject, injectable } from 'inversify' -import TYPES from '../../../Bootstrap/Types' -import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' -import { UseCaseInterface } from '../UseCaseInterface' -import { InitiateKeyShareDTO } from './InitiateKeyShareDTO' -import { InitiateKeyShareResponse } from './InitiateKeyShareResponse' - -@injectable() -export class InitiateKeyShare implements UseCaseInterface { - constructor( - @inject(TYPES.WorkspaceUserRepository) private workspaceUserRepository: WorkspaceUserRepositoryInterface, - @inject(TYPES.Timer) private timer: TimerInterface, - ) {} - - async execute(dto: InitiateKeyShareDTO): Promise { - const workspaceOwner = await this.workspaceUserRepository.findOneByUserUuidAndWorkspaceUuid({ - workspaceUuid: dto.workspaceUuid, - userUuid: dto.performingUserUuid, - }) - if ( - workspaceOwner === null || - ![WorkspaceAccessLevel.Admin, WorkspaceAccessLevel.Owner].includes(workspaceOwner.accessLevel) - ) { - return { - success: false, - } - } - - const workspaceUser = await this.workspaceUserRepository.findOneByUserUuidAndWorkspaceUuid({ - workspaceUuid: dto.workspaceUuid, - userUuid: dto.userUuid, - }) - - if (workspaceUser === null) { - return { - success: false, - } - } - - workspaceUser.encryptedWorkspaceKey = dto.encryptedWorkspaceKey - workspaceUser.status = WorkspaceUserStatus.Active - workspaceUser.updatedAt = this.timer.getTimestampInMicroseconds() - - await this.workspaceUserRepository.save(workspaceUser) - - return { - success: true, - } - } -} diff --git a/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShareDTO.ts b/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShareDTO.ts deleted file mode 100644 index aa1ffc45d..000000000 --- a/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShareDTO.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type InitiateKeyShareDTO = { - workspaceUuid: string - userUuid: string - performingUserUuid: string - encryptedWorkspaceKey: string -} diff --git a/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShareResponse.ts b/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShareResponse.ts deleted file mode 100644 index 8164e1eab..000000000 --- a/packages/workspace/src/Domain/UseCase/InitiateKeyShare/InitiateKeyShareResponse.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type InitiateKeyShareResponse = { - success: boolean -} diff --git a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.spec.ts b/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.spec.ts deleted file mode 100644 index 1c69f9a4c..000000000 --- a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import 'reflect-metadata' -import { TimerInterface } from '@standardnotes/time' - -import { WorkspaceInviteRepositoryInterface } from '../../Invite/WorkspaceInviteRepositoryInterface' - -import { InviteToWorkspace } from './InviteToWorkspace' -import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface' -import { DomainEventPublisherInterface, EmailRequestedEvent } from '@standardnotes/domain-events' -import { WorkspaceAccessLevel } from '@standardnotes/common' - -describe('InviteToWorkspace', () => { - let workspaceInviteRepository: WorkspaceInviteRepositoryInterface - let timer: TimerInterface - let domainEventFactory: DomainEventFactoryInterface - let domainEventPublisher: DomainEventPublisherInterface - - const createUseCase = () => - new InviteToWorkspace(workspaceInviteRepository, timer, domainEventFactory, domainEventPublisher) - - beforeEach(() => { - workspaceInviteRepository = {} as jest.Mocked - workspaceInviteRepository.save = jest.fn().mockImplementation((invite) => { - return { - ...invite, - uuid: 'i-1-2-3', - } - }) - - timer = {} as jest.Mocked - timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(1) - - domainEventPublisher = {} as jest.Mocked - domainEventPublisher.publish = jest.fn() - - domainEventFactory = {} as jest.Mocked - domainEventFactory.createEmailRequestedEvent = jest.fn().mockReturnValue({} as jest.Mocked) - }) - - it('should create an invite', async () => { - const result = await createUseCase().execute({ - inviteeEmail: 'test@test.te', - inviterUuid: 'u-1-2-3', - workspaceUuid: 'w-1-2-3', - accessLevel: WorkspaceAccessLevel.WriteAndRead, - }) - - expect(result).toEqual({ - invite: { - uuid: 'i-1-2-3', - inviterUuid: 'u-1-2-3', - inviteeEmail: 'test@test.te', - workspaceUuid: 'w-1-2-3', - status: 'created', - accessLevel: 'write-and-read', - createdAt: 1, - updatedAt: 1, - }, - }) - - expect(workspaceInviteRepository.save).toHaveBeenCalledWith({ - accessLevel: 'write-and-read', - inviterUuid: 'u-1-2-3', - inviteeEmail: 'test@test.te', - workspaceUuid: 'w-1-2-3', - status: 'created', - createdAt: 1, - updatedAt: 1, - }) - - expect(domainEventPublisher.publish).toHaveBeenCalled() - }) -}) diff --git a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.ts b/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.ts deleted file mode 100644 index 2322e0b20..000000000 --- a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspace.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { DomainEventPublisherInterface } from '@standardnotes/domain-events' -import { TimerInterface } from '@standardnotes/time' -import { EmailLevel } from '@standardnotes/domain-core' -import { inject, injectable } from 'inversify' - -import TYPES from '../../../Bootstrap/Types' -import { getBody, getSubject } from '../../Email/WorkspaceInviteCreated' -import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface' -import { WorkspaceInvite } from '../../Invite/WorkspaceInvite' -import { WorkspaceInviteRepositoryInterface } from '../../Invite/WorkspaceInviteRepositoryInterface' -import { WorkspaceInviteStatus } from '../../Invite/WorkspaceInviteStatus' - -import { UseCaseInterface } from '../UseCaseInterface' -import { InviteToWorkspaceDTO } from './InviteToWorkspaceDTO' -import { InviteToWorkspaceResponse } from './InviteToWorkspaceResponse' - -@injectable() -export class InviteToWorkspace implements UseCaseInterface { - constructor( - @inject(TYPES.WorkspaceInviteRepository) private workspaceInviteRepository: WorkspaceInviteRepositoryInterface, - @inject(TYPES.Timer) private timer: TimerInterface, - @inject(TYPES.DomainEventFactory) private domainEventFactory: DomainEventFactoryInterface, - @inject(TYPES.DomainEventPublisher) private domainEventPublisher: DomainEventPublisherInterface, - ) {} - - async execute(dto: InviteToWorkspaceDTO): Promise { - let invite = new WorkspaceInvite() - 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() - invite.createdAt = timestamp - invite.updatedAt = timestamp - - invite = await this.workspaceInviteRepository.save(invite) - - await this.domainEventPublisher.publish( - this.domainEventFactory.createEmailRequestedEvent({ - body: getBody(invite.uuid), - subject: getSubject(), - level: EmailLevel.LEVELS.System, - messageIdentifier: 'WORKSPACE_INVITE_CREATED', - userEmail: dto.inviteeEmail, - }), - ) - - return { - invite, - } - } -} diff --git a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspaceDTO.ts b/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspaceDTO.ts deleted file mode 100644 index ee18267be..000000000 --- a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspaceDTO.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { WorkspaceAccessLevel } from '@standardnotes/common' - -export type InviteToWorkspaceDTO = { - workspaceUuid: string - inviterUuid: string - inviteeEmail: string - accessLevel: WorkspaceAccessLevel -} diff --git a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspaceResponse.ts b/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspaceResponse.ts deleted file mode 100644 index 9740c86b4..000000000 --- a/packages/workspace/src/Domain/UseCase/InviteToWorkspace/InviteToWorkspaceResponse.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { WorkspaceInvite } from '../../Invite/WorkspaceInvite' - -export type InviteToWorkspaceResponse = { - invite: WorkspaceInvite -} diff --git a/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsers.spec.ts b/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsers.spec.ts deleted file mode 100644 index dbc73f058..000000000 --- a/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsers.spec.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { WorkspaceAccessLevel } from '@standardnotes/common' -import 'reflect-metadata' -import { Workspace } from '../../Workspace/Workspace' -import { WorkspaceRepositoryInterface } from '../../Workspace/WorkspaceRepositoryInterface' -import { WorkspaceUser } from '../../Workspace/WorkspaceUser' -import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' - -import { ListWorkspaceUsers } from './ListWorkspaceUsers' - -describe('ListWorkspaceUsers', () => { - let workspaceRepository: WorkspaceRepositoryInterface - let workspaceUserRepository: WorkspaceUserRepositoryInterface - let workspace: Workspace - let workspaceUser1: WorkspaceUser - let workspaceUser2: WorkspaceUser - - const createUseCase = () => new ListWorkspaceUsers(workspaceRepository, workspaceUserRepository) - - beforeEach(() => { - workspace = { uuid: 'j-1-2-3' } as jest.Mocked - - workspaceUser1 = { userUuid: 'u-1-2-3', accessLevel: WorkspaceAccessLevel.Owner } as jest.Mocked - workspaceUser2 = { - userUuid: 'u-2-3-4', - accessLevel: WorkspaceAccessLevel.WriteAndRead, - } as jest.Mocked - - workspaceRepository = {} as jest.Mocked - workspaceRepository.findOneByUuid = jest.fn().mockReturnValue(workspace) - - workspaceUserRepository = {} as jest.Mocked - workspaceUserRepository.findByWorkspaceUuid = jest.fn().mockReturnValue([workspaceUser1, workspaceUser2]) - }) - - it('should list users in a workspace where the user is owner or admin', async () => { - const result = await createUseCase().execute({ - userUuid: 'u-1-2-3', - workspaceUuid: 'j-1-2-3', - }) - - expect(result).toEqual({ - workspaceUsers: [workspaceUser1, workspaceUser2], - userIsOwnerOrAdmin: true, - }) - }) - - it('should list users in a workspace where the user is not the owner or admin with indiciation', async () => { - const result = await createUseCase().execute({ - userUuid: 'u-2-3-4', - workspaceUuid: 'j-1-2-3', - }) - - expect(result).toEqual({ - workspaceUsers: [workspaceUser1, workspaceUser2], - userIsOwnerOrAdmin: false, - }) - }) - - it('should not list users in a workspace where the user does not belong', async () => { - const result = await createUseCase().execute({ - userUuid: 'z-1-2-3', - workspaceUuid: 'j-1-2-3', - }) - - expect(result).toEqual({ - workspaceUsers: [], - userIsOwnerOrAdmin: false, - }) - }) - - it('should not list users in a workspace that does not exist', async () => { - workspaceRepository.findOneByUuid = jest.fn().mockReturnValue(null) - - const result = await createUseCase().execute({ - userUuid: 'u-1-2-3', - workspaceUuid: 'j-1-2-3', - }) - - expect(result).toEqual({ - workspaceUsers: [], - userIsOwnerOrAdmin: false, - }) - }) -}) diff --git a/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsers.ts b/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsers.ts deleted file mode 100644 index f364db9ab..000000000 --- a/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsers.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { WorkspaceAccessLevel } from '@standardnotes/common' -import { inject, injectable } from 'inversify' -import TYPES from '../../../Bootstrap/Types' -import { WorkspaceRepositoryInterface } from '../../Workspace/WorkspaceRepositoryInterface' -import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' -import { UseCaseInterface } from '../UseCaseInterface' -import { ListWorkspaceUsersDTO } from './ListWorkspaceUsersDTO' -import { ListWorkspaceUsersResponse } from './ListWorkspaceUsersResponse' - -@injectable() -export class ListWorkspaceUsers implements UseCaseInterface { - constructor( - @inject(TYPES.WorkspaceRepository) private workspaceRepository: WorkspaceRepositoryInterface, - @inject(TYPES.WorkspaceUserRepository) private workspaceUserRepository: WorkspaceUserRepositoryInterface, - ) {} - - async execute(dto: ListWorkspaceUsersDTO): Promise { - const workspace = await this.workspaceRepository.findOneByUuid(dto.workspaceUuid) - if (workspace === null) { - return { - workspaceUsers: [], - userIsOwnerOrAdmin: false, - } - } - - const workspaceUsers = await this.workspaceUserRepository.findByWorkspaceUuid(dto.workspaceUuid) - let userIsOwnerOrAdmin = false - let userIsInWorkspace = false - for (const workspaceUser of workspaceUsers) { - if (workspaceUser.userUuid === dto.userUuid) { - userIsInWorkspace = true - if ([WorkspaceAccessLevel.Admin, WorkspaceAccessLevel.Owner].includes(workspaceUser.accessLevel)) { - userIsOwnerOrAdmin = true - } - } - } - - if (!userIsInWorkspace) { - return { - workspaceUsers: [], - userIsOwnerOrAdmin: false, - } - } - - return { - workspaceUsers, - userIsOwnerOrAdmin, - } - } -} diff --git a/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsersDTO.ts b/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsersDTO.ts deleted file mode 100644 index 6e9430ded..000000000 --- a/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsersDTO.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type ListWorkspaceUsersDTO = { - workspaceUuid: string - userUuid: string -} diff --git a/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsersResponse.ts b/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsersResponse.ts deleted file mode 100644 index 2e51113f4..000000000 --- a/packages/workspace/src/Domain/UseCase/ListWorkspaceUsers/ListWorkspaceUsersResponse.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { WorkspaceUser } from '../../Workspace/WorkspaceUser' - -export type ListWorkspaceUsersResponse = { - workspaceUsers: WorkspaceUser[] - userIsOwnerOrAdmin: boolean -} diff --git a/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspaces.spec.ts b/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspaces.spec.ts deleted file mode 100644 index fdcb69980..000000000 --- a/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspaces.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import 'reflect-metadata' -import { WorkspaceAccessLevel } from '@standardnotes/common' -import { Logger } from 'winston' - -import { Workspace } from '../../Workspace/Workspace' -import { WorkspaceRepositoryInterface } from '../../Workspace/WorkspaceRepositoryInterface' -import { WorkspaceUser } from '../../Workspace/WorkspaceUser' -import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' - -import { ListWorkspaces } from './ListWorkspaces' - -describe('ListWorkspaces', () => { - let workspaceRepository: WorkspaceRepositoryInterface - let workspaceUserRepository: WorkspaceUserRepositoryInterface - let ownedWorkspace: Workspace - let joinedWorkspace: Workspace - let workspaceUser1: WorkspaceUser - let workspaceUser2: WorkspaceUser - let logger: Logger - - const createUseCase = () => new ListWorkspaces(workspaceRepository, workspaceUserRepository, logger) - - beforeEach(() => { - logger = {} as jest.Mocked - logger.debug = jest.fn() - - ownedWorkspace = { uuid: 'o-1-2-3' } as jest.Mocked - joinedWorkspace = { uuid: 'j-1-2-3' } as jest.Mocked - - workspaceUser1 = { accessLevel: WorkspaceAccessLevel.Owner } as jest.Mocked - workspaceUser2 = { accessLevel: WorkspaceAccessLevel.WriteAndRead } as jest.Mocked - - workspaceRepository = {} as jest.Mocked - workspaceRepository.findByUuids = jest - .fn() - .mockReturnValueOnce([ownedWorkspace]) - .mockReturnValueOnce([joinedWorkspace]) - - workspaceUserRepository = {} as jest.Mocked - workspaceUserRepository.findByUserUuid = jest.fn().mockReturnValue([workspaceUser1, workspaceUser2]) - }) - - it('should list owned and joined workspaces for a user', async () => { - const result = await createUseCase().execute({ - userUuid: 'u-1-2-3', - }) - - expect(result).toEqual({ - ownedWorkspaces: [ownedWorkspace], - joinedWorkspaces: [joinedWorkspace], - }) - }) - - it('should list empty owned and joined workspaces for a user that does not have any', async () => { - workspaceUserRepository.findByUserUuid = jest.fn().mockReturnValue([]) - - const result = await createUseCase().execute({ - userUuid: 'u-1-2-3', - }) - - expect(result).toEqual({ - ownedWorkspaces: [], - joinedWorkspaces: [], - }) - }) -}) diff --git a/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspaces.ts b/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspaces.ts deleted file mode 100644 index 824839a0a..000000000 --- a/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspaces.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { WorkspaceAccessLevel } from '@standardnotes/common' -import { inject, injectable } from 'inversify' -import { Logger } from 'winston' - -import TYPES from '../../../Bootstrap/Types' -import { Workspace } from '../../Workspace/Workspace' -import { WorkspaceRepositoryInterface } from '../../Workspace/WorkspaceRepositoryInterface' -import { WorkspaceUserRepositoryInterface } from '../../Workspace/WorkspaceUserRepositoryInterface' -import { UseCaseInterface } from '../UseCaseInterface' - -import { ListWorkspacesDTO } from './ListWorkspacesDTO' -import { ListWorkspacesResponse } from './ListWorkspacesResponse' - -@injectable() -export class ListWorkspaces implements UseCaseInterface { - constructor( - @inject(TYPES.WorkspaceRepository) private workspaceRepository: WorkspaceRepositoryInterface, - @inject(TYPES.WorkspaceUserRepository) private workspaceUserRepository: WorkspaceUserRepositoryInterface, - @inject(TYPES.Logger) private logger: Logger, - ) {} - - async execute(dto: ListWorkspacesDTO): Promise { - this.logger.debug(`Listing workspaces for user ${dto.userUuid}`) - - const workspaceAssociations = await this.workspaceUserRepository.findByUserUuid(dto.userUuid) - - const ownedWorkspacesUuids = [] - const joinedWorkspacesUuids = [] - for (const workspaceAssociation of workspaceAssociations) { - if ([WorkspaceAccessLevel.Admin, WorkspaceAccessLevel.Owner].includes(workspaceAssociation.accessLevel)) { - ownedWorkspacesUuids.push(workspaceAssociation.workspaceUuid) - } else { - joinedWorkspacesUuids.push(workspaceAssociation.workspaceUuid) - } - } - - this.logger.debug(`Owned workspaces uuids: ${JSON.stringify(ownedWorkspacesUuids)}`) - this.logger.debug(`Joined workspaces uuids: ${JSON.stringify(joinedWorkspacesUuids)}`) - - let ownedWorkspaces: Array = [] - if (ownedWorkspacesUuids.length > 0) { - ownedWorkspaces = await this.workspaceRepository.findByUuids(ownedWorkspacesUuids) - } - let joinedWorkspaces: Array = [] - if (joinedWorkspacesUuids.length > 0) { - joinedWorkspaces = await this.workspaceRepository.findByUuids(joinedWorkspacesUuids) - } - - return { - ownedWorkspaces, - joinedWorkspaces, - } - } -} diff --git a/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspacesDTO.ts b/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspacesDTO.ts deleted file mode 100644 index 71a4c020d..000000000 --- a/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspacesDTO.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type ListWorkspacesDTO = { - userUuid: string -} diff --git a/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspacesResponse.ts b/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspacesResponse.ts deleted file mode 100644 index 8c860d8d0..000000000 --- a/packages/workspace/src/Domain/UseCase/ListWorkspaces/ListWorkspacesResponse.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Workspace } from '../../Workspace/Workspace' - -export type ListWorkspacesResponse = { - ownedWorkspaces: Array - joinedWorkspaces: Array -} diff --git a/packages/workspace/src/Domain/UseCase/UseCaseInterface.ts b/packages/workspace/src/Domain/UseCase/UseCaseInterface.ts deleted file mode 100644 index 7c8405a9a..000000000 --- a/packages/workspace/src/Domain/UseCase/UseCaseInterface.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface UseCaseInterface { - execute(...args: any[]): Promise> -} diff --git a/packages/workspace/src/Domain/Workspace/Workspace.ts b/packages/workspace/src/Domain/Workspace/Workspace.ts deleted file mode 100644 index c15539503..000000000 --- a/packages/workspace/src/Domain/Workspace/Workspace.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { WorkspaceType } from '@standardnotes/common' -import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm' -import { WorkspaceInvite } from '../Invite/WorkspaceInvite' -import { WorkspaceUser } from './WorkspaceUser' - -@Entity({ name: 'workspaces' }) -export class Workspace { - @PrimaryGeneratedColumn('uuid') - declare uuid: string - - @Column({ - length: 64, - }) - declare type: WorkspaceType - - @Column({ - length: 255, - nullable: true, - type: 'varchar', - }) - declare name: string | null - - @Column({ - name: 'key_rotation_index', - default: 0, - }) - declare keyRotationIndex: number - - @Column({ - name: 'created_at', - type: 'bigint', - }) - declare createdAt: number - - @Column({ - name: 'updated_at', - type: 'bigint', - }) - declare updatedAt: number - - @OneToMany( - /* istanbul ignore next */ - () => WorkspaceInvite, - /* istanbul ignore next */ - (workspaceInvite) => workspaceInvite.workspace, - ) - declare invites: Promise - - @OneToMany( - /* istanbul ignore next */ - () => WorkspaceUser, - /* istanbul ignore next */ - (workspaceUser) => workspaceUser.workspace, - ) - declare users: Promise -} diff --git a/packages/workspace/src/Domain/Workspace/WorkspaceRepositoryInterface.ts b/packages/workspace/src/Domain/Workspace/WorkspaceRepositoryInterface.ts deleted file mode 100644 index 0f8d77de0..000000000 --- a/packages/workspace/src/Domain/Workspace/WorkspaceRepositoryInterface.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Workspace } from './Workspace' - -export interface WorkspaceRepositoryInterface { - save(workspace: Workspace): Promise - findByUuids(uuids: string[]): Promise - findOneByUuid(uuid: string): Promise -} diff --git a/packages/workspace/src/Domain/Workspace/WorkspaceUser.ts b/packages/workspace/src/Domain/Workspace/WorkspaceUser.ts deleted file mode 100644 index 4a826d5e9..000000000 --- a/packages/workspace/src/Domain/Workspace/WorkspaceUser.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { WorkspaceAccessLevel, WorkspaceUserStatus } from '@standardnotes/common' -import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm' -import { Workspace } from './Workspace' - -@Entity({ name: 'workspace_users' }) -@Index('index_workspace_users_on_workspace_and_user', ['userUuid', 'workspaceUuid'], { unique: true }) -export class WorkspaceUser { - @PrimaryGeneratedColumn('uuid') - declare uuid: string - - @Column({ - name: 'access_level', - length: 64, - }) - declare accessLevel: WorkspaceAccessLevel - - @Column({ - name: 'user_uuid', - length: 36, - }) - declare userUuid: string - - @Column({ - name: 'user_display_name', - type: 'varchar', - length: 255, - nullable: true, - }) - declare userDisplayName: string | null - - @Column({ - name: 'workspace_uuid', - length: 36, - }) - declare workspaceUuid: string - - @Column({ - name: 'encrypted_workspace_key', - length: 255, - type: 'varchar', - nullable: true, - }) - declare encryptedWorkspaceKey: string | null - - @Column({ - name: 'public_key', - length: 255, - type: 'varchar', - nullable: true, - }) - declare publicKey: string | null - - @Column({ - name: 'encrypted_private_key', - length: 255, - type: 'varchar', - nullable: true, - }) - declare encryptedPrivateKey: string | null - - @Column({ - name: 'status', - length: 64, - }) - declare status: WorkspaceUserStatus - - @Column({ - name: 'key_rotation_index', - default: 0, - }) - declare keyRotationIndex: number - - @Column({ - name: 'created_at', - type: 'bigint', - }) - declare createdAt: number - - @Column({ - name: 'updated_at', - type: 'bigint', - }) - declare updatedAt: number - - @ManyToOne( - /* istanbul ignore next */ - () => Workspace, - /* istanbul ignore next */ - (workspace) => workspace.users, - /* istanbul ignore next */ - { onDelete: 'CASCADE' }, - ) - @JoinColumn( - /* istanbul ignore next */ - { name: 'workspace_uuid' }, - ) - declare workspace: Promise -} diff --git a/packages/workspace/src/Domain/Workspace/WorkspaceUserRepositoryInterface.ts b/packages/workspace/src/Domain/Workspace/WorkspaceUserRepositoryInterface.ts deleted file mode 100644 index f296386a0..000000000 --- a/packages/workspace/src/Domain/Workspace/WorkspaceUserRepositoryInterface.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { WorkspaceUser } from './WorkspaceUser' - -export interface WorkspaceUserRepositoryInterface { - save(workspace: WorkspaceUser): Promise - findByUserUuid(userUuid: string): Promise - findByWorkspaceUuid(workspaceUuid: string): Promise - findOneByUserUuidAndWorkspaceUuid(dto: { workspaceUuid: string; userUuid: string }): Promise -} diff --git a/packages/workspace/src/Infra/InversifyExpressUtils/InversifyExpressHealthCheckController.ts b/packages/workspace/src/Infra/InversifyExpressUtils/InversifyExpressHealthCheckController.ts deleted file mode 100644 index 535288409..000000000 --- a/packages/workspace/src/Infra/InversifyExpressUtils/InversifyExpressHealthCheckController.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { controller, httpGet } from 'inversify-express-utils' - -@controller('/healthcheck') -export class InversifyExpressHealthCheckController { - @httpGet('/') - public async get(): Promise { - return 'OK' - } -} diff --git a/packages/workspace/src/Infra/InversifyExpressUtils/InversifyExpressInvitesController.ts b/packages/workspace/src/Infra/InversifyExpressUtils/InversifyExpressInvitesController.ts deleted file mode 100644 index 90f327817..000000000 --- a/packages/workspace/src/Infra/InversifyExpressUtils/InversifyExpressInvitesController.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Request, Response } from 'express' -import { inject } from 'inversify' -import { BaseHttpController, controller, httpPost, results } from 'inversify-express-utils' -import TYPES from '../../Bootstrap/Types' -import { WorkspacesController } from '../../Controller/WorkspacesController' - -@controller('/invites', TYPES.ApiGatewayAuthMiddleware) -export class InversifyExpressInvitesController extends BaseHttpController { - constructor(@inject(TYPES.WorkspacesController) private workspacesController: WorkspacesController) { - super() - } - - @httpPost('/:inviteUuid/accept') - async acceptInvite(request: Request, response: Response): Promise { - const result = await this.workspacesController.acceptInvite({ - ...request.body, - inviteUuid: request.params.inviteUuid, - userUuid: response.locals.user.uuid, - }) - - return this.json(result.data, result.status) - } -} diff --git a/packages/workspace/src/Infra/InversifyExpressUtils/InversifyExpressWorkspacesController.ts b/packages/workspace/src/Infra/InversifyExpressUtils/InversifyExpressWorkspacesController.ts deleted file mode 100644 index e5428c08b..000000000 --- a/packages/workspace/src/Infra/InversifyExpressUtils/InversifyExpressWorkspacesController.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { Request, Response } from 'express' -import { inject } from 'inversify' -import { BaseHttpController, controller, httpGet, httpPost, results } from 'inversify-express-utils' -import TYPES from '../../Bootstrap/Types' -import { WorkspacesController } from '../../Controller/WorkspacesController' - -@controller('/workspaces', TYPES.ApiGatewayAuthMiddleware) -export class InversifyExpressWorkspacesController extends BaseHttpController { - constructor(@inject(TYPES.WorkspacesController) private workspacesController: WorkspacesController) { - super() - } - - @httpPost('/') - async create(request: Request, response: Response): Promise { - const result = await this.workspacesController.createWorkspace({ - ...request.body, - ownerUuid: response.locals.user.uuid, - }) - - return this.json(result.data, result.status) - } - - @httpGet('/') - async listWorkspaces(_request: Request, response: Response): Promise { - const result = await this.workspacesController.listWorkspaces({ - userUuid: response.locals.user.uuid, - }) - - return this.json(result.data, result.status) - } - - @httpGet('/:workspaceUuid/users') - async listWorkspaceUsers(request: Request, response: Response): Promise { - const result = await this.workspacesController.listWorkspaceUsers({ - userUuid: response.locals.user.uuid, - workspaceUuid: request.params.workspaceUuid, - }) - - return this.json(result.data, result.status) - } - - @httpPost('/:workspaceUuid/users/:userUuid/keyshare') - async initiateKeyshare(request: Request, response: Response): Promise { - const result = await this.workspacesController.initiateKeyshare({ - userUuid: request.params.userUuid, - workspaceUuid: request.params.workspaceUuid, - encryptedWorkspaceKey: request.body.encryptedWorkspaceKey, - performingUserUuid: response.locals.user.uuid, - }) - - return this.json(result.data, result.status) - } - - @httpPost('/:workspaceUuid/invites') - async inviteToWorkspace(request: Request, response: Response): Promise { - if (request.params.workspaceUuid !== request.body.workspaceUuid) { - return this.json( - { - error: { - message: 'Invalid workspace uuid.', - }, - }, - 400, - ) - } - - const result = await this.workspacesController.inviteToWorkspace({ - ...request.body, - inviterUuid: response.locals.user.uuid, - }) - - return this.json(result.data, result.status) - } -} diff --git a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceInviteRepository.spec.ts b/packages/workspace/src/Infra/MySQL/MySQLWorkspaceInviteRepository.spec.ts deleted file mode 100644 index e50ef9b84..000000000 --- a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceInviteRepository.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import 'reflect-metadata' - -import { Repository, SelectQueryBuilder } from 'typeorm' - -import { WorkspaceInvite } from '../../Domain/Invite/WorkspaceInvite' -import { MySQLWorkspaceInviteRepository } from './MySQLWorkspaceInviteRepository' - -describe('MySQLWorkspaceInviteRepository', () => { - let ormRepository: Repository - let invite: WorkspaceInvite - let queryBuilder: SelectQueryBuilder - - const createRepository = () => new MySQLWorkspaceInviteRepository(ormRepository) - - beforeEach(() => { - invite = {} as jest.Mocked - - queryBuilder = {} as jest.Mocked> - - ormRepository = {} as jest.Mocked> - ormRepository.save = jest.fn() - ormRepository.createQueryBuilder = jest.fn().mockImplementation(() => queryBuilder) - }) - - it('should save', async () => { - await createRepository().save(invite) - - expect(ormRepository.save).toHaveBeenCalledWith(invite) - }) - - it('should find one by uuid', async () => { - queryBuilder.where = jest.fn().mockReturnThis() - queryBuilder.getOne = jest.fn().mockReturnValue(null) - - await createRepository().findOneByUuid('i-1-2-3') - - expect(queryBuilder.where).toHaveBeenCalledWith('uuid = :uuid', { uuid: 'i-1-2-3' }) - }) -}) diff --git a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceInviteRepository.ts b/packages/workspace/src/Infra/MySQL/MySQLWorkspaceInviteRepository.ts deleted file mode 100644 index d2dde8839..000000000 --- a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceInviteRepository.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { inject, injectable } from 'inversify' -import { Repository } from 'typeorm' - -import TYPES from '../../Bootstrap/Types' -import { WorkspaceInvite } from '../../Domain/Invite/WorkspaceInvite' -import { WorkspaceInviteRepositoryInterface } from '../../Domain/Invite/WorkspaceInviteRepositoryInterface' - -@injectable() -export class MySQLWorkspaceInviteRepository implements WorkspaceInviteRepositoryInterface { - constructor( - @inject(TYPES.ORMWorkspaceInviteRepository) - private ormRepository: Repository, - ) {} - - async findOneByUuid(uuid: string): Promise { - return this.ormRepository.createQueryBuilder().where('uuid = :uuid', { uuid }).getOne() - } - - async save(workspaceInvite: WorkspaceInvite): Promise { - return this.ormRepository.save(workspaceInvite) - } -} diff --git a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceRepository.spec.ts b/packages/workspace/src/Infra/MySQL/MySQLWorkspaceRepository.spec.ts deleted file mode 100644 index f373c643b..000000000 --- a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceRepository.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import 'reflect-metadata' - -import { Repository, SelectQueryBuilder } from 'typeorm' - -import { Workspace } from '../../Domain/Workspace/Workspace' - -import { MySQLWorkspaceRepository } from './MySQLWorkspaceRepository' - -describe('MySQLWorkspaceRepository', () => { - let ormRepository: Repository - let workspace: Workspace - let queryBuilder: SelectQueryBuilder - - const createRepository = () => new MySQLWorkspaceRepository(ormRepository) - - beforeEach(() => { - workspace = {} as jest.Mocked - - queryBuilder = {} as jest.Mocked> - - ormRepository = {} as jest.Mocked> - ormRepository.save = jest.fn() - ormRepository.createQueryBuilder = jest.fn().mockImplementation(() => queryBuilder) - }) - - it('should save', async () => { - await createRepository().save(workspace) - - expect(ormRepository.save).toHaveBeenCalledWith(workspace) - }) - - it('should find many by uuids', async () => { - queryBuilder.where = jest.fn().mockReturnThis() - queryBuilder.getMany = jest.fn().mockReturnValue([]) - - await createRepository().findByUuids(['i-1-2-3']) - - expect(queryBuilder.where).toHaveBeenCalledWith('uuid IN (:...uuids)', { uuids: ['i-1-2-3'] }) - }) - - it('should find one by uuid', async () => { - queryBuilder.where = jest.fn().mockReturnThis() - queryBuilder.getOne = jest.fn().mockReturnValue(null) - - await createRepository().findOneByUuid('i-1-2-3') - - expect(queryBuilder.where).toHaveBeenCalledWith('uuid = :uuid', { uuid: 'i-1-2-3' }) - }) -}) diff --git a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceRepository.ts b/packages/workspace/src/Infra/MySQL/MySQLWorkspaceRepository.ts deleted file mode 100644 index 6cbceaf07..000000000 --- a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceRepository.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { inject, injectable } from 'inversify' -import { Repository } from 'typeorm' -import TYPES from '../../Bootstrap/Types' -import { Workspace } from '../../Domain/Workspace/Workspace' -import { WorkspaceRepositoryInterface } from '../../Domain/Workspace/WorkspaceRepositoryInterface' - -@injectable() -export class MySQLWorkspaceRepository implements WorkspaceRepositoryInterface { - constructor( - @inject(TYPES.ORMWorkspaceRepository) - private ormRepository: Repository, - ) {} - - async findOneByUuid(uuid: string): Promise { - return this.ormRepository.createQueryBuilder().where('uuid = :uuid', { uuid }).getOne() - } - - async findByUuids(uuids: string[]): Promise { - return this.ormRepository.createQueryBuilder().where('uuid IN (:...uuids)', { uuids }).getMany() - } - - async save(workspace: Workspace): Promise { - return this.ormRepository.save(workspace) - } -} diff --git a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceUserRepository.spec.ts b/packages/workspace/src/Infra/MySQL/MySQLWorkspaceUserRepository.spec.ts deleted file mode 100644 index 57305a4b4..000000000 --- a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceUserRepository.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import 'reflect-metadata' - -import { Repository, SelectQueryBuilder } from 'typeorm' - -import { WorkspaceUser } from '../../Domain/Workspace/WorkspaceUser' -import { MySQLWorkspaceUserRepository } from './MySQLWorkspaceUserRepository' - -describe('MySQLWorkspaceUserRepository', () => { - let ormRepository: Repository - let workspace: WorkspaceUser - let queryBuilder: SelectQueryBuilder - - const createRepository = () => new MySQLWorkspaceUserRepository(ormRepository) - - beforeEach(() => { - workspace = {} as jest.Mocked - - queryBuilder = {} as jest.Mocked> - - ormRepository = {} as jest.Mocked> - ormRepository.save = jest.fn() - ormRepository.createQueryBuilder = jest.fn().mockImplementation(() => queryBuilder) - }) - - it('should save', async () => { - await createRepository().save(workspace) - - expect(ormRepository.save).toHaveBeenCalledWith(workspace) - }) - - it('should find many by user uuid', async () => { - queryBuilder.where = jest.fn().mockReturnThis() - queryBuilder.getMany = jest.fn().mockReturnValue([]) - - await createRepository().findByUserUuid('i-1-2-3') - - expect(queryBuilder.where).toHaveBeenCalledWith('user_uuid = :userUuid', { userUuid: 'i-1-2-3' }) - }) - - it('should find many by workspace uuid', async () => { - queryBuilder.where = jest.fn().mockReturnThis() - queryBuilder.getMany = jest.fn().mockReturnValue([]) - - await createRepository().findByWorkspaceUuid('i-1-2-3') - - expect(queryBuilder.where).toHaveBeenCalledWith('workspace_uuid = :workspaceUuid', { workspaceUuid: 'i-1-2-3' }) - }) - - it('should find one by workspace uuid and user uuid', async () => { - queryBuilder.where = jest.fn().mockReturnThis() - queryBuilder.getOne = jest.fn().mockReturnValue(null) - - await createRepository().findOneByUserUuidAndWorkspaceUuid({ workspaceUuid: 'w-1-2-3', userUuid: 'u-1-2-3' }) - - expect(queryBuilder.where).toHaveBeenCalledWith('workspace_uuid = :workspaceUuid AND user_uuid = :userUuid', { - workspaceUuid: 'w-1-2-3', - userUuid: 'u-1-2-3', - }) - }) -}) diff --git a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceUserRepository.ts b/packages/workspace/src/Infra/MySQL/MySQLWorkspaceUserRepository.ts deleted file mode 100644 index 431f20e6f..000000000 --- a/packages/workspace/src/Infra/MySQL/MySQLWorkspaceUserRepository.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { inject, injectable } from 'inversify' -import { Repository } from 'typeorm' - -import TYPES from '../../Bootstrap/Types' -import { WorkspaceUser } from '../../Domain/Workspace/WorkspaceUser' -import { WorkspaceUserRepositoryInterface } from '../../Domain/Workspace/WorkspaceUserRepositoryInterface' - -@injectable() -export class MySQLWorkspaceUserRepository implements WorkspaceUserRepositoryInterface { - constructor( - @inject(TYPES.ORMWorkspaceUserRepository) - private ormRepository: Repository, - ) {} - - async findOneByUserUuidAndWorkspaceUuid(dto: { - workspaceUuid: string - userUuid: string - }): Promise { - return this.ormRepository - .createQueryBuilder() - .where('workspace_uuid = :workspaceUuid AND user_uuid = :userUuid', { - workspaceUuid: dto.workspaceUuid, - userUuid: dto.userUuid, - }) - .getOne() - } - - async findByWorkspaceUuid(workspaceUuid: string): Promise { - return this.ormRepository.createQueryBuilder().where('workspace_uuid = :workspaceUuid', { workspaceUuid }).getMany() - } - - async findByUserUuid(userUuid: string): Promise { - return this.ormRepository.createQueryBuilder().where('user_uuid = :userUuid', { userUuid }).getMany() - } - - async save(workspaceUser: WorkspaceUser): Promise { - return this.ormRepository.save(workspaceUser) - } -} diff --git a/packages/workspace/test-setup.ts b/packages/workspace/test-setup.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/workspace/tsconfig.json b/packages/workspace/tsconfig.json deleted file mode 100644 index d87b89eeb..000000000 --- a/packages/workspace/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "composite": true, - "outDir": "./dist", - }, - "include": [ - "src/**/*", - "bin/**/*", - "migrations/**/*", - ], - "references": [] -} diff --git a/packages/workspace/wait-for.sh b/packages/workspace/wait-for.sh deleted file mode 100755 index f3d72b834..000000000 --- a/packages/workspace/wait-for.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -set -e - -host="$1" -shift -port="$1" -shift -cmd="$@" - -while ! nc -vz $host $port; do - >&2 echo "$host:$port is unavailable yet - waiting for it to start" - sleep 10 -done - ->&2 echo "$host:$port is up - executing command" -exec $cmd diff --git a/tsconfig.json b/tsconfig.json index 18fe5bfd2..c14b6f00b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -76,9 +76,6 @@ }, { "path": "./packages/websockets" - }, - { - "path": "./packages/workspace" } ] }