Skip to content

Commit

Permalink
Merge pull request #999 from merico-dev/split-create-or-update
Browse files Browse the repository at this point in the history
Split createOrUpdate into separate functions
  • Loading branch information
GerilLeto authored Jun 6, 2023
2 parents 7486517 + b28c8ae commit 036749a
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 53 deletions.
40 changes: 33 additions & 7 deletions api/src/controller/custom_function.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as express from 'express';
import { inject, interfaces as inverfaces } from 'inversify';
import { controller, httpPost, interfaces } from 'inversify-express-utils';
import { ApiOperationPost, ApiPath, SwaggerDefinitionConstant } from 'swagger-express-ts';
import { controller, httpPost, httpPut, interfaces } from 'inversify-express-utils';
import { ApiOperationPost, ApiOperationPut, ApiPath, SwaggerDefinitionConstant } from 'swagger-express-ts';
import { validate } from '../middleware/validation';
import { ROLE_TYPES } from '../api_models/role';
import permission from '../middleware/permission';
Expand Down Expand Up @@ -54,8 +54,8 @@ export class CustomFunctionController implements interfaces.Controller {
}

@ApiOperationPost({
path: '/createOrUpdate',
description: 'Create or update a custom function',
path: '/create',
description: 'Create a custom function',
parameters: {
body: {
description: 'custom function create or update request',
Expand All @@ -68,11 +68,11 @@ export class CustomFunctionController implements interfaces.Controller {
500: { description: 'SERVER ERROR', type: SwaggerDefinitionConstant.Response.Type.OBJECT, model: 'ApiError' },
},
})
@httpPost('/createOrUpdate', permission(ROLE_TYPES.ADMIN), validate(CustomFunctionCreateOrUpdateRequest))
public async createOrUpdate(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {
@httpPost('/create', permission(ROLE_TYPES.ADMIN), validate(CustomFunctionCreateOrUpdateRequest))
public async create(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {
try {
const { id, definition } = req.body as CustomFunctionCreateOrUpdateRequest;
const result = await this.customFunctionService.createOrUpdate(id, definition, req.locale);
const result = await this.customFunctionService.create(id, definition, req.locale);
res.json(result);
} catch (err) {
next(err);
Expand Down Expand Up @@ -105,6 +105,32 @@ export class CustomFunctionController implements interfaces.Controller {
}
}

@ApiOperationPut({
path: '/update',
description: 'Update a custom function',
parameters: {
body: {
description: 'custom function create or update request',
required: true,
model: 'CustomFunctionCreateOrUpdateRequest',
},
},
responses: {
200: { description: 'SUCCESS', type: SwaggerDefinitionConstant.Response.Type.OBJECT, model: 'CustomFunction' },
500: { description: 'SERVER ERROR', type: SwaggerDefinitionConstant.Response.Type.OBJECT, model: 'ApiError' },
},
})
@httpPut('/update', permission(ROLE_TYPES.ADMIN), validate(CustomFunctionCreateOrUpdateRequest))
public async update(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {
try {
const { id, definition } = req.body as CustomFunctionCreateOrUpdateRequest;
const result = await this.customFunctionService.update(id, definition, req.locale);
res.json(result);
} catch (err) {
next(err);
}
}

@ApiOperationPost({
path: '/delete',
description: 'Delete a custom function',
Expand Down
40 changes: 33 additions & 7 deletions api/src/controller/sql_snippet.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as express from 'express';
import { inject, interfaces as inverfaces } from 'inversify';
import { controller, httpPost, interfaces } from 'inversify-express-utils';
import { ApiOperationPost, ApiPath, SwaggerDefinitionConstant } from 'swagger-express-ts';
import { controller, httpPost, httpPut, interfaces } from 'inversify-express-utils';
import { ApiOperationPost, ApiOperationPut, ApiPath, SwaggerDefinitionConstant } from 'swagger-express-ts';
import { validate } from '../middleware/validation';
import { ROLE_TYPES } from '../api_models/role';
import permission from '../middleware/permission';
Expand Down Expand Up @@ -48,8 +48,8 @@ export class SqlSnippetController implements interfaces.Controller {
}

@ApiOperationPost({
path: '/createOrUpdate',
description: 'Create or update a sql snippet',
path: '/create',
description: 'Create a sql snippet',
parameters: {
body: {
description: 'sql snippet create or update request',
Expand All @@ -62,11 +62,11 @@ export class SqlSnippetController implements interfaces.Controller {
500: { description: 'SERVER ERROR', type: SwaggerDefinitionConstant.Response.Type.OBJECT, model: 'ApiError' },
},
})
@httpPost('/createOrUpdate', permission(ROLE_TYPES.ADMIN), validate(SqlSnippetCreateOrUpdateRequest))
public async createOrUpdate(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {
@httpPost('/create', permission(ROLE_TYPES.ADMIN), validate(SqlSnippetCreateOrUpdateRequest))
public async create(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {
try {
const { id, content } = req.body as SqlSnippetCreateOrUpdateRequest;
const result = await this.sqlSnippetService.createOrUpdate(id, content, req.locale);
const result = await this.sqlSnippetService.create(id, content, req.locale);
res.json(result);
} catch (err) {
next(err);
Expand Down Expand Up @@ -99,6 +99,32 @@ export class SqlSnippetController implements interfaces.Controller {
}
}

@ApiOperationPut({
path: '/update',
description: 'Update a sql snippet',
parameters: {
body: {
description: 'sql snippet create or update request',
required: true,
model: 'SqlSnippetCreateOrUpdateRequest',
},
},
responses: {
200: { description: 'SUCCESS', type: SwaggerDefinitionConstant.Response.Type.OBJECT, model: 'SqlSnippet' },
500: { description: 'SERVER ERROR', type: SwaggerDefinitionConstant.Response.Type.OBJECT, model: 'ApiError' },
},
})
@httpPut('/update', permission(ROLE_TYPES.ADMIN), validate(SqlSnippetCreateOrUpdateRequest))
public async update(req: express.Request, res: express.Response, next: express.NextFunction): Promise<void> {
try {
const { id, content } = req.body as SqlSnippetCreateOrUpdateRequest;
const result = await this.sqlSnippetService.update(id, content, req.locale);
res.json(result);
} catch (err) {
next(err);
}
}

@ApiOperationPost({
path: '/delete',
description: 'Delete a sql snippet',
Expand Down
2 changes: 2 additions & 0 deletions api/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@
"DASHBOARD_CONTENT_EDIT_REQUIRES_SUPERADMIN": "Only superadmin can edit preset dashboard contents",
"DASHBOARD_CONTENT_DELETE_REQUIRES_SUPERADMIN": "Only superadmin can delete preset dashboard contents",
"DASHBOARD_CONTENT_DOES_NOT_EXIST": "That dashboard content does not exist",
"CUSTOM_FUNCTION_ALREADY_EXISTS": "A custom function with that id already exists",
"CUSTOM_FUNCTION_NO_EDIT_PRESET": "Preset custom functions can not be edited",
"CUSTOM_FUNCTION_NO_DELETE_PRESET": "Preset custom functions can not be deleted",
"SQL_SNIPPET_ALREADY_EXISTS": "A sql snippet with that id already exists",
"SQL_SNIPPET_NO_EDIT_PRESET": "Preset sql snippets can not be edited",
"SQL_SNIPPET_NO_DELETE_PRESET": "Preset sql snippets can not be deleted"
}
2 changes: 2 additions & 0 deletions api/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@
"DASHBOARD_CONTENT_EDIT_REQUIRES_SUPERADMIN": "只有超级管理员才能编辑预设报表内容",
"DASHBOARD_CONTENT_DELETE_REQUIRES_SUPERADMIN": "只有超级管理员才能删除预设报表内容",
"DASHBOARD_CONTENT_DOES_NOT_EXIST": "目标报表内容不存在",
"CUSTOM_FUNCTION_ALREADY_EXISTS": "具有该ID的自定义函数已存在",
"CUSTOM_FUNCTION_NO_EDIT_PRESET": "不能修改预设自定义函数",
"CUSTOM_FUNCTION_NO_DELETE_PRESET": "不能删除预设自定义函数",
"SQL_SNIPPET_ALREADY_EXISTS": "具有该ID的sql snippet已存在",
"SQL_SNIPPET_NO_EDIT_PRESET": "不能修改预设sql snippets",
"SQL_SNIPPET_NO_DELETE_PRESET": "不能删除预设sql snippets"
}
21 changes: 14 additions & 7 deletions api/src/services/custom_function.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,22 @@ export class CustomFunctionService {
return await customFunctionRepo.findOneByOrFail({ id });
}

async createOrUpdate(id: string, definition: string, locale: string): Promise<CustomFunctionAPIModel> {
async create(id: string, definition: string, locale: string): Promise<CustomFunctionAPIModel> {
const customFunctionRepo = dashboardDataSource.getRepository(CustomFunction);
let customFunction = await customFunctionRepo.findOneBy({ id });
if (customFunction && customFunction.is_preset) {
throw new ApiError(BAD_REQUEST, { message: translate('CUSTOM_FUNCTION_NO_EDIT_PRESET', locale) });
if (await customFunctionRepo.exist({ where: { id } })) {
throw new ApiError(BAD_REQUEST, { message: translate('CUSTOM_FUNCTION_ALREADY_EXISTS', locale) });
}
if (!customFunction) {
customFunction = new CustomFunction();
customFunction.id = id;
const customFunction = new CustomFunction();
customFunction.id = id;
customFunction.definition = definition;
return await customFunctionRepo.save(customFunction);
}

async update(id: string, definition: string, locale: string): Promise<CustomFunctionAPIModel> {
const customFunctionRepo = dashboardDataSource.getRepository(CustomFunction);
const customFunction = await customFunctionRepo.findOneByOrFail({ id });
if (customFunction.is_preset) {
throw new ApiError(BAD_REQUEST, { message: translate('CUSTOM_FUNCTION_NO_EDIT_PRESET', locale) });
}
customFunction.definition = definition;
return await customFunctionRepo.save(customFunction);
Expand Down
21 changes: 14 additions & 7 deletions api/src/services/sql_snippet.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,22 @@ export class SqlSnippetService {
return await sqlSnippetRepo.findOneByOrFail({ id });
}

async createOrUpdate(id: string, content: string, locale: string): Promise<SqlSnippetAPIModel> {
async create(id: string, content: string, locale: string): Promise<SqlSnippetAPIModel> {
const sqlSnippetRepo = dashboardDataSource.getRepository(SqlSnippet);
let sqlSnippet = await sqlSnippetRepo.findOneBy({ id });
if (sqlSnippet && sqlSnippet.is_preset) {
throw new ApiError(BAD_REQUEST, { message: translate('SQL_SNIPPET_NO_EDIT_PRESET', locale) });
if (await sqlSnippetRepo.exist({ where: { id } })) {
throw new ApiError(BAD_REQUEST, { message: translate('SQL_SNIPPET_ALREADY_EXISTS', locale) });
}
if (!sqlSnippet) {
sqlSnippet = new SqlSnippet();
sqlSnippet.id = id;
const sqlSnippet = new SqlSnippet();
sqlSnippet.id = id;
sqlSnippet.content = content;
return await sqlSnippetRepo.save(sqlSnippet);
}

async update(id: string, content: string, locale: string): Promise<SqlSnippetAPIModel> {
const sqlSnippetRepo = dashboardDataSource.getRepository(SqlSnippet);
const sqlSnippet = await sqlSnippetRepo.findOneByOrFail({ id });
if (sqlSnippet.is_preset) {
throw new ApiError(BAD_REQUEST, { message: translate('SQL_SNIPPET_NO_EDIT_PRESET', locale) });
}
sqlSnippet.content = content;
return await sqlSnippetRepo.save(sqlSnippet);
Expand Down
7 changes: 5 additions & 2 deletions api/src/utils/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,12 @@ type DASHBOARD_CONTENT_KEYS =
| 'DASHBOARD_CONTENT_DELETE_REQUIRES_SUPERADMIN'
| 'DASHBOARD_CONTENT_DOES_NOT_EXIST';

type CUSTOM_FUNCTION_KEYS = 'CUSTOM_FUNCTION_NO_DELETE_PRESET' | 'CUSTOM_FUNCTION_NO_EDIT_PRESET';
type CUSTOM_FUNCTION_KEYS =
| 'CUSTOM_FUNCTION_ALREADY_EXISTS'
| 'CUSTOM_FUNCTION_NO_DELETE_PRESET'
| 'CUSTOM_FUNCTION_NO_EDIT_PRESET';

type SQL_SNIPPET_KEYS = 'SQL_SNIPPET_NO_EDIT_PRESET' | 'SQL_SNIPPET_NO_DELETE_PRESET';
type SQL_SNIPPET_KEYS = 'SQL_SNIPPET_ALREADY_EXISTS' | 'SQL_SNIPPET_NO_EDIT_PRESET' | 'SQL_SNIPPET_NO_DELETE_PRESET';

type LANGUAGE_KEYS =
| ACCOUNT_KEYS
Expand Down
4 changes: 4 additions & 0 deletions api/tests/e2e/06_query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ describe('QueryController', () => {

it('should query http successfully with GET', async () => {
const httpParams: HttpParams = {
host: '',
method: 'GET',
data: {},
params: {},
Expand Down Expand Up @@ -90,6 +91,7 @@ describe('QueryController', () => {

it('should query http successfully with POST', async () => {
const httpParams: HttpParams = {
host: '',
method: 'POST',
data: { title: 'foo', body: 'bar', userId: 1 },
params: {},
Expand All @@ -109,6 +111,7 @@ describe('QueryController', () => {

it('should query http successfully with PUT', async () => {
const httpParams: HttpParams = {
host: '',
method: 'PUT',
data: { id: 1, title: 'foo', body: 'bar', userId: 1 },
params: {},
Expand All @@ -128,6 +131,7 @@ describe('QueryController', () => {

it('should query http successfully with DELETE', async () => {
const httpParams: HttpParams = {
host: '',
method: 'DELETE',
data: {},
params: {},
Expand Down
47 changes: 41 additions & 6 deletions api/tests/e2e/13_custom_function.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from '~/api_models/custom_function';
import { notFoundId } from './constants';

describe('DashboardChangelogController', () => {
describe('CustomFunctionController', () => {
connectionHook();
let superadminLogin: AccountLoginResponse;

Expand All @@ -34,15 +34,15 @@ describe('DashboardChangelogController', () => {
await dashboardDataSource.getRepository(CustomFunction).save(presetCustomFunction);
});

describe('createOrUpdate', () => {
describe('create', () => {
it('should create successfully', async () => {
const request1: CustomFunctionCreateOrUpdateRequest = {
id: 'customFunction1',
definition: '() => console.log("hello world 1")',
};

const response1 = await server
.post('/custom_function/createOrUpdate')
.post('/custom_function/create')
.set('Authorization', `Bearer ${superadminLogin.token}`)
.send(request1);

Expand All @@ -59,7 +59,7 @@ describe('DashboardChangelogController', () => {
};

const response2 = await server
.post('/custom_function/createOrUpdate')
.post('/custom_function/create')
.set('Authorization', `Bearer ${superadminLogin.token}`)
.send(request2);

Expand All @@ -70,14 +70,33 @@ describe('DashboardChangelogController', () => {
});
});

it('should fail if duplicate', async () => {
const request: CustomFunctionCreateOrUpdateRequest = {
id: 'customFunction1',
definition: '() => console.log("hello world 1")',
};

const response = await server
.post('/custom_function/create')
.set('Authorization', `Bearer ${superadminLogin.token}`)
.send(request);

expect(response.body).toMatchObject({
code: 'BAD_REQUEST',
detail: { message: 'A custom function with that id already exists' },
});
});
});

describe('update', () => {
it('should update successfully', async () => {
const request: CustomFunctionCreateOrUpdateRequest = {
id: 'customFunction1',
definition: '() => console.log("hello world 1 updated")',
};

const response = await server
.post('/custom_function/createOrUpdate')
.put('/custom_function/update')
.set('Authorization', `Bearer ${superadminLogin.token}`)
.send(request);

Expand All @@ -95,7 +114,7 @@ describe('DashboardChangelogController', () => {
};

const response = await server
.post('/custom_function/createOrUpdate')
.put('/custom_function/update')
.set('Authorization', `Bearer ${superadminLogin.token}`)
.send(request);

Expand All @@ -104,6 +123,22 @@ describe('DashboardChangelogController', () => {
detail: { message: 'Preset custom functions can not be edited' },
});
});

it('should fail if not found', async () => {
const request: CustomFunctionCreateOrUpdateRequest = {
id: notFoundId,
definition: '',
};

const response = await server
.put('/custom_function/update')
.set('Authorization', `Bearer ${superadminLogin.token}`)
.send(request);

expect(response.body.code).toEqual('NOT_FOUND');
expect(response.body.detail.message).toContain('Could not find any entity of type "CustomFunction" matching');
expect(response.body.detail.message).toContain(notFoundId);
});
});

describe('list', () => {
Expand Down
Loading

0 comments on commit 036749a

Please sign in to comment.