yapi-next/vendors/server/controllers/open.js
2023-06-27 18:59:45 +08:00

423 lines
12 KiB
JavaScript

const projectModel = require('../models/project.js');
const interfaceColModel = require('../models/interfaceCol.js');
const interfaceCaseModel = require('../models/interfaceCase.js');
const interfaceModel = require('../models/interface.js');
const interfaceCatModel = require('../models/interfaceCat.js');
const followModel = require('../models/follow.js');
const userModel = require('../models/user.js');
const yapi = require('../yapi.js');
const baseController = require('./base.js');
const {
handleParams,
crossRequest,
handleCurrDomain,
checkNameIsExistInArray
} = require('../../common/postmanLib');
const { handleParamsValue, ArrayToObject } = require('../../common/utils.js');
const renderToHtml = require('../utils/reportHtml');
const HanldeImportData = require('../../common/HandleImportData');
const _ = require('underscore');
const createContex = require('../../common/createContext')
/**
* {
* postman: require('./m')
* }
*/
const importDataModule = {};
class openController extends baseController {
constructor(ctx) {
super(ctx);
this.projectModel = yapi.getInst(projectModel);
this.interfaceColModel = yapi.getInst(interfaceColModel);
this.interfaceCaseModel = yapi.getInst(interfaceCaseModel);
this.interfaceModel = yapi.getInst(interfaceModel);
this.interfaceCatModel = yapi.getInst(interfaceCatModel);
this.followModel = yapi.getInst(followModel);
this.userModel = yapi.getInst(userModel);
this.handleValue = this.handleValue.bind(this);
this.schemaMap = {
runAutoTest: {
'*id': 'number',
project_id: 'string',
token: 'string',
mode: {
type: 'string',
default: 'html'
},
email: {
type: 'boolean',
default: false
},
download: {
type: 'boolean',
default: false
},
closeRemoveAdditional: true
},
importData: {
'*type': 'string',
url: 'string',
'*token': 'string',
json: 'string',
project_id: 'string',
merge: {
type: 'string',
default: 'normal'
}
}
};
yapi.emitHook('import_data', importDataModule);
}
async importData(ctx) {
let type = ctx.params.type;
let content = ctx.params.json;
let project_id = ctx.params.project_id;
let dataSync = ctx.params.merge;
let warnMessage = ''
/**
* 因为以前接口文档写错了,做下兼容
*/
try{
if(!dataSync &&ctx.params.dataSync){
warnMessage = 'importData Api 已废弃 dataSync 传参,请联系管理员将 dataSync 改为 merge.'
dataSync = ctx.params.dataSync
}
}catch(e){}
let token = ctx.params.token;
if (!type || !importDataModule[type]) {
return (ctx.body = yapi.commons.resReturn(null, 40022, '不存在的导入方式'));
}
if (!content && !ctx.params.url) {
return (ctx.body = yapi.commons.resReturn(null, 40022, 'json 或者 url 参数,不能都为空'));
}
try {
let request = require("request");// let Promise = require('Promise');
let syncGet = function (url){
return new Promise(function(resolve, reject){
request.get({url : url}, function(error, response, body){
if(error){
reject(error);
}else{
resolve(body);
}
});
});
}
if(ctx.params.url){
content = await syncGet(ctx.params.url);
}else if(content.indexOf('http://') === 0 || content.indexOf('https://') === 0){
content = await syncGet(content);
}
content = JSON.parse(content);
} catch (e) {
return (ctx.body = yapi.commons.resReturn(null, 40022, 'json 格式有误:' + e));
}
let menuList = await this.interfaceCatModel.list(project_id);
/**
* 防止分类被都被删除时取不到 selectCatid
* 如果没有分类,增加一个默认分类
*/
if (menuList.length === 0) {
const catInst = yapi.getInst(interfaceCatModel);
const menu = await catInst.save({
name: '默认分类',
project_id: project_id,
desc: '默认分类',
uid: this.getUid(),
add_time: yapi.commons.time(),
up_time: yapi.commons.time()
});
menuList.push(menu);
}
let selectCatid = menuList[0]._id;
let projectData = await this.projectModel.get(project_id);
let res = await importDataModule[type](content);
let successMessage;
let errorMessage = [];
await HanldeImportData(
res,
project_id,
selectCatid,
menuList,
projectData.basePath,
dataSync,
err => {
errorMessage.push(err);
},
msg => {
successMessage = msg;
},
() => {},
token,
yapi.WEBCONFIG.port
);
if (errorMessage.length > 0) {
return (ctx.body = yapi.commons.resReturn(null, 404, errorMessage.join('\n')));
}
ctx.body = yapi.commons.resReturn(null, 0, successMessage + warnMessage);
}
async projectInterfaceData(ctx) {
ctx.body = 'projectInterfaceData';
}
handleValue(val, global) {
let globalValue = ArrayToObject(global);
let context = Object.assign({}, {global: globalValue}, this.records);
return handleParamsValue(val, context);
}
handleEvnParams(params) {
let result = [];
Object.keys(params).map(item => {
if (/env_/gi.test(item)) {
let curEnv = yapi.commons.trim(params[item]);
let value = { curEnv, project_id: item.split('_')[1] };
result.push(value);
}
});
return result;
}
async runAutoTest(ctx) {
if (!this.$tokenAuth) {
return (ctx.body = yapi.commons.resReturn(null, 40022, 'token 验证失败'));
}
// console.log(1231312)
const token = ctx.query.token;
const projectId = ctx.params.project_id;
const startTime = new Date().getTime();
const records = (this.records = {});
const reports = (this.reports = {});
const testList = [];
let id = ctx.params.id;
let curEnvList = this.handleEvnParams(ctx.params);
let colData = await this.interfaceColModel.get(id);
if (!colData) {
return (ctx.body = yapi.commons.resReturn(null, 40022, 'id值不存在'));
}
let projectData = await this.projectModel.get(projectId);
let caseList = await yapi.commons.getCaseList(id);
if (caseList.errcode !== 0) {
ctx.body = caseList;
}
caseList = caseList.data;
for (let i = 0, l = caseList.length; i < l; i++) {
let item = caseList[i];
let projectEvn = await this.projectModel.getByEnv(item.project_id);
item.id = item._id;
let curEnvItem = _.find(curEnvList, key => {
return key.project_id == item.project_id;
});
item.case_env = curEnvItem ? curEnvItem.curEnv || item.case_env : item.case_env;
item.req_headers = this.handleReqHeader(item.req_headers, projectEvn.env, item.case_env);
item.pre_script = projectData.pre_script;
item.after_script = projectData.after_script;
item.env = projectEvn.env;
let result;
// console.log('item',item.case_env)
try {
result = await this.handleTest(item);
} catch (err) {
result = err;
}
reports[item.id] = result;
records[item.id] = {
params: result.params,
body: result.res_body
};
testList.push(result);
}
function getMessage(testList) {
let successNum = 0,
failedNum = 0,
len = 0,
msg = '';
testList.forEach(item => {
len++;
if (item.code === 0) {
successNum++;
}
else {
failedNum++;
}
});
if (failedNum === 0) {
msg = `一共 ${len} 测试用例,全部验证通过`;
} else {
msg = `一共 ${len} 测试用例,${successNum} 个验证通过, ${failedNum} 个未通过。`;
}
return { msg, len, successNum, failedNum };
}
const endTime = new Date().getTime();
const executionTime = (endTime - startTime) / 1000;
let reportsResult = {
message: getMessage(testList),
runTime: executionTime + 's',
numbs: testList.length,
list: testList
};
if (ctx.params.email === true && reportsResult.message.failedNum !== 0) {
let autoTestUrl = `${
ctx.request.origin
}/api/open/run_auto_test?id=${id}&token=${token}&mode=${ctx.params.mode}`;
yapi.commons.sendNotice(projectId, {
title: `YApi自动化测试报告`,
content: `
<html>
<head>
<title>测试报告</title>
<meta charset="utf-8" />
<body>
<div>
<h3>测试结果:</h3>
<p>${reportsResult.message.msg}</p>
<h3>测试结果详情如下:</h3>
<p>${autoTestUrl}</p>
</div>
</body>
</html>`
});
}
let mode = ctx.params.mode || 'html';
if(ctx.params.download === true) {
ctx.set('Content-Disposition', `attachment; filename=test.${mode}`);
}
if (ctx.params.mode === 'json') {
return (ctx.body = reportsResult);
} else {
return (ctx.body = renderToHtml(reportsResult));
}
}
async handleTest(interfaceData) {
let requestParams = {};
let options;
options = handleParams(interfaceData, this.handleValue, requestParams);
let result = {
id: interfaceData.id,
name: interfaceData.casename,
path: interfaceData.path,
code: 400,
validRes: []
};
try {
options.taskId = this.getUid();
let data = await crossRequest(options, interfaceData.pre_script, interfaceData.after_script,createContex(
this.getUid(),
interfaceData.project_id,
interfaceData.interface_id
));
let res = data.res;
result = Object.assign(result, {
status: res.status,
statusText: res.statusText,
url: data.req.url,
method: data.req.method,
data: data.req.data,
headers: data.req.headers,
res_header: res.header,
res_body: res.body
});
if (options.data && typeof options.data === 'object') {
requestParams = Object.assign(requestParams, options.data);
}
let validRes = [];
let responseData = Object.assign(
{},
{
status: res.status,
body: res.body,
header: res.header,
statusText: res.statusText
}
);
await this.handleScriptTest(interfaceData, responseData, validRes, requestParams);
result.params = requestParams;
if (validRes.length === 0) {
result.code = 0;
result.validRes = [{ message: '验证通过' }];
} else if (validRes.length > 0) {
result.code = 1;
result.validRes = validRes;
}
} catch (data) {
result = Object.assign(options, result, {
res_header: data.header,
res_body: data.body || data.message,
status: null,
statusText: data.message,
code: 400
});
}
return result;
}
async handleScriptTest(interfaceData, response, validRes, requestParams) {
try {
let test = await yapi.commons.runCaseScript({
response: response,
records: this.records,
script: interfaceData.test_script,
params: requestParams
}, interfaceData.col_id, interfaceData.interface_id, this.getUid());
if (test.errcode !== 0) {
test.data.logs.forEach(item => {
validRes.push({
message: item
});
});
}
} catch (err) {
validRes.push({
message: 'Error: ' + err.message
});
}
}
handleReqHeader(req_header, envData, curEnvName) {
let currDomain = handleCurrDomain(envData, curEnvName);
let header = currDomain.header;
header.forEach(item => {
if (!checkNameIsExistInArray(item.name, req_header)) {
item.abled = true;
req_header.push(item);
}
});
req_header = req_header.filter(item => {
return item && typeof item === 'object';
});
return req_header;
}
}
module.exports = openController;