浏览代码

feat: http controllers for shared vaults. (#641)

Co-authored-by: Mo <mo@standardnotes.com>
Karol Sójko 1 年之前
父节点
当前提交
7a3946a9e2

+ 7 - 0
packages/syncing-server/src/Bootstrap/Types.ts

@@ -38,6 +38,10 @@ const TYPES = {
   Sync_SyncItems: Symbol.for('Sync_SyncItems'),
   Sync_CheckIntegrity: Symbol.for('Sync_CheckIntegrity'),
   Sync_GetItem: Symbol.for('Sync_GetItem'),
+  Sync_GetSharedVaults: Symbol.for('Sync_GetSharedVaults'),
+  Sync_CreateSharedVault: Symbol.for('Sync_CreateSharedVault'),
+  Sync_DeleteSharedVault: Symbol.for('Sync_DeleteSharedVault'),
+  Sync_CreateSharedVaultFileValetToken: Symbol.for('Sync_CreateSharedVaultFileValetToken'),
   // Handlers
   Sync_AccountDeletionRequestedEventHandler: Symbol.for('Sync_AccountDeletionRequestedEventHandler'),
   Sync_DuplicateItemSyncedEventHandler: Symbol.for('Sync_DuplicateItemSyncedEventHandler'),
@@ -68,6 +72,9 @@ const TYPES = {
   Sync_ItemTransferCalculator: Symbol.for('Sync_ItemTransferCalculator'),
   Sync_ControllerContainer: Symbol.for('Sync_ControllerContainer'),
   Sync_HomeServerItemsController: Symbol.for('Sync_HomeServerItemsController'),
+  // Mapping
+  Sync_SharedVaultHttpMapper: Symbol.for('Sync_SharedVaultHttpMapper'),
+  Sync_SharedVaultUserHttpMapper: Symbol.for('Sync_SharedVaultUserHttpMapper'),
 }
 
 export default TYPES

+ 128 - 0
packages/syncing-server/src/Infra/InversifyExpressUtils/HomeServer/HomeServerSharedVaultsController.ts

@@ -0,0 +1,128 @@
+import { Request, Response } from 'express'
+import { BaseHttpController, results } from 'inversify-express-utils'
+import { HttpStatusCode } from '@standardnotes/responses'
+import { ControllerContainerInterface, MapperInterface } from '@standardnotes/domain-core'
+
+import { GetSharedVaults } from '../../../Domain/UseCase/GetSharedVaults/GetSharedVaults'
+import { SharedVault } from '../../../Domain/SharedVault/SharedVault'
+import { SharedVaultHttpRepresentation } from '../../../Mapping/Http/SharedVaultHttpRepresentation'
+import { CreateSharedVault } from '../../../Domain/UseCase/CreateSharedVault/CreateSharedVault'
+import { SharedVaultUser } from '../../../Domain/SharedVault/User/SharedVaultUser'
+import { SharedVaultUserHttpRepresentation } from '../../../Mapping/Http/SharedVaultUserHttpRepresentation copy'
+import { DeleteSharedVault } from '../../../Domain/UseCase/DeleteSharedVault/DeleteSharedVault'
+import { CreateSharedVaultFileValetToken } from '../../../Domain/UseCase/CreateSharedVaultFileValetToken/CreateSharedVaultFileValetToken'
+
+export class HomeServerSharedVaultsController extends BaseHttpController {
+  constructor(
+    protected getSharedVaultsUseCase: GetSharedVaults,
+    protected createSharedVaultUseCase: CreateSharedVault,
+    protected deleteSharedVaultUseCase: DeleteSharedVault,
+    protected createSharedVaultFileValetTokenUseCase: CreateSharedVaultFileValetToken,
+    protected sharedVaultHttpMapper: MapperInterface<SharedVault, SharedVaultHttpRepresentation>,
+    protected sharedVaultUserHttpMapper: MapperInterface<SharedVaultUser, SharedVaultUserHttpRepresentation>,
+    private controllerContainer?: ControllerContainerInterface,
+  ) {
+    super()
+
+    if (this.controllerContainer !== undefined) {
+      this.controllerContainer.register('sync.shared-vaults.get-vaults', this.getSharedVaults.bind(this))
+      this.controllerContainer.register('sync.shared-vaults.create-vault', this.createSharedVault.bind(this))
+      this.controllerContainer.register('sync.shared-vaults.delete-vault', this.deleteSharedVault.bind(this))
+      this.controllerContainer.register(
+        'sync.shared-vaults.create-file-valet-token',
+        this.createValetTokenForSharedVaultFile.bind(this),
+      )
+    }
+  }
+
+  async getSharedVaults(_request: Request, response: Response): Promise<results.JsonResult> {
+    const result = await this.getSharedVaultsUseCase.execute({
+      userUuid: response.locals.user.uuid,
+    })
+
+    if (result.isFailed()) {
+      return this.json(
+        {
+          error: {
+            message: result.getError(),
+          },
+        },
+        HttpStatusCode.BadRequest,
+      )
+    }
+
+    return this.json({
+      sharedVaults: result.getValue().map((sharedVault) => this.sharedVaultHttpMapper.toProjection(sharedVault)),
+    })
+  }
+
+  async createSharedVault(_request: Request, response: Response): Promise<results.JsonResult> {
+    const result = await this.createSharedVaultUseCase.execute({
+      userUuid: response.locals.user.uuid,
+    })
+
+    if (result.isFailed()) {
+      return this.json(
+        {
+          error: {
+            message: result.getError(),
+          },
+        },
+        HttpStatusCode.BadRequest,
+      )
+    }
+
+    return this.json({
+      sharedVault: this.sharedVaultHttpMapper.toProjection(result.getValue().sharedVault),
+      sharedVaultUser: this.sharedVaultUserHttpMapper.toProjection(result.getValue().sharedVaultUser),
+    })
+  }
+
+  async deleteSharedVault(request: Request, response: Response): Promise<results.JsonResult> {
+    const result = await this.deleteSharedVaultUseCase.execute({
+      sharedVaultUuid: request.params.sharedVaultUuid,
+      originatorUuid: response.locals.user.uuid,
+    })
+
+    if (result.isFailed()) {
+      return this.json(
+        {
+          error: {
+            message: result.getError(),
+          },
+        },
+        HttpStatusCode.BadRequest,
+      )
+    }
+
+    return this.json({ success: true })
+  }
+
+  async createValetTokenForSharedVaultFile(request: Request, response: Response): Promise<results.JsonResult> {
+    const result = await this.createSharedVaultFileValetTokenUseCase.execute({
+      userUuid: response.locals.user.uuid,
+      sharedVaultUuid: request.params.sharedVaultUuid,
+      fileUuid: request.body.file_uuid,
+      remoteIdentifier: request.body.remote_identifier,
+      operation: request.body.operation,
+      unencryptedFileSize: request.body.unencrypted_file_size,
+      moveOperationType: request.body.move_operation_type,
+      sharedVaultToSharedVaultMoveTargetUuid: request.body.shared_vault_to_shared_vault_move_target_uuid,
+    })
+
+    if (result.isFailed()) {
+      return this.json(
+        {
+          error: {
+            message: result.getError(),
+          },
+        },
+        HttpStatusCode.BadRequest,
+      )
+    }
+
+    return this.json({
+      valetToken: result.getValue(),
+    })
+  }
+}

+ 59 - 0
packages/syncing-server/src/Infra/InversifyExpressUtils/InversifyExpressSharedVaultsController.ts

@@ -0,0 +1,59 @@
+import { controller, httpDelete, httpGet, httpPost, results } from 'inversify-express-utils'
+import { inject } from 'inversify'
+import { MapperInterface } from '@standardnotes/domain-core'
+import { Request, Response } from 'express'
+
+import { HomeServerSharedVaultsController } from './HomeServer/HomeServerSharedVaultsController'
+import TYPES from '../../Bootstrap/Types'
+import { SharedVault } from '../../Domain/SharedVault/SharedVault'
+import { SharedVaultUser } from '../../Domain/SharedVault/User/SharedVaultUser'
+import { CreateSharedVault } from '../../Domain/UseCase/CreateSharedVault/CreateSharedVault'
+import { CreateSharedVaultFileValetToken } from '../../Domain/UseCase/CreateSharedVaultFileValetToken/CreateSharedVaultFileValetToken'
+import { DeleteSharedVault } from '../../Domain/UseCase/DeleteSharedVault/DeleteSharedVault'
+import { GetSharedVaults } from '../../Domain/UseCase/GetSharedVaults/GetSharedVaults'
+import { SharedVaultHttpRepresentation } from '../../Mapping/Http/SharedVaultHttpRepresentation'
+import { SharedVaultUserHttpRepresentation } from '../../Mapping/Http/SharedVaultUserHttpRepresentation copy'
+
+@controller('/shared-vaults', TYPES.Sync_AuthMiddleware)
+export class InversifyExpressSharedVaultsController extends HomeServerSharedVaultsController {
+  constructor(
+    @inject(TYPES.Sync_GetSharedVaults) override getSharedVaultsUseCase: GetSharedVaults,
+    @inject(TYPES.Sync_CreateSharedVault) override createSharedVaultUseCase: CreateSharedVault,
+    @inject(TYPES.Sync_DeleteSharedVault) override deleteSharedVaultUseCase: DeleteSharedVault,
+    @inject(TYPES.Sync_CreateSharedVaultFileValetToken)
+    override createSharedVaultFileValetTokenUseCase: CreateSharedVaultFileValetToken,
+    @inject(TYPES.Sync_SharedVaultHttpMapper)
+    override sharedVaultHttpMapper: MapperInterface<SharedVault, SharedVaultHttpRepresentation>,
+    @inject(TYPES.Sync_SharedVaultUserHttpMapper)
+    override sharedVaultUserHttpMapper: MapperInterface<SharedVaultUser, SharedVaultUserHttpRepresentation>,
+  ) {
+    super(
+      getSharedVaultsUseCase,
+      createSharedVaultUseCase,
+      deleteSharedVaultUseCase,
+      createSharedVaultFileValetTokenUseCase,
+      sharedVaultHttpMapper,
+      sharedVaultUserHttpMapper,
+    )
+  }
+
+  @httpGet('/')
+  override async getSharedVaults(request: Request, response: Response): Promise<results.JsonResult> {
+    return super.getSharedVaults(request, response)
+  }
+
+  @httpPost('/')
+  override async createSharedVault(request: Request, response: Response): Promise<results.JsonResult> {
+    return super.createSharedVault(request, response)
+  }
+
+  @httpDelete('/:sharedVaultUuid')
+  override async deleteSharedVault(request: Request, response: Response): Promise<results.JsonResult> {
+    return super.deleteSharedVault(request, response)
+  }
+
+  @httpPost('/:sharedVaultUuid/valet-tokens')
+  override async createValetTokenForSharedVaultFile(request: Request, response: Response): Promise<results.JsonResult> {
+    return super.createValetTokenForSharedVaultFile(request, response)
+  }
+}

+ 21 - 0
packages/syncing-server/src/Mapping/Http/SharedVaultHttpMapper.ts

@@ -0,0 +1,21 @@
+import { MapperInterface } from '@standardnotes/domain-core'
+
+import { SharedVault } from '../../Domain/SharedVault/SharedVault'
+import { SharedVaultHttpRepresentation } from './SharedVaultHttpRepresentation'
+
+export class SharedVaultHttpMapper implements MapperInterface<SharedVault, SharedVaultHttpRepresentation> {
+  toDomain(_projection: SharedVaultHttpRepresentation): SharedVault {
+    throw new Error('Mapping from http representation to domain is not implemented.')
+  }
+
+  toProjection(domain: SharedVault): SharedVaultHttpRepresentation {
+    return {
+      uuid: domain.id.toString(),
+      user_uuid: domain.props.userUuid.value,
+      file_upload_bytes_limit: domain.props.fileUploadBytesLimit,
+      file_upload_bytes_used: domain.props.fileUploadBytesUsed,
+      created_at_timestamp: domain.props.timestamps.createdAt,
+      updated_at_timestamp: domain.props.timestamps.updatedAt,
+    }
+  }
+}

+ 8 - 0
packages/syncing-server/src/Mapping/Http/SharedVaultHttpRepresentation.ts

@@ -0,0 +1,8 @@
+export interface SharedVaultHttpRepresentation {
+  uuid: string
+  user_uuid: string
+  file_upload_bytes_used: number
+  file_upload_bytes_limit: number
+  created_at_timestamp: number
+  updated_at_timestamp: number
+}

+ 21 - 0
packages/syncing-server/src/Mapping/Http/SharedVaultUserHttpMapper.ts

@@ -0,0 +1,21 @@
+import { MapperInterface } from '@standardnotes/domain-core'
+
+import { SharedVaultUser } from '../../Domain/SharedVault/User/SharedVaultUser'
+import { SharedVaultUserHttpRepresentation } from './SharedVaultUserHttpRepresentation copy'
+
+export class SharedVaultUserHttpMapper implements MapperInterface<SharedVaultUser, SharedVaultUserHttpRepresentation> {
+  toDomain(_projection: SharedVaultUserHttpRepresentation): SharedVaultUser {
+    throw new Error('Mapping from http representation to domain is not implemented.')
+  }
+
+  toProjection(domain: SharedVaultUser): SharedVaultUserHttpRepresentation {
+    return {
+      uuid: domain.id.toString(),
+      user_uuid: domain.props.userUuid.value,
+      permission: domain.props.permission.value,
+      shared_vault_uuid: domain.props.sharedVaultUuid.value,
+      created_at_timestamp: domain.props.timestamps.createdAt,
+      updated_at_timestamp: domain.props.timestamps.updatedAt,
+    }
+  }
+}

+ 8 - 0
packages/syncing-server/src/Mapping/Http/SharedVaultUserHttpRepresentation copy.ts

@@ -0,0 +1,8 @@
+export interface SharedVaultUserHttpRepresentation {
+  uuid: string
+  shared_vault_uuid: string
+  user_uuid: string
+  permission: string
+  created_at_timestamp: number
+  updated_at_timestamp: number
+}

+ 3 - 3
packages/syncing-server/src/Mapping/SharedVaultInvitePersistenceMapper.ts → packages/syncing-server/src/Mapping/Persistence/SharedVaultInvitePersistenceMapper.ts

@@ -1,8 +1,8 @@
 import { Timestamps, MapperInterface, UniqueEntityId, Uuid, Validator } from '@standardnotes/domain-core'
 
-import { SharedVaultInvite } from '../Domain/SharedVault/User/Invite/SharedVaultInvite'
-import { TypeORMSharedVaultInvite } from '../Infra/TypeORM/TypeORMSharedVaultInvite'
-import { SharedVaultUserPermission } from '../Domain/SharedVault/User/SharedVaultUserPermission'
+import { SharedVaultInvite } from '../../Domain/SharedVault/User/Invite/SharedVaultInvite'
+import { TypeORMSharedVaultInvite } from '../../Infra/TypeORM/TypeORMSharedVaultInvite'
+import { SharedVaultUserPermission } from '../../Domain/SharedVault/User/SharedVaultUserPermission'
 
 export class SharedVaultInvitePersistenceMapper
   implements MapperInterface<SharedVaultInvite, TypeORMSharedVaultInvite>

+ 2 - 2
packages/syncing-server/src/Mapping/SharedVaultPersistenceMapper.ts → packages/syncing-server/src/Mapping/Persistence/SharedVaultPersistenceMapper.ts

@@ -1,7 +1,7 @@
 import { Timestamps, MapperInterface, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
 
-import { SharedVault } from '../Domain/SharedVault/SharedVault'
-import { TypeORMSharedVault } from '../Infra/TypeORM/TypeORMSharedVault'
+import { SharedVault } from '../../Domain/SharedVault/SharedVault'
+import { TypeORMSharedVault } from '../../Infra/TypeORM/TypeORMSharedVault'
 
 export class SharedVaultPersistenceMapper implements MapperInterface<SharedVault, TypeORMSharedVault> {
   toDomain(projection: TypeORMSharedVault): SharedVault {

+ 3 - 3
packages/syncing-server/src/Mapping/SharedVaultUserPersistenceMapper.ts → packages/syncing-server/src/Mapping/Persistence/SharedVaultUserPersistenceMapper.ts

@@ -1,8 +1,8 @@
 import { Timestamps, MapperInterface, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
 
-import { SharedVaultUser } from '../Domain/SharedVault/User/SharedVaultUser'
-import { TypeORMSharedVaultUser } from '../Infra/TypeORM/TypeORMSharedVaultUser'
-import { SharedVaultUserPermission } from '../Domain/SharedVault/User/SharedVaultUserPermission'
+import { SharedVaultUser } from '../../Domain/SharedVault/User/SharedVaultUser'
+import { TypeORMSharedVaultUser } from '../../Infra/TypeORM/TypeORMSharedVaultUser'
+import { SharedVaultUserPermission } from '../../Domain/SharedVault/User/SharedVaultUserPermission'
 
 export class SharedVaultUserPersistenceMapper implements MapperInterface<SharedVaultUser, TypeORMSharedVaultUser> {
   toDomain(projection: TypeORMSharedVaultUser): SharedVaultUser {