fix: 飞书webhook校验,国际化,变量增加

This commit is contained in:
wenyann 2021-04-14 14:23:09 +08:00 committed by 刘瑞斌
parent 78fcad3f42
commit c6c14031da
13 changed files with 130 additions and 49 deletions

View File

@ -0,0 +1,11 @@
package io.metersphere.api.dto.automation;
import io.metersphere.base.domain.ApiTestReport;
import lombok.Data;
@Data
public class ApiTestReportVariable extends ApiTestReport {
public String executionTime;
public String executor;
public String executionEnvironment;
}

View File

@ -1,10 +1,11 @@
package io.metersphere.api.jmeter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.automation.ApiTestReportVariable;
import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.service.*;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiScenarioReport;
import io.metersphere.base.domain.ApiTestReport;
import io.metersphere.base.domain.*;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
@ -27,6 +28,7 @@ import org.springframework.http.HttpMethod;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
/**
@ -56,6 +58,8 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
private ApiTestCaseService apiTestCaseService;
private ApiAutomationService apiAutomationService;
public String runMode = ApiRunMode.RUN.name();
// 测试ID
@ -110,7 +114,10 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
if (apiTestCaseService == null) {
LogUtil.error("apiTestCaseService is required");
}
apiAutomationService = CommonBeanFactory.getBean(ApiAutomationService.class);
if (apiAutomationService == null) {
LogUtil.error("apiAutomationService is required");
}
super.setupTest(context);
}
@ -169,6 +176,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
testResult.getScenarios().addAll(scenarios.values());
testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId));
ApiTestReport report = null;
ApiTestReportVariable reportTask = null;
String reportUrl = null;
// 这部分后续优化只留 DEFINITION SCENARIO 两部分
if (StringUtils.equals(this.runMode, ApiRunMode.DEBUG.name())) {
@ -183,7 +191,6 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
} else if (StringUtils.equals(this.runMode, ApiRunMode.JENKINS.name())) {
apiDefinitionService.addResult(testResult);
apiDefinitionExecResultService.saveApiResult(testResult, ApiRunMode.DEFINITION.name());
} else if (StringUtils.equals(this.runMode, ApiRunMode.JENKINS_API_PLAN.name())) {
apiDefinitionService.addResult(testResult);
apiDefinitionExecResultService.saveApiResult(testResult, ApiRunMode.API_PLAN.name());
@ -213,13 +220,35 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
// 执行报告不需要存储由用户确认后在存储
testResult.setTestId(testId);
ApiScenarioReport scenarioReport = apiScenarioReportService.complete(testResult, this.runMode);
//环境
ApiScenarioWithBLOBs apiScenario = apiAutomationService.getDto(scenarioReport.getScenarioId());
String executionEnvironment = apiScenario.getScenarioDefinition();
JSONObject json = JSONObject.parseObject(executionEnvironment);
JSONObject environment = JSONObject.parseObject(json.getString("environmentMap"));
String environmentId = environment.get(apiScenario.getProjectId()).toString();
String name = apiAutomationService.get(environmentId).getName();
report = new ApiTestReport();
report.setStatus(scenarioReport.getStatus());
report.setId(scenarioReport.getId());
report.setTriggerMode(scenarioReport.getTriggerMode());
report.setName(scenarioReport.getName());
//时间
Long time = apiScenario.getUpdateTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String executionTime = null;
String time_ = String.valueOf(time);
if (!time_.equals("null")) {
executionTime = sdf.format(new Date(Long.parseLong(time_)));
}
//执行人
String userName = apiAutomationService.getUser(apiScenario.getUserId()).getName();
//报告内容
reportTask = new ApiTestReportVariable();
reportTask.setStatus(scenarioReport.getStatus());
reportTask.setId(scenarioReport.getId());
reportTask.setTriggerMode(scenarioReport.getTriggerMode());
reportTask.setName(scenarioReport.getName());
reportTask.setExecutor(userName);
reportTask.setExecutionTime(executionTime);
reportTask.setExecutionEnvironment(name);
SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class);
assert systemParameterService != null;
BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo();
@ -247,13 +276,13 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
}
}
if (report != null && StringUtils.equals(ReportTriggerMode.API.name(), report.getTriggerMode())||StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), report.getTriggerMode())) {
sendTask(report, reportUrl, testResult);
if (reportTask != null && StringUtils.equals(ReportTriggerMode.API.name(), reportTask.getTriggerMode()) || StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), reportTask.getTriggerMode())) {
sendTask(reportTask, reportUrl, testResult);
}
}
private static void sendTask(ApiTestReport report, String reportUrl, TestResult testResult) {
private static void sendTask(ApiTestReportVariable report, String reportUrl, TestResult testResult) {
if (report == null) {
return;
}
@ -270,13 +299,13 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
String subject = "";
String event = "";
if (StringUtils.equals(ReportTriggerMode.API.name(), report.getTriggerMode())) {
successContext = "接口测试 API任务通知:'" + report.getName() + "'执行成功" + "\n" + "【接口定义暂无报告链接】" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测)路径" + url + "\n" + "(新版)接口测试路径" + url2;
failedContext = "接口测试 API任务通知:'" + report.getName() + "'执行失败" + "\n" + "【接口定义暂无报告链接】" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测试路径" + url + "\n" + "(新版)接口测试路径" + url2;
successContext = "接口测试 API任务通知:'" + report.getExecutor() + "所执行的" + report.getName() + "'执行成功" + "\n" + "执行环境:" + report.getExecutionEnvironment() + "\n" + "【接口定义暂无报告链接】" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测)路径" + url + "\n" + "(新版)接口测试路径" + url2;
failedContext = "接口测试 API任务通知:'" + report.getExecutor() + "所执行的" + report.getName() + "'执行失败" + "\n" + "执行环境:" + report.getExecutionEnvironment() + "\n" + "【接口定义暂无报告链接】" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测试路径" + url + "\n" + "(新版)接口测试路径" + url2;
subject = Translator.get("task_notification_jenkins");
}
if (StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), report.getTriggerMode())) {
successContext = "接口测试定时任务通知:'" + report.getName() + "'执行成功" + "\n" + "【接口定义暂无报告链接】" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测试路径" + url + "\n" + "(新版)接口测试路径" + url2;
failedContext = "接口测试定时任务通知:'" + report.getName() + "'执行失败" + "\n" + "【接口定义暂无报告链接】" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测试路径" + url + "\n" + "(新版)接口测试路径" + url2;
successContext = "接口测试定时任务通知:'" + report.getExecutor() + "所执行的" + report.getName() + "'执行成功" + "\n" + "执行环境:" + report.getExecutionEnvironment() + "\n" + "【接口定义暂无报告链接】" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测试路径" + url + "\n" + "(新版)接口测试路径" + url2;
failedContext = "接口测试定时任务通知:'" + report.getExecutor() + "所执行的" + report.getName() + "'执行失败" + "\n" + "执行环境:" + report.getExecutionEnvironment() + "\n" + "【接口定义暂无报告链接】" + "\n" + "请点击下面链接进入测试报告页面" + "\n" + "(旧版)接口测试路径" + url + "\n" + "(新版)接口测试路径" + url2;
subject = Translator.get("task_notification");
}
if (StringUtils.equals("Success", report.getStatus())) {
@ -297,6 +326,9 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
paramMap.put("type", "api");
paramMap.put("url", baseSystemConfigDTO.getUrl());
paramMap.put("status", report.getStatus());
paramMap.put("executor", report.getExecutor());
paramMap.put("executionTime", report.getExecutionTime());
paramMap.put("executionEnvironment", report.getExecutionEnvironment());
NoticeModel noticeModel = NoticeModel.builder()
.successContext(successContext)
.successMailTemplate("ApiSuccessfulNotification")

View File

@ -100,6 +100,22 @@ public class ApiAutomationService {
private ApiTestCaseService apiTestCaseService;
@Resource
private ApiDefinitionService apiDefinitionService;
@Resource
private ApiTestEnvironmentMapper apiTestEnvironmentMapper;
@Resource
private UserMapper userMapper;
public ApiScenarioWithBLOBs getDto(String id) {
return apiScenarioMapper.selectByPrimaryKey(id);
}
public ApiTestEnvironment get(String id) {
return apiTestEnvironmentMapper.selectByPrimaryKey(id);
}
public User getUser(String id) {
return userMapper.selectByPrimaryKey(id);
}
public List<ApiScenarioDTO> list(ApiScenarioRequest request) {
request = this.initRequest(request, true, true);

View File

@ -11,7 +11,8 @@
title="示例"
width="400"
trigger="click"
:content="title">
>
<ms-code-edit :read-only="true" height="400px" :data.sync="title" :modes="modes" :mode="'html'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.mail_template_example') }}
</el-button>
@ -21,7 +22,8 @@
title="示例"
width="400"
trigger="click"
:content="robotTitle">
>
<ms-code-edit :read-only="true" height="200px" :data.sync="robotTitle" :modes="modes" :mode="'text'"/>
<el-button icon="el-icon-warning" plain size="mini" slot="reference">
{{ $t('organization.message.robot_template') }}
</el-button>
@ -136,12 +138,14 @@
<script>
import {hasLicense} from "@/common/js/utils";
import MsCodeEdit from "@/business/components/api/definition/components/MsCodeEdit";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const noticeTemplate = requireComponent.keys().length > 0 ? requireComponent("./notice/NoticeTemplate.vue") : {};
export default {
name: "ScheduleNotification",
components: {
MsCodeEdit,
"NoticeTemplate": noticeTemplate.default
},
props: {
@ -154,6 +158,7 @@ export default {
},
data() {
return {
modes: ['text', 'html'],
title: '<!DOCTYPE html>\n' +
'<html lang="en">\n' +
'<head>\n' +
@ -167,7 +172,9 @@ export default {
' <p style="margin-left: 60px">您好:\n' +
' </div>\n' +
' <div style="margin-left: 100px">\n' +
' <p>您所执行的 ${testName} 接口测试运行失败<br/>\n' +
' <p>${executor}所执行的 ${testName} 接口测试运行失败<br/>\n' +
' <p>执行环境:${executionEnvironment}</p>' +
' <p>执行时间:${executionTime}</p>' +
' 请点击下面链接进入测试报告页面</p>\n' +
' <a href="${url}/#/${type}/report/view/${id}">${url}/#/${type}/report/view/${id}</a>\n' +
' <p>新版接口测试报告路径</p>\n' +
@ -178,7 +185,9 @@ export default {
'</body>\n' +
'</html>',
robotTitle:
"测试【任务通知】:'您所执行的 ${testName} ${type}测试运行${status}\n" +
"测试【任务通知】:'${executor}所执行的 ${testName} ${type}测试运行${status}\n" +
"测试环境为:${executionEnvironment}," +
"执行时间:${executionTime}\n" +
"请点击下面链接进入测试报告页面\n" +
"${url}/#/${type}/report/view/${id}" +
"新版接口测试报告路径\n" +
@ -201,7 +210,8 @@ export default {
receiveTypeOptions: [
{value: 'EMAIL', label: this.$t('organization.message.mail')},
{value: 'NAIL_ROBOT', label: this.$t('organization.message.nail_robot')},
{value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')}
{value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
}
},
@ -247,14 +257,14 @@ export default {
handleAddTask(index, data) {
if (data.event && data.userIds.length > 0 && data.type) {
// console.log(data.type)
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT' || data.type === 'LARK') {
if (!data.webhook) {
this.$warning(this.$t('organization.message.message_webhook'));
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.$warning(this.$t('organization.message.message'));

View File

@ -1,7 +1,7 @@
<template>
<el-dialog :close-on-click-modal="false"
:destroy-on-close="true"
:title="$t('已完成的测试报告')" width="60%"
:title="$t('load_test.completed_test_report')" width="60%"
:visible.sync="loadReportVisible">
<el-table v-loading="reportLoadingResult.loading"
class="basic-config"

View File

@ -228,14 +228,14 @@ export default {
if (data.event && data.userIds.length > 0 && data.type) {
// console.log(data.type)
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT' || data.type === 'LARK') {
if (!data.webhook) {
this.$warning(this.$t('organization.message.message_webhook'));
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.$warning(this.$t('organization.message.message'));

View File

@ -170,7 +170,9 @@ export default {
' <p style="margin-left: 60px">您好:\n' +
' </div>\n' +
' <div style="margin-left: 100px">\n' +
' <p>您所执行的 ${testName} 接口测试运行失败<br/>\n' +
' <p>${executor}所执行的 ${testName} 接口测试运行失败<br/>\n' +
' <p>执行环境:${executionEnvironment}</p>' +
' <p>执行时间:${executionTime}</p>' +
' 请点击下面链接进入测试报告页面</p>\n' +
' <a href="${url}/#/${type}/report/view/${id}">${url}/#/${type}/report/view/${id}</a>\n' +
' <p>新版接口测试报告路径</p>\n' +
@ -181,7 +183,9 @@ export default {
'</body>\n' +
'</html>',
robotTitle:
"测试【任务通知】:'您所执行的 ${testName} ${type}测试运行${status}\n" +
"测试【任务通知】:'${executor}所执行的 ${testName} ${type}测试运行${status}," +
"测试环境为:${executionEnvironment}," +
"执行时间:${executionTime}\n" +
"请点击下面链接进入测试报告页面\n" +
"${url}/#/${type}/report/view/${id}" +
"新版接口测试报告路径\n" +
@ -238,14 +242,14 @@ export default {
handleAddTask(index, data) {
if (data.event && data.userIds.length > 0 && data.type) {
// console.log(data.type)
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT' || data.type === 'LARK') {
if (!data.webhook) {
this.$warning(this.$t('organization.message.message_webhook'));
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.$warning(this.$t('organization.message.message'));

View File

@ -171,7 +171,9 @@ export default {
' <p style="margin-left: 60px">您好:\n' +
' </div>\n' +
' <div style="margin-left: 100px">\n' +
' <p>您所执行的 ${testName} 接口测试运行失败<br/>\n' +
' <p>${executor}所执行的 ${testName} 接口测试运行失败<br/>\n' +
' <p>执行环境:${executionEnvironment}</p>' +
' <p>执行时间:${executionTime}</p>' +
' 请点击下面链接进入测试报告页面</p>\n' +
' <a href="${url}/#/${type}/report/view/${id}">${url}/#/${type}/report/view/${id}</a>\n' +
' <p>新版接口测试报告路径</p>\n' +
@ -182,7 +184,9 @@ export default {
'</body>\n' +
'</html>',
robotTitle:
"测试【任务通知】:'您所执行的 ${testName} ${type}测试运行${status}\n" +
"测试【任务通知】:'${executor}所执行的 ${testName} ${type}测试运行${status}," +
"测试环境为:${executionEnvironment}," +
"执行时间:${executionTime}\n" +
"请点击下面链接进入测试报告页面\n" +
"${url}/#/${type}/report/view/${id}" +
"新版接口测试报告路径\n" +
@ -205,7 +209,8 @@ export default {
receiveTypeOptions: [
{value: 'EMAIL', label: this.$t('organization.message.mail')},
{value: 'NAIL_ROBOT', label: this.$t('organization.message.nail_robot')},
{value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')}
{value: 'WECHAT_ROBOT', label: this.$t('organization.message.enterprise_wechat_robot')},
{value: 'LARK', label: this.$t('organization.message.lark')}
],
}
},
@ -251,14 +256,14 @@ export default {
handleAddTask(index, data) {
if (data.event && data.userIds.length > 0 && data.type) {
// console.log(data.type)
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT' || data.type === 'LARK') {
if (!data.webhook) {
this.$warning(this.$t('organization.message.message_webhook'));
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.$warning(this.$t('organization.message.message'));

View File

@ -237,14 +237,14 @@ export default {
if (data.event && data.userIds.length > 0 && data.type) {
// console.log(data.type)
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT' || data.type === 'LARK') {
if (!data.webhook) {
this.$warning(this.$t('organization.message.message_webhook'));
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.$warning(this.$t('organization.message.message'));

View File

@ -238,14 +238,14 @@ export default {
if (data.event && data.userIds.length > 0 && data.type) {
// console.log(data.type)
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT') {
if (data.type === 'NAIL_ROBOT' || data.type === 'WECHAT_ROBOT' || data.type === 'LARK') {
if (!data.webhook) {
this.$warning(this.$t('organization.message.message_webhook'));
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.addTask(data)
this.addTask(data);
}
} else {
this.$warning(this.$t('organization.message.message'));

View File

@ -306,7 +306,7 @@ export default {
'3. When selecting the receiver, it must be the person included in the group you created. The mobile phone number of the receiver is required and it is the mobile phone number used by the nailing enterprise,',
message: 'Event, receiver and receiving method are required\n' +
'\n',
message_webhook: 'Webhook is required when the receiving mode is nail or enterprise robot',
message_webhook: 'Webhook is required when the receiving mode is nail or enterprise robot or lark',
template: "Template"
},
integration: {
@ -461,6 +461,7 @@ export default {
delete_batch_confirm: 'Confirm batch delete report',
},
load_test: {
completed_test_report: 'Completed test report',
test: 'Test',
name: 'Test Name',
same_project_test: 'Only tests within the same project can be run',

View File

@ -304,7 +304,7 @@ export default {
' 2.机器人选择为群机器人,安全验证选择“自定义关键词” "任务通知";\n' +
' 3.选择接收人时必须是你所建的群里包含的人,接收人手机号为必填项且为钉钉企业所使用的手机号,',
message: '事件,接收人,接收方式为必填项',
message_webhook: '接收方式为钉钉和企业机器人webhook为必填项',
message_webhook: '接收方式为钉钉和企业机器人,飞书webhook为必填项',
template: "模版"
},
integration: {
@ -459,6 +459,7 @@ export default {
delete_batch_confirm: '确认批量删除报告',
},
load_test: {
completed_test_report: '已完成测试报告',
test: '测试',
name: '测试名称',
same_project_test: '只能运行同一项目内的测试',

View File

@ -304,7 +304,7 @@ export default {
' 2.機器人選擇為群機器人,安全驗證選擇“自定義關鍵詞” "任務通知";\n' +
' 3.選擇接收人時必須是妳所建的群裏包含的人,接收人手機號為必填項且為釘釘企業所使用的手機號,',
message: '事件,接收人,接收方式為必填項',
message_webhook: '接收方式為釘釘和企業機器人webhook為必填項',
message_webhook: '接收方式為釘釘和企業機器人,飛書webhook為必填項',
template: "模版"
},
integration: {
@ -459,6 +459,7 @@ export default {
delete_batch_confirm: '確認批量刪除報告',
},
load_test: {
completed_test_report: '已完成的測試報告',
test: '測試',
name: '測試名稱',
same_project_test: '只能運行同壹項目內的測試',