mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
feat(core): Add endpoint DELETE /projects/:projectId/folders/:folderId (no-changelog) (#13516)
This commit is contained in:
@@ -3,8 +3,10 @@ import { Container } from '@n8n/di';
|
||||
import type { User } from '@/databases/entities/user';
|
||||
import { FolderRepository } from '@/databases/repositories/folder.repository';
|
||||
import { ProjectRepository } from '@/databases/repositories/project.repository';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
import { createFolder } from '@test-integration/db/folders';
|
||||
import { createTag } from '@test-integration/db/tags';
|
||||
import { createWorkflow } from '@test-integration/db/workflows';
|
||||
|
||||
import { createTeamProject, linkUserToProject } from '../shared/db/projects';
|
||||
import { createOwner, createMember } from '../shared/db/users';
|
||||
@@ -23,12 +25,14 @@ const testServer = utils.setupTestServer({
|
||||
|
||||
let projectRepository: ProjectRepository;
|
||||
let folderRepository: FolderRepository;
|
||||
let workflowRepository: WorkflowRepository;
|
||||
|
||||
beforeEach(async () => {
|
||||
await testDb.truncate(['Folder', 'SharedWorkflow', 'Tag', 'Project', 'ProjectRelation']);
|
||||
|
||||
projectRepository = Container.get(ProjectRepository);
|
||||
folderRepository = Container.get(FolderRepository);
|
||||
workflowRepository = Container.get(WorkflowRepository);
|
||||
|
||||
owner = await createOwner();
|
||||
member = await createMember();
|
||||
@@ -463,3 +467,205 @@ describe('PATCH /projects/:projectId/folders/:folderId', () => {
|
||||
expect(folderWithTags?.tags[0].id).toBe(tag3.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE /projects/:projectId/folders/:folderId', () => {
|
||||
test('should not delete folder when project does not exist', async () => {
|
||||
await authOwnerAgent
|
||||
.delete('/projects/non-existing-id/folders/some-folder-id')
|
||||
.send({})
|
||||
.expect(403);
|
||||
});
|
||||
|
||||
test('should not delete folder when folder does not exist', async () => {
|
||||
const project = await createTeamProject('test project', owner);
|
||||
|
||||
await authOwnerAgent
|
||||
.delete(`/projects/${project.id}/folders/non-existing-folder`)
|
||||
.send({})
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
test('should not delete folder if user has project:viewer role in team project', async () => {
|
||||
const project = await createTeamProject(undefined, owner);
|
||||
const folder = await createFolder(project);
|
||||
await linkUserToProject(member, project, 'project:viewer');
|
||||
|
||||
await authMemberAgent
|
||||
.delete(`/projects/${project.id}/folders/${folder.id}`)
|
||||
.send({})
|
||||
.expect(403);
|
||||
|
||||
const folderInDb = await folderRepository.findOneBy({ id: folder.id });
|
||||
expect(folderInDb).toBeDefined();
|
||||
});
|
||||
|
||||
test("should not allow deleting folder in another user's personal project", async () => {
|
||||
const ownerPersonalProject = await projectRepository.getPersonalProjectForUserOrFail(owner.id);
|
||||
const folder = await createFolder(ownerPersonalProject);
|
||||
|
||||
await authMemberAgent
|
||||
.delete(`/projects/${ownerPersonalProject.id}/folders/${folder.id}`)
|
||||
.send({})
|
||||
.expect(403);
|
||||
|
||||
const folderInDb = await folderRepository.findOneBy({ id: folder.id });
|
||||
expect(folderInDb).toBeDefined();
|
||||
});
|
||||
|
||||
test('should delete folder if user has project:editor role in team project', async () => {
|
||||
const project = await createTeamProject(undefined, owner);
|
||||
const folder = await createFolder(project);
|
||||
await linkUserToProject(member, project, 'project:editor');
|
||||
|
||||
await authMemberAgent
|
||||
.delete(`/projects/${project.id}/folders/${folder.id}`)
|
||||
.send({})
|
||||
.expect(200);
|
||||
|
||||
const folderInDb = await folderRepository.findOneBy({ id: folder.id });
|
||||
expect(folderInDb).toBeNull();
|
||||
});
|
||||
|
||||
test('should delete folder if user has project:admin role in team project', async () => {
|
||||
const project = await createTeamProject(undefined, owner);
|
||||
const folder = await createFolder(project);
|
||||
|
||||
await authOwnerAgent
|
||||
.delete(`/projects/${project.id}/folders/${folder.id}`)
|
||||
.send({})
|
||||
.expect(200);
|
||||
|
||||
const folderInDb = await folderRepository.findOneBy({ id: folder.id });
|
||||
expect(folderInDb).toBeNull();
|
||||
});
|
||||
|
||||
test('should delete folder in personal project', async () => {
|
||||
const personalProject = await projectRepository.getPersonalProjectForUserOrFail(owner.id);
|
||||
const folder = await createFolder(personalProject);
|
||||
|
||||
await authOwnerAgent
|
||||
.delete(`/projects/${personalProject.id}/folders/${folder.id}`)
|
||||
.send({})
|
||||
.expect(200);
|
||||
|
||||
const folderInDb = await folderRepository.findOneBy({ id: folder.id });
|
||||
expect(folderInDb).toBeNull();
|
||||
});
|
||||
|
||||
test('should delete folder, all child folders, and contained workflows when no transfer folder is specified', async () => {
|
||||
const project = await createTeamProject('test', owner);
|
||||
const rootFolder = await createFolder(project, { name: 'Root' });
|
||||
const childFolder = await createFolder(project, {
|
||||
name: 'Child',
|
||||
parentFolder: rootFolder,
|
||||
});
|
||||
|
||||
// Create workflows in the folders
|
||||
const workflow1 = await createWorkflow({ parentFolder: rootFolder }, owner);
|
||||
|
||||
const workflow2 = await createWorkflow({ parentFolder: childFolder }, owner);
|
||||
|
||||
await authOwnerAgent.delete(`/projects/${project.id}/folders/${rootFolder.id}`);
|
||||
|
||||
// Check folders
|
||||
const rootFolderInDb = await folderRepository.findOneBy({ id: rootFolder.id });
|
||||
const childFolderInDb = await folderRepository.findOneBy({ id: childFolder.id });
|
||||
|
||||
expect(rootFolderInDb).toBeNull();
|
||||
expect(childFolderInDb).toBeNull();
|
||||
|
||||
// Check workflows
|
||||
const workflow1InDb = await workflowRepository.findOneBy({ id: workflow1.id });
|
||||
const workflow2InDb = await workflowRepository.findOneBy({ id: workflow2.id });
|
||||
expect(workflow1InDb).toBeNull();
|
||||
expect(workflow2InDb).toBeNull();
|
||||
});
|
||||
|
||||
test('should transfer folder contents when transferToFolderId is specified', async () => {
|
||||
const project = await createTeamProject('test', owner);
|
||||
const sourceFolder = await createFolder(project, { name: 'Source' });
|
||||
const targetFolder = await createFolder(project, { name: 'Target' });
|
||||
const childFolder = await createFolder(project, {
|
||||
name: 'Child',
|
||||
parentFolder: sourceFolder,
|
||||
});
|
||||
|
||||
const workflow1 = await createWorkflow({ parentFolder: sourceFolder }, owner);
|
||||
|
||||
const workflow2 = await createWorkflow({ parentFolder: childFolder }, owner);
|
||||
|
||||
const payload = {
|
||||
transferToFolderId: targetFolder.id,
|
||||
};
|
||||
|
||||
await authOwnerAgent
|
||||
.delete(`/projects/${project.id}/folders/${sourceFolder.id}`)
|
||||
.send(payload)
|
||||
.expect(200);
|
||||
|
||||
const sourceFolderInDb = await folderRepository.findOne({
|
||||
where: { id: sourceFolder.id },
|
||||
relations: ['parentFolder'],
|
||||
});
|
||||
const childFolderInDb = await folderRepository.findOne({
|
||||
where: { id: childFolder.id },
|
||||
relations: ['parentFolder'],
|
||||
});
|
||||
|
||||
// Check folders
|
||||
expect(sourceFolderInDb).toBeNull();
|
||||
expect(childFolderInDb).toBeDefined();
|
||||
expect(childFolderInDb?.parentFolder?.id).toBe(targetFolder.id);
|
||||
|
||||
// Check workflows
|
||||
const workflow1InDb = await workflowRepository.findOne({
|
||||
where: { id: workflow1.id },
|
||||
relations: ['parentFolder'],
|
||||
});
|
||||
expect(workflow1InDb).toBeDefined();
|
||||
expect(workflow1InDb?.parentFolder?.id).toBe(targetFolder.id);
|
||||
|
||||
const workflow2InDb = await workflowRepository.findOne({
|
||||
where: { id: workflow2.id },
|
||||
relations: ['parentFolder'],
|
||||
});
|
||||
expect(workflow2InDb).toBeDefined();
|
||||
expect(workflow2InDb?.parentFolder?.id).toBe(childFolder.id);
|
||||
});
|
||||
|
||||
test('should not transfer folder contents when transfer folder does not exist', async () => {
|
||||
const project = await createTeamProject('test', owner);
|
||||
const folder = await createFolder(project);
|
||||
|
||||
const payload = {
|
||||
transferToFolderId: 'non-existing-folder',
|
||||
};
|
||||
|
||||
await authOwnerAgent
|
||||
.delete(`/projects/${project.id}/folders/${folder.id}`)
|
||||
.send(payload)
|
||||
.expect(404);
|
||||
|
||||
const folderInDb = await folderRepository.findOneBy({ id: folder.id });
|
||||
expect(folderInDb).toBeDefined();
|
||||
});
|
||||
|
||||
test('should not transfer folder contents when transfer folder is in another project', async () => {
|
||||
const project1 = await createTeamProject('Project 1', owner);
|
||||
const project2 = await createTeamProject('Project 2', owner);
|
||||
const sourceFolder = await createFolder(project1);
|
||||
const targetFolder = await createFolder(project2);
|
||||
|
||||
const payload = {
|
||||
transferToFolderId: targetFolder.id,
|
||||
};
|
||||
|
||||
await authOwnerAgent
|
||||
.delete(`/projects/${project1.id}/folders/${sourceFolder.id}`)
|
||||
.send(payload)
|
||||
.expect(404);
|
||||
|
||||
const folderInDb = await folderRepository.findOneBy({ id: sourceFolder.id });
|
||||
expect(folderInDb).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user