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 @@ diff --git a/frontend/src/business/components/settings/organization/MessageSettings.vue b/frontend/src/business/components/settings/organization/MessageSettings.vue new file mode 100644 index 0000000000..550887ed0c --- /dev/null +++ b/frontend/src/business/components/settings/organization/MessageSettings.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/frontend/src/business/components/settings/organization/TaskNotification.vue b/frontend/src/business/components/settings/organization/TaskNotification.vue new file mode 100644 index 0000000000..ef20fba840 --- /dev/null +++ b/frontend/src/business/components/settings/organization/TaskNotification.vue @@ -0,0 +1,537 @@ + + + + + diff --git a/frontend/src/business/components/settings/router.js b/frontend/src/business/components/settings/router.js index 08c5d7842f..93da75f536 100644 --- a/frontend/src/business/components/settings/router.js +++ b/frontend/src/business/components/settings/router.js @@ -48,6 +48,11 @@ export default { component: () => import('@/business/components/settings/organization/ServiceIntegration'), meta: {organization: true, title: 'organization.service_integration'} }, + { + path: 'messagesettings', + component: () => import('@/business/components/settings/organization/MessageSettings'), + meta: {organization: true, title: 'organization.message_settings'} + }, { path: 'member', component: () => import('@/business/components/settings/workspace/WorkspaceMember'), diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index 64f3df719d..8094dd2d43 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -213,6 +213,20 @@ export default { select: 'Select Organization', service_integration: 'Service integration', defect_manage: 'Defect management platform', + message_settings:'Message settings', + message:{ + jenkins_task_notification:'Jenkins task notification', + test_plan_task_notification:'Test plan task notification', + test_review_task_notice:'Test review task notice', + defect_task_notification:'Defect task notification', + create_new_notification:'Create a new notification', + select_events:'Select event', + select_receiving_method:'Select receiving method', + mail:'mail', + nail_robot:'Nail robot', + enterprise_wechat_robot:'Enterprise wechat robot', + + }, integration: { select_defect_platform: 'Please select the defect management platform to be integrated:', basic_auth_info: 'Basic Auth account information:', diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index 376dc6a835..9f2a07198a 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -214,6 +214,22 @@ export default { delete_warning: '删除该组织将同步删除该组织下所有相关工作空间和相关工作空间下的所有项目,以及项目中的所有用例、接口测试、性能测试等,确定要删除吗?', service_integration: '服务集成', defect_manage: '缺陷管理平台', + message_settings:'消息设置', + message:{ + jenkins_task_notification:'Jenkins任务通知', + test_plan_task_notification:'测试计划任务通知', + test_review_task_notice:'测试评审任务通知', + create_new_notification:'创建新通知', + select_events:'选择事件', + defect_task_notification:'缺陷任务通知', + select_receiving_method:'选择接收方式', + mail:'邮件', + nail_robot:'钉钉机器人', + enterprise_wechat_robot:'企业微信机器人', + + + + }, integration: { select_defect_platform: '请选择要集成的缺陷管理平台:', basic_auth_info: 'Basic Auth 账号信息:', diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index 2f7c4fd8b1..8ed221e910 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -214,6 +214,19 @@ export default { delete_warning: '刪除該組織將同步刪除該組織下所有相關工作空間和相關工作空間下的所有項目,以及項目中的所有用例、接口測試、性能測試等,確定要刪除嗎?', service_integration: '服務集成', defect_manage: '缺陷管理平臺', + message_settings:'消息設定', + message:{ + jenkins_task_notification:'Jenkins任務通知', + test_plan_task_notification:'測試計畫任務通知', + test_review_task_notice:'測試評審任務通知', + defect_task_notification:'缺陷任務通知', + create_new_notification:'創建新通知', + select_events:'選擇事件', + select_receiving_method:'選擇接收管道', + mail:'郵件', + nail_robot:'釘釘機器人', + enterprise_wechat_robot:'企業微信機器人', + }, integration: { select_defect_platform: '請選擇要集成的缺陷管理平臺:', basic_auth_info: 'Basic Auth 賬號信息:', @@ -236,7 +249,10 @@ export default { successful_operation: '操作成功', not_integrated: '未集成該平臺', choose_platform: '請選擇集成的平臺', - verified: '驗證通過' + verified: '驗證通過', + mail:'郵件', + nail_robot:'釘釘機器人', + enterprise_wechat_robot:'企業微信機器人', } }, project: {