const interfaceColModel = require('../models/interfaceCol.js'); const interfaceCaseModel = require('../models/interfaceCase.js'); const interfaceModel = require('../models/interface.js'); const projectModel = require('../models/project.js'); const baseController = require('./base.js'); const yapi = require('../yapi.js'); const _ = require('underscore'); class interfaceColController extends baseController { constructor(ctx) { super(ctx); this.colModel = yapi.getInst(interfaceColModel); this.caseModel = yapi.getInst(interfaceCaseModel); this.interfaceModel = yapi.getInst(interfaceModel); this.projectModel = yapi.getInst(projectModel); } /** * 获取所有接口集 * @interface /col/list * @method GET * @category col * @foldnumber 10 * @param {String} project_id email名称,不能为空 * @returns {Object} * @example */ async list(ctx) { try { let id = ctx.query.project_id; let project = await this.projectModel.getBaseInfo(id); if (project.project_type === 'private') { if ((await this.checkAuth(project._id, 'project', 'view')) !== true) { return (ctx.body = yapi.commons.resReturn(null, 406, '没有权限')); } } let result = await this.colModel.list(id); result = result.sort((a, b) => { return a.index - b.index; }); for (let i = 0; i < result.length; i++) { result[i] = result[i].toObject(); let caseList = await this.caseModel.list(result[i]._id); for(let j=0; j< caseList.length; j++){ let item = caseList[j].toObject(); let interfaceData = await this.interfaceModel.getBaseinfo(item.interface_id); item.path = interfaceData.path; caseList[j] = item; } caseList = caseList.sort((a, b) => { return a.index - b.index; }); result[i].caseList = caseList; } ctx.body = yapi.commons.resReturn(result); } catch (e) { ctx.body = yapi.commons.resReturn(null, 402, e.message); } } /** * 增加接口集 * @interface /col/add_col * @method POST * @category col * @foldnumber 10 * @param {Number} project_id * @param {String} name * @param {String} desc * @returns {Object} * @example */ async addCol(ctx) { try { let params = ctx.request.body; params = yapi.commons.handleParams(params, { name: 'string', project_id: 'number', desc: 'string' }); if (!params.project_id) { return (ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空')); } if (!params.name) { return (ctx.body = yapi.commons.resReturn(null, 400, '名称不能为空')); } let auth = await this.checkAuth(params.project_id, 'project', 'edit'); if (!auth) { return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限')); } let result = await this.colModel.save({ name: params.name, project_id: params.project_id, desc: params.desc, uid: this.getUid(), add_time: yapi.commons.time(), up_time: yapi.commons.time() }); let username = this.getUsername(); yapi.commons.saveLog({ content: `${username} 添加了接口集 ${params.name}`, type: 'project', uid: this.getUid(), username: username, typeid: params.project_id }); // this.projectModel.up(params.project_id,{up_time: new Date().getTime()}).then(); ctx.body = yapi.commons.resReturn(result); } catch (e) { ctx.body = yapi.commons.resReturn(null, 402, e.message); } } /** * 获取一个接口集下的所有的测试用例 * @interface /col/case_list * @method GET * @category col * @foldnumber 10 * @param {String} col_id 接口集id * @returns {Object} * @example */ async getCaseList(ctx) { try { let id = ctx.query.col_id; if (!id || id == 0) { return (ctx.body = yapi.commons.resReturn(null, 407, 'col_id不能为空')); } let colData = await this.colModel.get(id); let project = await this.projectModel.getBaseInfo(colData.project_id); if (project.project_type === 'private') { if ((await this.checkAuth(project._id, 'project', 'view')) !== true) { return (ctx.body = yapi.commons.resReturn(null, 406, '没有权限')); } } ctx.body = await yapi.commons.getCaseList(id); } catch (e) { ctx.body = yapi.commons.resReturn(null, 402, e.message); } } /** * 获取一个接口集下的所有的测试用例的环境变量 * @interface /col/case_env_list * @method GET * @category col * @foldnumber 10 * @param {String} col_id 接口集id * @returns {Object} * @example */ async getCaseEnvList(ctx) { try { let id = ctx.query.col_id; if (!id || id == 0) { return (ctx.body = yapi.commons.resReturn(null, 407, 'col_id不能为空')); } let colData = await this.colModel.get(id); let project = await this.projectModel.getBaseInfo(colData.project_id); if (project.project_type === 'private') { if ((await this.checkAuth(project._id, 'project', 'view')) !== true) { return (ctx.body = yapi.commons.resReturn(null, 406, '没有权限')); } } // 通过col_id 找到 caseList let projectList = await this.caseModel.list(id, 'project_id'); // 对projectList 进行去重处理 projectList = this.unique(projectList, 'project_id'); // 遍历projectList 找到项目和env let projectEnvList = []; for (let i = 0; i < projectList.length; i++) { let result = await this.projectModel.getBaseInfo(projectList[i], 'name env'); projectEnvList.push(result); } ctx.body = yapi.commons.resReturn(projectEnvList); } catch (e) { ctx.body = yapi.commons.resReturn(null, 402, e.message); } } requestParamsToObj(arr) { if (!arr || !Array.isArray(arr) || arr.length === 0) { return {}; } let obj = {}; arr.forEach(item => { obj[item.name] = ''; }); return obj; } /** * 获取一个接口集下的所有的测试用例 * @interface /col/case_list_by_var_params * @method GET * @category col * @foldnumber 10 * @param {String} col_id 接口集id * @returns {Object} * @example */ async getCaseListByVariableParams(ctx) { try { let id = ctx.query.col_id; if (!id || id == 0) { return (ctx.body = yapi.commons.resReturn(null, 407, 'col_id不能为空')); } let resultList = await this.caseModel.list(id, 'all'); if (resultList.length === 0) { return (ctx.body = yapi.commons.resReturn([])); } let project = await this.projectModel.getBaseInfo(resultList[0].project_id); if (project.project_type === 'private') { if ((await this.checkAuth(project._id, 'project', 'view')) !== true) { return (ctx.body = yapi.commons.resReturn(null, 406, '没有权限')); } } for (let index = 0; index < resultList.length; index++) { let result = resultList[index].toObject(); let item = {}, body, query, bodyParams, pathParams; let data = await this.interfaceModel.get(result.interface_id); if (!data) { await this.caseModel.del(result._id); continue; } item._id = result._id; item.casename = result.casename; body = yapi.commons.json_parse(data.res_body); body = typeof body === 'object' ? body : {}; if (data.res_body_is_json_schema) { body = yapi.commons.schemaToJson(body, { alwaysFakeOptionals: true }); } item.body = Object.assign({}, body); query = this.requestParamsToObj(data.req_query); pathParams = this.requestParamsToObj(data.req_params); if (data.req_body_type === 'form') { bodyParams = this.requestParamsToObj(data.req_body_form); } else { bodyParams = yapi.commons.json_parse(data.req_body_other); if (data.req_body_is_json_schema) { bodyParams = yapi.commons.schemaToJson(bodyParams, { alwaysFakeOptionals: true }); } bodyParams = typeof bodyParams === 'object' ? bodyParams : {}; } item.params = Object.assign(pathParams, query, bodyParams); item.index = result.index; resultList[index] = item; } ctx.body = yapi.commons.resReturn(resultList); } catch (e) { ctx.body = yapi.commons.resReturn(null, 402, e.message); } } /** * 增加一个测试用例 * @interface /col/add_case * @method POST * @category col * @foldnumber 10 * @param {String} casename * @param {Number} col_id * @param {Number} project_id * @param {String} domain * @param {String} path * @param {String} method * @param {Object} req_query * @param {Object} req_headers * @param {String} req_body_type * @param {Array} req_body_form * @param {String} req_body_other * @returns {Object} * @example */ async addCase(ctx) { try { let params = ctx.request.body; params = yapi.commons.handleParams(params, { casename: 'string', project_id: 'number', col_id: 'number', interface_id: 'number', case_env: 'string' }); if (!params.project_id) { return (ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空')); } if (!params.interface_id) { return (ctx.body = yapi.commons.resReturn(null, 400, '接口id不能为空')); } let auth = await this.checkAuth(params.project_id, 'project', 'edit'); if (!auth) { return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限')); } if (!params.col_id) { return (ctx.body = yapi.commons.resReturn(null, 400, '接口集id不能为空')); } if (!params.casename) { return (ctx.body = yapi.commons.resReturn(null, 400, '用例名称不能为空')); } params.uid = this.getUid(); params.index = 0; params.add_time = yapi.commons.time(); params.up_time = yapi.commons.time(); let result = await this.caseModel.save(params); let username = this.getUsername(); this.colModel.get(params.col_id).then(col => { yapi.commons.saveLog({ content: `${username} 在接口集 ${col.name} 下添加了测试用例 ${params.casename}`, type: 'project', uid: this.getUid(), username: username, typeid: params.project_id }); }); this.projectModel.up(params.project_id, { up_time: new Date().getTime() }).then(); ctx.body = yapi.commons.resReturn(result); } catch (e) { ctx.body = yapi.commons.resReturn(null, 402, e.message); } } async addCaseList(ctx) { try { let params = ctx.request.body; params = yapi.commons.handleParams(params, { project_id: 'number', col_id: 'number' }); if (!params.interface_list || !Array.isArray(params.interface_list)) { return (ctx.body = yapi.commons.resReturn(null, 400, 'interface_list 参数有误')); } if (!params.project_id) { return (ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空')); } let auth = await this.checkAuth(params.project_id, 'project', 'edit'); if (!auth) { return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限')); } if (!params.col_id) { return (ctx.body = yapi.commons.resReturn(null, 400, '接口集id不能为空')); } let data = { uid: this.getUid(), index: 0, add_time: yapi.commons.time(), up_time: yapi.commons.time(), project_id: params.project_id, col_id: params.col_id }; for (let i = 0; i < params.interface_list.length; i++) { let interfaceData = await this.interfaceModel.get(params.interface_list[i]); data.interface_id = params.interface_list[i]; data.casename = interfaceData.title; // 处理json schema 解析 if ( interfaceData.req_body_type === 'json' && interfaceData.req_body_other && interfaceData.req_body_is_json_schema ) { let req_body_other = yapi.commons.json_parse(interfaceData.req_body_other); req_body_other = yapi.commons.schemaToJson(req_body_other, { alwaysFakeOptionals: true }); data.req_body_other = JSON.stringify(req_body_other); } else { data.req_body_other = interfaceData.req_body_other; } data.req_body_type = interfaceData.req_body_type; let caseResultData = await this.caseModel.save(data); let username = this.getUsername(); this.colModel.get(params.col_id).then(col => { yapi.commons.saveLog({ content: `${username} 在接口集 ${col.name} 下导入了测试用例 ${data.casename}`, type: 'project', uid: this.getUid(), username: username, typeid: params.project_id }); }); } this.projectModel.up(params.project_id, { up_time: new Date().getTime() }).then(); ctx.body = yapi.commons.resReturn('ok'); } catch (e) { ctx.body = yapi.commons.resReturn(null, 402, e.message); } } async cloneCaseList(ctx) { try { let params = ctx.request.body; params = yapi.commons.handleParams(params, { project_id: 'number', col_id: 'number', new_col_id: 'number' }); const { project_id, col_id, new_col_id } = params; if (!project_id) { return (ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空')); } let auth = await this.checkAuth(params.project_id, 'project', 'edit'); if (!auth) { return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限')); } if (!col_id) { return (ctx.body = yapi.commons.resReturn(null, 400, '被克隆的接口集id不能为空')); } if (!new_col_id) { return (ctx.body = yapi.commons.resReturn(null, 400, '克隆的接口集id不能为空')); } let oldColCaselistData = await this.caseModel.list(col_id, 'all'); oldColCaselistData = oldColCaselistData.sort((a, b) => { return a.index - b.index; }); const newCaseList = []; const oldCaseObj = {}; let obj = {}; const handleTypeParams = (data, name) => { let res = data[name]; const type = Object.prototype.toString.call(res); if (type === '[object Array]' && res.length) { res = JSON.stringify(res); try { res = JSON.parse(handleReplaceStr(res)); } catch (e) { console.log('e ->', e); } } else if (type === '[object String]' && data[name]) { res = handleReplaceStr(res); } return res; }; const handleReplaceStr = str => { if (str.indexOf('$') !== -1) { str = str.replace(/\$\.([0-9]+)\./g, function(match, p1) { p1 = p1.toString(); return `$.${newCaseList[oldCaseObj[p1]]}.` || ''; }); } return str; }; // 处理数据里面的$id; const handleParams = data => { data.col_id = new_col_id; delete data._id; delete data.add_time; delete data.up_time; delete data.__v; data.req_body_other = handleTypeParams(data, 'req_body_other'); data.req_query = handleTypeParams(data, 'req_query'); data.req_params = handleTypeParams(data, 'req_params'); data.req_body_form = handleTypeParams(data, 'req_body_form'); return data; }; for (let i = 0; i < oldColCaselistData.length; i++) { obj = oldColCaselistData[i].toObject(); // 将被克隆的id和位置绑定 oldCaseObj[obj._id] = i; let caseData = handleParams(obj); let newCase = await this.caseModel.save(caseData); newCaseList.push(newCase._id); } this.projectModel.up(params.project_id, { up_time: new Date().getTime() }).then(); ctx.body = yapi.commons.resReturn('ok'); } catch (e) { ctx.body = yapi.commons.resReturn(null, 402, e.message); } } /** * 更新一个测试用例 * @interface /col/up_case * @method POST * @category col * @foldnumber 10 * @param {number} id * @param {String} casename * @param {String} domain * @param {String} path * @param {String} method * @param {Object} req_query * @param {Object} req_headers * @param {String} req_body_type * @param {Array} req_body_form * @param {String} req_body_other * @returns {Object} * @example */ async upCase(ctx) { try { let params = ctx.request.body; params = yapi.commons.handleParams(params, { id: 'number', casename: 'string' }); if (!params.id) { return (ctx.body = yapi.commons.resReturn(null, 400, '用例id不能为空')); } // if (!params.casename) { // return (ctx.body = yapi.commons.resReturn(null, 400, '用例名称不能为空')); // } let caseData = await this.caseModel.get(params.id); let auth = await this.checkAuth(caseData.project_id, 'project', 'edit'); if (!auth) { return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限')); } params.uid = this.getUid(); //不允许修改接口id和项目id delete params.interface_id; delete params.project_id; let result = await this.caseModel.up(params.id, params); let username = this.getUsername(); this.colModel.get(caseData.col_id).then(col => { yapi.commons.saveLog({ content: `${username} 在接口集 ${col.name} 更新了测试用例 ${params.casename || caseData.casename}`, type: 'project', uid: this.getUid(), username: username, typeid: caseData.project_id }); }); this.projectModel.up(caseData.project_id, { up_time: new Date().getTime() }).then(); ctx.body = yapi.commons.resReturn(result); } catch (e) { ctx.body = yapi.commons.resReturn(null, 402, e.message); } } /** * 获取一个测试用例详情 * @interface /col/case * @method GET * @category col * @foldnumber 10 * @param {String} caseid * @returns {Object} * @example */ async getCase(ctx) { try { let id = ctx.query.caseid; let result = await this.caseModel.get(id); if (!result) { return (ctx.body = yapi.commons.resReturn(null, 400, '不存在的case')); } result = result.toObject(); let data = await this.interfaceModel.get(result.interface_id); if (!data) { return (ctx.body = yapi.commons.resReturn(null, 400, '找不到对应的接口,请联系管理员')); } data = data.toObject(); let projectData = await this.projectModel.getBaseInfo(data.project_id); result.path = projectData.basepath + data.path; result.method = data.method; result.req_body_type = data.req_body_type; result.req_headers = yapi.commons.handleParamsValue(data.req_headers, result.req_headers); result.res_body = data.res_body; result.res_body_type = data.res_body_type; result.req_body_form = yapi.commons.handleParamsValue( data.req_body_form, result.req_body_form ); result.req_query = yapi.commons.handleParamsValue(data.req_query, result.req_query); result.req_params = yapi.commons.handleParamsValue(data.req_params, result.req_params); result.interface_up_time = data.up_time; result.req_body_is_json_schema = data.req_body_is_json_schema; result.res_body_is_json_schema = data.res_body_is_json_schema; ctx.body = yapi.commons.resReturn(result); } catch (e) { ctx.body = yapi.commons.resReturn(null, 400, e.message); } } /** * 更新一个接口集name或描述 * @interface /col/up_col * @method POST * @category col * @foldnumber 10 * @param {String} name * @param {String} desc * @returns {Object} * @example */ async upCol(ctx) { try { let params = ctx.request.body; let id = params.col_id; if (!id) { return (ctx.body = yapi.commons.resReturn(null, 400, '缺少 col_id 参数')); } let colData = await this.colModel.get(id); if (!colData) { return (ctx.body = yapi.commons.resReturn(null, 400, '不存在')); } let auth = await this.checkAuth(colData.project_id, 'project', 'edit'); if (!auth) { return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限')); } delete params.col_id; let result = await this.colModel.up(id, params); let username = this.getUsername(); yapi.commons.saveLog({ content: `${username} 更新了测试集合 ${colData.name} 的信息`, type: 'project', uid: this.getUid(), username: username, typeid: colData.project_id }); ctx.body = yapi.commons.resReturn(result); } catch (e) { ctx.body = yapi.commons.resReturn(null, 400, e.message); } } /** * 更新多个接口case index * @interface /col/up_case_index * @method POST * @category col * @foldnumber 10 * @param {Array} [id, index] * @returns {Object} * @example */ async upCaseIndex(ctx) { try { let params = ctx.request.body; if (!params || !Array.isArray(params)) { ctx.body = yapi.commons.resReturn(null, 400, '请求参数必须是数组'); } params.forEach(item => { if (item.id) { this.caseModel.upCaseIndex(item.id, item.index).then( res => {}, err => { yapi.commons.log(err.message, 'error'); } ); } }); return (ctx.body = yapi.commons.resReturn('成功!')); } catch (e) { ctx.body = yapi.commons.resReturn(null, 400, e.message); } } /** * 更新多个测试集合 index * @interface /col/up_col_index * @method POST * @category col * @foldnumber 10 * @param {Array} [id, index] * @returns {Object} * @example */ async upColIndex(ctx) { try { let params = ctx.request.body; if (!params || !Array.isArray(params)) { ctx.body = yapi.commons.resReturn(null, 400, '请求参数必须是数组'); } params.forEach(item => { if (item.id) { this.colModel.upColIndex(item.id, item.index).then( res => {}, err => { yapi.commons.log(err.message, 'error'); } ); } }); return (ctx.body = yapi.commons.resReturn('成功!')); } catch (e) { ctx.body = yapi.commons.resReturn(null, 400, e.message); } } /** * 删除一个接口集 * @interface /col/del_col * @method GET * @category col * @foldnumber 10 * @param {String} * @returns {Object} * @example */ async delCol(ctx) { try { let id = ctx.query.col_id; let colData = await this.colModel.get(id); if (!colData) { ctx.body = yapi.commons.resReturn(null, 400, '不存在的id'); } if (colData.uid !== this.getUid()) { let auth = await this.checkAuth(colData.project_id, 'project', 'danger'); if (!auth) { return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限')); } } let result = await this.colModel.del(id); await this.caseModel.delByCol(id); let username = this.getUsername(); yapi.commons.saveLog({ content: `${username} 删除了接口集 ${ colData.name } 及其下面的接口`, type: 'project', uid: this.getUid(), username: username, typeid: colData.project_id }); return (ctx.body = yapi.commons.resReturn(result)); } catch (e) { yapi.commons.resReturn(null, 400, e.message); } } /** * * @param {*} ctx */ async delCase(ctx) { try { let caseid = ctx.query.caseid; let caseData = await this.caseModel.get(caseid); if (!caseData) { ctx.body = yapi.commons.resReturn(null, 400, '不存在的caseid'); } if (caseData.uid !== this.getUid()) { let auth = await this.checkAuth(caseData.project_id, 'project', 'danger'); if (!auth) { return (ctx.body = yapi.commons.resReturn(null, 400, '没有权限')); } } let result = await this.caseModel.del(caseid); let username = this.getUsername(); this.colModel.get(caseData.col_id).then(col => { yapi.commons.saveLog({ content: `${username} 删除了接口集 ${col.name} 下的接口 ${caseData.casename}`, type: 'project', uid: this.getUid(), username: username, typeid: caseData.project_id }); }); this.projectModel.up(caseData.project_id, { up_time: new Date().getTime() }).then(); return (ctx.body = yapi.commons.resReturn(result)); } catch (e) { yapi.commons.resReturn(null, 400, e.message); } } async runCaseScript(ctx) { let params = ctx.request.body; ctx.body = await yapi.commons.runCaseScript(params, params.col_id, params.interface_id, this.getUid()); } // 数组去重 unique(array, compare) { let hash = {}; let arr = array.reduce(function(item, next) { hash[next[compare]] ? '' : (hash[next[compare]] = true && item.push(next)); // console.log('item',item.project_id) return item; }, []); // 输出去重以后的project_id return arr.map(item => { return item[compare]; }); } } module.exports = interfaceColController;