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:
parent
07c5b7b0eb
commit
010c286f7c
@ -19,7 +19,7 @@ const Transports = {
|
|||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
dailyRotateFile(options: any) {
|
dailyRotateFile(options: any = {}) {
|
||||||
let dirname = getLoggerFilePath();
|
let dirname = getLoggerFilePath();
|
||||||
if (!path.isAbsolute(dirname)) {
|
if (!path.isAbsolute(dirname)) {
|
||||||
dirname = path.resolve(process.cwd(), dirname);
|
dirname = path.resolve(process.cwd(), dirname);
|
||||||
|
@ -47,7 +47,7 @@ export const useCustomizeRequestActionProps = () => {
|
|||||||
await form.submit();
|
await form.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestConfig = {};
|
let formValues = {};
|
||||||
const methods = ['POST', 'PUT', 'PATCH'];
|
const methods = ['POST', 'PUT', 'PATCH'];
|
||||||
if (xAction === 'customize:form:request' && methods.includes(options['method'])) {
|
if (xAction === 'customize:form:request' && methods.includes(options['method'])) {
|
||||||
const fieldNames = fields.map((field) => field.name);
|
const fieldNames = fields.map((field) => field.name);
|
||||||
@ -60,7 +60,7 @@ export const useCustomizeRequestActionProps = () => {
|
|||||||
resource,
|
resource,
|
||||||
actionFields: getActiveFieldsName?.('form') || [],
|
actionFields: getActiveFieldsName?.('form') || [],
|
||||||
});
|
});
|
||||||
requestConfig['data'] = values;
|
formValues = values;
|
||||||
}
|
}
|
||||||
|
|
||||||
actionField.data ??= {};
|
actionField.data ??= {};
|
||||||
@ -70,10 +70,10 @@ export const useCustomizeRequestActionProps = () => {
|
|||||||
url: `/customRequests:send/${fieldSchema['x-uid']}`,
|
url: `/customRequests:send/${fieldSchema['x-uid']}`,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: {
|
||||||
requestConfig,
|
|
||||||
currentRecord: {
|
currentRecord: {
|
||||||
id: record[getPrimaryKey()],
|
id: record[getPrimaryKey()],
|
||||||
appends: service.params[0].appends,
|
appends: service.params[0].appends,
|
||||||
|
data: formValues,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -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",
|
||||||
|
}
|
||||||
|
`;
|
@ -9,10 +9,10 @@ describe('actions', () => {
|
|||||||
let agent: ReturnType<MockServer['agent']>;
|
let agent: ReturnType<MockServer['agent']>;
|
||||||
let resource: ReturnType<ReturnType<MockServer['agent']>['resource']>;
|
let resource: ReturnType<ReturnType<MockServer['agent']>['resource']>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeAll(async () => {
|
||||||
app = mockServer({
|
app = mockServer({
|
||||||
registerActions: true,
|
registerActions: true,
|
||||||
acl: true,
|
acl: false,
|
||||||
plugins: ['users', 'auth', 'acl', 'custom-request'],
|
plugins: ['users', 'auth', 'acl', 'custom-request'],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -24,35 +24,47 @@ describe('actions', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('send', () => {
|
describe('send', () => {
|
||||||
let params;
|
let params = null;
|
||||||
beforeEach(async () => {
|
beforeAll(async () => {
|
||||||
app.resource({
|
app.resourcer.getResource('customRequests').addAction('test', (ctx: Context) => {
|
||||||
name: 'custom-request-test',
|
params = ctx.action.params.values;
|
||||||
actions: {
|
return ctx.action.params.values;
|
||||||
test(ctx: Context) {
|
|
||||||
params = ctx.action.params;
|
|
||||||
console.log('🚀 ~ file: actions.test.ts:34 ~ test ~ params:', params);
|
|
||||||
return 'test ok';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
beforeEach(async () => {
|
|
||||||
await repo.create({
|
await repo.create({
|
||||||
values: {
|
values: {
|
||||||
key: 'test',
|
key: 'test',
|
||||||
options: {
|
options: {
|
||||||
url: 'http://localhost:13000/api/custom-request-test:test',
|
url: '/customRequests:test',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
data: {
|
||||||
|
username: '{{ currentRecord.username }}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('basic', async () => {
|
test('basic', async () => {
|
||||||
const res = await resource.send({
|
const res = await resource.send({
|
||||||
filterByTk: 'test',
|
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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Context, Next } from '@nocobase/actions';
|
import { Context, Next } from '@nocobase/actions';
|
||||||
import actions from '@nocobase/actions';
|
|
||||||
import { parse } from '@nocobase/utils';
|
import { parse } from '@nocobase/utils';
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import CustomRequestPlugin from '../plugin';
|
||||||
|
|
||||||
const getHeaders = (headers: Record<string, any>) => {
|
const getHeaders = (headers: Record<string, any>) => {
|
||||||
return Object.keys(headers).reduce((hds, key) => {
|
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 { filterByTk, resourceName, values = {} } = ctx.action.params;
|
||||||
const {
|
const {
|
||||||
currentRecord: { id: currentRecordId, appends: currentRecordAppends } = {
|
currentRecord = {
|
||||||
id: 0,
|
id: 0,
|
||||||
appends: [],
|
appends: [],
|
||||||
|
data: {},
|
||||||
},
|
},
|
||||||
requestConfig: requestConfigFirst = {},
|
|
||||||
} = values;
|
} = values;
|
||||||
|
|
||||||
// root role has all permissions
|
// root role has all permissions
|
||||||
@ -68,24 +68,26 @@ export async function send(ctx: Context, next: Next) {
|
|||||||
|
|
||||||
ctx.withoutDataWrapping = true;
|
ctx.withoutDataWrapping = true;
|
||||||
|
|
||||||
const { collectionName, url, headers = {}, params = {}, data = {}, ...options } = requestConfig.options;
|
const { collectionName, url, headers = [], params = [], data = {}, ...options } = requestConfig.options;
|
||||||
let currentRecord = {};
|
let currentRecordVariables = {};
|
||||||
if (collectionName && typeof currentRecordId !== 'undefined') {
|
if (collectionName && typeof currentRecord.id !== 'undefined') {
|
||||||
const recordRepo = ctx.db.getRepository(collectionName);
|
const recordRepo = ctx.db.getRepository(collectionName);
|
||||||
currentRecord = await recordRepo.findOne({
|
currentRecordVariables = await recordRepo.findOne({
|
||||||
filterByTk: currentRecordId,
|
filterByTk: currentRecord.id,
|
||||||
appends: currentRecordAppends,
|
appends: currentRecord.appends,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const variables = {
|
const variables = {
|
||||||
currentRecord,
|
currentRecord: {
|
||||||
|
...currentRecordVariables,
|
||||||
|
...currentRecord.data,
|
||||||
|
},
|
||||||
currentUser: ctx.auth.user,
|
currentUser: ctx.auth.user,
|
||||||
currentTime: new Date().toISOString(),
|
currentTime: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
const axiosRequestConfig = {
|
||||||
ctx.body = await axios({
|
|
||||||
baseURL: ctx.origin,
|
baseURL: ctx.origin,
|
||||||
...options,
|
...options,
|
||||||
url: parse(url)(variables),
|
url: parse(url)(variables),
|
||||||
@ -95,18 +97,37 @@ export async function send(ctx: Context, next: Next) {
|
|||||||
...omitNullAndUndefined(parse(arrayToObject(headers))(variables)),
|
...omitNullAndUndefined(parse(arrayToObject(headers))(variables)),
|
||||||
},
|
},
|
||||||
params: parse(arrayToObject(params))(variables),
|
params: parse(arrayToObject(params))(variables),
|
||||||
data: parse({
|
data: parse(data)(variables),
|
||||||
...data,
|
};
|
||||||
...requestConfigFirst?.data,
|
|
||||||
})(variables),
|
const requestUrl = axios.getUri(axiosRequestConfig);
|
||||||
}).then((res) => {
|
this.logger.info(`custom-request:send:${filterByTk} request url ${requestUrl}`);
|
||||||
|
this.logger.info(
|
||||||
|
`custom-request:send:${filterByTk} request config ${JSON.stringify({
|
||||||
|
...axiosRequestConfig,
|
||||||
|
headers: {
|
||||||
|
...axiosRequestConfig.headers,
|
||||||
|
Authorization: null,
|
||||||
|
},
|
||||||
|
})}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ctx.body = await axios(axiosRequestConfig).then((res) => {
|
||||||
|
this.logger.info(`custom-request:send:${filterByTk} success`);
|
||||||
return res.data;
|
return res.data;
|
||||||
});
|
});
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
if (axios.isAxiosError(err)) {
|
if (axios.isAxiosError(err)) {
|
||||||
ctx.status = err.response?.status || 500;
|
ctx.status = err.response?.status || 500;
|
||||||
ctx.body = err.response?.data || { message: err.message };
|
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 {
|
} else {
|
||||||
|
this.logger.error(`custom-request:send:${filterByTk} error. status: ${ctx.status}, message: ${err.message}`);
|
||||||
ctx.throw(500, err?.message);
|
ctx.throw(500, err?.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,31 @@
|
|||||||
|
import { Logger, LoggerOptions, Transports, createLogger, getLoggerFilePath } from '@nocobase/logger';
|
||||||
import { InstallOptions, Plugin } from '@nocobase/server';
|
import { InstallOptions, Plugin } from '@nocobase/server';
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
import { send } from './actions/send';
|
|
||||||
import { listByCurrentRole } from './actions/listByCurrentRole';
|
import { listByCurrentRole } from './actions/listByCurrentRole';
|
||||||
|
import { send } from './actions/send';
|
||||||
|
|
||||||
export class CustomRequestPlugin extends Plugin {
|
export class CustomRequestPlugin extends Plugin {
|
||||||
|
logger: Logger;
|
||||||
|
|
||||||
afterAdd() {}
|
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() {
|
async load() {
|
||||||
await this.db.import({
|
await this.db.import({
|
||||||
@ -16,7 +35,7 @@ export class CustomRequestPlugin extends Plugin {
|
|||||||
this.app.resource({
|
this.app.resource({
|
||||||
name: 'customRequests',
|
name: 'customRequests',
|
||||||
actions: {
|
actions: {
|
||||||
send,
|
send: send.bind(this),
|
||||||
listByCurrentRole,
|
listByCurrentRole,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user