mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 09:36:44 +00:00
fix: Add folder scopes to global owner and admin roles (#19230)
This commit is contained in:
@@ -78,6 +78,11 @@ export const GLOBAL_OWNER_SCOPES: Scope[] = [
|
||||
'project:delete',
|
||||
'insights:list',
|
||||
'folder:move',
|
||||
'folder:read',
|
||||
'folder:update',
|
||||
'folder:delete',
|
||||
'folder:create',
|
||||
'folder:list',
|
||||
'oidc:manage',
|
||||
'dataStore:list',
|
||||
'role:manage',
|
||||
|
||||
@@ -18,8 +18,9 @@ import {
|
||||
Put,
|
||||
Param,
|
||||
Licensed,
|
||||
Middleware,
|
||||
} from '@n8n/decorators';
|
||||
import { Response } from 'express';
|
||||
import { NextFunction, Response } from 'express';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
import { FolderNotFoundError } from '@/errors/folder-not-found.error';
|
||||
@@ -28,14 +29,32 @@ import { InternalServerError } from '@/errors/response-errors/internal-server.er
|
||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||
import { FolderService } from '@/services/folder.service';
|
||||
import { EnterpriseWorkflowService } from '@/workflows/workflow.service.ee';
|
||||
import { ProjectService } from '@/services/project.service.ee';
|
||||
|
||||
@RestController('/projects/:projectId/folders')
|
||||
export class ProjectController {
|
||||
constructor(
|
||||
private readonly folderService: FolderService,
|
||||
private readonly enterpriseWorkflowService: EnterpriseWorkflowService,
|
||||
private readonly projectService: ProjectService,
|
||||
) {}
|
||||
|
||||
@Middleware()
|
||||
async validateProjectExists(
|
||||
req: AuthenticatedRequest<{ projectId: string }>,
|
||||
res: Response,
|
||||
next: NextFunction,
|
||||
) {
|
||||
try {
|
||||
const { projectId } = req.params;
|
||||
await this.projectService.getProject(projectId);
|
||||
next();
|
||||
} catch (e) {
|
||||
res.status(404).send('Project not found');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Post('/')
|
||||
@ProjectScope('folder:create')
|
||||
@Licensed('feat:folders')
|
||||
@@ -44,8 +63,10 @@ export class ProjectController {
|
||||
_res: Response,
|
||||
@Body payload: CreateFolderDto,
|
||||
) {
|
||||
const { projectId } = req.params;
|
||||
|
||||
try {
|
||||
const folder = await this.folderService.createFolder(payload, req.params.projectId);
|
||||
const folder = await this.folderService.createFolder(payload, projectId);
|
||||
return folder;
|
||||
} catch (e) {
|
||||
if (e instanceof FolderNotFoundError) {
|
||||
|
||||
@@ -87,7 +87,7 @@ describe('POST /projects/:projectId/folders', () => {
|
||||
name: 'Test Folder',
|
||||
};
|
||||
|
||||
await authOwnerAgent.post('/projects/non-existing-id/folders').send(payload).expect(403);
|
||||
await authOwnerAgent.post('/projects/non-existing-id/folders').send(payload).expect(404);
|
||||
});
|
||||
|
||||
test('should not create folder when name is empty', async () => {
|
||||
@@ -278,7 +278,7 @@ describe('GET /projects/:projectId/folders/:folderId/tree', () => {
|
||||
});
|
||||
|
||||
test('should not get folder tree when project does not exist', async () => {
|
||||
await authOwnerAgent.get('/projects/non-existing-id/folders/some-folder-id/tree').expect(403);
|
||||
await authOwnerAgent.get('/projects/non-existing-id/folders/some-folder-id/tree').expect(404);
|
||||
});
|
||||
|
||||
test('should not get folder tree when folder does not exist', async () => {
|
||||
@@ -418,7 +418,7 @@ describe('GET /projects/:projectId/folders/:folderId/credentials', () => {
|
||||
test('should not get folder credentials when project does not exist', async () => {
|
||||
await authOwnerAgent
|
||||
.get('/projects/non-existing-id/folders/some-folder-id/credentials')
|
||||
.expect(403);
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
test('should not get folder credentials when folder does not exist', async () => {
|
||||
@@ -545,7 +545,7 @@ describe('PATCH /projects/:projectId/folders/:folderId', () => {
|
||||
await authOwnerAgent
|
||||
.patch('/projects/non-existing-id/folders/some-folder-id')
|
||||
.send(payload)
|
||||
.expect(403);
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
test('should not update folder when folder does not exist', async () => {
|
||||
@@ -1005,7 +1005,7 @@ describe('DELETE /projects/:projectId/folders/:folderId', () => {
|
||||
await authOwnerAgent
|
||||
.delete('/projects/non-existing-id/folders/some-folder-id')
|
||||
.send({})
|
||||
.expect(403);
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
test('should not delete folder when folder does not exist', async () => {
|
||||
@@ -1303,7 +1303,7 @@ describe('GET /projects/:projectId/folders', () => {
|
||||
});
|
||||
|
||||
test('should not list folders when project does not exist', async () => {
|
||||
await authOwnerAgent.get('/projects/non-existing-id/folders').expect(403);
|
||||
await authOwnerAgent.get('/projects/non-existing-id/folders').expect(404);
|
||||
});
|
||||
|
||||
test('should not list folders if user has no access to project', async () => {
|
||||
@@ -1731,7 +1731,7 @@ describe('GET /projects/:projectId/folders/content', () => {
|
||||
test('should not list folders when project does not exist', async () => {
|
||||
await authOwnerAgent
|
||||
.get('/projects/non-existing-id/folders/no-existing-id/content')
|
||||
.expect(403);
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
test('should not return folder content if user has no access to project', async () => {
|
||||
|
||||
@@ -853,6 +853,30 @@ describe('GET /project/:projectId', () => {
|
||||
role: 'project:admin',
|
||||
});
|
||||
});
|
||||
|
||||
test('should have correct folder scopes when, as an admin / owner, I fetch a project created by a different user', async () => {
|
||||
const [ownerUser, testUser1] = await Promise.all([createOwner(), createUser()]);
|
||||
|
||||
const createdProject = await createTeamProject(undefined, testUser1);
|
||||
|
||||
const memberAgent = testServer.authAgentFor(ownerUser);
|
||||
|
||||
const resp = await memberAgent.get(`/projects/${createdProject.id}`);
|
||||
expect(resp.status).toBe(200);
|
||||
|
||||
expect(resp.body.data.id).toBe(createdProject.id);
|
||||
expect(resp.body.data.name).toBe(createdProject.name);
|
||||
|
||||
expect(resp.body.data.scopes).toEqual(
|
||||
expect.arrayContaining([
|
||||
'folder:read',
|
||||
'folder:update',
|
||||
'folder:delete',
|
||||
'folder:create',
|
||||
'folder:list',
|
||||
]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE /project/:projectId', () => {
|
||||
|
||||
Reference in New Issue
Block a user