From ed48350d3e9f480a525ea26e91adde345a2db1ca Mon Sep 17 00:00:00 2001 From: Mo Date: Wed, 31 May 2023 09:01:26 -0500 Subject: [PATCH] feat: on the fly vault creation during sync --- .../mysql/1684173017359-create_vault.ts | 4 --- .../Bootstrap/ServerContainerConfigLoader.ts | 1 + .../src/Controller/VaultsController.ts | 18 ++---------- .../src/Domain/Item/ItemService.ts | 28 +++++++++++++++++++ .../src/Domain/Item/SaveRule/VaultFilter.ts | 4 +-- .../Item/SaveRule/VaultSaveOperation.ts | 2 +- .../src/Domain/Vault/Factory/VaultFactory.ts | 1 - .../src/Domain/Vault/Factory/VaultHash.ts | 1 - .../src/Domain/Vault/Model/Vault.ts | 6 ---- .../src/Domain/Vault/Service/VaultService.ts | 18 ++++++------ .../Vault/Service/VaultServiceInterface.ts | 10 +++++-- .../VaultUser/Service/VaultUserService.ts | 4 +-- .../Service/VaultUserServiceInterface.ts | 6 +--- .../src/Projection/VaultProjection.ts | 1 - .../src/Projection/VaultProjector.ts | 1 - 15 files changed, 53 insertions(+), 52 deletions(-) diff --git a/packages/syncing-server/migrations/mysql/1684173017359-create_vault.ts b/packages/syncing-server/migrations/mysql/1684173017359-create_vault.ts index 3ad8e3328..70b67e7a3 100644 --- a/packages/syncing-server/migrations/mysql/1684173017359-create_vault.ts +++ b/packages/syncing-server/migrations/mysql/1684173017359-create_vault.ts @@ -25,10 +25,6 @@ export class CreateVault1684173017359 implements MigrationInterface { length: '36', isNullable: false, }), - new TableColumn({ - name: 'vault_key_timestamp', - type: 'bigint', - }), new TableColumn({ name: 'file_upload_bytes_used', type: 'bigint', diff --git a/packages/syncing-server/src/Bootstrap/ServerContainerConfigLoader.ts b/packages/syncing-server/src/Bootstrap/ServerContainerConfigLoader.ts index 6067804ea..1bc44e5ca 100644 --- a/packages/syncing-server/src/Bootstrap/ServerContainerConfigLoader.ts +++ b/packages/syncing-server/src/Bootstrap/ServerContainerConfigLoader.ts @@ -148,6 +148,7 @@ export class ServerContainerConfigLoader extends CommonContainerConfigLoader { context.container.get(TYPES.ItemProjector), context.container.get(TYPES.MAX_ITEMS_LIMIT), context.container.get(TYPES.VaultUserRepository), + context.container.get(TYPES.VaultService), context.container.get(TYPES.Logger), ) }) diff --git a/packages/syncing-server/src/Controller/VaultsController.ts b/packages/syncing-server/src/Controller/VaultsController.ts index 9282bc605..5770b493b 100644 --- a/packages/syncing-server/src/Controller/VaultsController.ts +++ b/packages/syncing-server/src/Controller/VaultsController.ts @@ -16,7 +16,6 @@ import { ProjectorInterface } from '../Projection/ProjectorInterface' import { Vault } from '../Domain/Vault/Model/Vault' import { VaultProjection } from '../Projection/VaultProjection' import { VaultUserProjection } from '../Projection/VaultUserProjection' -import { VaultUserServiceInterface } from '../Domain/VaultUser/Service/VaultUserServiceInterface' import { CreateVaultFileValetToken } from '../Domain/UseCase/CreateVaultFileValetToken/CreateVaultFileValetToken' import { RemovedVaultUserServiceInterface } from '../Domain/RemovedVaultUser/Service/RemovedVaultUserServiceInterface' @@ -24,7 +23,6 @@ import { RemovedVaultUserServiceInterface } from '../Domain/RemovedVaultUser/Ser export class VaultsController extends BaseHttpController { constructor( @inject(TYPES.VaultService) private vaultService: VaultServiceInterface, - @inject(TYPES.VaultUserService) private vaultUserService: VaultUserServiceInterface, @inject(TYPES.RemovedVaultUserService) private removedVaultUserService: RemovedVaultUserServiceInterface, @inject(TYPES.VaultProjector) private vaultProjector: ProjectorInterface, @inject(TYPES.VaultUserProjector) private vaultUserProjector: ProjectorInterface, @@ -74,7 +72,6 @@ export class VaultsController extends BaseHttpController { const result = await this.vaultService.createVault({ userUuid: response.locals.user.uuid, vaultUuid: request.body.vault_uuid, - vaultKeyTimestamp: request.body.vault_key_timestamp, specifiedItemsKeyUuid: request.body.specified_items_key_uuid, }) @@ -82,19 +79,9 @@ export class VaultsController extends BaseHttpController { return this.errorResponse(400, 'Could not create vault') } - const vaultUser = await this.vaultUserService.addVaultUser({ - vaultUuid: result.uuid, - userUuid: response.locals.user.uuid, - permissions: 'admin', - }) - - if (!vaultUser) { - return this.errorResponse(400, 'Could not add user to vault') - } - return this.json({ - vault: this.vaultProjector.projectFull(result), - vaultUser: this.vaultUserProjector.projectFull(vaultUser), + vault: this.vaultProjector.projectFull(result.vault), + vaultUser: this.vaultUserProjector.projectFull(result.vaultUser), }) } @@ -103,7 +90,6 @@ export class VaultsController extends BaseHttpController { const result = await this.vaultService.updateVault({ vaultUuid: request.params.vaultUuid, originatorUuid: response.locals.user.uuid, - vaultKeyTimestamp: request.body.vault_key_timestamp, specifiedItemsKeyUuid: request.body.specified_items_key_uuid, }) diff --git a/packages/syncing-server/src/Domain/Item/ItemService.ts b/packages/syncing-server/src/Domain/Item/ItemService.ts index 5c00b5893..560c63ac9 100644 --- a/packages/syncing-server/src/Domain/Item/ItemService.ts +++ b/packages/syncing-server/src/Domain/Item/ItemService.ts @@ -21,6 +21,7 @@ import { ProjectorInterface } from '../../Projection/ProjectorInterface' import { ItemProjection } from '../../Projection/ItemProjection' import { VaultUserRepositoryInterface } from '../VaultUser/Repository/VaultUserRepositoryInterface' import { ConflictType } from '../../Tmp/ConflictType' +import { VaultServiceInterface } from '../Vault/Service/VaultServiceInterface' export class ItemService implements ItemServiceInterface { private readonly DEFAULT_ITEMS_LIMIT = 150 @@ -39,6 +40,7 @@ export class ItemService implements ItemServiceInterface { private itemProjector: ProjectorInterface, private maxItemsSyncLimit: number, private vaultUsersRepository: VaultUserRepositoryInterface, + private vaultService: VaultServiceInterface, private logger: Logger, ) {} @@ -97,6 +99,8 @@ export class ItemService implements ItemServiceInterface { const savedItems: Array = [] const conflicts: Array = [] + await this.dynamicallyCreateVaultsBasedOnIncomingItems(dto) + const lastUpdatedTimestamp = this.timer.getTimestampInMicroseconds() for (const itemHash of dto.itemHashes) { @@ -183,6 +187,30 @@ export class ItemService implements ItemServiceInterface { return retrievedItems } + private async dynamicallyCreateVaultsBasedOnIncomingItems(dto: SaveItemsDTO): Promise { + const processedVaultUuids = new Set() + + for (const itemHash of dto.itemHashes) { + if (!itemHash.vault_uuid || processedVaultUuids.has(itemHash.vault_uuid)) { + continue + } + + processedVaultUuids.add(itemHash.vault_uuid) + + const vaultItemsKeyUuid = + itemHash.content_type === ContentType.VaultItemsKey ? itemHash.uuid : itemHash.items_key_id + if (!vaultItemsKeyUuid) { + continue + } + + await this.vaultService.createVault({ + userUuid: dto.userUuid, + vaultUuid: itemHash.vault_uuid, + specifiedItemsKeyUuid: vaultItemsKeyUuid, + }) + } + } + private calculateSyncToken(lastUpdatedTimestamp: number, savedItems: Array): string { if (savedItems.length) { const sortedItems = savedItems.sort((itemA: Item, itemB: Item) => { diff --git a/packages/syncing-server/src/Domain/Item/SaveRule/VaultFilter.ts b/packages/syncing-server/src/Domain/Item/SaveRule/VaultFilter.ts index 383e20701..389c9f386 100644 --- a/packages/syncing-server/src/Domain/Item/SaveRule/VaultFilter.ts +++ b/packages/syncing-server/src/Domain/Item/SaveRule/VaultFilter.ts @@ -64,7 +64,7 @@ export class VaultFilter implements ItemSaveRuleInterface { ) { return { type: 'move-to-other-vault', - sourceVaultUuid: existingItemVaultUuid, + vaultUuid: existingItemVaultUuid, targetVaultUuid: targetItemVaultUuid, existingItem: dto.existingItem, ...common, @@ -195,7 +195,7 @@ export class VaultFilter implements ItemSaveRuleInterface { } private async handleMoveToOtherVaultOperation(operation: MoveToOtherVaultSaveOperation): Promise { - const sourceVaultPermissions = await this.getVaultPermissions(operation.userUuid, operation.sourceVaultUuid) + const sourceVaultPermissions = await this.getVaultPermissions(operation.userUuid, operation.vaultUuid) const targetVaultPermissions = await this.getVaultPermissions(operation.userUuid, operation.targetVaultUuid) if (!sourceVaultPermissions || !targetVaultPermissions) { diff --git a/packages/syncing-server/src/Domain/Item/SaveRule/VaultSaveOperation.ts b/packages/syncing-server/src/Domain/Item/SaveRule/VaultSaveOperation.ts index 763747a37..802261692 100644 --- a/packages/syncing-server/src/Domain/Item/SaveRule/VaultSaveOperation.ts +++ b/packages/syncing-server/src/Domain/Item/SaveRule/VaultSaveOperation.ts @@ -20,7 +20,7 @@ export type RemoveFromVaultSaveOperation = SaveOperationCommon & { export type MoveToOtherVaultSaveOperation = SaveOperationCommon & { type: 'move-to-other-vault' - sourceVaultUuid: string + vaultUuid: string targetVaultUuid: string existingItem: Item } diff --git a/packages/syncing-server/src/Domain/Vault/Factory/VaultFactory.ts b/packages/syncing-server/src/Domain/Vault/Factory/VaultFactory.ts index ca1b6e9b9..b488a2af0 100644 --- a/packages/syncing-server/src/Domain/Vault/Factory/VaultFactory.ts +++ b/packages/syncing-server/src/Domain/Vault/Factory/VaultFactory.ts @@ -11,7 +11,6 @@ export class VaultFactory implements VaultFactoryInterface { newVault.uuid = dto.vaultHash.uuid newVault.userUuid = dto.userUuid newVault.specifiedItemsKeyUuid = dto.vaultHash.specified_items_key_uuid - newVault.vaultKeyTimestamp = dto.vaultHash.vault_key_timestamp newVault.fileUploadBytesUsed = dto.vaultHash.file_upload_bytes_used newVault.fileUploadBytesLimit = dto.vaultHash.file_upload_bytes_limit diff --git a/packages/syncing-server/src/Domain/Vault/Factory/VaultHash.ts b/packages/syncing-server/src/Domain/Vault/Factory/VaultHash.ts index 2bce670cc..e1ffb8d42 100644 --- a/packages/syncing-server/src/Domain/Vault/Factory/VaultHash.ts +++ b/packages/syncing-server/src/Domain/Vault/Factory/VaultHash.ts @@ -2,7 +2,6 @@ export type VaultHash = { uuid: string user_uuid: string specified_items_key_uuid: string - vault_key_timestamp: number file_upload_bytes_used: number file_upload_bytes_limit: number created_at_timestamp?: number diff --git a/packages/syncing-server/src/Domain/Vault/Model/Vault.ts b/packages/syncing-server/src/Domain/Vault/Model/Vault.ts index 3f043ad70..c3d3e6e8c 100644 --- a/packages/syncing-server/src/Domain/Vault/Model/Vault.ts +++ b/packages/syncing-server/src/Domain/Vault/Model/Vault.ts @@ -18,12 +18,6 @@ export class Vault { }) declare specifiedItemsKeyUuid: string - @Column({ - name: 'vault_key_timestamp', - type: 'bigint', - }) - declare vaultKeyTimestamp: number - @Column({ name: 'file_upload_bytes_used', type: 'bigint', diff --git a/packages/syncing-server/src/Domain/Vault/Service/VaultService.ts b/packages/syncing-server/src/Domain/Vault/Service/VaultService.ts index 48fd47177..50af510da 100644 --- a/packages/syncing-server/src/Domain/Vault/Service/VaultService.ts +++ b/packages/syncing-server/src/Domain/Vault/Service/VaultService.ts @@ -1,7 +1,7 @@ import { TimerInterface } from '@standardnotes/time' import { Vault } from '../Model/Vault' import { VaultsRepositoryInterface } from '../Repository/VaultRepositoryInterface' -import { CreateVaultDTO, VaultServiceInterface, UpdateVaultDTO } from './VaultServiceInterface' +import { CreateVaultDTO, VaultServiceInterface, UpdateVaultDTO, CreateVaultResult } from './VaultServiceInterface' import { VaultFactoryInterface } from '../Factory/VaultFactoryInterface' import { VaultUserServiceInterface } from '../../VaultUser/Service/VaultUserServiceInterface' import { VaultInviteServiceInterface } from '../../VaultInvite/Service/VaultInviteServiceInterface' @@ -15,7 +15,7 @@ export class VaultService implements VaultServiceInterface { private timer: TimerInterface, ) {} - async createVault(dto: CreateVaultDTO): Promise { + async createVault(dto: CreateVaultDTO): Promise { const existingVault = await this.vaultRepository.findByUuid(dto.vaultUuid) if (existingVault) { return null @@ -28,7 +28,6 @@ export class VaultService implements VaultServiceInterface { uuid: dto.vaultUuid, user_uuid: dto.userUuid, specified_items_key_uuid: dto.specifiedItemsKeyUuid, - vault_key_timestamp: dto.vaultKeyTimestamp, file_upload_bytes_limit: 1_000_000, file_upload_bytes_used: 0, created_at_timestamp: timestamp, @@ -38,7 +37,13 @@ export class VaultService implements VaultServiceInterface { const savedVault = await this.vaultRepository.create(vault) - return savedVault + const vaultUser = await this.vaultUserService.addVaultUser({ + vaultUuid: savedVault.uuid, + userUuid: dto.userUuid, + permissions: 'admin', + }) + + return { vault, vaultUser } } async getVault(dto: { vaultUuid: string }): Promise { @@ -67,12 +72,7 @@ export class VaultService implements VaultServiceInterface { return null } - if (dto.vaultKeyTimestamp < vault.vaultKeyTimestamp) { - return null - } - vault.specifiedItemsKeyUuid = dto.specifiedItemsKeyUuid - vault.vaultKeyTimestamp = dto.vaultKeyTimestamp vault.updatedAtTimestamp = this.timer.getTimestampInMicroseconds() const savedVault = await this.vaultRepository.save(vault) diff --git a/packages/syncing-server/src/Domain/Vault/Service/VaultServiceInterface.ts b/packages/syncing-server/src/Domain/Vault/Service/VaultServiceInterface.ts index c696781cb..8b9e0c3a5 100644 --- a/packages/syncing-server/src/Domain/Vault/Service/VaultServiceInterface.ts +++ b/packages/syncing-server/src/Domain/Vault/Service/VaultServiceInterface.ts @@ -1,21 +1,25 @@ +import { VaultUser } from './../../VaultUser/Model/VaultUser' import { Vault } from '../Model/Vault' export type CreateVaultDTO = { userUuid: string vaultUuid: string - vaultKeyTimestamp: number specifiedItemsKeyUuid: string } +export type CreateVaultResult = { + vault: Vault + vaultUser: VaultUser +} + export type UpdateVaultDTO = { originatorUuid: string vaultUuid: string - vaultKeyTimestamp: number specifiedItemsKeyUuid: string } export interface VaultServiceInterface { - createVault(dto: CreateVaultDTO): Promise + createVault(dto: CreateVaultDTO): Promise updateVault(dto: UpdateVaultDTO): Promise diff --git a/packages/syncing-server/src/Domain/VaultUser/Service/VaultUserService.ts b/packages/syncing-server/src/Domain/VaultUser/Service/VaultUserService.ts index a18503207..92ffdb813 100644 --- a/packages/syncing-server/src/Domain/VaultUser/Service/VaultUserService.ts +++ b/packages/syncing-server/src/Domain/VaultUser/Service/VaultUserService.ts @@ -22,10 +22,10 @@ export class VaultUserService implements VaultUserServiceInterface { vaultUuid: string userUuid: string permissions: VaultUserPermission - }): Promise { + }): Promise { const vault = await this.vaultRepository.findByUuid(dto.vaultUuid) if (!vault) { - return null + throw new Error('Attempting to add a vault user to a non-existent vault') } await this.removedVaultUserService.deleteRemovedVaultUser({ diff --git a/packages/syncing-server/src/Domain/VaultUser/Service/VaultUserServiceInterface.ts b/packages/syncing-server/src/Domain/VaultUser/Service/VaultUserServiceInterface.ts index b7993d825..89cafe302 100644 --- a/packages/syncing-server/src/Domain/VaultUser/Service/VaultUserServiceInterface.ts +++ b/packages/syncing-server/src/Domain/VaultUser/Service/VaultUserServiceInterface.ts @@ -3,11 +3,7 @@ import { VaultUserPermission } from '../Model/VaultUserPermission' import { GetVaultUsersDTO } from './GetVaultUsersDTO' export interface VaultUserServiceInterface { - addVaultUser(dto: { - vaultUuid: string - userUuid: string - permissions: VaultUserPermission - }): Promise + addVaultUser(dto: { vaultUuid: string; userUuid: string; permissions: VaultUserPermission }): Promise getAllVaultUsersForUser(dto: GetVaultUsersDTO): Promise diff --git a/packages/syncing-server/src/Projection/VaultProjection.ts b/packages/syncing-server/src/Projection/VaultProjection.ts index 47cb1470b..cdefdc985 100644 --- a/packages/syncing-server/src/Projection/VaultProjection.ts +++ b/packages/syncing-server/src/Projection/VaultProjection.ts @@ -2,7 +2,6 @@ export type VaultProjection = { uuid: string user_uuid: string specified_items_key_uuid: string - vault_key_timestamp: number file_upload_bytes_used: number file_upload_bytes_limit: number created_at_timestamp: number diff --git a/packages/syncing-server/src/Projection/VaultProjector.ts b/packages/syncing-server/src/Projection/VaultProjector.ts index 59b0da391..dd2f01c12 100644 --- a/packages/syncing-server/src/Projection/VaultProjector.ts +++ b/packages/syncing-server/src/Projection/VaultProjector.ts @@ -21,7 +21,6 @@ export class VaultProjector implements ProjectorInterface