diff --git a/src/modules/folder/folder.module.ts b/src/modules/folder/folder.module.ts index 0c8ef9b4c..dc86b6653 100644 --- a/src/modules/folder/folder.module.ts +++ b/src/modules/folder/folder.module.ts @@ -7,7 +7,6 @@ import { FileModule } from '../file/file.module'; import { CryptoModule } from '../../externals/crypto/crypto.module'; import { CryptoService } from '../../externals/crypto/crypto.service'; import { FolderController } from './folder.controller'; -import { UserModel } from '../user/user.model'; import { UserModule } from '../user/user.module'; import { SharingModule } from '../sharing/sharing.module'; import { WorkspacesModule } from '../workspaces/workspaces.module'; @@ -15,7 +14,7 @@ import { NotificationModule } from '../../externals/notifications/notifications. @Module({ imports: [ - SequelizeModule.forFeature([FolderModel, UserModel]), + SequelizeModule.forFeature([FolderModel]), forwardRef(() => FileModule), forwardRef(() => UserModule), CryptoModule, diff --git a/src/modules/user/user.module.ts b/src/modules/user/user.module.ts index 609cd7fbd..08b98d9c2 100644 --- a/src/modules/user/user.module.ts +++ b/src/modules/user/user.module.ts @@ -33,12 +33,10 @@ import { ShareModule } from '../share/share.module'; import { KeyServerModel } from '../keyserver/key-server.model'; import { AvatarService } from '../../externals/avatar/avatar.service'; import { AppSumoModule } from '../app-sumo/app-sumo.module'; -import { AppSumoUseCase } from '../app-sumo/app-sumo.usecase'; import { PlanModule } from '../plan/plan.module'; import { SequelizePreCreatedUsersRepository } from './pre-created-users.repository'; import { PreCreatedUserModel } from './pre-created-users.model'; import { SharingModule } from '../sharing/sharing.module'; -import { SharingService } from '../sharing/sharing.service'; import { SequelizeAttemptChangeEmailRepository } from './attempt-change-email.repository'; import { AttemptChangeEmailModel } from './attempt-change-email.model'; import { MailerService } from '../../externals/mailer/mailer.service'; @@ -98,10 +96,6 @@ import { AsymmetricEncryptionModule } from '../../externals/asymmetric-encryptio PaymentsService, NewsletterService, AvatarService, - BridgeService, - PaymentsService, - AppSumoUseCase, - SharingService, MailerService, ], exports: [ diff --git a/src/modules/user/user.usecase.spec.ts b/src/modules/user/user.usecase.spec.ts index 87589ceb1..5f56b27e5 100644 --- a/src/modules/user/user.usecase.spec.ts +++ b/src/modules/user/user.usecase.spec.ts @@ -77,6 +77,7 @@ import { SequelizeSharingRepository } from '../sharing/sharing.repository'; import { SequelizePreCreatedUsersRepository } from './pre-created-users.repository'; import { SharingInvite } from '../sharing/sharing.domain'; import { aes } from '@internxt/lib'; +import { WorkspacesUsecases } from '../workspaces/workspaces.usecase'; jest.mock('../../middlewares/passport', () => { const originalModule = jest.requireActual('../../middlewares/passport'); @@ -113,6 +114,7 @@ describe('User use cases', () => { let sharingRepository: SequelizeSharingRepository; let preCreatedUsersRepository: SequelizePreCreatedUsersRepository; let asymmetricEncryptionService: AsymmetricEncryptionService; + let workspaceUseCases: WorkspacesUsecases; const user = User.build({ id: 1, @@ -207,6 +209,7 @@ describe('User use cases', () => { asymmetricEncryptionService = moduleRef.get( AsymmetricEncryptionService, ); + workspaceUseCases = moduleRef.get(WorkspacesUsecases); }); describe('Resetting a user', () => { @@ -219,6 +222,7 @@ describe('User use cases', () => { deleteFiles: false, deleteFolders: false, deleteShares: false, + deleteWorkspaces: false, }); expect(deleteSharesSpy).not.toBeCalled(); @@ -236,6 +240,7 @@ describe('User use cases', () => { deleteFiles: false, deleteFolders: false, deleteShares: true, + deleteWorkspaces: false, }); expect(deleteSharesSpy).toBeCalledWith(user); @@ -243,6 +248,19 @@ describe('User use cases', () => { expect(deleteFilesSpy).not.toBeCalled(); }); + it('When delete workspaces is true, then user owned workspaces are reset and user is removed from invited workspaces', async () => { + await userUseCases.resetUser(user, { + deleteFiles: false, + deleteFolders: false, + deleteShares: false, + deleteWorkspaces: true, + }); + + expect( + workspaceUseCases.removeUserFromNonOwnedWorkspaces, + ).toHaveBeenCalled(); + }); + describe('When resources do not exist', () => { it('When delete folders is true, then the folders are deleted', async () => { const deleteSharesSpy = jest.spyOn(shareUseCases, 'deleteByUser'); @@ -256,6 +274,7 @@ describe('User use cases', () => { deleteFiles: false, deleteFolders: true, deleteShares: false, + deleteWorkspaces: false, }); expect(getFoldersSpy).toBeCalledWith( @@ -283,6 +302,7 @@ describe('User use cases', () => { deleteFiles: true, deleteFolders: false, deleteShares: false, + deleteWorkspaces: false, }); expect(getFilesSpy).toBeCalledWith( @@ -312,6 +332,7 @@ describe('User use cases', () => { deleteFiles: false, deleteFolders: true, deleteShares: false, + deleteWorkspaces: false, }); expect(getFoldersSpy).toBeCalledWith( @@ -339,6 +360,7 @@ describe('User use cases', () => { deleteFiles: true, deleteFolders: false, deleteShares: false, + deleteWorkspaces: false, }); expect(getFilesSpy).toBeCalledWith( diff --git a/src/modules/user/user.usecase.ts b/src/modules/user/user.usecase.ts index 7e0820354..2a2fafe8a 100644 --- a/src/modules/user/user.usecase.ts +++ b/src/modules/user/user.usecase.ts @@ -87,6 +87,7 @@ import { CacheManagerService } from '../cache-manager/cache-manager.service'; import { RefreshTokenResponseDto } from './dto/responses/refresh-token.dto'; import { SharingInvite } from '../sharing/sharing.domain'; import { AsymmetricEncryptionService } from '../../externals/asymmetric-encryption/asymmetric-encryption.service'; +import { WorkspacesUsecases } from '../workspaces/workspaces.usecase'; export class ReferralsNotAvailableError extends Error { constructor() { @@ -163,6 +164,8 @@ export class UserUseCases { private readonly backupUseCases: BackupUseCase, private readonly cacheManager: CacheManagerService, private readonly asymmetricEncryptionService: AsymmetricEncryptionService, + @Inject(forwardRef(() => WorkspacesUsecases)) + private readonly workspaceUseCases: WorkspacesUsecases, ) {} findByEmail(email: User['email']): Promise { @@ -968,6 +971,7 @@ export class UserUseCases { deleteFiles: true, deleteFolders: true, deleteShares: true, + deleteWorkspaces: true, }); } @@ -982,10 +986,14 @@ export class UserUseCases { deleteFiles: boolean; deleteFolders: boolean; deleteShares: boolean; + deleteWorkspaces: boolean; }, ): Promise { if (options.deleteShares) { await this.shareUseCases.deleteByUser(user); + await this.sharingRepository.deleteSharingsBy({ sharedWith: user.uuid }); + await this.sharingRepository.deleteSharingsBy({ ownerId: user.uuid }); + await this.sharingRepository.deleteInvitesBy({ sharedWith: user.uuid }); } if (options.deleteFolders) { @@ -1031,6 +1039,10 @@ export class UserUseCases { done = files.length < limit || files.length === 0; } while (!done); } + + if (options.deleteWorkspaces) { + await this.workspaceUseCases.removeUserFromNonOwnedWorkspaces(user); + } } async updatePassword( diff --git a/src/modules/workspaces/workspaces.usecase.ts b/src/modules/workspaces/workspaces.usecase.ts index acd704cb4..3e948392e 100644 --- a/src/modules/workspaces/workspaces.usecase.ts +++ b/src/modules/workspaces/workspaces.usecase.ts @@ -2,6 +2,8 @@ import { BadRequestException, ConflictException, ForbiddenException, + forwardRef, + Inject, Injectable, InternalServerErrorException, Logger, @@ -81,14 +83,18 @@ export class WorkspacesUsecases { constructor( private readonly teamRepository: SequelizeWorkspaceTeamRepository, private readonly workspaceRepository: SequelizeWorkspaceRepository, + @Inject(forwardRef(() => SharingService)) private readonly sharingUseCases: SharingService, private readonly paymentService: PaymentsService, private readonly networkService: BridgeService, private readonly userRepository: SequelizeUserRepository, + @Inject(forwardRef(() => UserUseCases)) private readonly userUsecases: UserUseCases, private readonly configService: ConfigService, private readonly mailerService: MailerService, + @Inject(forwardRef(() => FileUseCases)) private readonly fileUseCases: FileUseCases, + @Inject(forwardRef(() => FolderUseCases)) private readonly folderUseCases: FolderUseCases, private readonly avatarService: AvatarService, private readonly fuzzySearchUseCases: FuzzySearchUseCases,