fix(plugin-custom-request): variables not work in form block (#2873)

* fix: custom-request not work in form

* feat: setup logger

* test: add test case and fix crush error

* feat: improve logger

* feat: update log option

* fix: logger

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
Dunqing 2023-10-19 09:49:33 -05:00 committed by GitHub
parent 07c5b7b0eb
commit 010c286f7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 111 additions and 50 deletions

View File

@ -19,7 +19,7 @@ const Transports = {
...options,
});
},
dailyRotateFile(options: any) {
dailyRotateFile(options: any = {}) {
let dirname = getLoggerFilePath();
if (!path.isAbsolute(dirname)) {
dirname = path.resolve(process.cwd(), dirname);

View File

@ -47,7 +47,7 @@ export const useCustomizeRequestActionProps = () => {
await form.submit();
}
const requestConfig = {};
let formValues = {};
const methods = ['POST', 'PUT', 'PATCH'];
if (xAction === 'customize:form:request' && methods.includes(options['method'])) {
const fieldNames = fields.map((field) => field.name);
@ -60,7 +60,7 @@ export const useCustomizeRequestActionProps = () => {
resource,
actionFields: getActiveFieldsName?.('form') || [],
});
requestConfig['data'] = values;
formValues = values;
}
actionField.data ??= {};
@ -70,10 +70,10 @@ export const useCustomizeRequestActionProps = () => {
url: `/customRequests:send/${fieldSchema['x-uid']}`,
method: 'POST',
data: {
requestConfig,
currentRecord: {
id: record[getPrimaryKey()],
appends: service.params[0].appends,
data: formValues,
},
},
});

View File

@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`actions send basic 1`] = `undefined`;
exports[`actions send currentRecord.data 1`] = `
{
"username": "testname",
}
`;

View File

@ -9,10 +9,10 @@ describe('actions', () => {
let agent: ReturnType<MockServer['agent']>;
let resource: ReturnType<ReturnType<MockServer['agent']>['resource']>;
beforeEach(async () => {
beforeAll(async () => {
app = mockServer({
registerActions: true,
acl: true,
acl: false,
plugins: ['users', 'auth', 'acl', 'custom-request'],
});
@ -24,35 +24,47 @@ describe('actions', () => {
});
describe('send', () => {
let params;
beforeEach(async () => {
app.resource({
name: 'custom-request-test',
actions: {
test(ctx: Context) {
params = ctx.action.params;
console.log('🚀 ~ file: actions.test.ts:34 ~ test ~ params:', params);
return 'test ok';
},
},
let params = null;
beforeAll(async () => {
app.resourcer.getResource('customRequests').addAction('test', (ctx: Context) => {
params = ctx.action.params.values;
return ctx.action.params.values;
});
});
beforeEach(async () => {
await repo.create({
values: {
key: 'test',
options: {
url: 'http://localhost:13000/api/custom-request-test:test',
url: '/customRequests:test',
method: 'GET',
data: {
username: '{{ currentRecord.username }}',
},
},
},
});
});
test('basic', async () => {
const res = await resource.send({
filterByTk: 'test',
});
console.log(res.status);
expect(res.status).toBe(200);
expect(params).toMatchSnapshot();
});
test('currentRecord.data', async () => {
const res = await resource.send({
filterByTk: 'test',
values: {
currentRecord: {
data: {
username: 'testname',
},
},
},
});
expect(res.status).toBe(200);
expect(params).toMatchSnapshot();
});
});
});

View File

@ -1,8 +1,8 @@
import { Context, Next } from '@nocobase/actions';
import actions from '@nocobase/actions';
import { parse } from '@nocobase/utils';
import axios from 'axios';
import CustomRequestPlugin from '../plugin';
const getHeaders = (headers: Record<string, any>) => {
return Object.keys(headers).reduce((hds, key) => {
@ -29,14 +29,14 @@ const omitNullAndUndefined = (obj: any) => {
}, {});
};
export async function send(ctx: Context, next: Next) {
export async function send(this: CustomRequestPlugin, ctx: Context, next: Next) {
const { filterByTk, resourceName, values = {} } = ctx.action.params;
const {
currentRecord: { id: currentRecordId, appends: currentRecordAppends } = {
currentRecord = {
id: 0,
appends: [],
data: {},
},
requestConfig: requestConfigFirst = {},
} = values;
// root role has all permissions
@ -68,45 +68,66 @@ export async function send(ctx: Context, next: Next) {
ctx.withoutDataWrapping = true;
const { collectionName, url, headers = {}, params = {}, data = {}, ...options } = requestConfig.options;
let currentRecord = {};
if (collectionName && typeof currentRecordId !== 'undefined') {
const { collectionName, url, headers = [], params = [], data = {}, ...options } = requestConfig.options;
let currentRecordVariables = {};
if (collectionName && typeof currentRecord.id !== 'undefined') {
const recordRepo = ctx.db.getRepository(collectionName);
currentRecord = await recordRepo.findOne({
filterByTk: currentRecordId,
appends: currentRecordAppends,
currentRecordVariables = await recordRepo.findOne({
filterByTk: currentRecord.id,
appends: currentRecord.appends,
});
}
const variables = {
currentRecord,
currentRecord: {
...currentRecordVariables,
...currentRecord.data,
},
currentUser: ctx.auth.user,
currentTime: new Date().toISOString(),
};
try {
ctx.body = await axios({
baseURL: ctx.origin,
...options,
url: parse(url)(variables),
const axiosRequestConfig = {
baseURL: ctx.origin,
...options,
url: parse(url)(variables),
headers: {
Authorization: 'Bearer ' + ctx.getBearerToken(),
...getHeaders(ctx.headers),
...omitNullAndUndefined(parse(arrayToObject(headers))(variables)),
},
params: parse(arrayToObject(params))(variables),
data: parse(data)(variables),
};
const requestUrl = axios.getUri(axiosRequestConfig);
this.logger.info(`custom-request:send:${filterByTk} request url ${requestUrl}`);
this.logger.info(
`custom-request:send:${filterByTk} request config ${JSON.stringify({
...axiosRequestConfig,
headers: {
Authorization: 'Bearer ' + ctx.getBearerToken(),
...getHeaders(ctx.headers),
...omitNullAndUndefined(parse(arrayToObject(headers))(variables)),
...axiosRequestConfig.headers,
Authorization: null,
},
params: parse(arrayToObject(params))(variables),
data: parse({
...data,
...requestConfigFirst?.data,
})(variables),
}).then((res) => {
})}`,
);
try {
ctx.body = await axios(axiosRequestConfig).then((res) => {
this.logger.info(`custom-request:send:${filterByTk} success`);
return res.data;
});
} catch (err: any) {
} catch (err) {
if (axios.isAxiosError(err)) {
ctx.status = err.response?.status || 500;
ctx.body = err.response?.data || { message: err.message };
this.logger.error(
`custom-request:send:${filterByTk} error. status: ${ctx.status}, body: ${
typeof ctx.body === 'string' ? ctx.body : JSON.stringify(ctx.body)
}`,
);
} else {
this.logger.error(`custom-request:send:${filterByTk} error. status: ${ctx.status}, message: ${err.message}`);
ctx.throw(500, err?.message);
}
}

View File

@ -1,12 +1,31 @@
import { Logger, LoggerOptions, Transports, createLogger, getLoggerFilePath } from '@nocobase/logger';
import { InstallOptions, Plugin } from '@nocobase/server';
import { resolve } from 'path';
import { send } from './actions/send';
import { listByCurrentRole } from './actions/listByCurrentRole';
import { send } from './actions/send';
export class CustomRequestPlugin extends Plugin {
logger: Logger;
afterAdd() {}
beforeLoad() {}
beforeLoad() {
this.logger = this.getLogger();
}
getLogger(): Logger {
const logger = createLogger({
transports: [
'console',
Transports.dailyRotateFile({
dirname: getLoggerFilePath('custom-request'),
filename: this.app.name + '-%DATE%.log',
}),
],
} as LoggerOptions);
return logger;
}
async load() {
await this.db.import({
@ -16,7 +35,7 @@ export class CustomRequestPlugin extends Plugin {
this.app.resource({
name: 'customRequests',
actions: {
send,
send: send.bind(this),
listByCurrentRole,
},
});