Pārlūkot izejas kodu

feat: add getting shared vaults for a user (#639)

Karol Sójko 1 gadu atpakaļ
vecāks
revīzija
d2b2c339f2

+ 1 - 0
packages/syncing-server/src/Domain/SharedVault/SharedVaultRepositoryInterface.ts

@@ -3,6 +3,7 @@ import { SharedVault } from './SharedVault'
 
 
 export interface SharedVaultRepositoryInterface {
 export interface SharedVaultRepositoryInterface {
   findByUuid(uuid: Uuid): Promise<SharedVault | null>
   findByUuid(uuid: Uuid): Promise<SharedVault | null>
+  findByUuids(uuids: Uuid[], lastSyncTime?: number): Promise<SharedVault[]>
   save(sharedVault: SharedVault): Promise<void>
   save(sharedVault: SharedVault): Promise<void>
   remove(sharedVault: SharedVault): Promise<void>
   remove(sharedVault: SharedVault): Promise<void>
 }
 }

+ 1 - 0
packages/syncing-server/src/Domain/SharedVault/User/SharedVaultUserRepositoryInterface.ts

@@ -4,6 +4,7 @@ import { SharedVaultUser } from './SharedVaultUser'
 
 
 export interface SharedVaultUserRepositoryInterface {
 export interface SharedVaultUserRepositoryInterface {
   findByUuid(sharedVaultUserUuid: Uuid): Promise<SharedVaultUser | null>
   findByUuid(sharedVaultUserUuid: Uuid): Promise<SharedVaultUser | null>
+  findByUserUuid(userUuid: Uuid): Promise<SharedVaultUser[]>
   save(sharedVaultUser: SharedVaultUser): Promise<void>
   save(sharedVaultUser: SharedVaultUser): Promise<void>
   remove(sharedVault: SharedVaultUser): Promise<void>
   remove(sharedVault: SharedVaultUser): Promise<void>
   findByUserUuidAndSharedVaultUuid(dto: { userUuid: Uuid; sharedVaultUuid: Uuid }): Promise<SharedVaultUser | null>
   findByUserUuidAndSharedVaultUuid(dto: { userUuid: Uuid; sharedVaultUuid: Uuid }): Promise<SharedVaultUser | null>

+ 68 - 0
packages/syncing-server/src/Domain/UseCase/GetSharedVaults/GetSharedVaults.spec.ts

@@ -0,0 +1,68 @@
+import { Timestamps, Uuid } from '@standardnotes/domain-core'
+import { SharedVault } from '../../SharedVault/SharedVault'
+import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
+import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
+import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
+import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
+import { GetSharedVaults } from './GetSharedVaults'
+
+describe('GetSharedVaults', () => {
+  let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
+  let sharedVaultRepository: SharedVaultRepositoryInterface
+  let sharedVault: SharedVault
+  let sharedVaultUser: SharedVaultUser
+
+  const createUseCase = () => new GetSharedVaults(sharedVaultUserRepository, sharedVaultRepository)
+
+  beforeEach(() => {
+    sharedVaultUser = SharedVaultUser.create({
+      userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
+      sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
+      permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Admin).getValue(),
+      timestamps: Timestamps.create(123, 123).getValue(),
+    }).getValue()
+    sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
+    sharedVaultUserRepository.findByUserUuid = jest.fn().mockResolvedValue([sharedVaultUser])
+
+    sharedVault = SharedVault.create({
+      userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
+      timestamps: Timestamps.create(123, 123).getValue(),
+      fileUploadBytesLimit: 123,
+      fileUploadBytesUsed: 123,
+    }).getValue()
+    sharedVaultRepository = {} as jest.Mocked<SharedVaultRepositoryInterface>
+    sharedVaultRepository.findByUuids = jest.fn().mockResolvedValue([sharedVault])
+  })
+
+  it('returns shared vaults', async () => {
+    const useCase = createUseCase()
+
+    const result = await useCase.execute({
+      userUuid: '00000000-0000-0000-0000-000000000000',
+    })
+
+    expect(result.getValue()).toEqual([sharedVault])
+  })
+
+  it('returns empty array if no shared vaults found', async () => {
+    sharedVaultUserRepository.findByUserUuid = jest.fn().mockResolvedValue([])
+
+    const useCase = createUseCase()
+
+    const result = await useCase.execute({
+      userUuid: '00000000-0000-0000-0000-000000000000',
+    })
+
+    expect(result.getValue()).toEqual([])
+  })
+
+  it('returns error if user uuid is invalid', async () => {
+    const useCase = createUseCase()
+
+    const result = await useCase.execute({
+      userUuid: 'invalid',
+    })
+
+    expect(result.isFailed()).toBeTruthy()
+  })
+})

+ 35 - 0
packages/syncing-server/src/Domain/UseCase/GetSharedVaults/GetSharedVaults.ts

@@ -0,0 +1,35 @@
+import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
+
+import { SharedVault } from '../../SharedVault/SharedVault'
+import { GetSharedVaultsDTO } from './GetSharedVaultsDTO'
+import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
+import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
+
+export class GetSharedVaults implements UseCaseInterface<SharedVault[]> {
+  constructor(
+    private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
+    private sharedVaultRepository: SharedVaultRepositoryInterface,
+  ) {}
+
+  async execute(dto: GetSharedVaultsDTO): Promise<Result<SharedVault[]>> {
+    const userUuidOrError = Uuid.create(dto.userUuid)
+    if (userUuidOrError.isFailed()) {
+      return Result.fail(userUuidOrError.getError())
+    }
+    const userUuid = userUuidOrError.getValue()
+
+    const ownedSharedVaultsAssociations = await this.sharedVaultUserRepository.findByUserUuid(userUuid)
+
+    const sharedVaultUuids = ownedSharedVaultsAssociations.map(
+      (sharedVaultUser) => sharedVaultUser.props.sharedVaultUuid,
+    )
+
+    if (sharedVaultUuids.length === 0) {
+      return Result.ok([])
+    }
+
+    const sharedVaults = await this.sharedVaultRepository.findByUuids(sharedVaultUuids, dto.lastSyncTime)
+
+    return Result.ok(sharedVaults)
+  }
+}

+ 4 - 0
packages/syncing-server/src/Domain/UseCase/GetSharedVaults/GetSharedVaultsDTO.ts

@@ -0,0 +1,4 @@
+export interface GetSharedVaultsDTO {
+  userUuid: string
+  lastSyncTime?: number
+}

+ 14 - 0
packages/syncing-server/src/Infra/TypeORM/TypeORMSharedVaultRepository.ts

@@ -11,6 +11,20 @@ export class TypeORMSharedVaultRepository implements SharedVaultRepositoryInterf
     private mapper: MapperInterface<SharedVault, TypeORMSharedVault>,
     private mapper: MapperInterface<SharedVault, TypeORMSharedVault>,
   ) {}
   ) {}
 
 
+  async findByUuids(uuids: Uuid[], lastSyncTime?: number | undefined): Promise<SharedVault[]> {
+    const queryBuilder = await this.ormRepository
+      .createQueryBuilder('shared_vault')
+      .where('shared_vault.uuid IN (:...sharedVaultUuids)', { sharedVaultUuids: uuids.map((uuid) => uuid.value) })
+
+    if (lastSyncTime !== undefined) {
+      queryBuilder.andWhere('shared_vault.updated_at_timestamp > :lastSyncTime', { lastSyncTime })
+    }
+
+    const persistence = await queryBuilder.getMany()
+
+    return persistence.map((p) => this.mapper.toDomain(p))
+  }
+
   async save(sharedVault: SharedVault): Promise<void> {
   async save(sharedVault: SharedVault): Promise<void> {
     const persistence = this.mapper.toProjection(sharedVault)
     const persistence = this.mapper.toProjection(sharedVault)
 
 

+ 11 - 0
packages/syncing-server/src/Infra/TypeORM/TypeORMSharedVaultUserRepository.ts

@@ -11,6 +11,17 @@ export class TypeORMSharedVaultUserRepository implements SharedVaultUserReposito
     private mapper: MapperInterface<SharedVaultUser, TypeORMSharedVaultUser>,
     private mapper: MapperInterface<SharedVaultUser, TypeORMSharedVaultUser>,
   ) {}
   ) {}
 
 
+  async findByUserUuid(userUuid: Uuid): Promise<SharedVaultUser[]> {
+    const persistence = await this.ormRepository
+      .createQueryBuilder('shared_vault_user')
+      .where('shared_vault_user.user_uuid = :userUuid', {
+        userUuid: userUuid.value,
+      })
+      .getMany()
+
+    return persistence.map((p) => this.mapper.toDomain(p))
+  }
+
   async findByUserUuidAndSharedVaultUuid(dto: {
   async findByUserUuidAndSharedVaultUuid(dto: {
     userUuid: Uuid
     userUuid: Uuid
     sharedVaultUuid: Uuid
     sharedVaultUuid: Uuid