diff --git a/backend/pom.xml b/backend/pom.xml
index 19531f4b4f..ea153a84bc 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 9f23b8c526..a946a09c29 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/domain/MessageTask.java b/backend/src/main/java/io/metersphere/base/domain/MessageTask.java
new file mode 100644
index 0000000000..8399db0f6f
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/base/domain/MessageTask.java
@@ -0,0 +1,24 @@
+package io.metersphere.base.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class MessageTask implements Serializable {
+ private String id;
+
+ private String type;
+
+ private String event;
+
+ private String userid;
+
+ private String username;
+
+ private String tasktype;
+
+ private String webhook;
+
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/backend/src/main/java/io/metersphere/base/domain/MessageTaskExample.java b/backend/src/main/java/io/metersphere/base/domain/MessageTaskExample.java
new file mode 100644
index 0000000000..d596efbfd3
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/base/domain/MessageTaskExample.java
@@ -0,0 +1,690 @@
+package io.metersphere.base.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MessageTaskExample {
+ protected String orderByClause;
+
+ protected boolean distinct;
+
+ protected List oredCriteria;
+
+ public MessageTaskExample() {
+ oredCriteria = new ArrayList();
+ }
+
+ public void setOrderByClause(String orderByClause) {
+ this.orderByClause = orderByClause;
+ }
+
+ public String getOrderByClause() {
+ return orderByClause;
+ }
+
+ public void setDistinct(boolean distinct) {
+ this.distinct = distinct;
+ }
+
+ public boolean isDistinct() {
+ return distinct;
+ }
+
+ public List getOredCriteria() {
+ return oredCriteria;
+ }
+
+ public void or(Criteria criteria) {
+ oredCriteria.add(criteria);
+ }
+
+ public Criteria or() {
+ Criteria criteria = createCriteriaInternal();
+ oredCriteria.add(criteria);
+ return criteria;
+ }
+
+ public Criteria createCriteria() {
+ Criteria criteria = createCriteriaInternal();
+ if (oredCriteria.size() == 0) {
+ oredCriteria.add(criteria);
+ }
+ return criteria;
+ }
+
+ protected Criteria createCriteriaInternal() {
+ Criteria criteria = new Criteria();
+ return criteria;
+ }
+
+ public void clear() {
+ oredCriteria.clear();
+ orderByClause = null;
+ distinct = false;
+ }
+
+ protected abstract static class GeneratedCriteria {
+ protected List criteria;
+
+ protected GeneratedCriteria() {
+ super();
+ criteria = new ArrayList();
+ }
+
+ public boolean isValid() {
+ return criteria.size() > 0;
+ }
+
+ public List getAllCriteria() {
+ return criteria;
+ }
+
+ public List getCriteria() {
+ return criteria;
+ }
+
+ protected void addCriterion(String condition) {
+ if (condition == null) {
+ throw new RuntimeException("Value for condition cannot be null");
+ }
+ criteria.add(new Criterion(condition));
+ }
+
+ protected void addCriterion(String condition, Object value, String property) {
+ if (value == null) {
+ throw new RuntimeException("Value for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value));
+ }
+
+ protected void addCriterion(String condition, Object value1, Object value2, String property) {
+ if (value1 == null || value2 == null) {
+ throw new RuntimeException("Between values for " + property + " cannot be null");
+ }
+ criteria.add(new Criterion(condition, value1, value2));
+ }
+
+ public Criteria andIdIsNull() {
+ addCriterion("id is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIsNotNull() {
+ addCriterion("id is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdEqualTo(String value) {
+ addCriterion("id =", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotEqualTo(String value) {
+ addCriterion("id <>", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThan(String value) {
+ addCriterion("id >", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdGreaterThanOrEqualTo(String value) {
+ addCriterion("id >=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThan(String value) {
+ addCriterion("id <", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLessThanOrEqualTo(String value) {
+ addCriterion("id <=", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdLike(String value) {
+ addCriterion("id like", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotLike(String value) {
+ addCriterion("id not like", value, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdIn(List values) {
+ addCriterion("id in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotIn(List values) {
+ addCriterion("id not in", values, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdBetween(String value1, String value2) {
+ addCriterion("id between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andIdNotBetween(String value1, String value2) {
+ addCriterion("id not between", value1, value2, "id");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeIsNull() {
+ addCriterion("`type` is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeIsNotNull() {
+ addCriterion("`type` is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeEqualTo(String value) {
+ addCriterion("`type` =", value, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeNotEqualTo(String value) {
+ addCriterion("`type` <>", value, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeGreaterThan(String value) {
+ addCriterion("`type` >", value, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeGreaterThanOrEqualTo(String value) {
+ addCriterion("`type` >=", value, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeLessThan(String value) {
+ addCriterion("`type` <", value, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeLessThanOrEqualTo(String value) {
+ addCriterion("`type` <=", value, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeLike(String value) {
+ addCriterion("`type` like", value, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeNotLike(String value) {
+ addCriterion("`type` not like", value, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeIn(List values) {
+ addCriterion("`type` in", values, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeNotIn(List values) {
+ addCriterion("`type` not in", values, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeBetween(String value1, String value2) {
+ addCriterion("`type` between", value1, value2, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andTypeNotBetween(String value1, String value2) {
+ addCriterion("`type` not between", value1, value2, "type");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventIsNull() {
+ addCriterion("event is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventIsNotNull() {
+ addCriterion("event is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventEqualTo(String value) {
+ addCriterion("event =", value, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventNotEqualTo(String value) {
+ addCriterion("event <>", value, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventGreaterThan(String value) {
+ addCriterion("event >", value, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventGreaterThanOrEqualTo(String value) {
+ addCriterion("event >=", value, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventLessThan(String value) {
+ addCriterion("event <", value, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventLessThanOrEqualTo(String value) {
+ addCriterion("event <=", value, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventLike(String value) {
+ addCriterion("event like", value, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventNotLike(String value) {
+ addCriterion("event not like", value, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventIn(List values) {
+ addCriterion("event in", values, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventNotIn(List values) {
+ addCriterion("event not in", values, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventBetween(String value1, String value2) {
+ addCriterion("event between", value1, value2, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andEventNotBetween(String value1, String value2) {
+ addCriterion("event not between", value1, value2, "event");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridIsNull() {
+ addCriterion("userId is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridIsNotNull() {
+ addCriterion("userId is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridEqualTo(String value) {
+ addCriterion("userId =", value, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridNotEqualTo(String value) {
+ addCriterion("userId <>", value, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridGreaterThan(String value) {
+ addCriterion("userId >", value, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridGreaterThanOrEqualTo(String value) {
+ addCriterion("userId >=", value, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridLessThan(String value) {
+ addCriterion("userId <", value, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridLessThanOrEqualTo(String value) {
+ addCriterion("userId <=", value, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridLike(String value) {
+ addCriterion("userId like", value, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridNotLike(String value) {
+ addCriterion("userId not like", value, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridIn(List values) {
+ addCriterion("userId in", values, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridNotIn(List values) {
+ addCriterion("userId not in", values, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridBetween(String value1, String value2) {
+ addCriterion("userId between", value1, value2, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUseridNotBetween(String value1, String value2) {
+ addCriterion("userId not between", value1, value2, "userid");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameIsNull() {
+ addCriterion("userName is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameIsNotNull() {
+ addCriterion("userName is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameEqualTo(String value) {
+ addCriterion("userName =", value, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameNotEqualTo(String value) {
+ addCriterion("userName <>", value, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameGreaterThan(String value) {
+ addCriterion("userName >", value, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameGreaterThanOrEqualTo(String value) {
+ addCriterion("userName >=", value, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameLessThan(String value) {
+ addCriterion("userName <", value, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameLessThanOrEqualTo(String value) {
+ addCriterion("userName <=", value, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameLike(String value) {
+ addCriterion("userName like", value, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameNotLike(String value) {
+ addCriterion("userName not like", value, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameIn(List values) {
+ addCriterion("userName in", values, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameNotIn(List values) {
+ addCriterion("userName not in", values, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameBetween(String value1, String value2) {
+ addCriterion("userName between", value1, value2, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andUsernameNotBetween(String value1, String value2) {
+ addCriterion("userName not between", value1, value2, "username");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeIsNull() {
+ addCriterion("taskType is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeIsNotNull() {
+ addCriterion("taskType is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeEqualTo(String value) {
+ addCriterion("taskType =", value, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeNotEqualTo(String value) {
+ addCriterion("taskType <>", value, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeGreaterThan(String value) {
+ addCriterion("taskType >", value, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeGreaterThanOrEqualTo(String value) {
+ addCriterion("taskType >=", value, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeLessThan(String value) {
+ addCriterion("taskType <", value, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeLessThanOrEqualTo(String value) {
+ addCriterion("taskType <=", value, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeLike(String value) {
+ addCriterion("taskType like", value, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeNotLike(String value) {
+ addCriterion("taskType not like", value, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeIn(List values) {
+ addCriterion("taskType in", values, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeNotIn(List values) {
+ addCriterion("taskType not in", values, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeBetween(String value1, String value2) {
+ addCriterion("taskType between", value1, value2, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andTasktypeNotBetween(String value1, String value2) {
+ addCriterion("taskType not between", value1, value2, "tasktype");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookIsNull() {
+ addCriterion("webhook is null");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookIsNotNull() {
+ addCriterion("webhook is not null");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookEqualTo(String value) {
+ addCriterion("webhook =", value, "webhook");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookNotEqualTo(String value) {
+ addCriterion("webhook <>", value, "webhook");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookGreaterThan(String value) {
+ addCriterion("webhook >", value, "webhook");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookGreaterThanOrEqualTo(String value) {
+ addCriterion("webhook >=", value, "webhook");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookLessThan(String value) {
+ addCriterion("webhook <", value, "webhook");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookLessThanOrEqualTo(String value) {
+ addCriterion("webhook <=", value, "webhook");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookLike(String value) {
+ addCriterion("webhook like", value, "webhook");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookNotLike(String value) {
+ addCriterion("webhook not like", value, "webhook");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookIn(List values) {
+ addCriterion("webhook in", values, "webhook");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookNotIn(List values) {
+ addCriterion("webhook not in", values, "webhook");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookBetween(String value1, String value2) {
+ addCriterion("webhook between", value1, value2, "webhook");
+ return (Criteria) this;
+ }
+
+ public Criteria andWebhookNotBetween(String value1, String value2) {
+ addCriterion("webhook not between", value1, value2, "webhook");
+ return (Criteria) this;
+ }
+ }
+
+ public static class Criteria extends GeneratedCriteria {
+
+ protected Criteria() {
+ super();
+ }
+ }
+
+ public static class Criterion {
+ private String condition;
+
+ private Object value;
+
+ private Object secondValue;
+
+ private boolean noValue;
+
+ private boolean singleValue;
+
+ private boolean betweenValue;
+
+ private boolean listValue;
+
+ private String typeHandler;
+
+ public String getCondition() {
+ return condition;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public Object getSecondValue() {
+ return secondValue;
+ }
+
+ public boolean isNoValue() {
+ return noValue;
+ }
+
+ public boolean isSingleValue() {
+ return singleValue;
+ }
+
+ public boolean isBetweenValue() {
+ return betweenValue;
+ }
+
+ public boolean isListValue() {
+ return listValue;
+ }
+
+ public String getTypeHandler() {
+ return typeHandler;
+ }
+
+ protected Criterion(String condition) {
+ super();
+ this.condition = condition;
+ this.typeHandler = null;
+ this.noValue = true;
+ }
+
+ protected Criterion(String condition, Object value, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.typeHandler = typeHandler;
+ if (value instanceof List>) {
+ this.listValue = true;
+ } else {
+ this.singleValue = true;
+ }
+ }
+
+ protected Criterion(String condition, Object value) {
+ this(condition, value, null);
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
+ super();
+ this.condition = condition;
+ this.value = value;
+ this.secondValue = secondValue;
+ this.typeHandler = typeHandler;
+ this.betweenValue = true;
+ }
+
+ protected Criterion(String condition, Object value, Object secondValue) {
+ this(condition, value, secondValue, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.java b/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.java
new file mode 100644
index 0000000000..de3d5b7289
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.java
@@ -0,0 +1,31 @@
+package io.metersphere.base.mapper;
+
+import io.metersphere.base.domain.MessageTask;
+import io.metersphere.base.domain.MessageTaskExample;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface MessageTaskMapper {
+ long countByExample(MessageTaskExample example);
+
+ int deleteByExample(MessageTaskExample example);
+
+ int deleteByPrimaryKey(String id);
+
+ int insert(MessageTask record);
+
+ int insertSelective(MessageTask record);
+
+ List selectByExample(MessageTaskExample example);
+
+ MessageTask selectByPrimaryKey(String id);
+
+ int updateByExampleSelective(@Param("record") MessageTask record, @Param("example") MessageTaskExample example);
+
+ int updateByExample(@Param("record") MessageTask record, @Param("example") MessageTaskExample example);
+
+ int updateByPrimaryKeySelective(MessageTask record);
+
+ int updateByPrimaryKey(MessageTask record);
+}
\ No newline at end of file
diff --git a/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.xml
new file mode 100644
index 0000000000..7a6fe747af
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/base/mapper/MessageTaskMapper.xml
@@ -0,0 +1,247 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and ${criterion.condition}
+
+
+ and ${criterion.condition} #{criterion.value}
+
+
+ and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
+
+
+ and ${criterion.condition}
+
+ #{listItem}
+
+
+
+
+
+
+
+
+
+
+ id, `type`, event, userId, userName, taskType, webhook
+
+
+
+
+ delete from message_task
+ where id = #{id,jdbcType=VARCHAR}
+
+
+ delete from message_task
+
+
+
+
+
+ insert into message_task (id, `type`, event,
+ userId, userName, taskType,
+ webhook)
+ values (#{id,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR}, #{event,jdbcType=VARCHAR},
+ #{userid,jdbcType=VARCHAR}, #{username,jdbcType=VARCHAR}, #{tasktype,jdbcType=VARCHAR},
+ #{webhook,jdbcType=VARCHAR})
+
+
+ insert into message_task
+
+
+ id,
+
+
+ `type`,
+
+
+ event,
+
+
+ userId,
+
+
+ userName,
+
+
+ taskType,
+
+
+ webhook,
+
+
+
+
+ #{id,jdbcType=VARCHAR},
+
+
+ #{type,jdbcType=VARCHAR},
+
+
+ #{event,jdbcType=VARCHAR},
+
+
+ #{userid,jdbcType=VARCHAR},
+
+
+ #{username,jdbcType=VARCHAR},
+
+
+ #{tasktype,jdbcType=VARCHAR},
+
+
+ #{webhook,jdbcType=VARCHAR},
+
+
+
+
+
+ update message_task
+
+
+ id = #{record.id,jdbcType=VARCHAR},
+
+
+ `type` = #{record.type,jdbcType=VARCHAR},
+
+
+ event = #{record.event,jdbcType=VARCHAR},
+
+
+ userId = #{record.userid,jdbcType=VARCHAR},
+
+
+ userName = #{record.username,jdbcType=VARCHAR},
+
+
+ taskType = #{record.tasktype,jdbcType=VARCHAR},
+
+
+ webhook = #{record.webhook,jdbcType=VARCHAR},
+
+
+
+
+
+
+
+ update message_task
+ set id = #{record.id,jdbcType=VARCHAR},
+ `type` = #{record.type,jdbcType=VARCHAR},
+ event = #{record.event,jdbcType=VARCHAR},
+ userId = #{record.userid,jdbcType=VARCHAR},
+ userName = #{record.username,jdbcType=VARCHAR},
+ taskType = #{record.tasktype,jdbcType=VARCHAR},
+ webhook = #{record.webhook,jdbcType=VARCHAR}
+
+
+
+
+
+ update message_task
+
+
+ `type` = #{type,jdbcType=VARCHAR},
+
+
+ event = #{event,jdbcType=VARCHAR},
+
+
+ userId = #{userid,jdbcType=VARCHAR},
+
+
+ userName = #{username,jdbcType=VARCHAR},
+
+
+ taskType = #{tasktype,jdbcType=VARCHAR},
+
+
+ webhook = #{webhook,jdbcType=VARCHAR},
+
+
+ where id = #{id,jdbcType=VARCHAR}
+
+
+ update message_task
+ set `type` = #{type,jdbcType=VARCHAR},
+ event = #{event,jdbcType=VARCHAR},
+ userId = #{userid,jdbcType=VARCHAR},
+ userName = #{username,jdbcType=VARCHAR},
+ taskType = #{tasktype,jdbcType=VARCHAR},
+ webhook = #{webhook,jdbcType=VARCHAR}
+ where id = #{id,jdbcType=VARCHAR}
+
+
\ No newline at end of file
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 1fa73dfe1f..62571a403a 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
@@ -285,4 +285,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/commons/constants/NoticeConstants.java b/backend/src/main/java/io/metersphere/commons/constants/NoticeConstants.java
index 3e45464c3e..427d75630a 100644
--- a/backend/src/main/java/io/metersphere/commons/constants/NoticeConstants.java
+++ b/backend/src/main/java/io/metersphere/commons/constants/NoticeConstants.java
@@ -3,4 +3,11 @@ package io.metersphere.commons.constants;
public interface NoticeConstants {
String EXECUTE_SUCCESSFUL = "EXECUTE_SUCCESSFUL";
String EXECUTE_FAILED = "EXECUTE_FAILED";
+ String EMAIL = "EMAIL";
+ String NAIL_ROBOT = "NAIL_ROBOT";
+ String WECHAT_ROBOT = "WECHAT_ROBOT";
+ String CREATE = "CREATE";
+ String UPDATE = "CREATE";
+ String DELETE = "DELETE";
+
}
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..fdfe68436c 100644
--- a/backend/src/main/java/io/metersphere/notice/controller/NoticeController.java
+++ b/backend/src/main/java/io/metersphere/notice/controller/NoticeController.java
@@ -1,6 +1,8 @@
package io.metersphere.notice.controller;
+import io.metersphere.notice.controller.request.MessageRequest;
import io.metersphere.notice.controller.request.NoticeRequest;
+import io.metersphere.notice.domain.MessageSettingDetail;
import io.metersphere.notice.domain.NoticeDetail;
import io.metersphere.notice.service.NoticeService;
import org.springframework.web.bind.annotation.*;
@@ -24,4 +26,19 @@ public class NoticeController {
return noticeService.queryNotice(testId);
}
+ @PostMapping("save/message/task")
+ public void saveMessage(@RequestBody MessageRequest messageRequest) {
+ noticeService.saveMessageTask(messageRequest);
+ }
+
+ @GetMapping("/search/message")
+ public List searchMessage() {
+ return noticeService.searchMessage();
+ }
+
+ @GetMapping("/delete/message")
+ public void deleteMessage() {
+
+ }
}
+
diff --git a/backend/src/main/java/io/metersphere/notice/controller/request/MessageRequest.java b/backend/src/main/java/io/metersphere/notice/controller/request/MessageRequest.java
new file mode 100644
index 0000000000..407ce2c9fa
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/controller/request/MessageRequest.java
@@ -0,0 +1,11 @@
+package io.metersphere.notice.controller.request;
+
+import io.metersphere.notice.domain.MessageDetail;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class MessageRequest {
+ private List messageDetail;
+}
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..45f40beabf
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/domain/MessageDetail.java
@@ -0,0 +1,17 @@
+package io.metersphere.notice.domain;
+
+import io.metersphere.base.domain.MessageTask;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+public class MessageDetail extends MessageTask {
+ private List userIds = new ArrayList<>();
+ private List userNames = new ArrayList<>();
+ private List events = new ArrayList<>();
+ private String taskType;
+ private String webhook;
+ private String type;
+}
diff --git a/backend/src/main/java/io/metersphere/notice/domain/MessageSettingDetail.java b/backend/src/main/java/io/metersphere/notice/domain/MessageSettingDetail.java
new file mode 100644
index 0000000000..79f3e4eada
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/domain/MessageSettingDetail.java
@@ -0,0 +1,13 @@
+package io.metersphere.notice.domain;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class MessageSettingDetail {
+ private List jenkinsTask;
+ private List testCasePlanTask;
+ private List reviewTask;
+ private List defectTask;
+}
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..9c16a3f6d4
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/message/LinkMessage.java
@@ -0,0 +1,45 @@
+package io.metersphere.notice.message;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+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..6a36e52fbc
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/message/TextMessage.java
@@ -0,0 +1,64 @@
+package io.metersphere.notice.message;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+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..61016ef63a
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/service/DingTaskService.java
@@ -0,0 +1,34 @@
+package io.metersphere.notice.service;
+
+import com.dingtalk.api.DefaultDingTalkClient;
+import com.dingtalk.api.DingTalkClient;
+import com.dingtalk.api.request.OapiRobotSendRequest;
+import com.dingtalk.api.response.OapiRobotSendResponse;
+import com.taobao.api.ApiException;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+
+@Service
+public class DingTaskService {
+ public void sendDingTask(String context, List userIds) {
+ DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/robot/send?access_token=5129dc4c073d28f67c7452e0de6536c3ca496728d8c014d0a209b88a8814307a");
+ OapiRobotSendRequest request = new OapiRobotSendRequest();
+ request.setMsgtype("text");
+ OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
+ text.setContent(context);
+ request.setText(text);
+ OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
+ at.setAtMobiles(Arrays.asList("15135125273"));
+ request.setAt(at);
+ OapiRobotSendResponse response = null;
+ try {
+ response = client.execute(request);
+ } catch (ApiException e) {
+ e.printStackTrace();
+ }
+ System.out.println(response.getErrcode());
+ }
+
+}
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..dad9dcd651 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");
}
}
@@ -249,5 +250,6 @@ public class MailService {
return recipientEmails;
}
+
}
diff --git a/backend/src/main/java/io/metersphere/notice/service/NoticeService.java b/backend/src/main/java/io/metersphere/notice/service/NoticeService.java
index 913a44461c..4871143549 100644
--- a/backend/src/main/java/io/metersphere/notice/service/NoticeService.java
+++ b/backend/src/main/java/io/metersphere/notice/service/NoticeService.java
@@ -1,9 +1,14 @@
package io.metersphere.notice.service;
+import io.metersphere.base.domain.MessageTask;
+import io.metersphere.base.domain.MessageTaskExample;
import io.metersphere.base.domain.Notice;
import io.metersphere.base.domain.NoticeExample;
+import io.metersphere.base.mapper.MessageTaskMapper;
import io.metersphere.base.mapper.NoticeMapper;
+import io.metersphere.notice.controller.request.MessageRequest;
import io.metersphere.notice.controller.request.NoticeRequest;
+import io.metersphere.notice.domain.MessageSettingDetail;
import io.metersphere.notice.domain.NoticeDetail;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
@@ -20,6 +25,8 @@ import static io.metersphere.commons.constants.NoticeConstants.EXECUTE_SUCCESSFU
public class NoticeService {
@Resource
private NoticeMapper noticeMapper;
+ @Resource
+ private MessageTaskMapper messageTaskMapper;
public void saveNotice(NoticeRequest noticeRequest) {
NoticeExample example = new NoticeExample();
@@ -78,4 +85,32 @@ public class NoticeService {
return result;
}
-}
+ public void saveMessageTask(MessageRequest messageRequest) {
+ messageRequest.getMessageDetail().forEach(list -> {
+ list.getEvents().forEach(n -> {
+ list.getUserIds().forEach(m -> {
+ MessageTask message = new MessageTask();
+ message.setId(UUID.randomUUID().toString());
+ message.setEvent(n);
+ message.setTasktype(list.getTaskType());
+ message.setUserid(m);
+ message.setType(list.getType());
+ message.setUsername("a");
+ message.setWebhook(list.getWebhook());
+ messageTaskMapper.insert(message);
+ });
+ });
+ });
+
+
+ }
+
+ public List searchMessage() {
+ MessageTaskExample messageTaskExample = new MessageTaskExample();
+ messageTaskExample.createCriteria();
+ List messageTasks = new ArrayList<>();
+ List messageSettingDetail = new ArrayList<>();
+ messageTasks = messageTaskMapper.selectByExample(messageTaskExample);
+ return messageSettingDetail;
+ }
+}
\ No newline at end of file
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..0c61c0380b
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/notice/service/WxChatTaskService.java
@@ -0,0 +1,27 @@
+package io.metersphere.notice.service;
+
+import io.metersphere.notice.message.TextMessage;
+import io.metersphere.notice.util.SendResult;
+import io.metersphere.notice.util.WxChatbotClient;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class WxChatTaskService {
+ public void enterpriseWechatTask() {
+ TextMessage message = new TextMessage("脸给你打歪");
+ List mentionedMobileList = new ArrayList();
+ mentionedMobileList.add("15135125273");//@群内成员 手机号
+ message.setMentionedMobileList(mentionedMobileList);
+ message.setIsAtAll(true);//@所有人
+ try {
+ SendResult result = WxChatbotClient.send("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=a03acc34-4988-4200-a9c7-7c9b30c5601e", message);
+ System.out.println(result);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
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/service/FileService.java b/backend/src/main/java/io/metersphere/service/FileService.java
index ff2801320e..a74fb7b243 100644
--- a/backend/src/main/java/io/metersphere/service/FileService.java
+++ b/backend/src/main/java/io/metersphere/service/FileService.java
@@ -13,6 +13,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@@ -132,7 +133,7 @@ public class FileService {
final List testCaseFiles = testCaseFileMapper.selectByExample(testCaseFileExample);
if (CollectionUtils.isEmpty(testCaseFiles)) {
- return null;
+ return new ArrayList<>();
}
List fileIds = testCaseFiles.stream().map(TestCaseFile::getFileId).collect(Collectors.toList());
diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseCommentService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseCommentService.java
index 42c7800298..cd0ce95a47 100644
--- a/backend/src/main/java/io/metersphere/track/service/TestCaseCommentService.java
+++ b/backend/src/main/java/io/metersphere/track/service/TestCaseCommentService.java
@@ -8,10 +8,15 @@ import io.metersphere.base.mapper.TestCaseCommentMapper;
import io.metersphere.base.mapper.TestCaseMapper;
import io.metersphere.base.mapper.TestCaseReviewMapper;
import io.metersphere.base.mapper.UserMapper;
+import io.metersphere.commons.constants.NoticeConstants;
+import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
+import io.metersphere.notice.service.DingTaskService;
import io.metersphere.notice.service.MailService;
+import io.metersphere.notice.service.WxChatTaskService;
import io.metersphere.track.request.testreview.SaveCommentRequest;
import io.metersphere.track.request.testreview.SaveTestCaseReviewRequest;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -34,6 +39,10 @@ public class TestCaseCommentService {
MailService mailService;
@Resource
TestCaseMapper testCaseMapper;
+ @Resource
+ DingTaskService dingTaskService;
+ @Resource
+ WxChatTaskService wxChatTaskService;
public void saveComment(SaveCommentRequest request) {
TestCaseComment testCaseComment = new TestCaseComment();
@@ -49,7 +58,18 @@ public class TestCaseCommentService {
SaveTestCaseReviewRequest caseReviewRequest = new SaveTestCaseReviewRequest();
List userIds = new ArrayList<>();
userIds.add(testCaseWithBLOBs.getMaintainer());
- mailService.sendCommentNotice(userIds, request, testCaseWithBLOBs);
+ String context = getReviewContext(request, testCaseWithBLOBs);
+ try {
+ if (StringUtils.equals(NoticeConstants.NAIL_ROBOT, "NAIL_ROBOT")) {
+ dingTaskService.sendDingTask(context, userIds);
+ } else if (StringUtils.equals(NoticeConstants.WECHAT_ROBOT, "WECHAT_ROBOT")) {
+ wxChatTaskService.enterpriseWechatTask();
+ } else {
+ mailService.sendCommentNotice(userIds, request, testCaseWithBLOBs);
+ }
+ } catch (Exception e) {
+ LogUtil.error(e);
+ }
}
@@ -72,4 +92,10 @@ public class TestCaseCommentService {
testCaseCommentExample.createCriteria().andCaseIdEqualTo(caseId);
testCaseCommentMapper.deleteByExample(testCaseCommentExample);
}
+
+ private String getReviewContext(SaveCommentRequest request, TestCaseWithBLOBs testCaseWithBLOBs) {
+ String context = "";
+ context = testCaseWithBLOBs.getMaintainer() + "发起的" + "'" + testCaseWithBLOBs.getName() + "'" + "添加评论:" + request.getDescription();
+ return context;
+ }
}
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 809fd0bb06..5c61abc8a3 100644
--- a/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java
+++ b/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java
@@ -6,17 +6,18 @@ import io.metersphere.base.mapper.ext.ExtProjectMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseReviewMapper;
import io.metersphere.base.mapper.ext.ExtTestReviewCaseMapper;
+import io.metersphere.commons.constants.NoticeConstants;
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;
+import io.metersphere.notice.service.DingTaskService;
import io.metersphere.notice.service.MailService;
+import io.metersphere.notice.service.WxChatTaskService;
import io.metersphere.service.UserService;
import io.metersphere.track.dto.TestCaseReviewDTO;
import io.metersphere.track.dto.TestReviewCaseDTO;
@@ -36,7 +37,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
-
+import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
@@ -72,6 +73,10 @@ public class TestCaseReviewService {
MailService mailService;
@Resource
ExtTestCaseMapper extTestCaseMapper;
+ @Resource
+ DingTaskService dingTaskService;
+ @Resource
+ WxChatTaskService wxChatTaskService;
public void saveTestCaseReview(SaveTestCaseReviewRequest reviewRequest) {
checkCaseReviewExist(reviewRequest);
@@ -99,8 +104,15 @@ public class TestCaseReviewService {
reviewRequest.setCreator(SessionUtils.getUser().getId());
reviewRequest.setStatus(TestCaseReviewStatus.Prepare.name());
testCaseReviewMapper.insert(reviewRequest);
+ String context = getReviewContext(reviewRequest, "create");
try {
- mailService.sendReviewerNotice(userIds, reviewRequest);
+ if (StringUtils.equals(NoticeConstants.NAIL_ROBOT, "NAIL_ROBOT")) {
+ dingTaskService.sendDingTask(context, userIds);
+ } else if (StringUtils.equals(NoticeConstants.WECHAT_ROBOT, "WECHAT_ROBOT")) {
+ wxChatTaskService.enterpriseWechatTask();
+ } else {
+ mailService.sendReviewerNotice(userIds, reviewRequest);
+ }
} catch (Exception e) {
LogUtil.error(e);
}
@@ -374,7 +386,14 @@ public class TestCaseReviewService {
testCaseReviewMapper.updateByPrimaryKeySelective(testCaseReview);
try {
BeanUtils.copyProperties(testCaseReviewRequest, _testCaseReview);
- mailService.sendEndNotice(userIds, testCaseReviewRequest);
+ String context = getReviewContext(testCaseReviewRequest, "create");
+ if (StringUtils.equals(NoticeConstants.NAIL_ROBOT, "NAIL_ROBOT")) {
+ dingTaskService.sendDingTask(context, userIds);
+ } else if (StringUtils.equals(NoticeConstants.WECHAT_ROBOT, "WECHAT_ROBOT")) {
+ wxChatTaskService.enterpriseWechatTask();
+ } else {
+ mailService.sendEndNotice(userIds, testCaseReviewRequest);
+ }
} catch (Exception e) {
LogUtil.error(e);
}
@@ -465,4 +484,28 @@ public class TestCaseReviewService {
request.setProjectIds(projectIds);
return extTestReviewCaseMapper.list(request);
}
+
+ private String getReviewContext(SaveTestCaseReviewRequest reviewRequest, String type) {
+ Long startTime = reviewRequest.getCreateTime();
+ Long endTime = reviewRequest.getEndTime();
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String start = null;
+ String sTime = String.valueOf(startTime);
+ String eTime = String.valueOf(endTime);
+ if (!sTime.equals("null")) {
+ start = sdf.format(new Date(Long.parseLong(sTime)));
+ }
+ String end = null;
+ if (!eTime.equals("null")) {
+ end = sdf.format(new Date(Long.parseLong(eTime)));
+ }
+ String context = "";
+ if (StringUtils.equals("create", type)) {
+ context = reviewRequest.getCreator() + "发起的" + "'" + reviewRequest.getName() + "'" + "待开始,计划开始时间是" + start + "计划结束时间为" + end + "请跟进";
+ } else if (StringUtils.equals("end", type)) {
+ context = reviewRequest.getCreator() + "发起的" + "'" + reviewRequest.getName() + "'" + "已完成,计划开始时间是" + start + "计划结束时间为" + end + "已完成";
+ }
+
+ return context;
+ }
}
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/java/io/metersphere/track/service/TestReviewTestCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestReviewTestCaseService.java
index 3c0270b8c3..89362dca7e 100644
--- a/backend/src/main/java/io/metersphere/track/service/TestReviewTestCaseService.java
+++ b/backend/src/main/java/io/metersphere/track/service/TestReviewTestCaseService.java
@@ -15,10 +15,12 @@ import io.metersphere.track.dto.TestReviewCaseDTO;
import io.metersphere.track.request.testplancase.TestReviewCaseBatchRequest;
import io.metersphere.track.request.testreview.DeleteRelevanceRequest;
import io.metersphere.track.request.testreview.QueryCaseReviewRequest;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -64,17 +66,17 @@ public class TestReviewTestCaseService {
return testCaseReviewUsers.stream().map(TestCaseReviewUsers::getUserId).collect(Collectors.toList());
}
- private String getReviewName(List userIds, Map userMap) {
- StringBuilder stringBuilder = new StringBuilder();
- String name = "";
-
+ private String getReviewName(List userIds, Map userMap) {
+ List userNames = new ArrayList<>();
if (userIds.size() > 0) {
for (String id : userIds) {
- stringBuilder.append(userMap.get(id)).append("、");
+ String n = userMap.get(id);
+ if (StringUtils.isNotBlank(n)) {
+ userNames.add(n);
+ }
}
- name = stringBuilder.toString().substring(0, stringBuilder.length() - 1);
}
- return name;
+ return StringUtils.join(userNames, "、");
}
public int deleteTestCase(DeleteRelevanceRequest request) {
diff --git a/backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java b/backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java
index 5aa583730d..465110fc92 100644
--- a/backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java
+++ b/backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java
@@ -95,11 +95,12 @@ public class XmindCaseParser {
}
String path = "";
for (int i = 0; i < nodes.length; i++) {
- path += nodes[i].trim() + "/";
if (i != 0 && StringUtils.equals(nodes[i].trim(), "")) {
- process.append(path + ":" + Translator.get("module_not_null") + "; ");
+ process.append(Translator.get("module") + ":【" + path + "】" + Translator.get("module_not_null") + "; ");
} else if (nodes[i].trim().length() > 30) {
process.append(nodes[i].trim() + ":" + Translator.get("test_track.length_less_than") + "30 ;");
+ } else {
+ path += nodes[i].trim() + "/";
}
}
});
@@ -124,7 +125,7 @@ public class XmindCaseParser {
}
for (int i = 0; i < nodes.length; i++) {
if (i != 0 && StringUtils.equals(nodes[i].trim(), "")) {
- stringBuilder.append(Translator.get("test_case") + "," + data.getName() + Translator.get("module_not_null") + "; ");
+ stringBuilder.append(Translator.get("test_case") + ":【" + data.getName() + "】" + Translator.get("module_not_null") + "; ");
break;
} else if (nodes[i].trim().length() > 30) {
stringBuilder.append(nodes[i].trim() + ":" + Translator.get("module") + Translator.get("test_track.length_less_than") + "30 ;");
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/backend/src/main/resources/db/migration/V32__test_case_prerequisite.sql b/backend/src/main/resources/db/migration/V32__test_case_prerequisite.sql
new file mode 100644
index 0000000000..8eced76731
--- /dev/null
+++ b/backend/src/main/resources/db/migration/V32__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/frontend/src/business/components/performance/report/PerformanceTestReport.vue b/frontend/src/business/components/performance/report/PerformanceTestReport.vue
index 569eca7028..e94b84a186 100644
--- a/frontend/src/business/components/performance/report/PerformanceTestReport.vue
+++ b/frontend/src/business/components/performance/report/PerformanceTestReport.vue
@@ -139,9 +139,9 @@ export default {
{text: 'Error', value: 'Error'}
],
triggerFilters: [
- {text: '手动', value: 'MANUAL'},
- {text: '定时任务', value: 'SCHEDULE'},
- {text: 'API', value: 'API'}
+ {text: this.$t('commons.trigger_mode.manual'), value: 'MANUAL'},
+ {text: this.$t('commons.trigger_mode.schedule'), value: 'SCHEDULE'},
+ {text: this.$t('commons.trigger_mode.api'), value: 'API'}
],
buttons: [
{
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 @@