diff --git a/backend/pom.xml b/backend/pom.xml
index c85ffa4cc2..7b96a55141 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -351,7 +351,17 @@
json
20171018
-
+
+
+ com.aliyun
+ alibaba-dingtalk-service-sdk
+ 1.0.1
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.6
+
diff --git a/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java b/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java
index 67173ef791..207ecf1f9c 100644
--- a/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java
+++ b/backend/src/main/java/io/metersphere/api/jmeter/APIBackendListenerClient.java
@@ -5,11 +5,13 @@ import io.metersphere.api.service.APITestService;
import io.metersphere.base.domain.ApiTestReport;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
+import io.metersphere.commons.constants.TestPlanTestCaseStatus;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.notice.domain.NoticeDetail;
import io.metersphere.notice.service.MailService;
import io.metersphere.notice.service.NoticeService;
+import io.metersphere.track.service.TestPlanTestCaseService;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.assertions.AssertionResult;
import org.apache.jmeter.samplers.SampleResult;
@@ -117,6 +119,21 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
apiReportService.complete(testResult, report);
queue.clear();
super.teardownTest(context);
+
+ TestPlanTestCaseService testPlanTestCaseService = CommonBeanFactory.getBean(TestPlanTestCaseService.class);
+ List ids = testPlanTestCaseService.getTestPlanTestCaseIds(testResult.getTestId());
+ if (ids.size() > 0) {
+ try {
+ if (StringUtils.equals(APITestStatus.Success.name(), report.getStatus())) {
+ testPlanTestCaseService.updateTestCaseStates(ids, TestPlanTestCaseStatus.Pass.name());
+ } else {
+ testPlanTestCaseService.updateTestCaseStates(ids, TestPlanTestCaseStatus.Failure.name());
+ }
+ } catch (Exception e) {
+ LogUtil.error(e);
+ }
+
+ }
NoticeService noticeService = CommonBeanFactory.getBean(NoticeService.class);
try {
List noticeList = noticeService.queryNotice(testResult.getTestId());
diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.java
index 0cfb60a557..a42648ab81 100644
--- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.java
+++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.java
@@ -26,4 +26,9 @@ public interface ExtTestPlanTestCaseMapper {
List getPendingTestCases(@Param("request") QueryTestPlanCaseRequest request);
List getStatusByPlanId(String planId);
+
+ int updateTestCaseStates(@Param("ids") List ids, @Param("reportStatus") String reportStatus);
+
+ List getTestPlanTestCaseIds(String testId);
+
}
diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml
index 577f53ed1f..1c7b037ade 100644
--- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml
+++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanTestCaseMapper.xml
@@ -279,4 +279,24 @@
from test_plan_test_case
where plan_id = #{planId}
+
+
+ update test_plan_test_case
+
+
+ status=#{reportStatus,jdbcType=VARCHAR}
+
+
+ where id in
+
+ #{id}
+
+
\ No newline at end of file
diff --git a/backend/src/main/java/io/metersphere/notice/controller/NoticeController.java b/backend/src/main/java/io/metersphere/notice/controller/NoticeController.java
index f0b816d633..7a7a033fc2 100644
--- a/backend/src/main/java/io/metersphere/notice/controller/NoticeController.java
+++ b/backend/src/main/java/io/metersphere/notice/controller/NoticeController.java
@@ -24,4 +24,9 @@ public class NoticeController {
return noticeService.queryNotice(testId);
}
+ @PostMapping("save/message")
+ public void saveMessage() {
+
+ }
}
+
diff --git a/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java b/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java
new file mode 100644
index 0000000000..6db39677e9
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java
@@ -0,0 +1,4 @@
+package io.metersphere.notice.domain;
+
+public class MessageDetail {
+}
diff --git a/backend/src/main/java/io/metersphere/notice/message/LinkMessage.java b/backend/src/main/java/io/metersphere/notice/message/LinkMessage.java
new file mode 100644
index 0000000000..7faf699dee
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/message/LinkMessage.java
@@ -0,0 +1,46 @@
+package io.metersphere.notice.message;
+
+import com.alibaba.fastjson.JSON;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Data
+public class LinkMessage implements Message {
+
+ private String title;
+ private String text;
+ private String picUrl;
+ private String messageUrl;
+
+ public String toJsonString() {
+ Map items = new HashMap();
+ items.put("msgtype", "link");
+
+ Map linkContent = new HashMap();
+ if (StringUtils.isBlank(title)) {
+ throw new IllegalArgumentException("title should not be blank");
+ }
+ linkContent.put("title", title);
+
+ if (StringUtils.isBlank(messageUrl)) {
+ throw new IllegalArgumentException("messageUrl should not be blank");
+ }
+ linkContent.put("messageUrl", messageUrl);
+
+ if (StringUtils.isBlank(text)) {
+ throw new IllegalArgumentException("text should not be blank");
+ }
+ linkContent.put("text", text);
+
+ if (StringUtils.isNotBlank(picUrl)) {
+ linkContent.put("picUrl", picUrl);
+ }
+
+ items.put("link", linkContent);
+
+ return JSON.toJSONString(items);
+ }
+}
diff --git a/backend/src/main/java/io/metersphere/notice/message/Message.java b/backend/src/main/java/io/metersphere/notice/message/Message.java
new file mode 100644
index 0000000000..c8bc65e0a2
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/message/Message.java
@@ -0,0 +1,5 @@
+package io.metersphere.notice.message;
+
+public interface Message {
+ String toJsonString();
+}
diff --git a/backend/src/main/java/io/metersphere/notice/message/TextMessage.java b/backend/src/main/java/io/metersphere/notice/message/TextMessage.java
new file mode 100644
index 0000000000..d112a25323
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/message/TextMessage.java
@@ -0,0 +1,65 @@
+package io.metersphere.notice.message;
+
+import com.alibaba.fastjson.JSON;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class TextMessage implements Message {
+ private String text;
+ private List mentionedMobileList;
+ private boolean isAtAll;
+
+ public TextMessage(String text) {
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public boolean isAtAll() {
+ return isAtAll;
+ }
+
+ public void setIsAtAll(boolean isAtAll) {
+ this.isAtAll = isAtAll;
+ }
+
+ public List getMentionedMobileList() {
+ return mentionedMobileList;
+ }
+
+ public void setMentionedMobileList(List mentionedMobileList) {
+ this.mentionedMobileList = mentionedMobileList;
+ }
+
+ public String toJsonString() {
+ Map items = new HashMap();
+ items.put("msgtype", "text");
+
+ Map textContent = new HashMap();
+ if (StringUtils.isBlank(text)) {
+ throw new IllegalArgumentException("text should not be blank");
+ }
+ textContent.put("content", text);
+ if (isAtAll) {
+ if (mentionedMobileList == null) mentionedMobileList = new ArrayList();
+ mentionedMobileList.add("@all");
+ }
+ if (mentionedMobileList != null && !mentionedMobileList.isEmpty()) {
+ textContent.put("mentioned_mobile_list", mentionedMobileList);
+ }
+ items.put("text", textContent);
+ return JSON.toJSONString(items);
+ }
+}
diff --git a/backend/src/main/java/io/metersphere/notice/service/DingTaskService.java b/backend/src/main/java/io/metersphere/notice/service/DingTaskService.java
new file mode 100644
index 0000000000..17ebf292f8
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/service/DingTaskService.java
@@ -0,0 +1,9 @@
+package io.metersphere.notice.service;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class DingTaskService {
+
+
+}
diff --git a/backend/src/main/java/io/metersphere/notice/service/MailService.java b/backend/src/main/java/io/metersphere/notice/service/MailService.java
index d1137264af..2438349fcd 100644
--- a/backend/src/main/java/io/metersphere/notice/service/MailService.java
+++ b/backend/src/main/java/io/metersphere/notice/service/MailService.java
@@ -95,6 +95,7 @@ public class MailService {
try {
javaMailSender.send(mimeMessage);
} catch (MailException e) {
+ LogUtil.error(e);
LogUtil.error("Failed to send mail");
}
}
diff --git a/backend/src/main/java/io/metersphere/notice/service/WxChatTaskService.java b/backend/src/main/java/io/metersphere/notice/service/WxChatTaskService.java
new file mode 100644
index 0000000000..346a57398e
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/service/WxChatTaskService.java
@@ -0,0 +1,7 @@
+package io.metersphere.notice.service;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class WxChatTaskService {
+}
diff --git a/backend/src/main/java/io/metersphere/notice/util/SendResult.java b/backend/src/main/java/io/metersphere/notice/util/SendResult.java
new file mode 100644
index 0000000000..7b3b861d49
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/util/SendResult.java
@@ -0,0 +1,47 @@
+package io.metersphere.notice.util;
+
+import com.alibaba.fastjson.JSON;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ */
+public class SendResult {
+ private boolean isSuccess;
+ private Integer errorCode;
+ private String errorMsg;
+
+ public boolean isSuccess() {
+ return isSuccess;
+ }
+
+ public void setIsSuccess(boolean isSuccess) {
+ this.isSuccess = isSuccess;
+ }
+
+ public Integer getErrorCode() {
+ return errorCode;
+ }
+
+ public void setErrorCode(Integer errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ public String getErrorMsg() {
+ return errorMsg;
+ }
+
+ public void setErrorMsg(String errorMsg) {
+ this.errorMsg = errorMsg;
+ }
+
+ public String toString() {
+ Map items = new HashMap();
+ items.put("errorCode", errorCode);
+ items.put("errorMsg", errorMsg);
+ items.put("isSuccess", isSuccess);
+ return JSON.toJSONString(items);
+ }
+}
diff --git a/backend/src/main/java/io/metersphere/notice/util/WxChatbotClient.java b/backend/src/main/java/io/metersphere/notice/util/WxChatbotClient.java
new file mode 100644
index 0000000000..7125adadfe
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/util/WxChatbotClient.java
@@ -0,0 +1,50 @@
+package io.metersphere.notice.util;
+
+import com.alibaba.fastjson.JSONObject;
+import io.metersphere.notice.message.Message;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+
+/**
+ *
+ */
+public class WxChatbotClient {
+
+ static HttpClient httpclient = HttpClients.createDefault();
+
+ public static SendResult send(String webhook, Message message) throws IOException {
+
+ if (StringUtils.isBlank(webhook)) {
+ return new SendResult();
+ }
+ HttpPost httppost = new HttpPost(webhook);
+ httppost.addHeader("Content-Type", "application/json; charset=utf-8");
+ StringEntity se = new StringEntity(message.toJsonString(), "utf-8");
+ httppost.setEntity(se);
+
+ SendResult sendResult = new SendResult();
+ HttpResponse response = httpclient.execute(httppost);
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ String result = EntityUtils.toString(response.getEntity());
+ JSONObject obj = JSONObject.parseObject(result);
+
+ Integer errcode = obj.getInteger("errcode");
+ sendResult.setErrorCode(errcode);
+ sendResult.setErrorMsg(obj.getString("errmsg"));
+ sendResult.setIsSuccess(errcode.equals(0));
+ }
+
+ return sendResult;
+ }
+
+}
+
+
diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java
index 4717468b20..214db09993 100644
--- a/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java
+++ b/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java
@@ -6,12 +6,10 @@ import io.metersphere.base.mapper.ext.ExtProjectMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseReviewMapper;
import io.metersphere.base.mapper.ext.ExtTestReviewCaseMapper;
import io.metersphere.commons.constants.TestCaseReviewStatus;
-import io.metersphere.commons.constants.TestPlanTestCaseStatus;
import io.metersphere.commons.constants.TestReviewCaseStatus;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.LogUtil;
-import io.metersphere.commons.utils.MathUtils;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.request.member.QueryMemberRequest;
@@ -32,6 +30,7 @@ import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
+
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@@ -94,6 +93,7 @@ public class TestCaseReviewService {
reviewRequest.setCreator(SessionUtils.getUser().getId());
reviewRequest.setStatus(TestCaseReviewStatus.Prepare.name());
testCaseReviewMapper.insert(reviewRequest);
+
try {
mailService.sendReviewerNotice(userIds, reviewRequest);
} catch (Exception e) {
diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanTestCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanTestCaseService.java
index 272c8f8c4c..04abe860b0 100644
--- a/backend/src/main/java/io/metersphere/track/service/TestPlanTestCaseService.java
+++ b/backend/src/main/java/io/metersphere/track/service/TestPlanTestCaseService.java
@@ -140,4 +140,12 @@ public class TestPlanTestCaseService {
example.createCriteria().andIdIn(request.getIds());
testPlanTestCaseMapper.deleteByExample(example);
}
+
+ public List getTestPlanTestCaseIds(String testId) {
+ return extTestPlanTestCaseMapper.getTestPlanTestCaseIds(testId);
+ }
+
+ public int updateTestCaseStates(List ids, String reportStatus) {
+ return extTestPlanTestCaseMapper.updateTestCaseStates(ids, reportStatus);
+ }
}
diff --git a/backend/src/main/resources/db/migration/V30__test_case_prerequisite.sql b/backend/src/main/resources/db/migration/V30__test_case_prerequisite.sql
new file mode 100644
index 0000000000..8eced76731
--- /dev/null
+++ b/backend/src/main/resources/db/migration/V30__test_case_prerequisite.sql
@@ -0,0 +1 @@
+alter table test_case modify prerequisite varchar(500) null comment 'Test case prerequisite condition';
\ No newline at end of file
diff --git a/backend/src/main/resources/db/migration/V31__message_task.sql b/backend/src/main/resources/db/migration/V31__message_task.sql
new file mode 100644
index 0000000000..bc4e7a3bad
--- /dev/null
+++ b/backend/src/main/resources/db/migration/V31__message_task.sql
@@ -0,0 +1,12 @@
+create table message_task
+(
+ id varchar(255) not null,
+ type varchar(255) not null comment '消息类型',
+ event varchar(255) not null comment '通知事件类型',
+ userId varchar(500) not null comment '接收人id',
+ userName varchar(500) not null comment '接收人姓名',
+ taskType varchar(255) not null,
+ webhook varchar(255) not null comment 'webhook地址',
+ constraint message_manage_pk
+ primary key (id)
+)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
\ No newline at end of file
diff --git a/frontend/src/business/components/settings/organization/IssuesManagement.vue b/frontend/src/business/components/settings/organization/IssuesManagement.vue
index 80c08decba..6506b90f06 100644
--- a/frontend/src/business/components/settings/organization/IssuesManagement.vue
+++ b/frontend/src/business/components/settings/organization/IssuesManagement.vue
@@ -1,7 +1,7 @@