Merge pull request #2314 from automatisch/create-folder
feat: Implement create folder API endpoint
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
import { renderObject } from '../../../../helpers/renderer.js';
|
||||
|
||||
export default async (request, response) => {
|
||||
const folder = await request.currentUser
|
||||
.$relatedQuery('folders')
|
||||
.insertAndFetch({
|
||||
name: request.body.name,
|
||||
});
|
||||
|
||||
renderObject(response, folder, { status: 201 });
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import request from 'supertest';
|
||||
import app from '../../../../app.js';
|
||||
import createAuthTokenByUserId from '../../../../helpers/create-auth-token-by-user-id.js';
|
||||
import { createUser } from '../../../../../test/factories/user.js';
|
||||
import createFolderMock from '../../../../../test/mocks/rest/api/v1/folders/create-folder.js';
|
||||
import { createPermission } from '../../../../../test/factories/permission.js';
|
||||
|
||||
describe('POST /api/v1/folders', () => {
|
||||
let currentUser, currentUserRole, token;
|
||||
|
||||
beforeEach(async () => {
|
||||
currentUser = await createUser();
|
||||
currentUserRole = await currentUser.$relatedQuery('role');
|
||||
|
||||
token = await createAuthTokenByUserId(currentUser.id);
|
||||
});
|
||||
|
||||
it('should return created flow', async () => {
|
||||
await createPermission({
|
||||
action: 'create',
|
||||
subject: 'Flow',
|
||||
roleId: currentUserRole.id,
|
||||
conditions: ['isCreator'],
|
||||
});
|
||||
|
||||
const response = await request(app)
|
||||
.post('/api/v1/folders')
|
||||
.set('Authorization', token)
|
||||
.send({
|
||||
name: 'Test Folder',
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
const refetchedFolder = await currentUser
|
||||
.$relatedQuery('folders')
|
||||
.findById(response.body.data.id);
|
||||
|
||||
const expectedPayload = await createFolderMock(refetchedFolder);
|
||||
|
||||
expect(response.body).toMatchObject(expectedPayload);
|
||||
});
|
||||
});
|
||||
@@ -133,6 +133,10 @@ const authorizationList = {
|
||||
action: 'create',
|
||||
subject: 'Connection',
|
||||
},
|
||||
'POST /api/v1/folders/': {
|
||||
action: 'create',
|
||||
subject: 'Flow',
|
||||
},
|
||||
};
|
||||
|
||||
export const authorizeUser = async (request, response, next) => {
|
||||
|
||||
@@ -20,6 +20,7 @@ import Permission from './permission.js';
|
||||
import Role from './role.js';
|
||||
import Step from './step.js';
|
||||
import Subscription from './subscription.ee.js';
|
||||
import Folder from './folder.js';
|
||||
import UsageData from './usage-data.ee.js';
|
||||
import Billing from '../helpers/billing/index.ee.js';
|
||||
import NotAuthorizedError from '../errors/not-authorized.js';
|
||||
@@ -178,6 +179,14 @@ class User extends Base {
|
||||
to: 'users.id',
|
||||
},
|
||||
},
|
||||
folders: {
|
||||
relation: Base.HasManyRelation,
|
||||
modelClass: Folder,
|
||||
join: {
|
||||
from: 'users.id',
|
||||
to: 'folders.user_id',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
static get virtualAttributes() {
|
||||
|
||||
@@ -14,6 +14,7 @@ import Role from './role.js';
|
||||
import Step from './step.js';
|
||||
import Subscription from './subscription.ee.js';
|
||||
import UsageData from './usage-data.ee.js';
|
||||
import Folder from './folder.js';
|
||||
import User from './user.js';
|
||||
import deleteUserQueue from '../queues/delete-user.ee.js';
|
||||
import emailQueue from '../queues/email.js';
|
||||
@@ -153,6 +154,14 @@ describe('User model', () => {
|
||||
to: 'users.id',
|
||||
},
|
||||
},
|
||||
folders: {
|
||||
relation: Base.HasManyRelation,
|
||||
modelClass: Folder,
|
||||
join: {
|
||||
from: 'users.id',
|
||||
to: 'folders.user_id',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(relationMappings).toStrictEqual(expectedRelations);
|
||||
|
||||
10
packages/backend/src/routes/api/v1/folders.js
Normal file
10
packages/backend/src/routes/api/v1/folders.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Router } from 'express';
|
||||
import { authenticateUser } from '../../../helpers/authentication.js';
|
||||
import { authorizeUser } from '../../../helpers/authorization.js';
|
||||
import createFolderAction from '../../../controllers/api/v1/folders/create-folder.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post('/', authenticateUser, authorizeUser, createFolderAction);
|
||||
|
||||
export default router;
|
||||
@@ -19,6 +19,7 @@ import rolesRouter from './api/v1/admin/roles.ee.js';
|
||||
import permissionsRouter from './api/v1/admin/permissions.ee.js';
|
||||
import adminUsersRouter from './api/v1/admin/users.ee.js';
|
||||
import installationUsersRouter from './api/v1/installation/users.js';
|
||||
import foldersRouter from './api/v1/folders.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -42,5 +43,6 @@ router.use('/api/v1/admin/roles', rolesRouter);
|
||||
router.use('/api/v1/admin/permissions', permissionsRouter);
|
||||
router.use('/api/v1/admin/saml-auth-providers', adminSamlAuthProvidersRouter);
|
||||
router.use('/api/v1/installation/users', installationUsersRouter);
|
||||
router.use('/api/v1/folders', foldersRouter);
|
||||
|
||||
export default router;
|
||||
|
||||
10
packages/backend/src/serializers/folder.js
Normal file
10
packages/backend/src/serializers/folder.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const folderSerilializer = (folder) => {
|
||||
return {
|
||||
id: folder.id,
|
||||
name: folder.name,
|
||||
createdAt: folder.createdAt.getTime(),
|
||||
updatedAt: folder.updatedAt.getTime(),
|
||||
};
|
||||
};
|
||||
|
||||
export default folderSerilializer;
|
||||
22
packages/backend/src/serializers/folder.test.js
Normal file
22
packages/backend/src/serializers/folder.test.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { createFolder } from '../../test/factories/folder';
|
||||
import folderSerializer from './folder';
|
||||
|
||||
describe('folder serializer', () => {
|
||||
let folder;
|
||||
|
||||
beforeEach(async () => {
|
||||
folder = await createFolder();
|
||||
});
|
||||
|
||||
it('should return folder data', async () => {
|
||||
const expectedPayload = {
|
||||
id: folder.id,
|
||||
name: folder.name,
|
||||
createdAt: folder.createdAt.getTime(),
|
||||
updatedAt: folder.updatedAt.getTime(),
|
||||
};
|
||||
|
||||
expect(folderSerializer(folder)).toStrictEqual(expectedPayload);
|
||||
});
|
||||
});
|
||||
@@ -19,6 +19,7 @@ import executionStepSerializer from './execution-step.js';
|
||||
import subscriptionSerializer from './subscription.ee.js';
|
||||
import adminUserSerializer from './admin/user.js';
|
||||
import configSerializer from './config.js';
|
||||
import folderSerializer from './folder.js';
|
||||
|
||||
const serializers = {
|
||||
AdminUser: adminUserSerializer,
|
||||
@@ -42,6 +43,7 @@ const serializers = {
|
||||
ExecutionStep: executionStepSerializer,
|
||||
Subscription: subscriptionSerializer,
|
||||
Config: configSerializer,
|
||||
Folder: folderSerializer,
|
||||
};
|
||||
|
||||
export default serializers;
|
||||
|
||||
10
packages/backend/test/factories/folder.js
Normal file
10
packages/backend/test/factories/folder.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import Folder from '../../src/models/folder.js';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
export const createFolder = async (params = {}) => {
|
||||
params.name = params?.name || faker.lorem.word();
|
||||
|
||||
const folder = await Folder.query().insertAndFetch(params);
|
||||
|
||||
return folder;
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
const createFolderMock = async (flow) => {
|
||||
const data = {
|
||||
id: flow.id,
|
||||
name: flow.name,
|
||||
createdAt: flow.createdAt.getTime(),
|
||||
updatedAt: flow.updatedAt.getTime(),
|
||||
};
|
||||
|
||||
return {
|
||||
data: data,
|
||||
meta: {
|
||||
count: 1,
|
||||
currentPage: null,
|
||||
isArray: false,
|
||||
totalPages: null,
|
||||
type: 'Folder',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default createFolderMock;
|
||||
Reference in New Issue
Block a user