fix(项目管理): 修复消息管理项目用户移除还会发送通知的问题

--bug=1036614 --user=郭雨琦 https://www.tapd.cn/55049933/bugtrace/bugs/view/1155049933001036614
This commit is contained in:
guoyuqi 2024-03-05 18:31:49 +08:00 committed by Craftsman
parent e810e8c8c7
commit 4f8ba53cf2
14 changed files with 107 additions and 59 deletions

View File

@ -15,6 +15,7 @@ import io.metersphere.system.domain.*;
import io.metersphere.system.dto.sdk.OptionDTO; import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.dto.sdk.request.MessageTaskRequest; import io.metersphere.system.dto.sdk.request.MessageTaskRequest;
import io.metersphere.system.mapper.CustomFieldMapper; import io.metersphere.system.mapper.CustomFieldMapper;
import io.metersphere.system.mapper.ExtSystemProjectMapper;
import io.metersphere.system.mapper.UserMapper; import io.metersphere.system.mapper.UserMapper;
import io.metersphere.system.mapper.UserRoleRelationMapper; import io.metersphere.system.mapper.UserRoleRelationMapper;
import io.metersphere.system.notice.constants.NoticeConstants; import io.metersphere.system.notice.constants.NoticeConstants;
@ -57,6 +58,8 @@ public class NoticeMessageTaskService {
private ExtProjectUserRoleMapper extProjectUserRoleMapper; private ExtProjectUserRoleMapper extProjectUserRoleMapper;
@Resource @Resource
protected CustomFieldMapper customFieldMapper; protected CustomFieldMapper customFieldMapper;
@Resource
private ExtSystemProjectMapper extSystemProjectMapper;
public static final String USER_IDS = "user_ids"; public static final String USER_IDS = "user_ids";
@ -336,9 +339,7 @@ public class NoticeMessageTaskService {
projectRobotExample.createCriteria().andIdIn(robotIds); projectRobotExample.createCriteria().andIdIn(robotIds);
List<ProjectRobot> projectRobots = projectRobotMapper.selectByExample(projectRobotExample); List<ProjectRobot> projectRobots = projectRobotMapper.selectByExample(projectRobotExample);
Map<String, ProjectRobot> robotMap = projectRobots.stream().collect(Collectors.toMap(ProjectRobot::getId, item -> item)); Map<String, ProjectRobot> robotMap = projectRobots.stream().collect(Collectors.toMap(ProjectRobot::getId, item -> item));
UserExample userExample = new UserExample(); List<User> users = extSystemProjectMapper.getProjectMemberByUserId(projectId, userIds);
userExample.createCriteria().andIdIn(userIds).andDeletedEqualTo(false);
List<User> users = userMapper.selectByExample(userExample);
Map<String, String> userNameMap = users.stream().collect(Collectors.toMap(User::getId, User::getName)); Map<String, String> userNameMap = users.stream().collect(Collectors.toMap(User::getId, User::getName));
Map<String, String> defaultRelatedUserMap = MessageTemplateUtils.getDefaultRelatedUserMap(); Map<String, String> defaultRelatedUserMap = MessageTemplateUtils.getDefaultRelatedUserMap();
userNameMap.putAll(defaultRelatedUserMap); userNameMap.putAll(defaultRelatedUserMap);
@ -383,11 +384,13 @@ public class NoticeMessageTaskService {
MessageTaskBlob messageTaskBlob = messageTaskBlobMap.get(messageTask.getId()); MessageTaskBlob messageTaskBlob = messageTaskBlobMap.get(messageTask.getId());
List<String> receiverIds = messageTask.getReceivers(); List<String> receiverIds = messageTask.getReceivers();
for (String receiverId : receiverIds) { for (String receiverId : receiverIds) {
if (userNameMap.get(receiverId)!=null) {
OptionDTO optionDTO = new OptionDTO(); OptionDTO optionDTO = new OptionDTO();
optionDTO.setId(receiverId); optionDTO.setId(receiverId);
optionDTO.setName(userNameMap.get(receiverId)); optionDTO.setName(userNameMap.get(receiverId));
receivers.add(optionDTO); receivers.add(optionDTO);
} }
}
String platform = robotMap.get(messageTask.getProjectRobotId()).getPlatform(); String platform = robotMap.get(messageTask.getProjectRobotId()).getPlatform();
String defaultSubject; String defaultSubject;
if (StringUtils.equalsIgnoreCase(platform, NoticeConstants.Type.MAIL)) { if (StringUtils.equalsIgnoreCase(platform, NoticeConstants.Type.MAIL)) {

View File

@ -1,5 +1,6 @@
package io.metersphere.system.mapper; package io.metersphere.system.mapper;
import io.metersphere.system.domain.User;
import io.metersphere.system.dto.OrganizationProjectOptionsDTO; import io.metersphere.system.dto.OrganizationProjectOptionsDTO;
import io.metersphere.system.dto.ProjectDTO; import io.metersphere.system.dto.ProjectDTO;
import io.metersphere.system.dto.ProjectResourcePoolDTO; import io.metersphere.system.dto.ProjectResourcePoolDTO;
@ -31,4 +32,6 @@ public interface ExtSystemProjectMapper {
String selectModuleSettingsByResourceIdAndTable(@Param("resourceId") String resourceId, @Param("resourceTable") String resourceTable); String selectModuleSettingsByResourceIdAndTable(@Param("resourceId") String resourceId, @Param("resourceTable") String resourceTable);
List<UserExtendDTO> getMemberByProjectId(@Param("projectId") String projectId, @Param("keyword") String keyword); List<UserExtendDTO> getMemberByProjectId(@Param("projectId") String projectId, @Param("keyword") String keyword);
List<User> getProjectMemberByUserId(@Param("projectId") String projectId, @Param("userIds") List<String> userIds);
} }

View File

@ -209,4 +209,19 @@
order by u.name order by u.name
limit 100 limit 100
</select> </select>
<select id="getProjectMemberByUserId" resultType="io.metersphere.system.domain.User">
select distinct u.* from user_role_relation urr join `user` u on urr.user_id = u.id
where
u.deleted = 0 and u.enable = 1
<if test="projectId != null and projectId != ''">
and urr.source_id = #{projectId}
</if>
<if test="userIds != null and userIds.size > 0 ">
and u.id in
<foreach collection="userIds" item="userId" open="(" separator="," close=")">
#{userId}
</foreach>
</if>
</select>
</mapper> </mapper>

View File

@ -21,5 +21,6 @@ public class MessageDetail implements Serializable {
private String template; private String template;
private String appKey; private String appKey;
private String appSecret; private String appSecret;
private String projectId;
} }

View File

@ -25,8 +25,7 @@ import io.metersphere.plan.mapper.TestPlanFollowerMapper;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.domain.User; import io.metersphere.system.domain.User;
import io.metersphere.system.domain.UserExample; import io.metersphere.system.mapper.ExtSystemProjectMapper;
import io.metersphere.system.mapper.UserMapper;
import io.metersphere.system.notice.MessageDetail; import io.metersphere.system.notice.MessageDetail;
import io.metersphere.system.notice.NoticeModel; import io.metersphere.system.notice.NoticeModel;
import io.metersphere.system.notice.Receiver; import io.metersphere.system.notice.Receiver;
@ -59,7 +58,8 @@ public abstract class AbstractNoticeSender implements NoticeSender {
@Resource @Resource
private CaseReviewFollowerMapper caseReviewFollowerMapper; private CaseReviewFollowerMapper caseReviewFollowerMapper;
@Resource @Resource
private UserMapper userMapper; private ExtSystemProjectMapper extSystemProjectMapper;
protected String getContext(MessageDetail messageDetail, NoticeModel noticeModel) { protected String getContext(MessageDetail messageDetail, NoticeModel noticeModel) {
//处理自定义字段的值 //处理自定义字段的值
@ -150,7 +150,7 @@ public abstract class AbstractNoticeSender implements NoticeSender {
// 去重复 // 去重复
List<String> userIds = toUsers.stream().map(Receiver::getUserId).distinct().toList(); List<String> userIds = toUsers.stream().map(Receiver::getUserId).distinct().toList();
LogUtils.info("userIds: ", JSON.toJSONString(userIds)); LogUtils.info("userIds: ", JSON.toJSONString(userIds));
List<User> users = getUsers(userIds); List<User> users = getUsers(userIds, messageDetail.getProjectId());
List<String> realUserIds = users.stream().map(User::getId).toList(); List<String> realUserIds = users.stream().map(User::getId).toList();
return toUsers.stream().filter(t -> realUserIds.contains(t.getUserId())).toList(); return toUsers.stream().filter(t -> realUserIds.contains(t.getUserId())).toList();
} }
@ -233,12 +233,25 @@ public abstract class AbstractNoticeSender implements NoticeSender {
return receivers; return receivers;
} }
protected List<User> getUsers(List<String> userIds) { protected List<User> getUsers(List<String> userIds, String projectId) {
UserExample userExample = new UserExample();
if (CollectionUtils.isNotEmpty(userIds)) { if (CollectionUtils.isNotEmpty(userIds)) {
userExample.createCriteria().andIdIn(userIds); return extSystemProjectMapper.getProjectMemberByUserId(projectId, userIds);
return userMapper.selectByExample(userExample); } else {
}
return new ArrayList<>(); return new ArrayList<>();
} }
} }
protected List<Receiver> getReceivers(List<Receiver> receivers, Boolean excludeSelf, String operator) {
// 排除自己
List<Receiver> realReceivers = new ArrayList<>();
if (excludeSelf) {
for (Receiver receiver : receivers) {
if (!StringUtils.equals(receiver.getUserId(), operator)) {
LogUtils.info("发送人是自己不发");
realReceivers.add(receiver);
}
}
}
return realReceivers;
}
}

View File

@ -42,6 +42,8 @@ public class SendNoticeAspect {
private ThreadLocal<String> source = new ThreadLocal<>(); private ThreadLocal<String> source = new ThreadLocal<>();
private final static String ID = "id"; private final static String ID = "id";
private final static String PROJECT_ID = "projectId";
@Pointcut("@annotation(io.metersphere.system.notice.annotation.SendNotice)") @Pointcut("@annotation(io.metersphere.system.notice.annotation.SendNotice)")
public void pointcut() { public void pointcut() {
@ -154,8 +156,15 @@ public class SendNoticeAspect {
LogUtils.info("event:" + event); LogUtils.info("event:" + event);
String resultStr = JSON.toJSONString(retValue); String resultStr = JSON.toJSONString(retValue);
Map object = JSON.parseMap(resultStr); Map object = JSON.parseMap(resultStr);
if (MapUtils.isNotEmpty(object) && object.containsKey(ID)) { if (MapUtils.isNotEmpty(object)) {
resources.add(object); for (Map resource : resources) {
if (object.containsKey(ID) && resource.get(ID) == null) {
resource.put(ID, object.get(ID));
}
if (object.containsKey(PROJECT_ID) && resource.get(PROJECT_ID) == null) {
resource.put(PROJECT_ID, object.get(PROJECT_ID));
}
}
} }
afterReturningNoticeSendService.sendNotice(taskType, event, resources, sessionUser, currentProjectId); afterReturningNoticeSendService.sendNotice(taskType, event, resources, sessionUser, currentProjectId);
} catch (Exception e) { } catch (Exception e) {

View File

@ -7,6 +7,7 @@ import io.metersphere.system.notice.NoticeModel;
import io.metersphere.system.notice.Receiver; import io.metersphere.system.notice.Receiver;
import io.metersphere.system.notice.sender.AbstractNoticeSender; import io.metersphere.system.notice.sender.AbstractNoticeSender;
import io.metersphere.system.notice.utils.DingClient; import io.metersphere.system.notice.utils.DingClient;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@ -16,11 +17,15 @@ import java.util.stream.Collectors;
public class DingCustomNoticeSender extends AbstractNoticeSender { public class DingCustomNoticeSender extends AbstractNoticeSender {
public void sendDingCustom(MessageDetail messageDetail, NoticeModel noticeModel, String context) { public void sendDingCustom(MessageDetail messageDetail, NoticeModel noticeModel, String context) {
List<String> userIds = noticeModel.getReceivers().stream() List<Receiver> receivers = super.getReceivers(noticeModel.getReceivers(), noticeModel.isExcludeSelf(), noticeModel.getOperator());
if (CollectionUtils.isEmpty(receivers)) {
return;
}
List<String> userIds = receivers.stream()
.map(Receiver::getUserId) .map(Receiver::getUserId)
.distinct() .distinct()
.collect(Collectors.toList()); .collect(Collectors.toList());
List<User> users = super.getUsers(userIds); List<User> users = super.getUsers(userIds, messageDetail.getProjectId());
List<String> mobileList = users.stream().map(User::getPhone).toList(); List<String> mobileList = users.stream().map(User::getPhone).toList();
LogUtils.info("钉钉自定义机器人收件人: {}", userIds); LogUtils.info("钉钉自定义机器人收件人: {}", userIds);

View File

@ -17,7 +17,7 @@ import org.springframework.stereotype.Component;
@Component @Component
public class DingEnterPriseNoticeSender extends AbstractNoticeSender { public class DingEnterPriseNoticeSender extends AbstractNoticeSender {
public void sendDing(MessageDetail messageDetail, NoticeModel noticeModel, String context) throws Exception { public void sendDing(MessageDetail messageDetail, String context) throws Exception {
Client client = DingEnterPriseNoticeSender.createClient(); Client client = DingEnterPriseNoticeSender.createClient();
GetAccessTokenResponse accessToken = getAccessToken(messageDetail.getAppKey(), messageDetail.getAppSecret()); GetAccessTokenResponse accessToken = getAccessToken(messageDetail.getAppKey(), messageDetail.getAppSecret());
OrgGroupSendHeaders orgGroupSendHeaders = new OrgGroupSendHeaders(); OrgGroupSendHeaders orgGroupSendHeaders = new OrgGroupSendHeaders();
@ -92,7 +92,7 @@ public class DingEnterPriseNoticeSender extends AbstractNoticeSender {
public void send(MessageDetail messageDetail, NoticeModel noticeModel) { public void send(MessageDetail messageDetail, NoticeModel noticeModel) {
String context = super.getContext(messageDetail, noticeModel); String context = super.getContext(messageDetail, noticeModel);
try { try {
sendDing(messageDetail, noticeModel, context); sendDing(messageDetail, context);
LogUtils.debug("发送钉钉内部机器人结束"); LogUtils.debug("发送钉钉内部机器人结束");
} catch (Exception e) { } catch (Exception e) {
LogUtils.error(e); LogUtils.error(e);

View File

@ -11,10 +11,8 @@ import io.metersphere.system.notice.sender.AbstractNoticeSender;
import io.metersphere.system.service.NotificationService; import io.metersphere.system.service.NotificationService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -25,25 +23,12 @@ public class InSiteNoticeSender extends AbstractNoticeSender {
private NotificationService notificationService; private NotificationService notificationService;
public void sendAnnouncement(MessageDetail messageDetail, NoticeModel noticeModel, String context) { public void sendAnnouncement(MessageDetail messageDetail, NoticeModel noticeModel, String context) {
List<Receiver> receivers = noticeModel.getReceivers(); List<Receiver> receivers = super.getReceivers(noticeModel.getReceivers(), noticeModel.isExcludeSelf(), noticeModel.getOperator());
// 排除自己 if (CollectionUtils.isEmpty(receivers)) {
List<Receiver> realReceivers = new ArrayList<>();
if (noticeModel.isExcludeSelf() ) {
for (Receiver receiver : receivers) {
if (!StringUtils.equals(receiver.getUserId(), noticeModel.getOperator())) {
LogUtils.info("发送人是自己不发");
realReceivers.add(receiver);
}
}
}
if (CollectionUtils.isEmpty(realReceivers)) {
return; return;
} }
LogUtils.info("发送站内通知: {}", receivers);
LogUtils.info("发送站内通知: {}", realReceivers); receivers.forEach(receiver -> {
realReceivers.forEach(receiver -> {
Map<String, Object> paramMap = noticeModel.getParamMap(); Map<String, Object> paramMap = noticeModel.getParamMap();
Notification notification = new Notification(); Notification notification = new Notification();
notification.setSubject(noticeModel.getSubject()); notification.setSubject(noticeModel.getSubject());

View File

@ -7,6 +7,7 @@ import io.metersphere.system.notice.sender.AbstractNoticeSender;
import io.metersphere.system.notice.utils.LarkClient; import io.metersphere.system.notice.utils.LarkClient;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.domain.User; import io.metersphere.system.domain.User;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -17,11 +18,16 @@ import java.util.stream.Collectors;
public class LarkNoticeSender extends AbstractNoticeSender { public class LarkNoticeSender extends AbstractNoticeSender {
public void sendLark(MessageDetail messageDetail, NoticeModel noticeModel, String context) { public void sendLark(MessageDetail messageDetail, NoticeModel noticeModel, String context) {
List<String> userIds = noticeModel.getReceivers().stream() List<Receiver> receivers = super.getReceivers(noticeModel.getReceivers(), noticeModel.isExcludeSelf(), noticeModel.getOperator());
if (CollectionUtils.isEmpty(receivers)) {
return;
}
List<String> userIds = receivers.stream()
.map(Receiver::getUserId) .map(Receiver::getUserId)
.distinct() .distinct()
.collect(Collectors.toList()); .collect(Collectors.toList());
List<User> users = super.getUsers(userIds);
List<User> users = super.getUsers(userIds, messageDetail.getProjectId());
List<String> collect = users.stream() List<String> collect = users.stream()
.map(ud -> "<at email=\"" + ud.getEmail() + "\">" + ud.getName() + "</at>") .map(ud -> "<at email=\"" + ud.getEmail() + "\">" + ud.getName() + "</at>")
.toList(); .toList();

View File

@ -33,17 +33,16 @@ public class MailNoticeSender extends AbstractNoticeSender {
@Resource @Resource
private SystemParameterMapper systemParameterMapper; private SystemParameterMapper systemParameterMapper;
public void sendMail(String context, NoticeModel noticeModel) throws Exception { public void sendMail(String context, NoticeModel noticeModel, String projectId) throws Exception {
List<Receiver> receivers = super.getReceivers(noticeModel.getReceivers(), noticeModel.isExcludeSelf(), noticeModel.getOperator());
List<String> userIds = noticeModel.getReceivers().stream() if (CollectionUtils.isEmpty(receivers)) {
return;
}
List<String> userIds = receivers.stream()
.map(Receiver::getUserId) .map(Receiver::getUserId)
.distinct() .distinct()
.collect(Collectors.toList()); .collect(Collectors.toList());
if (CollectionUtils.isEmpty(userIds)) { String[] users = super.getUsers(userIds, projectId).stream()
return;
}
String[] users = super.getUsers(userIds).stream()
.map(User::getEmail) .map(User::getEmail)
.distinct() .distinct()
.toArray(String[]::new); .toArray(String[]::new);
@ -156,7 +155,7 @@ public class MailNoticeSender extends AbstractNoticeSender {
public void send(MessageDetail messageDetail, NoticeModel noticeModel) { public void send(MessageDetail messageDetail, NoticeModel noticeModel) {
String context = super.getContext(messageDetail, noticeModel); String context = super.getContext(messageDetail, noticeModel);
try { try {
sendMail(context, noticeModel); sendMail(context, noticeModel, messageDetail.getProjectId());
LogUtils.debug("发送邮件结束"); LogUtils.debug("发送邮件结束");
} catch (Exception e) { } catch (Exception e) {
LogUtils.error(e); LogUtils.error(e);

View File

@ -7,6 +7,7 @@ import io.metersphere.system.notice.NoticeModel;
import io.metersphere.system.notice.Receiver; import io.metersphere.system.notice.Receiver;
import io.metersphere.system.notice.sender.AbstractNoticeSender; import io.metersphere.system.notice.sender.AbstractNoticeSender;
import io.metersphere.system.notice.utils.WeComClient; import io.metersphere.system.notice.utils.WeComClient;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@ -16,11 +17,15 @@ import java.util.stream.Collectors;
public class WeComNoticeSender extends AbstractNoticeSender { public class WeComNoticeSender extends AbstractNoticeSender {
public void sendWeCom(MessageDetail messageDetail, NoticeModel noticeModel, String context) { public void sendWeCom(MessageDetail messageDetail, NoticeModel noticeModel, String context) {
List<String> userIds = noticeModel.getReceivers().stream() List<Receiver> receivers = super.getReceivers(noticeModel.getReceivers(), noticeModel.isExcludeSelf(), noticeModel.getOperator());
if (CollectionUtils.isEmpty(receivers)) {
return;
}
List<String> userIds = receivers.stream()
.map(Receiver::getUserId) .map(Receiver::getUserId)
.distinct() .distinct()
.collect(Collectors.toList()); .collect(Collectors.toList());
List<User> users = super.getUsers(userIds); List<User> users = super.getUsers(userIds, messageDetail.getProjectId());
List<String> mobileList = users.stream().map(User::getPhone).toList(); List<String> mobileList = users.stream().map(User::getPhone).toList();
LogUtils.info("企业微信收件人: {}", userIds); LogUtils.info("企业微信收件人: {}", userIds);
WeComClient.send(messageDetail.getWebhook(), messageDetail.getSubject() + ": \n" + context, mobileList); WeComClient.send(messageDetail.getWebhook(), messageDetail.getSubject() + ": \n" + context, mobileList);

View File

@ -25,7 +25,10 @@ public class WebhookNoticeSender extends AbstractNoticeSender {
private void send(MessageDetail messageDetail, NoticeModel noticeModel, String context) { private void send(MessageDetail messageDetail, NoticeModel noticeModel, String context) {
List<Receiver> receivers = noticeModel.getReceivers(); List<Receiver> receivers = super.getReceivers(noticeModel.getReceivers(), noticeModel.isExcludeSelf(), noticeModel.getOperator());
if (CollectionUtils.isEmpty(receivers)) {
return;
}
CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null; CloseableHttpResponse response = null;
if (CollectionUtils.isNotEmpty(receivers)) { if (CollectionUtils.isNotEmpty(receivers)) {

View File

@ -89,6 +89,7 @@ public class MessageDetailService {
messageDetail.setTaskType(messageTask.getTaskType()); messageDetail.setTaskType(messageTask.getTaskType());
messageDetail.setEvent(messageTask.getEvent()); messageDetail.setEvent(messageTask.getEvent());
messageDetail.setCreateTime(messageTask.getCreateTime()); messageDetail.setCreateTime(messageTask.getCreateTime());
messageDetail.setProjectId(messageTask.getProjectId());
String projectRobotId = messageTask.getProjectRobotId(); String projectRobotId = messageTask.getProjectRobotId();
ProjectRobot projectRobot = projectRobotMap.get(projectRobotId); ProjectRobot projectRobot = projectRobotMap.get(projectRobotId);
//如果当前机器人停止那么当前任务也失效 //如果当前机器人停止那么当前任务也失效