From c7bcdc544d3031d851e245fe3f50efb95d1d77cd Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Wed, 12 Mar 2025 10:34:51 -0400 Subject: [PATCH] feat(core): Transfer folder structure when deleting user (no-changelog) (#13845) --- .../__tests__/users.controller.test.ts | 1 + .../cli/src/controllers/users.controller.ts | 8 ++++++ .../repositories/folder.repository.ts | 17 ++++++++++++ packages/cli/src/services/folder.service.ts | 15 +++++------ .../cli/src/services/project.service.ee.ts | 2 +- .../cli/test/integration/users.api.test.ts | 27 +++++++++++++++++++ 6 files changed, 60 insertions(+), 10 deletions(-) diff --git a/packages/cli/src/controllers/__tests__/users.controller.test.ts b/packages/cli/src/controllers/__tests__/users.controller.test.ts index 5eaaca5840..3afa448801 100644 --- a/packages/cli/src/controllers/__tests__/users.controller.test.ts +++ b/packages/cli/src/controllers/__tests__/users.controller.test.ts @@ -25,6 +25,7 @@ describe('UsersController', () => { mock(), projectService, eventService, + mock(), ); beforeEach(() => { diff --git a/packages/cli/src/controllers/users.controller.ts b/packages/cli/src/controllers/users.controller.ts index 80d38fcfcd..000b069ac3 100644 --- a/packages/cli/src/controllers/users.controller.ts +++ b/packages/cli/src/controllers/users.controller.ts @@ -29,6 +29,7 @@ import { ExternalHooks } from '@/external-hooks'; import type { PublicUser } from '@/interfaces'; import { listQueryMiddleware } from '@/middlewares'; import { AuthenticatedRequest, ListQuery, UserRequest } from '@/requests'; +import { FolderService } from '@/services/folder.service'; import { ProjectService } from '@/services/project.service.ee'; import { UserService } from '@/services/user.service'; import { WorkflowService } from '@/workflows/workflow.service'; @@ -48,6 +49,7 @@ export class UsersController { private readonly credentialsService: CredentialsService, private readonly projectService: ProjectService, private readonly eventService: EventService, + private readonly folderService: FolderService, ) {} static ERROR_MESSAGES = { @@ -215,6 +217,12 @@ export class UsersController { transfereePersonalProject.id, trx, ); + + await this.folderService.transferAllFoldersToProject( + personalProjectToDelete.id, + transfereePersonalProject.id, + trx, + ); }); await this.projectService.clearCredentialCanUseExternalSecretsCache( diff --git a/packages/cli/src/databases/repositories/folder.repository.ts b/packages/cli/src/databases/repositories/folder.repository.ts index 16e410c51c..b0afe3d26e 100644 --- a/packages/cli/src/databases/repositories/folder.repository.ts +++ b/packages/cli/src/databases/repositories/folder.repository.ts @@ -276,4 +276,21 @@ export class FolderRepository extends Repository { getPersonalProject(transferee), ]); + await Promise.all([ + createFolder(memberPersonalProject, { name: 'folder1' }), + createFolder(memberPersonalProject, { name: 'folder2' }), + createFolder(transfereePersonalProject, { name: 'folder3' }), + createFolder(transfereePersonalProject, { name: 'folder1' }), + ]); + const deleteSpy = jest.spyOn(Container.get(CacheService), 'deleteMany'); // @@ -485,6 +494,7 @@ describe('DELETE /users/:id', () => { const projectRelationRepository = Container.get(ProjectRelationRepository); const sharedWorkflowRepository = Container.get(SharedWorkflowRepository); const sharedCredentialsRepository = Container.get(SharedCredentialsRepository); + const folderRepository = Container.get(FolderRepository); await Promise.all([ // user, their personal project and their relationship to the team project is gone @@ -574,6 +584,23 @@ describe('DELETE /users/:id', () => { }), ).resolves.not.toBeNull(), ]); + + // Assert that the folders have been transferred + + const transfereeFolders = await folderRepository.findBy({ + homeProject: { id: transfereePersonalProject.id }, + }); + + const deletedUserFolders = await folderRepository.findBy({ + homeProject: { id: memberPersonalProject.id }, + }); + + expect(transfereeFolders).toHaveLength(4); + expect(transfereeFolders.map((folder) => folder.name)).toEqual( + expect.arrayContaining(['folder1', 'folder2', 'folder3', 'folder1']), + ); + + expect(deletedUserFolders).toHaveLength(0); }); test('should fail to delete self', async () => {