diff --git a/backend/src/main/java/io/metersphere/base/domain/Notification.java b/backend/src/main/java/io/metersphere/base/domain/Notification.java new file mode 100644 index 0000000000..9fb7981ea1 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/Notification.java @@ -0,0 +1,23 @@ +package io.metersphere.base.domain; + +import java.io.Serializable; +import lombok.Data; + +@Data +public class Notification implements Serializable { + private Long id; + + private String type; + + private String receiver; + + private String title; + + private String status; + + private Long createTime; + + private String content; + + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/domain/NotificationExample.java b/backend/src/main/java/io/metersphere/base/domain/NotificationExample.java new file mode 100644 index 0000000000..1f1dbeedbd --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/domain/NotificationExample.java @@ -0,0 +1,600 @@ +package io.metersphere.base.domain; + +import java.util.ArrayList; +import java.util.List; + +public class NotificationExample { + protected String orderByClause; + + protected boolean distinct; + + protected List oredCriteria; + + public NotificationExample() { + 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(Long value) { + addCriterion("id =", value, "id"); + return (Criteria) this; + } + + public Criteria andIdNotEqualTo(Long value) { + addCriterion("id <>", value, "id"); + return (Criteria) this; + } + + public Criteria andIdGreaterThan(Long value) { + addCriterion("id >", value, "id"); + return (Criteria) this; + } + + public Criteria andIdGreaterThanOrEqualTo(Long value) { + addCriterion("id >=", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLessThan(Long value) { + addCriterion("id <", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLessThanOrEqualTo(Long value) { + addCriterion("id <=", 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(Long value1, Long value2) { + addCriterion("id between", value1, value2, "id"); + return (Criteria) this; + } + + public Criteria andIdNotBetween(Long value1, Long 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 andReceiverIsNull() { + addCriterion("receiver is null"); + return (Criteria) this; + } + + public Criteria andReceiverIsNotNull() { + addCriterion("receiver is not null"); + return (Criteria) this; + } + + public Criteria andReceiverEqualTo(String value) { + addCriterion("receiver =", value, "receiver"); + return (Criteria) this; + } + + public Criteria andReceiverNotEqualTo(String value) { + addCriterion("receiver <>", value, "receiver"); + return (Criteria) this; + } + + public Criteria andReceiverGreaterThan(String value) { + addCriterion("receiver >", value, "receiver"); + return (Criteria) this; + } + + public Criteria andReceiverGreaterThanOrEqualTo(String value) { + addCriterion("receiver >=", value, "receiver"); + return (Criteria) this; + } + + public Criteria andReceiverLessThan(String value) { + addCriterion("receiver <", value, "receiver"); + return (Criteria) this; + } + + public Criteria andReceiverLessThanOrEqualTo(String value) { + addCriterion("receiver <=", value, "receiver"); + return (Criteria) this; + } + + public Criteria andReceiverLike(String value) { + addCriterion("receiver like", value, "receiver"); + return (Criteria) this; + } + + public Criteria andReceiverNotLike(String value) { + addCriterion("receiver not like", value, "receiver"); + return (Criteria) this; + } + + public Criteria andReceiverIn(List values) { + addCriterion("receiver in", values, "receiver"); + return (Criteria) this; + } + + public Criteria andReceiverNotIn(List values) { + addCriterion("receiver not in", values, "receiver"); + return (Criteria) this; + } + + public Criteria andReceiverBetween(String value1, String value2) { + addCriterion("receiver between", value1, value2, "receiver"); + return (Criteria) this; + } + + public Criteria andReceiverNotBetween(String value1, String value2) { + addCriterion("receiver not between", value1, value2, "receiver"); + return (Criteria) this; + } + + public Criteria andTitleIsNull() { + addCriterion("title is null"); + return (Criteria) this; + } + + public Criteria andTitleIsNotNull() { + addCriterion("title is not null"); + return (Criteria) this; + } + + public Criteria andTitleEqualTo(String value) { + addCriterion("title =", value, "title"); + return (Criteria) this; + } + + public Criteria andTitleNotEqualTo(String value) { + addCriterion("title <>", value, "title"); + return (Criteria) this; + } + + public Criteria andTitleGreaterThan(String value) { + addCriterion("title >", value, "title"); + return (Criteria) this; + } + + public Criteria andTitleGreaterThanOrEqualTo(String value) { + addCriterion("title >=", value, "title"); + return (Criteria) this; + } + + public Criteria andTitleLessThan(String value) { + addCriterion("title <", value, "title"); + return (Criteria) this; + } + + public Criteria andTitleLessThanOrEqualTo(String value) { + addCriterion("title <=", value, "title"); + return (Criteria) this; + } + + public Criteria andTitleLike(String value) { + addCriterion("title like", value, "title"); + return (Criteria) this; + } + + public Criteria andTitleNotLike(String value) { + addCriterion("title not like", value, "title"); + return (Criteria) this; + } + + public Criteria andTitleIn(List values) { + addCriterion("title in", values, "title"); + return (Criteria) this; + } + + public Criteria andTitleNotIn(List values) { + addCriterion("title not in", values, "title"); + return (Criteria) this; + } + + public Criteria andTitleBetween(String value1, String value2) { + addCriterion("title between", value1, value2, "title"); + return (Criteria) this; + } + + public Criteria andTitleNotBetween(String value1, String value2) { + addCriterion("title not between", value1, value2, "title"); + return (Criteria) this; + } + + public Criteria andStatusIsNull() { + addCriterion("`status` is null"); + return (Criteria) this; + } + + public Criteria andStatusIsNotNull() { + addCriterion("`status` is not null"); + return (Criteria) this; + } + + public Criteria andStatusEqualTo(String value) { + addCriterion("`status` =", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotEqualTo(String value) { + addCriterion("`status` <>", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusGreaterThan(String value) { + addCriterion("`status` >", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusGreaterThanOrEqualTo(String value) { + addCriterion("`status` >=", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusLessThan(String value) { + addCriterion("`status` <", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusLessThanOrEqualTo(String value) { + addCriterion("`status` <=", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusLike(String value) { + addCriterion("`status` like", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotLike(String value) { + addCriterion("`status` not like", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusIn(List values) { + addCriterion("`status` in", values, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotIn(List values) { + addCriterion("`status` not in", values, "status"); + return (Criteria) this; + } + + public Criteria andStatusBetween(String value1, String value2) { + addCriterion("`status` between", value1, value2, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotBetween(String value1, String value2) { + addCriterion("`status` not between", value1, value2, "status"); + return (Criteria) this; + } + + public Criteria andCreateTimeIsNull() { + addCriterion("create_time is null"); + return (Criteria) this; + } + + public Criteria andCreateTimeIsNotNull() { + addCriterion("create_time is not null"); + return (Criteria) this; + } + + public Criteria andCreateTimeEqualTo(Long value) { + addCriterion("create_time =", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotEqualTo(Long value) { + addCriterion("create_time <>", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeGreaterThan(Long value) { + addCriterion("create_time >", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeGreaterThanOrEqualTo(Long value) { + addCriterion("create_time >=", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeLessThan(Long value) { + addCriterion("create_time <", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeLessThanOrEqualTo(Long value) { + addCriterion("create_time <=", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeIn(List values) { + addCriterion("create_time in", values, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotIn(List values) { + addCriterion("create_time not in", values, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeBetween(Long value1, Long value2) { + addCriterion("create_time between", value1, value2, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotBetween(Long value1, Long value2) { + addCriterion("create_time not between", value1, value2, "createTime"); + 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/NotificationMapper.java b/backend/src/main/java/io/metersphere/base/mapper/NotificationMapper.java new file mode 100644 index 0000000000..6af1de0c1b --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/NotificationMapper.java @@ -0,0 +1,36 @@ +package io.metersphere.base.mapper; + +import io.metersphere.base.domain.Notification; +import io.metersphere.base.domain.NotificationExample; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +public interface NotificationMapper { + long countByExample(NotificationExample example); + + int deleteByExample(NotificationExample example); + + int deleteByPrimaryKey(Long id); + + int insert(Notification record); + + int insertSelective(Notification record); + + List selectByExampleWithBLOBs(NotificationExample example); + + List selectByExample(NotificationExample example); + + Notification selectByPrimaryKey(Long id); + + int updateByExampleSelective(@Param("record") Notification record, @Param("example") NotificationExample example); + + int updateByExampleWithBLOBs(@Param("record") Notification record, @Param("example") NotificationExample example); + + int updateByExample(@Param("record") Notification record, @Param("example") NotificationExample example); + + int updateByPrimaryKeySelective(Notification record); + + int updateByPrimaryKeyWithBLOBs(Notification record); + + int updateByPrimaryKey(Notification record); +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/NotificationMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/NotificationMapper.xml new file mode 100644 index 0000000000..cc90b7695a --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/NotificationMapper.xml @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + 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`, receiver, title, `status`, create_time + + + content + + + + + + delete from notification + where id = #{id,jdbcType=BIGINT} + + + delete from notification + + + + + + insert into notification (id, `type`, receiver, + title, `status`, create_time, + content) + values (#{id,jdbcType=BIGINT}, #{type,jdbcType=VARCHAR}, #{receiver,jdbcType=VARCHAR}, + #{title,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, + #{content,jdbcType=LONGVARCHAR}) + + + insert into notification + + + id, + + + `type`, + + + receiver, + + + title, + + + `status`, + + + create_time, + + + content, + + + + + #{id,jdbcType=BIGINT}, + + + #{type,jdbcType=VARCHAR}, + + + #{receiver,jdbcType=VARCHAR}, + + + #{title,jdbcType=VARCHAR}, + + + #{status,jdbcType=VARCHAR}, + + + #{createTime,jdbcType=BIGINT}, + + + #{content,jdbcType=LONGVARCHAR}, + + + + + + update notification + + + id = #{record.id,jdbcType=BIGINT}, + + + `type` = #{record.type,jdbcType=VARCHAR}, + + + receiver = #{record.receiver,jdbcType=VARCHAR}, + + + title = #{record.title,jdbcType=VARCHAR}, + + + `status` = #{record.status,jdbcType=VARCHAR}, + + + create_time = #{record.createTime,jdbcType=BIGINT}, + + + content = #{record.content,jdbcType=LONGVARCHAR}, + + + + + + + + update notification + set id = #{record.id,jdbcType=BIGINT}, + `type` = #{record.type,jdbcType=VARCHAR}, + receiver = #{record.receiver,jdbcType=VARCHAR}, + title = #{record.title,jdbcType=VARCHAR}, + `status` = #{record.status,jdbcType=VARCHAR}, + create_time = #{record.createTime,jdbcType=BIGINT}, + content = #{record.content,jdbcType=LONGVARCHAR} + + + + + + update notification + set id = #{record.id,jdbcType=BIGINT}, + `type` = #{record.type,jdbcType=VARCHAR}, + receiver = #{record.receiver,jdbcType=VARCHAR}, + title = #{record.title,jdbcType=VARCHAR}, + `status` = #{record.status,jdbcType=VARCHAR}, + create_time = #{record.createTime,jdbcType=BIGINT} + + + + + + update notification + + + `type` = #{type,jdbcType=VARCHAR}, + + + receiver = #{receiver,jdbcType=VARCHAR}, + + + title = #{title,jdbcType=VARCHAR}, + + + `status` = #{status,jdbcType=VARCHAR}, + + + create_time = #{createTime,jdbcType=BIGINT}, + + + content = #{content,jdbcType=LONGVARCHAR}, + + + where id = #{id,jdbcType=BIGINT} + + + update notification + set `type` = #{type,jdbcType=VARCHAR}, + receiver = #{receiver,jdbcType=VARCHAR}, + title = #{title,jdbcType=VARCHAR}, + `status` = #{status,jdbcType=VARCHAR}, + create_time = #{createTime,jdbcType=BIGINT}, + content = #{content,jdbcType=LONGVARCHAR} + where id = #{id,jdbcType=BIGINT} + + + update notification + set `type` = #{type,jdbcType=VARCHAR}, + receiver = #{receiver,jdbcType=VARCHAR}, + title = #{title,jdbcType=VARCHAR}, + `status` = #{status,jdbcType=VARCHAR}, + create_time = #{createTime,jdbcType=BIGINT} + where id = #{id,jdbcType=BIGINT} + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtNotificationMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtNotificationMapper.java new file mode 100644 index 0000000000..108a8541c8 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtNotificationMapper.java @@ -0,0 +1,21 @@ +package io.metersphere.base.mapper.ext; + + +import io.metersphere.base.domain.Notification; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface ExtNotificationMapper { + + Notification getNotification(@Param("id") Integer id, @Param("receiver") String receiver); + + List listNotification(@Param("search") String search, @Param("receiver") String receiver); + + List listReadNotification(@Param("search") String search, @Param("receiver") String receiver); + + List listUnreadNotification(@Param("search") String search, @Param("receiver") String receiver); + + int countNotification(@Param("notification") Notification notification); + +} diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtNotificationMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtNotificationMapper.xml new file mode 100644 index 0000000000..027cc9e61f --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtNotificationMapper.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/commons/constants/NotificationConstants.java b/backend/src/main/java/io/metersphere/commons/constants/NotificationConstants.java new file mode 100644 index 0000000000..a8574a5068 --- /dev/null +++ b/backend/src/main/java/io/metersphere/commons/constants/NotificationConstants.java @@ -0,0 +1,12 @@ +package io.metersphere.commons.constants; + +public class NotificationConstants { + + public enum Type { + MESSAGE, ANNOUNCEMENT + } + + public enum Status { + READ, UNREAD + } +} diff --git a/backend/src/main/java/io/metersphere/commons/utils/SessionUtils.java b/backend/src/main/java/io/metersphere/commons/utils/SessionUtils.java index 8b81a9e3e2..c8ab04c115 100644 --- a/backend/src/main/java/io/metersphere/commons/utils/SessionUtils.java +++ b/backend/src/main/java/io/metersphere/commons/utils/SessionUtils.java @@ -7,7 +7,10 @@ import org.apache.shiro.session.Session; import org.apache.shiro.session.mgt.DefaultSessionManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.support.DefaultSubjectContext; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import javax.servlet.http.HttpServletRequest; import java.util.Collection; import static io.metersphere.commons.constants.SessionConstants.ATTR_USER; @@ -65,14 +68,26 @@ public class SessionUtils { } public static String getCurrentWorkspaceId() { + HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); + if (request.getHeader("WORKSPACE_ID") != null) { + return request.getHeader("WORKSPACE_ID"); + } return getUser().getLastWorkspaceId(); } public static String getCurrentOrganizationId() { + HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); + if (request.getHeader("ORGANIZATION_ID") != null) { + return request.getHeader("ORGANIZATION_ID"); + } return getUser().getLastOrganizationId(); } public static String getCurrentProjectId() { + HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); + if (request.getHeader("PROJECT_ID") != null) { + return request.getHeader("PROJECT_ID"); + } return getUser().getLastProjectId(); } } diff --git a/backend/src/main/java/io/metersphere/notice/sender/SendNoticeAspect.java b/backend/src/main/java/io/metersphere/notice/sender/SendNoticeAspect.java index 0f551bb08d..7b39c0f8db 100644 --- a/backend/src/main/java/io/metersphere/notice/sender/SendNoticeAspect.java +++ b/backend/src/main/java/io/metersphere/notice/sender/SendNoticeAspect.java @@ -35,10 +35,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - -/** - * 系统日志:切面处理类 - */ @Aspect @Component public class SendNoticeAspect { diff --git a/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java b/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java index dcdb601d0e..5505f7fd21 100644 --- a/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java +++ b/backend/src/main/java/io/metersphere/notice/service/NoticeSendService.java @@ -1,19 +1,26 @@ package io.metersphere.notice.service; import com.alibaba.nacos.client.utils.StringUtils; +import io.metersphere.base.domain.User; import io.metersphere.commons.constants.NoticeConstants; import io.metersphere.commons.utils.LogUtil; +import io.metersphere.commons.utils.SessionUtils; +import io.metersphere.controller.request.organization.QueryOrgMemberRequest; import io.metersphere.notice.domain.MessageDetail; +import io.metersphere.notice.sender.AbstractNoticeSender; import io.metersphere.notice.sender.NoticeModel; -import io.metersphere.notice.sender.NoticeSender; import io.metersphere.notice.sender.impl.DingNoticeSender; import io.metersphere.notice.sender.impl.LarkNoticeSender; import io.metersphere.notice.sender.impl.MailNoticeSender; import io.metersphere.notice.sender.impl.WeComNoticeSender; +import io.metersphere.service.UserService; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.RegExUtils; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; +import java.util.Map; @Component public class NoticeSendService { @@ -27,9 +34,13 @@ public class NoticeSendService { private LarkNoticeSender larkNoticeSender; @Resource private NoticeService noticeService; + @Resource + private NotificationService notificationService; + @Resource + private UserService userService; - private NoticeSender getNoticeSender(MessageDetail messageDetail) { - NoticeSender noticeSender = null; + private AbstractNoticeSender getNoticeSender(MessageDetail messageDetail) { + AbstractNoticeSender noticeSender = null; switch (messageDetail.getType()) { case NoticeConstants.Type.EMAIL: noticeSender = mailNoticeSender; @@ -50,11 +61,11 @@ public class NoticeSendService { } public void send(String taskType, NoticeModel noticeModel) { - String loadReportId = (String) noticeModel.getParamMap().get("id"); try { List messageDetails; switch (taskType) { case NoticeConstants.Mode.API: + String loadReportId = (String) noticeModel.getParamMap().get("id"); messageDetails = noticeService.searchMessageByTypeBySend(NoticeConstants.TaskType.JENKINS_TASK, loadReportId); break; case NoticeConstants.Mode.SCHEDULE: @@ -64,13 +75,38 @@ public class NoticeSendService { messageDetails = noticeService.searchMessageByType(taskType); break; } - messageDetails.forEach(messageDetail -> { - if (StringUtils.equals(messageDetail.getEvent(), noticeModel.getEvent())) { - this.getNoticeSender(messageDetail).send(messageDetail, noticeModel); - } + // 发送实体通知 + messageDetails.stream() + .filter(messageDetail -> StringUtils.equals(messageDetail.getEvent(), noticeModel.getEvent())) + .forEach(messageDetail -> this.getNoticeSender(messageDetail).send(messageDetail, noticeModel)); + // 发送站内通知 + QueryOrgMemberRequest request = new QueryOrgMemberRequest(); + request.setOrganizationId(SessionUtils.getCurrentOrganizationId()); + List orgAllMember = userService.getOrgAllMember(request); + // 替换变量 + noticeModel.setContext(getContent(noticeModel)); + orgAllMember.forEach(receiver -> { + String context = noticeModel.getContext(); + LogUtil.debug("发送站内通知: {}, 内容: {}", receiver.getName(), context); + notificationService.sendAnnouncement(noticeModel.getSubject(), context, receiver.getId()); }); } catch (Exception e) { LogUtil.error(e.getMessage(), e); } } + + private String getContent(NoticeModel noticeModel) { + String template = noticeModel.getContext(); + Map paramMap = noticeModel.getParamMap(); + if (MapUtils.isNotEmpty(paramMap)) { + for (String k : paramMap.keySet()) { + if (paramMap.get(k) != null) { + template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", paramMap.get(k).toString()); + } else { + template = RegExUtils.replaceAll(template, "\\$\\{" + k + "}", ""); + } + } + } + return template; + } } diff --git a/backend/src/main/java/io/metersphere/notice/service/NotificationService.java b/backend/src/main/java/io/metersphere/notice/service/NotificationService.java new file mode 100644 index 0000000000..9e82da315c --- /dev/null +++ b/backend/src/main/java/io/metersphere/notice/service/NotificationService.java @@ -0,0 +1,88 @@ +package io.metersphere.notice.service; + + +import io.metersphere.base.domain.Notification; +import io.metersphere.base.domain.NotificationExample; +import io.metersphere.base.mapper.NotificationMapper; +import io.metersphere.base.mapper.ext.ExtNotificationMapper; +import io.metersphere.commons.constants.NotificationConstants; +import io.metersphere.commons.utils.SessionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; + +@Service +@Transactional(rollbackFor = Exception.class) +public class NotificationService { + + @Resource + private NotificationMapper notificationMapper; + + @Resource + private ExtNotificationMapper extNotificationMapper; + + public void sendAnnouncement(String subject, String content, String receiver) { + Notification notification = new Notification(); + notification.setTitle(subject); + notification.setContent(content); + notification.setType(NotificationConstants.Type.ANNOUNCEMENT.name()); + notification.setStatus(NotificationConstants.Status.UNREAD.name()); + notification.setCreateTime(System.currentTimeMillis()); + notification.setReceiver(receiver); + notificationMapper.insert(notification); + } + + public Notification getNotification(int id) { + return extNotificationMapper.getNotification(id, SessionUtils.getUser().getId()); + } + + public int readAll() { + Notification record = new Notification(); + record.setStatus(NotificationConstants.Status.READ.name()); + NotificationExample example = new NotificationExample(); + example.createCriteria().andReceiverEqualTo(SessionUtils.getUser().getId()); + return notificationMapper.updateByExampleSelective(record, example); + } + + public int countNotification(Notification notification) { + notification.setReceiver(SessionUtils.getUser().getId()); + return extNotificationMapper.countNotification(notification); + } + + public int read(long id) { + Notification record = new Notification(); + record.setStatus(NotificationConstants.Status.READ.name()); + NotificationExample example = new NotificationExample(); + example.createCriteria().andIdEqualTo(id).andReceiverEqualTo(SessionUtils.getUser().getId()); + return notificationMapper.updateByExampleSelective(record, example); + } + + public List listNotification(Notification notification) { + String search = null; + if (StringUtils.isNotBlank(notification.getTitle())) { + search = "%" + notification.getTitle() + "%"; + } + return extNotificationMapper.listNotification(search, SessionUtils.getUser().getId()); + } + + public List listReadNotification(Notification notification) { + String search = null; + if (StringUtils.isNotBlank(notification.getTitle())) { + search = "%" + notification.getTitle() + "%"; + } + return extNotificationMapper.listReadNotification(search, SessionUtils.getUser().getId()); + } + + public List listUnreadNotification(Notification notification) { + String search = null; + if (StringUtils.isNotBlank(notification.getTitle())) { + search = "%" + notification.getTitle() + "%"; + } + return extNotificationMapper.listUnreadNotification(search, SessionUtils.getUser().getId()); + } + + +} diff --git a/backend/src/main/resources/db/migration/V93__v1.12_release.sql b/backend/src/main/resources/db/migration/V93__v1.12_release.sql index f48240819f..86e0185f84 100644 --- a/backend/src/main/resources/db/migration/V93__v1.12_release.sql +++ b/backend/src/main/resources/db/migration/V93__v1.12_release.sql @@ -49,4 +49,20 @@ ALTER TABLE load_test ALTER TABLE api_test_case ADD follow_people VARCHAR(100) NULL; -ALTER TABLE test_plan ADD report_summary TEXT NULL COMMENT '测试计划报告总结'; +ALTER TABLE test_plan + ADD report_summary TEXT NULL COMMENT '测试计划报告总结'; + +CREATE TABLE IF NOT EXISTS `notification` +( + `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'ID', + `type` VARCHAR(30) DEFAULT NULL COMMENT '通知类型', + `receiver` VARCHAR(100) DEFAULT NULL COMMENT '接收人', + `title` VARCHAR(100) DEFAULT NULL COMMENT '标题', + `content` LONGTEXT COMMENT '内容', + `status` VARCHAR(30) DEFAULT NULL COMMENT '状态', + `create_time` BIGINT(13) DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `IDX_RECEIVER` (`receiver`) USING BTREE +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE utf8mb4_general_ci; \ No newline at end of file diff --git a/frontend/src/business/App.vue b/frontend/src/business/App.vue index 1d276c522d..92d844e403 100644 --- a/frontend/src/business/App.vue +++ b/frontend/src/business/App.vue @@ -17,6 +17,7 @@ + @@ -36,6 +37,7 @@ import {hasLicense, saveLocalStorage, setColor, setDefaultTheme} from "@/common/ import {registerRequestHeaders} from "@/common/js/ajax"; import {ORIGIN_COLOR} from "@/common/js/constants"; import MsTaskCenter from "@/business/components/task/TaskCenter"; +import MsNoticeCenter from "@/business/components/notice/NoticeCenter"; const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/); const header = requireComponent.keys().length > 0 ? requireComponent("./license/LicenseMessage.vue") : {}; const display = requireComponent.keys().length > 0 ? requireComponent("./display/Display.vue") : {}; @@ -181,6 +183,7 @@ export default { } }, components: { + MsNoticeCenter, MsTaskCenter, MsLanguageSwitch, MsUser, diff --git a/frontend/src/business/components/notice/NoticeCenter.vue b/frontend/src/business/components/notice/NoticeCenter.vue new file mode 100644 index 0000000000..afe47ad3f5 --- /dev/null +++ b/frontend/src/business/components/notice/NoticeCenter.vue @@ -0,0 +1,442 @@ + + + + + + + diff --git a/frontend/src/common/js/ajax.js b/frontend/src/common/js/ajax.js index 27bd3b2e4f..6ef98509df 100644 --- a/frontend/src/common/js/ajax.js +++ b/frontend/src/common/js/ajax.js @@ -2,6 +2,7 @@ import {Message, MessageBox} from 'element-ui'; import axios from "axios"; import i18n from '../../i18n/i18n'; import {TokenKey} from "@/common/js/constants"; +import {getCurrentOrganizationId, getCurrentProjectID, getCurrentWorkspaceId} from "@/common/js/utils"; export function registerRequestHeaders() { axios.interceptors.request.use(config => { @@ -9,6 +10,10 @@ export function registerRequestHeaders() { if (user && user.csrfToken) { config.headers['CSRF-TOKEN'] = user.csrfToken; } + // 包含 组织 工作空间 项目的标识 + config.headers['ORGANIZATION_ID'] = getCurrentOrganizationId(); + config.headers['WORKSPACE_ID'] = getCurrentWorkspaceId(); + config.headers['PROJECT_ID'] = getCurrentProjectID(); return config; }); } diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index 9c49fad079..bf6aabec44 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -168,6 +168,7 @@ export default { api_case: "Api Case", scenario_case: "Scenario Case", task_center: "Task center", + notice_center: "Notice center", all_module_title: "All module", create_user: 'Creator', run_message: "The task is being executed, please go to the task center to view the details", diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index a4b6ff1be3..6f0d1a5719 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -169,6 +169,7 @@ export default { api_case: "接口用例", scenario_case: "场景用例", task_center: "任务中心", + notice_center: "消息中心", all_module_title: "全部模块", create_user: '创建人', run_message: "任务执行中,请到任务中心查看详情", diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index e350fa3d92..16997602ee 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -169,6 +169,7 @@ export default { api_case: "接口用例", scenario_case: "場景用例", task_center: "任务中心", + notice_center: "消息中心", all_module_title: "全部模塊", create_user: "創建人", run_message: "任務執行中,請到任務中心查看詳情",