feat(缺陷管理): 缺陷评论功能
This commit is contained in:
parent
0bde349e40
commit
8de0d13870
|
@ -90,3 +90,8 @@ bug_attachment_upload_error=缺陷附件上传失败
|
||||||
bug_attachment_delete_error=缺陷附件删除失败
|
bug_attachment_delete_error=缺陷附件删除失败
|
||||||
no_bug_select=未勾选缺陷
|
no_bug_select=未勾选缺陷
|
||||||
bug_select_not_found=未查询到勾选的缺陷
|
bug_select_not_found=未查询到勾选的缺陷
|
||||||
|
bug_comment.event.not_blank=缺陷评论事件类型不能为空
|
||||||
|
bug_comment.parent_id.not_blank=缺陷评论父级ID不能为空
|
||||||
|
bug_comment.parent.not_exist=父级评论不存在
|
||||||
|
bug_comment.reply_user.not_blank=缺陷回复人不能为空
|
||||||
|
bug_comment_not_exist=缺陷评论不存在
|
||||||
|
|
|
@ -90,3 +90,8 @@ bug_attachment_upload_error=Bug attachment upload error
|
||||||
bug_attachment_delete_error=Bug attachment delete error
|
bug_attachment_delete_error=Bug attachment delete error
|
||||||
no_bug_select=No bug selected
|
no_bug_select=No bug selected
|
||||||
bug_select_not_found=Selected bug not found
|
bug_select_not_found=Selected bug not found
|
||||||
|
bug_comment.event.not_blank=Bug comment event cannot be empty
|
||||||
|
bug_comment.parent_id.not_blank=Bug comment parent-id cannot be empty
|
||||||
|
bug_comment.parent.not_exist=Bug comment parent does not exist
|
||||||
|
bug_comment.reply_user.not_blank=Bug comment reply-user cannot be empty
|
||||||
|
bug_comment_not_exist=Bug comment does not exist
|
||||||
|
|
|
@ -90,3 +90,8 @@ bug_attachment_upload_error=缺陷附件上传失败
|
||||||
bug_attachment_delete_error=缺陷附件删除失败
|
bug_attachment_delete_error=缺陷附件删除失败
|
||||||
no_bug_select=未勾选缺陷
|
no_bug_select=未勾选缺陷
|
||||||
bug_select_not_found=未查询到勾选的缺陷
|
bug_select_not_found=未查询到勾选的缺陷
|
||||||
|
bug_comment.event.not_blank=缺陷评论事件类型不能为空
|
||||||
|
bug_comment.parent_id.not_blank=缺陷评论父级ID不能为空
|
||||||
|
bug_comment.parent.not_exist=父级评论不存在
|
||||||
|
bug_comment.reply_user.not_blank=缺陷回复人不能为空
|
||||||
|
bug_comment_not_exist=缺陷评论不存在
|
||||||
|
|
|
@ -90,4 +90,9 @@ bug_attachment_upload_error=缺陷附件上傳失敗
|
||||||
bug_attachment_delete_error=缺陷附件刪除失敗
|
bug_attachment_delete_error=缺陷附件刪除失敗
|
||||||
no_bug_select=未勾選缺陷
|
no_bug_select=未勾選缺陷
|
||||||
bug_select_not_found=未查詢到勾選的缺陷
|
bug_select_not_found=未查詢到勾選的缺陷
|
||||||
|
bug_comment.event.not_blank=評論事件類型不能為空
|
||||||
|
bug_comment.parent_id.not_blank=缺陷評論父級ID不能為空
|
||||||
|
bug_comment.parent.not_exist=父級評論不存在
|
||||||
|
bug_comment.reply_user.not_blank=缺陷回復人不能為空
|
||||||
|
bug_comment_not_exist=缺陷評論不存在
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package io.metersphere.bug.controller;
|
||||||
|
|
||||||
|
import io.metersphere.bug.domain.BugComment;
|
||||||
|
import io.metersphere.bug.dto.BugCommentDTO;
|
||||||
|
import io.metersphere.bug.dto.BugCommentUserInfo;
|
||||||
|
import io.metersphere.bug.dto.request.BugCommentEditRequest;
|
||||||
|
import io.metersphere.bug.service.BugCommentService;
|
||||||
|
import io.metersphere.system.utils.SessionUtils;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Tag(name = "缺陷管理-评论")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/bug/comment")
|
||||||
|
public class BugCommentController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BugCommentService bugCommentService;
|
||||||
|
|
||||||
|
@GetMapping("/get/{bugId}")
|
||||||
|
public List<BugCommentDTO> get(@PathVariable String bugId) {
|
||||||
|
return bugCommentService.getComments(bugId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/user-extra/{bugId}")
|
||||||
|
public List<BugCommentUserInfo> getUserExtra(@PathVariable String bugId) {
|
||||||
|
return bugCommentService.getUserExtra(bugId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/add")
|
||||||
|
public BugComment add(@RequestBody BugCommentEditRequest request) {
|
||||||
|
return bugCommentService.addComment(request, SessionUtils.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/update")
|
||||||
|
public BugComment update(@RequestBody BugCommentEditRequest request) {
|
||||||
|
return bugCommentService.updateComment(request, SessionUtils.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/delete/{commentId}")
|
||||||
|
public void delete(@PathVariable String commentId) {
|
||||||
|
bugCommentService.deleteComment(commentId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package io.metersphere.bug.dto;
|
||||||
|
|
||||||
|
import io.metersphere.bug.domain.BugComment;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class BugCommentDTO extends BugComment {
|
||||||
|
|
||||||
|
@Schema(description = "创建人名称")
|
||||||
|
private String createUserName;
|
||||||
|
|
||||||
|
@Schema(description = "回复人名称")
|
||||||
|
private String replyUserName;
|
||||||
|
|
||||||
|
@Schema(description = "子评论")
|
||||||
|
private List<BugCommentDTO> childComments;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package io.metersphere.bug.dto;
|
||||||
|
|
||||||
|
import io.metersphere.system.dto.sdk.OptionDTO;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class BugCommentNoticeDTO extends BugDTO{
|
||||||
|
|
||||||
|
@Schema(description = "通知人集合, @用户, 使用';'隔开! ")
|
||||||
|
private String notifier;
|
||||||
|
|
||||||
|
@Schema(description = "自定义字段值集合")
|
||||||
|
private List<OptionDTO> fields;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package io.metersphere.bug.dto;
|
||||||
|
|
||||||
|
import io.metersphere.system.domain.User;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class BugCommentUserInfo extends User {
|
||||||
|
|
||||||
|
@Schema(description = "用户头像")
|
||||||
|
private String createUserAvatar;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package io.metersphere.bug.dto.request;
|
||||||
|
|
||||||
|
import io.metersphere.validation.groups.Created;
|
||||||
|
import io.metersphere.validation.groups.Updated;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class BugCommentEditRequest {
|
||||||
|
|
||||||
|
@Schema(description = "评论ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotBlank(message = "{bug_comment.id.not_blank}", groups = {Updated.class})
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Schema(description = "缺陷ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private String bugId;
|
||||||
|
|
||||||
|
@Schema(description = "回复人")
|
||||||
|
private String replyUser;
|
||||||
|
|
||||||
|
@Schema(description = "通知人, @名称展示, 以用户ID';'分隔")
|
||||||
|
private String notifier;
|
||||||
|
|
||||||
|
@Schema(description = "父评论ID")
|
||||||
|
private String parentId;
|
||||||
|
|
||||||
|
@Schema(description = "评论内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@Schema(description = "任务事件(仅评论: ’COMMENT‘; 评论并@: ’AT‘; 回复评论/回复并@: ’REPLAY‘;)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotBlank(message = "{bug_comment.event.not_blank}", groups = {Created.class})
|
||||||
|
private String event;
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
package io.metersphere.bug.service;
|
||||||
|
|
||||||
|
import io.metersphere.bug.domain.Bug;
|
||||||
|
import io.metersphere.bug.dto.BugCommentNoticeDTO;
|
||||||
|
import io.metersphere.bug.dto.BugCustomFieldDTO;
|
||||||
|
import io.metersphere.bug.dto.request.BugCommentEditRequest;
|
||||||
|
import io.metersphere.bug.mapper.BugMapper;
|
||||||
|
import io.metersphere.bug.mapper.ExtBugCustomFieldMapper;
|
||||||
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
|
import io.metersphere.system.domain.User;
|
||||||
|
import io.metersphere.system.dto.sdk.OptionDTO;
|
||||||
|
import io.metersphere.system.mapper.UserMapper;
|
||||||
|
import io.metersphere.system.notice.NoticeModel;
|
||||||
|
import io.metersphere.system.notice.constants.NoticeConstants;
|
||||||
|
import io.metersphere.system.notice.utils.MessageTemplateUtils;
|
||||||
|
import io.metersphere.system.service.NoticeSendService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.beanutils.BeanMap;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public class BugCommentNoticeService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BugMapper bugMapper;
|
||||||
|
@Resource
|
||||||
|
private UserMapper userMapper;
|
||||||
|
@Resource
|
||||||
|
private NoticeSendService noticeSendService;
|
||||||
|
@Resource
|
||||||
|
private ExtBugCustomFieldMapper extBugCustomFieldMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缺陷通知参数
|
||||||
|
* @param request 页面请求参数
|
||||||
|
* @return 缺陷通知参数
|
||||||
|
*/
|
||||||
|
public BugCommentNoticeDTO getBugCommentNotice(BugCommentEditRequest request) {
|
||||||
|
Bug bug = bugMapper.selectByPrimaryKey(request.getBugId());
|
||||||
|
BugCommentNoticeDTO bugCommentNoticeDTO = new BugCommentNoticeDTO();
|
||||||
|
BeanUtils.copyBean(bugCommentNoticeDTO, bug);
|
||||||
|
setNotifier(request, bugCommentNoticeDTO);
|
||||||
|
setCustomField(bugCommentNoticeDTO);
|
||||||
|
return bugCommentNoticeDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送缺陷通知
|
||||||
|
*/
|
||||||
|
@Async
|
||||||
|
public void sendNotice(BugCommentEditRequest request, BugCommentNoticeDTO noticeDTO, String currentUser) {
|
||||||
|
User user = userMapper.selectByPrimaryKey(currentUser);
|
||||||
|
Map<String, String> defaultTemplateMap = MessageTemplateUtils.getDefaultTemplateMap();
|
||||||
|
String template = defaultTemplateMap.get(NoticeConstants.TaskType.BUG_TASK + "_" + request.getEvent());
|
||||||
|
Map<String, String> defaultSubjectMap = MessageTemplateUtils.getDefaultTemplateSubjectMap();
|
||||||
|
String subject = defaultSubjectMap.get(NoticeConstants.TaskType.BUG_TASK + "_" + request.getEvent());
|
||||||
|
BeanMap beanMap = new BeanMap(noticeDTO);
|
||||||
|
Map paramMap = new HashMap<>(beanMap);
|
||||||
|
paramMap.put(NoticeConstants.RelatedUser.OPERATOR, user.getName());
|
||||||
|
NoticeModel noticeModel = NoticeModel.builder()
|
||||||
|
.operator(currentUser)
|
||||||
|
.context(template)
|
||||||
|
.subject(subject)
|
||||||
|
.paramMap(paramMap)
|
||||||
|
.event(request.getEvent())
|
||||||
|
.status((String) paramMap.get("status"))
|
||||||
|
.excludeSelf(true)
|
||||||
|
.relatedUsers(getRelateUser(noticeDTO.getNotifier()))
|
||||||
|
.build();
|
||||||
|
noticeSendService.send(NoticeConstants.TaskType.BUG_TASK, noticeModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置缺陷通知的自定义字段值
|
||||||
|
* @param bugCommentNoticeDTO 缺陷通知参数
|
||||||
|
*/
|
||||||
|
private void setCustomField(BugCommentNoticeDTO bugCommentNoticeDTO) {
|
||||||
|
List<BugCustomFieldDTO> bugCustomFields = extBugCustomFieldMapper.getBugCustomFields(List.of(bugCommentNoticeDTO.getId()), bugCommentNoticeDTO.getProjectId());
|
||||||
|
if (CollectionUtils.isNotEmpty(bugCustomFields)) {
|
||||||
|
List<OptionDTO> fields = bugCustomFields.stream().map(field -> new OptionDTO(field.getName(), field.getValue())).toList();
|
||||||
|
bugCommentNoticeDTO.setFields(fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论通知@用户处理与功能用例保持一致即可, 根据事件类型设置通知人
|
||||||
|
* 如果是REPLAY事件,需要判断有无@的人,如果有@的人且和当前被回复的人不是同一人,这里只被回复的人,如果是同一人,这里通知人为空,走AT事件
|
||||||
|
* 如果不是REPLAY事件,需要判断有无被回复的人,如果被回复的人不在被@人里,则用页面参数传递的通知人,如果在,则排除这个人,如果没有被回复的人,用页面数据
|
||||||
|
*
|
||||||
|
* @param request 页面请求参数
|
||||||
|
* @param bugCommentNoticeDTO 缺陷通知参数
|
||||||
|
*/
|
||||||
|
private void setNotifier(BugCommentEditRequest request, BugCommentNoticeDTO bugCommentNoticeDTO) {
|
||||||
|
String notifier = request.getNotifier();
|
||||||
|
String replyUser = request.getReplyUser();
|
||||||
|
if (StringUtils.equals(request.getEvent(), NoticeConstants.Event.REPLY)) {
|
||||||
|
// REPLAY事件, 只通知回复人(且不为空);
|
||||||
|
bugCommentNoticeDTO.setNotifier(replyUser);
|
||||||
|
} else {
|
||||||
|
// AT事件, 如果有回复人, 直接排除;
|
||||||
|
if (StringUtils.isNotBlank(replyUser) && StringUtils.isNotBlank(notifier)) {
|
||||||
|
List<String> notifierList = new ArrayList<>(Arrays.asList(notifier.split(";")));
|
||||||
|
if (notifierList.contains(replyUser)) {
|
||||||
|
notifierList.remove(replyUser);
|
||||||
|
bugCommentNoticeDTO.setNotifier(String.join(";", notifierList));
|
||||||
|
} else {
|
||||||
|
bugCommentNoticeDTO.setNotifier(notifier);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bugCommentNoticeDTO.setNotifier(notifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据通知人分隔的字符串获取参数
|
||||||
|
* @return 通知人列表
|
||||||
|
*/
|
||||||
|
private List<String> getRelateUser(String notifier) {
|
||||||
|
if (StringUtils.isBlank(notifier)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Arrays.asList(notifier.split(";"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,291 @@
|
||||||
|
package io.metersphere.bug.service;
|
||||||
|
|
||||||
|
import io.metersphere.bug.domain.Bug;
|
||||||
|
import io.metersphere.bug.domain.BugComment;
|
||||||
|
import io.metersphere.bug.domain.BugCommentExample;
|
||||||
|
import io.metersphere.bug.dto.BugCommentDTO;
|
||||||
|
import io.metersphere.bug.dto.BugCommentNoticeDTO;
|
||||||
|
import io.metersphere.bug.dto.BugCommentUserInfo;
|
||||||
|
import io.metersphere.bug.dto.request.BugCommentEditRequest;
|
||||||
|
import io.metersphere.bug.mapper.BugCommentMapper;
|
||||||
|
import io.metersphere.bug.mapper.BugMapper;
|
||||||
|
import io.metersphere.sdk.exception.MSException;
|
||||||
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
|
import io.metersphere.sdk.util.Translator;
|
||||||
|
import io.metersphere.system.domain.User;
|
||||||
|
import io.metersphere.system.domain.UserExample;
|
||||||
|
import io.metersphere.system.dto.sdk.OptionDTO;
|
||||||
|
import io.metersphere.system.mapper.BaseUserMapper;
|
||||||
|
import io.metersphere.system.mapper.UserMapper;
|
||||||
|
import io.metersphere.system.notice.constants.NoticeConstants;
|
||||||
|
import io.metersphere.system.uid.IDGenerator;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public class BugCommentService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BugMapper bugMapper;
|
||||||
|
@Resource
|
||||||
|
private UserMapper userMapper;
|
||||||
|
@Resource
|
||||||
|
private BaseUserMapper baseUserMapper;
|
||||||
|
@Resource
|
||||||
|
private BugCommentMapper bugCommentMapper;
|
||||||
|
@Resource
|
||||||
|
private BugCommentNoticeService bugCommentNoticeService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缺陷评论
|
||||||
|
* @param bugId 缺陷ID
|
||||||
|
* @return 缺陷评论
|
||||||
|
*/
|
||||||
|
public List<BugCommentDTO> getComments(String bugId) {
|
||||||
|
BugCommentExample example = new BugCommentExample();
|
||||||
|
example.createCriteria().andBugIdEqualTo(bugId);
|
||||||
|
List<BugComment> bugComments = bugCommentMapper.selectByExample(example);
|
||||||
|
if (CollectionUtils.isEmpty(bugComments)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// BugComment -> BugCommentDTO
|
||||||
|
Map<String, String> userMap = getUserMap(bugComments);
|
||||||
|
List<BugCommentDTO> bugCommentDTOList = bugComments.stream().map(bugComment -> {
|
||||||
|
BugCommentDTO commentDTO = new BugCommentDTO();
|
||||||
|
BeanUtils.copyBean(commentDTO, bugComment);
|
||||||
|
commentDTO.setCreateUserName(userMap.get(bugComment.getCreateUser()));
|
||||||
|
commentDTO.setReplyUserName(userMap.get(bugComment.getReplyUser()));
|
||||||
|
return commentDTO;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
// 父级评论
|
||||||
|
List<BugCommentDTO> parentComments = bugCommentDTOList.stream().filter(bugCommentDTO -> StringUtils.isEmpty(bugCommentDTO.getParentId()))
|
||||||
|
.sorted(Comparator.comparing(BugCommentDTO::getCreateTime, Comparator.reverseOrder())).toList();
|
||||||
|
parentComments.forEach(parentComment -> {
|
||||||
|
// 子级评论
|
||||||
|
List<BugCommentDTO> childComments = bugCommentDTOList.stream().filter(bugCommentDTO -> StringUtils.equals(bugCommentDTO.getParentId(), parentComment.getId()))
|
||||||
|
.sorted(Comparator.comparing(BugCommentDTO::getCreateTime, Comparator.reverseOrder())).toList();
|
||||||
|
parentComment.setChildComments(childComments);
|
||||||
|
});
|
||||||
|
return parentComments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户全部信息
|
||||||
|
* @param bugId 缺陷ID
|
||||||
|
* @return 用户集合
|
||||||
|
*/
|
||||||
|
public List<BugCommentUserInfo> getUserExtra(String bugId) {
|
||||||
|
BugCommentExample example = new BugCommentExample();
|
||||||
|
example.createCriteria().andBugIdEqualTo(bugId);
|
||||||
|
List<BugComment> bugComments = bugCommentMapper.selectByExample(example);
|
||||||
|
if (CollectionUtils.isEmpty(bugComments)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> userIds = new ArrayList<>(bugComments.stream().map(BugComment::getCreateUser).toList());
|
||||||
|
bugComments.forEach(bugComment -> {
|
||||||
|
if (StringUtils.isNotEmpty(bugComment.getNotifier())) {
|
||||||
|
// 通知人@内容以';'分隔
|
||||||
|
userIds.addAll(Arrays.asList(bugComment.getNotifier().split(";")));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
UserExample userExample = new UserExample();
|
||||||
|
userExample.createCriteria().andIdIn(userIds.stream().distinct().toList());
|
||||||
|
List<User> users = userMapper.selectByExample(userExample);
|
||||||
|
return users.stream().map(user -> {
|
||||||
|
BugCommentUserInfo userInfo = new BugCommentUserInfo();
|
||||||
|
BeanUtils.copyBean(userInfo, user);
|
||||||
|
return userInfo;
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加评论
|
||||||
|
* @param request 评论请求参数
|
||||||
|
* @param currentUser 当前用户ID
|
||||||
|
* @return 缺陷评论
|
||||||
|
*/
|
||||||
|
public BugComment addComment(BugCommentEditRequest request, String currentUser) {
|
||||||
|
checkBug(request.getBugId());
|
||||||
|
BugComment bugComment = getBugComment(request, currentUser, false);
|
||||||
|
if (StringUtils.equals(request.getEvent(), NoticeConstants.Event.REPLY)) {
|
||||||
|
return addBugCommentAndReplyNotice(request, bugComment, currentUser);
|
||||||
|
} else {
|
||||||
|
return addBugCommentAndCommentNotice(request, bugComment, currentUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改评论
|
||||||
|
* @param request 评论请求参数
|
||||||
|
* @param currentUser 当前用户ID
|
||||||
|
* @return 缺陷评论
|
||||||
|
*/
|
||||||
|
public BugComment updateComment(BugCommentEditRequest request, String currentUser) {
|
||||||
|
checkComment(request.getId());
|
||||||
|
BugComment bugComment = getBugComment(request, currentUser, true);
|
||||||
|
return updateBugCommentAndNotice(request, bugComment, currentUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除评论
|
||||||
|
* @param commentId 评论ID
|
||||||
|
*/
|
||||||
|
public void deleteComment(String commentId) {
|
||||||
|
checkComment(commentId);
|
||||||
|
BugComment bugComment = bugCommentMapper.selectByPrimaryKey(commentId);
|
||||||
|
if (StringUtils.isEmpty(bugComment.getParentId())) {
|
||||||
|
// 如果是父评论, 先删除子评论
|
||||||
|
BugCommentExample example = new BugCommentExample();
|
||||||
|
example.createCriteria().andParentIdEqualTo(commentId);
|
||||||
|
bugCommentMapper.deleteByExample(example);
|
||||||
|
}
|
||||||
|
// 删除当条评论
|
||||||
|
bugCommentMapper.deleteByPrimaryKey(commentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新建评论并发送REPLY通知(需处理@提醒人)
|
||||||
|
* @param request 缺陷评论请求参数
|
||||||
|
* @param bugComment 缺陷评论
|
||||||
|
* @return 缺陷评论
|
||||||
|
*/
|
||||||
|
public BugComment addBugCommentAndReplyNotice(BugCommentEditRequest request, BugComment bugComment, String currentUser) {
|
||||||
|
checkAndSetReplyComment(request, bugComment);
|
||||||
|
bugCommentMapper.insertSelective(bugComment);
|
||||||
|
// 回复通知
|
||||||
|
BugCommentNoticeDTO bugCommentNotice = bugCommentNoticeService.getBugCommentNotice(request);
|
||||||
|
bugCommentNoticeService.sendNotice(request, bugCommentNotice, currentUser);
|
||||||
|
// @通知
|
||||||
|
request.setEvent(NoticeConstants.Event.AT);
|
||||||
|
bugCommentNotice = bugCommentNoticeService.getBugCommentNotice(request);
|
||||||
|
bugCommentNoticeService.sendNotice(request, bugCommentNotice, currentUser);
|
||||||
|
return bugComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新建评论并发送COMMENT通知(需处理@提醒人)
|
||||||
|
* @param request 缺陷评论请求参数
|
||||||
|
* @param bugComment 缺陷评论
|
||||||
|
* @return 缺陷评论
|
||||||
|
*/
|
||||||
|
public BugComment addBugCommentAndCommentNotice(BugCommentEditRequest request, BugComment bugComment, String currentUser) {
|
||||||
|
bugComment.setNotifier(request.getNotifier());
|
||||||
|
bugCommentMapper.insertSelective(bugComment);
|
||||||
|
/*
|
||||||
|
* 通知;
|
||||||
|
* 如果通知@人不为空, 先发送@通知, 再发送评论通知.
|
||||||
|
* 如果通知@人为空, 只发送评论通知.
|
||||||
|
*/
|
||||||
|
BugCommentNoticeDTO bugCommentNotice = bugCommentNoticeService.getBugCommentNotice(request);
|
||||||
|
bugCommentNoticeService.sendNotice(request, bugCommentNotice, currentUser);
|
||||||
|
if (StringUtils.isEmpty(request.getParentId()) && StringUtils.equals(request.getEvent(), NoticeConstants.Event.AT)) {
|
||||||
|
request.setEvent(NoticeConstants.Event.COMMENT);
|
||||||
|
bugCommentNoticeService.sendNotice(request, bugCommentNotice, currentUser);
|
||||||
|
}
|
||||||
|
return bugComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BugComment updateBugCommentAndNotice(BugCommentEditRequest request, BugComment bugComment, String currentUser) {
|
||||||
|
bugComment.setNotifier(request.getNotifier());
|
||||||
|
bugCommentMapper.updateByPrimaryKeySelective(bugComment);
|
||||||
|
if (StringUtils.equals(request.getEvent(), NoticeConstants.Event.COMMENT)) {
|
||||||
|
// COMMENT事件, 无需通知
|
||||||
|
return bugComment;
|
||||||
|
}
|
||||||
|
// REPLY及AT通知, 都只处理@通知人
|
||||||
|
if (StringUtils.equals(request.getEvent(), NoticeConstants.Event.REPLY)) {
|
||||||
|
// REPLY事件需保留回复人
|
||||||
|
request.setReplyUser(null);
|
||||||
|
request.setEvent(NoticeConstants.Event.AT);
|
||||||
|
}
|
||||||
|
BugCommentNoticeDTO bugCommentNotice = bugCommentNoticeService.getBugCommentNotice(request);
|
||||||
|
bugCommentNoticeService.sendNotice(request, bugCommentNotice, currentUser);
|
||||||
|
return bugComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取评论
|
||||||
|
* @param request 缺陷评论请求参数
|
||||||
|
* @param currentUser 当前用户ID
|
||||||
|
* @return 缺陷评论
|
||||||
|
*/
|
||||||
|
public static BugComment getBugComment(BugCommentEditRequest request, String currentUser, boolean isUpdate) {
|
||||||
|
BugComment bugComment = new BugComment();
|
||||||
|
bugComment.setId(isUpdate ? request.getId() : IDGenerator.nextStr());
|
||||||
|
bugComment.setBugId(request.getBugId());
|
||||||
|
bugComment.setContent(request.getContent());
|
||||||
|
if (!isUpdate) {
|
||||||
|
bugComment.setCreateUser(currentUser);
|
||||||
|
bugComment.setCreateTime(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
bugComment.setUpdateUser(currentUser);
|
||||||
|
bugComment.setUpdateTime(System.currentTimeMillis());
|
||||||
|
return bugComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验并设置评论信息
|
||||||
|
* @param request 缺陷评论请求参数
|
||||||
|
* @param bugComment 缺陷评论
|
||||||
|
*/
|
||||||
|
private void checkAndSetReplyComment(BugCommentEditRequest request, BugComment bugComment) {
|
||||||
|
if (StringUtils.isEmpty(request.getParentId())) {
|
||||||
|
throw new MSException(Translator.get("bug_comment.parent_id.not_blank"));
|
||||||
|
}
|
||||||
|
BugComment parentComment = bugCommentMapper.selectByPrimaryKey(request.getParentId());
|
||||||
|
if (parentComment == null) {
|
||||||
|
throw new MSException(Translator.get("bug_comment.parent.not_exist"));
|
||||||
|
}
|
||||||
|
bugComment.setParentId(request.getParentId());
|
||||||
|
if (StringUtils.isEmpty(request.getReplyUser())) {
|
||||||
|
throw new MSException(Translator.get("bug_comment.reply_user.not_blank"));
|
||||||
|
}
|
||||||
|
bugComment.setReplyUser(request.getReplyUser());
|
||||||
|
bugComment.setNotifier(request.getNotifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验缺陷是否存在
|
||||||
|
* @param bugId 缺陷ID
|
||||||
|
*/
|
||||||
|
private void checkBug(String bugId) {
|
||||||
|
Bug bug = bugMapper.selectByPrimaryKey(bugId);
|
||||||
|
if (bug == null) {
|
||||||
|
throw new IllegalArgumentException(Translator.get("bug_not_exist"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验评论是否存在
|
||||||
|
* @param commentId 评论ID
|
||||||
|
*/
|
||||||
|
private void checkComment(String commentId) {
|
||||||
|
BugComment bugComment = bugCommentMapper.selectByPrimaryKey(commentId);
|
||||||
|
if (bugComment == null) {
|
||||||
|
throw new IllegalArgumentException(Translator.get("bug_comment_not_exist"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户Map
|
||||||
|
* @param bugComments 缺陷评论集合
|
||||||
|
* @return 用户信息Map
|
||||||
|
*/
|
||||||
|
private Map<String, String> getUserMap(List<BugComment> bugComments) {
|
||||||
|
List<String> userIds = new ArrayList<>();
|
||||||
|
userIds.addAll(bugComments.stream().map(BugComment::getCreateUser).toList());
|
||||||
|
userIds.addAll(bugComments.stream().map(BugComment::getReplyUser).toList());
|
||||||
|
List<OptionDTO> options = baseUserMapper.selectUserOptionByIds(userIds.stream().distinct().toList());
|
||||||
|
return options.stream().collect(Collectors.toMap(OptionDTO::getId, OptionDTO::getName));
|
||||||
|
}
|
||||||
|
}
|
|
@ -552,8 +552,7 @@ public class BugService {
|
||||||
*/
|
*/
|
||||||
private List<BugDTO> buildExtraInfo(List<BugDTO> bugs) {
|
private List<BugDTO> buildExtraInfo(List<BugDTO> bugs) {
|
||||||
// 获取用户集合
|
// 获取用户集合
|
||||||
List<String> userIds = new ArrayList<>();
|
List<String> userIds = new ArrayList<>(bugs.stream().map(BugDTO::getCreateUser).toList());
|
||||||
userIds.addAll(bugs.stream().map(BugDTO::getCreateUser).toList());
|
|
||||||
userIds.addAll(bugs.stream().map(BugDTO::getUpdateUser).toList());
|
userIds.addAll(bugs.stream().map(BugDTO::getUpdateUser).toList());
|
||||||
userIds.addAll(bugs.stream().map(BugDTO::getDeleteUser).toList());
|
userIds.addAll(bugs.stream().map(BugDTO::getDeleteUser).toList());
|
||||||
userIds.addAll(bugs.stream().map(BugDTO::getHandleUser).toList());
|
userIds.addAll(bugs.stream().map(BugDTO::getHandleUser).toList());
|
||||||
|
|
|
@ -0,0 +1,312 @@
|
||||||
|
package io.metersphere.bug.controller;
|
||||||
|
|
||||||
|
import io.metersphere.bug.domain.BugComment;
|
||||||
|
import io.metersphere.bug.dto.BugCommentDTO;
|
||||||
|
import io.metersphere.bug.dto.BugCommentUserInfo;
|
||||||
|
import io.metersphere.bug.dto.request.BugCommentEditRequest;
|
||||||
|
import io.metersphere.bug.mapper.BugCommentMapper;
|
||||||
|
import io.metersphere.project.domain.Notification;
|
||||||
|
import io.metersphere.project.domain.NotificationExample;
|
||||||
|
import io.metersphere.project.mapper.NotificationMapper;
|
||||||
|
import io.metersphere.sdk.util.JSON;
|
||||||
|
import io.metersphere.system.base.BaseTest;
|
||||||
|
import io.metersphere.system.controller.handler.ResultHolder;
|
||||||
|
import io.metersphere.system.notice.constants.NoticeConstants;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.junit.jupiter.api.*;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||||
|
public class BugCommentTests extends BaseTest {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BugCommentMapper bugCommentMapper;
|
||||||
|
@Resource
|
||||||
|
private NotificationMapper notificationMapper;
|
||||||
|
|
||||||
|
public static final String BUG_COMMENT_GET = "/bug/comment/get";
|
||||||
|
public static final String BUG_COMMENT_USER_GET = "/bug/comment/user-extra";
|
||||||
|
public static final String BUG_COMMENT_ADD = "/bug/comment/add";
|
||||||
|
public static final String BUG_COMMENT_UPDATE = "/bug/comment/update";
|
||||||
|
public static final String BUG_COMMENT_DELETE = "/bug/comment/delete";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(0)
|
||||||
|
@Sql(scripts = {"/dml/init_bug_comment.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
|
||||||
|
public void testGetBugComment() throws Exception {
|
||||||
|
MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_COMMENT_GET + "/default-bug-id-for-comment");
|
||||||
|
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
|
ResultHolder resultHolder = JSON.parseObject(sortData, ResultHolder.class);
|
||||||
|
List<BugCommentDTO> comments = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BugCommentDTO.class);
|
||||||
|
Assertions.assertTrue(CollectionUtils.isNotEmpty(comments));
|
||||||
|
Assertions.assertTrue(StringUtils.equals("default-bug-comment-id-3", comments.get(0).getId()));
|
||||||
|
// 第二条评论的子评论不为空且ID为default-bug-comment-id-2
|
||||||
|
Assertions.assertTrue(CollectionUtils.isNotEmpty(comments.get(1).getChildComments()) &&
|
||||||
|
StringUtils.equals("default-bug-comment-id-2", comments.get(1).getChildComments().get(0).getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(1)
|
||||||
|
public void testGetBugEmptyComment() throws Exception {
|
||||||
|
MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_COMMENT_GET + "/default-bug-id-for-comment1");
|
||||||
|
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
|
ResultHolder resultHolder = JSON.parseObject(sortData, ResultHolder.class);
|
||||||
|
List<BugCommentDTO> comments = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BugCommentDTO.class);
|
||||||
|
// 该缺陷没有评论
|
||||||
|
Assertions.assertTrue(CollectionUtils.isEmpty(comments));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(2)
|
||||||
|
public void testGetBugUserExtra() throws Exception {
|
||||||
|
MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_COMMENT_USER_GET + "/default-bug-id-for-comment");
|
||||||
|
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
|
ResultHolder resultHolder = JSON.parseObject(sortData, ResultHolder.class);
|
||||||
|
List<BugCommentUserInfo> userInfos = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BugCommentUserInfo.class);
|
||||||
|
Assertions.assertTrue(CollectionUtils.isNotEmpty(userInfos));
|
||||||
|
long count = userInfos.stream().filter(userInfo -> StringUtils.contains(userInfo.getId(), "oasis-user-id")).count();
|
||||||
|
// 该缺陷评论存在两个通知人
|
||||||
|
Assertions.assertEquals(3, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(3)
|
||||||
|
public void testGetBugEmptyUserExtra() throws Exception {
|
||||||
|
MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_COMMENT_USER_GET + "/default-bug-id-for-comment1");
|
||||||
|
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
|
ResultHolder resultHolder = JSON.parseObject(sortData, ResultHolder.class);
|
||||||
|
List<BugCommentUserInfo> userInfos = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), BugCommentUserInfo.class);
|
||||||
|
Assertions.assertTrue(CollectionUtils.isEmpty(userInfos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(4)
|
||||||
|
public void testAddBugCommentOnlySuccess() throws Exception {
|
||||||
|
// 只评论, 不@用户, 也不是回复
|
||||||
|
BugCommentEditRequest request = new BugCommentEditRequest();
|
||||||
|
request.setBugId("default-bug-id-for-comment1");
|
||||||
|
request.setContent("This is a comment test!");
|
||||||
|
request.setEvent(NoticeConstants.Event.COMMENT);
|
||||||
|
BugComment bugComment = saveOrUpdateComment(request, false);
|
||||||
|
// 查询通知表中记录
|
||||||
|
NotificationExample example = new NotificationExample();
|
||||||
|
example.createCriteria().andResourceIdEqualTo("default-bug-id-for-comment1").andResourceTypeEqualTo(NoticeConstants.TaskType.BUG_TASK);
|
||||||
|
List<Notification> notifications = notificationMapper.selectByExample(example);
|
||||||
|
Assertions.assertTrue(CollectionUtils.isNotEmpty(notifications));
|
||||||
|
Assertions.assertTrue(StringUtils.equals(notifications.get(0).getReceiver(), "oasis-user-id"));
|
||||||
|
BugComment comment = bugCommentMapper.selectByPrimaryKey(bugComment.getId());
|
||||||
|
Assertions.assertTrue(StringUtils.equals(comment.getContent(), "This is a comment test!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(5)
|
||||||
|
public void testAddBugCommentOnlyError() throws Exception {
|
||||||
|
// 只评论, 不@用户, 也不是回复 (缺陷不存在)
|
||||||
|
BugCommentEditRequest request = new BugCommentEditRequest();
|
||||||
|
request.setBugId("default-bug-id-for-comment-x");
|
||||||
|
request.setContent("This is a comment test!");
|
||||||
|
request.setEvent(NoticeConstants.Event.COMMENT);
|
||||||
|
this.requestPost(BUG_COMMENT_ADD, request, status().is5xxServerError());
|
||||||
|
// 回复评论, 没有父级评论ID
|
||||||
|
request.setReplyUser("oasis-user-id1");
|
||||||
|
request.setBugId("default-bug-id-for-comment");
|
||||||
|
request.setContent("This is a comment test!");
|
||||||
|
request.setEvent(NoticeConstants.Event.REPLY);
|
||||||
|
this.requestPost(BUG_COMMENT_ADD, request, status().is5xxServerError());
|
||||||
|
// 回复评论, 父级评论不存在
|
||||||
|
request.setReplyUser("oasis-user-id1");
|
||||||
|
request.setBugId("default-bug-id-for-comment");
|
||||||
|
request.setContent("This is a comment test!");
|
||||||
|
request.setParentId("default-bug-comment-id-3-x");
|
||||||
|
request.setEvent(NoticeConstants.Event.REPLY);
|
||||||
|
this.requestPost(BUG_COMMENT_ADD, request, status().is5xxServerError());
|
||||||
|
// 回复评论, 但回复人为空
|
||||||
|
request.setReplyUser(null);
|
||||||
|
request.setBugId("default-bug-id-for-comment");
|
||||||
|
request.setContent("This is a comment test!");
|
||||||
|
request.setParentId("default-bug-comment-id-3");
|
||||||
|
request.setEvent(NoticeConstants.Event.REPLY);
|
||||||
|
this.requestPost(BUG_COMMENT_ADD, request, status().is5xxServerError());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(6)
|
||||||
|
public void testAddBugCommentWithAtEventSuccess() throws Exception {
|
||||||
|
// 评论并@用户, 不是回复
|
||||||
|
BugCommentEditRequest request = new BugCommentEditRequest();
|
||||||
|
request.setBugId("default-bug-id-for-comment");
|
||||||
|
request.setContent("This is a at comment test!");
|
||||||
|
request.setNotifier(String.join(";", "oasis-user-id4"));
|
||||||
|
request.setEvent(NoticeConstants.Event.AT);
|
||||||
|
BugComment bugComment = saveOrUpdateComment(request, false);
|
||||||
|
// 查询通知表中记录
|
||||||
|
NotificationExample example = new NotificationExample();
|
||||||
|
example.createCriteria().andResourceIdEqualTo("default-bug-id-for-comment").andResourceTypeEqualTo(NoticeConstants.TaskType.BUG_TASK);
|
||||||
|
List<Notification> notifications = notificationMapper.selectByExample(example);
|
||||||
|
// 存在2条通知
|
||||||
|
Assertions.assertEquals(2, notifications.size());
|
||||||
|
long atCount = notifications.stream().filter(notification -> StringUtils.equals(notification.getOperation(), NoticeConstants.Event.AT)).count();
|
||||||
|
// 仅有1条AT方法通知
|
||||||
|
Assertions.assertEquals(atCount, 1);
|
||||||
|
BugComment comment = bugCommentMapper.selectByPrimaryKey(bugComment.getId());
|
||||||
|
Assertions.assertTrue(StringUtils.equals(comment.getContent(), "This is a at comment test!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(7)
|
||||||
|
public void testAddBugCommentWithReplyEventSuccess() throws Exception {
|
||||||
|
// 评论并回复用户, 但不@
|
||||||
|
BugCommentEditRequest request = new BugCommentEditRequest();
|
||||||
|
request.setBugId("default-bug-id-for-comment");
|
||||||
|
request.setContent("This is a reply comment test!");
|
||||||
|
request.setReplyUser("oasis-user-id1");
|
||||||
|
request.setParentId("default-bug-comment-id-3");
|
||||||
|
request.setEvent(NoticeConstants.Event.REPLY);
|
||||||
|
BugComment bugComment = saveOrUpdateComment(request, false);
|
||||||
|
// 查询通知表中记录
|
||||||
|
NotificationExample example = new NotificationExample();
|
||||||
|
example.createCriteria().andResourceIdEqualTo("default-bug-id-for-comment").andResourceTypeEqualTo(NoticeConstants.TaskType.BUG_TASK);
|
||||||
|
List<Notification> notifications = notificationMapper.selectByExample(example);
|
||||||
|
// 存在3条通知
|
||||||
|
Assertions.assertEquals(3, notifications.size());
|
||||||
|
long reCount = notifications.stream().filter(notification -> StringUtils.equals(notification.getOperation(), NoticeConstants.Event.REPLY)).count();
|
||||||
|
// 仅有1条REPLY方法通知
|
||||||
|
Assertions.assertEquals(reCount, 1);
|
||||||
|
BugComment comment = bugCommentMapper.selectByPrimaryKey(bugComment.getId());
|
||||||
|
Assertions.assertTrue(StringUtils.equals(comment.getContent(), "This is a reply comment test!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(8)
|
||||||
|
public void testAddBugCommentWithReplyAndAtEventSuccess() throws Exception {
|
||||||
|
// 评论并回复用户, 但不@当前回复人
|
||||||
|
BugCommentEditRequest request = new BugCommentEditRequest();
|
||||||
|
request.setBugId("default-bug-id-for-comment");
|
||||||
|
request.setContent("This is a reply && at comment test!");
|
||||||
|
request.setReplyUser("oasis-user-id");
|
||||||
|
request.setNotifier(String.join(";", "oasis-user-id3", "oasis-user-id4"));
|
||||||
|
request.setParentId("default-bug-comment-id-2");
|
||||||
|
request.setEvent(NoticeConstants.Event.REPLY);
|
||||||
|
BugComment bugComment = saveOrUpdateComment(request, false);
|
||||||
|
// 查询通知表中记录
|
||||||
|
NotificationExample example = new NotificationExample();
|
||||||
|
example.createCriteria().andResourceIdEqualTo("default-bug-id-for-comment").andResourceTypeEqualTo(NoticeConstants.TaskType.BUG_TASK);
|
||||||
|
List<Notification> notifications = notificationMapper.selectByExample(example);
|
||||||
|
// 存在7条通知
|
||||||
|
Assertions.assertEquals(6, notifications.size());
|
||||||
|
long reCount = notifications.stream().filter(notification -> StringUtils.equals(notification.getOperation(), NoticeConstants.Event.REPLY)).count();
|
||||||
|
// 仅有2条REPLY方法通知
|
||||||
|
Assertions.assertEquals(reCount, 2);
|
||||||
|
BugComment comment = bugCommentMapper.selectByPrimaryKey(bugComment.getId());
|
||||||
|
Assertions.assertTrue(StringUtils.equals(comment.getContent(), "This is a reply && at comment test!"));
|
||||||
|
// 评论并回复用户, @当前回复人
|
||||||
|
request.setNotifier(String.join(";", "oasis-user-id", "oasis-user-id2"));
|
||||||
|
saveOrUpdateComment(request, false);
|
||||||
|
List<Notification> notificationsList = notificationMapper.selectByExample(example);
|
||||||
|
// 存在8条通知
|
||||||
|
Assertions.assertEquals(8, notificationsList.size());
|
||||||
|
long reCount1 = notificationsList.stream().filter(notification -> StringUtils.equals(notification.getOperation(), NoticeConstants.Event.REPLY)).count();
|
||||||
|
// 仅有3条REPLY方法通知
|
||||||
|
Assertions.assertEquals(reCount1, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(9)
|
||||||
|
public void testUpdateBugCommentOnlySuccess() throws Exception {
|
||||||
|
// 只编辑第一级评论
|
||||||
|
BugCommentEditRequest request = new BugCommentEditRequest();
|
||||||
|
request.setId("default-bug-comment-id-3");
|
||||||
|
request.setBugId("default-bug-id-for-comment");
|
||||||
|
request.setContent("This is a comment test!");
|
||||||
|
request.setEvent(NoticeConstants.Event.COMMENT);
|
||||||
|
BugComment bugComment = saveOrUpdateComment(request, true);
|
||||||
|
NotificationExample example = new NotificationExample();
|
||||||
|
example.createCriteria().andResourceIdEqualTo("default-bug-id-for-comment").andResourceTypeEqualTo(NoticeConstants.TaskType.BUG_TASK);
|
||||||
|
List<Notification> notifications = notificationMapper.selectByExample(example);
|
||||||
|
// 存在8条通知
|
||||||
|
Assertions.assertEquals(8, notifications.size());
|
||||||
|
BugComment comment = bugCommentMapper.selectByPrimaryKey(bugComment.getId());
|
||||||
|
Assertions.assertTrue(StringUtils.equals(comment.getContent(), "This is a comment test!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(10)
|
||||||
|
public void testUpdateBugCommentWithReplyEventSuccess() throws Exception {
|
||||||
|
// 只编辑回复的评论并且带有@用户
|
||||||
|
BugCommentEditRequest request = new BugCommentEditRequest();
|
||||||
|
request.setId("default-bug-comment-id-2");
|
||||||
|
request.setBugId("default-bug-id-for-comment");
|
||||||
|
request.setContent("This is a comment && reply test!");
|
||||||
|
request.setReplyUser("admin");
|
||||||
|
request.setNotifier(String.join(";", "oasis-user-id1", "oasis-user-id2", "admin"));
|
||||||
|
request.setEvent(NoticeConstants.Event.REPLY);
|
||||||
|
BugComment bugComment = saveOrUpdateComment(request, true);
|
||||||
|
NotificationExample example = new NotificationExample();
|
||||||
|
example.createCriteria().andResourceIdEqualTo("default-bug-id-for-comment").andResourceTypeEqualTo(NoticeConstants.TaskType.BUG_TASK);
|
||||||
|
List<Notification> notifications = notificationMapper.selectByExample(example);
|
||||||
|
// 存在10条通知, 会排除掉当前登录用户
|
||||||
|
Assertions.assertEquals(10, notifications.size());
|
||||||
|
BugComment comment = bugCommentMapper.selectByPrimaryKey(bugComment.getId());
|
||||||
|
Assertions.assertTrue(StringUtils.equals(comment.getContent(), "This is a comment && reply test!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(11)
|
||||||
|
public void testUpdateBugCommentWithAtEventSuccess() throws Exception {
|
||||||
|
// 编辑第一级并带有@的评论
|
||||||
|
BugCommentEditRequest request = new BugCommentEditRequest();
|
||||||
|
request.setId("default-bug-comment-id-3");
|
||||||
|
request.setBugId("default-bug-id-for-comment");
|
||||||
|
request.setContent("This is a comment && at test!");
|
||||||
|
request.setNotifier(String.join(";", "oasis-user-id3", "oasis-user-id4"));
|
||||||
|
request.setEvent(NoticeConstants.Event.AT);
|
||||||
|
BugComment bugComment = saveOrUpdateComment(request, true);
|
||||||
|
NotificationExample example = new NotificationExample();
|
||||||
|
example.createCriteria().andResourceIdEqualTo("default-bug-id-for-comment").andResourceTypeEqualTo(NoticeConstants.TaskType.BUG_TASK);
|
||||||
|
List<Notification> notifications = notificationMapper.selectByExample(example);
|
||||||
|
// 存在12条通知
|
||||||
|
Assertions.assertEquals(12, notifications.size());
|
||||||
|
BugComment comment = bugCommentMapper.selectByPrimaryKey(bugComment.getId());
|
||||||
|
Assertions.assertTrue(StringUtils.equals(comment.getContent(), "This is a comment && at test!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(12)
|
||||||
|
public void testDeleteBugCommentSuccess() throws Exception {
|
||||||
|
// 删除第一级评论
|
||||||
|
this.requestGet(BUG_COMMENT_DELETE + "/default-bug-comment-id-1");
|
||||||
|
BugComment comment = bugCommentMapper.selectByPrimaryKey("default-bug-comment-id-2");
|
||||||
|
Assertions.assertNull(comment);
|
||||||
|
// 删除第二级评论
|
||||||
|
this.requestGet(BUG_COMMENT_DELETE + "/default-bug-comment-id-4");
|
||||||
|
BugComment comment1 = bugCommentMapper.selectByPrimaryKey("default-bug-comment-id-4");
|
||||||
|
Assertions.assertNull(comment1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(13)
|
||||||
|
public void testDeleteBugCommentError() throws Exception {
|
||||||
|
// 评论不存在
|
||||||
|
this.requestGet(BUG_COMMENT_DELETE + "/default-bug-comment-id-x");
|
||||||
|
}
|
||||||
|
|
||||||
|
private BugComment saveOrUpdateComment(BugCommentEditRequest request, boolean isUpdated) throws Exception{
|
||||||
|
MvcResult mvcResult = this.requestPostWithOkAndReturn(isUpdated ? BUG_COMMENT_UPDATE : BUG_COMMENT_ADD, request);
|
||||||
|
String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
|
ResultHolder resultHolder = JSON.parseObject(sortData, ResultHolder.class);
|
||||||
|
return JSON.parseObject(JSON.toJSONString(resultHolder.getData()), BugComment.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
INSERT INTO project (id, num, organization_id, name, description, create_user, update_user, create_time, update_time) VALUE
|
||||||
|
('default-project-for-bug-comment', null, '100001', '测试项目(缺陷)', '系统默认创建的项目(缺陷)', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
|
||||||
|
|
||||||
|
INSERT INTO user(id, name, email, password, create_time, update_time, language, last_organization_id, phone, source, last_project_id, create_user, update_user, deleted) VALUES
|
||||||
|
('oasis-user-id', 'oasis', 'oasis@test.com', MD5('metersphere'), UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', false),
|
||||||
|
('oasis-user-id1', 'oasis1', 'oasis1@test.com', MD5('metersphere'), UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', false),
|
||||||
|
('oasis-user-id2', 'oasis2', 'oasis2@test.com', MD5('metersphere'), UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', false),
|
||||||
|
('oasis-user-id3', 'oasis3', 'oasis3@test.com', MD5('metersphere'), UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', false),
|
||||||
|
('oasis-user-id4', 'oasis4', 'oasis4@test.com', MD5('metersphere'), UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', false);
|
||||||
|
|
||||||
|
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,
|
||||||
|
update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tag, platform_bug_id, deleted) VALUE
|
||||||
|
('default-bug-id-for-comment', 100099, 'default-bug-for-comment', 'oasis', 'oasis', 'oasis-user-id', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id', 'Local', 'open', 'default-tag', null, 0),
|
||||||
|
('default-bug-id-for-comment1', 100099, 'default-bug-for-comment', 'oasis', 'oasis', 'oasis-user-id', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id', 'Local', 'open', 'default-tag', null, 0);
|
||||||
|
|
||||||
|
INSERT INTO bug_comment (id, bug_id, reply_user, notifier, parent_id, content, create_user, create_time, update_user, update_time) VALUES
|
||||||
|
('default-bug-comment-id-1', 'default-bug-id-for-comment', null, null, null, 'This is a test comment!', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000),
|
||||||
|
('default-bug-comment-id-2', 'default-bug-id-for-comment', 'admin', 'oasis-user-id1;oasis-user-id2', 'default-bug-comment-id-1', 'This is a test comment!', 'oasis-user-id', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000),
|
||||||
|
('default-bug-comment-id-3', 'default-bug-id-for-comment', null, null, null, 'This is a test comment!', 'oasis-user-id1', UNIX_TIMESTAMP() * 1000 + 1000, 'admin', UNIX_TIMESTAMP() * 1000),
|
||||||
|
('default-bug-comment-id-4', 'default-bug-id-for-comment', 'oasis-user-id1', null, 'default-bug-comment-id-3', 'This is a test comment!', 'oasis-user-id2', UNIX_TIMESTAMP() * 1000 + 1000, 'admin', UNIX_TIMESTAMP() * 1000);
|
||||||
|
|
||||||
|
INSERT INTO bug_custom_field (bug_id, field_id, value) VALUE ('default-bug-id-for-comment1', 'comment_test_field', '["default", "default-1"]');
|
||||||
|
|
||||||
|
INSERT INTO custom_field (id, name, scene, type, remark, internal, scope_type, create_time, update_time, create_user, scope_id) VALUE
|
||||||
|
('comment_test_field', '测试字段', 'BUG', 'MULTIPLE_SELECT', '', 0, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', '100001100001');
|
|
@ -5,10 +5,12 @@ import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class OptionDTO {
|
public class OptionDTO implements Serializable {
|
||||||
@Schema(description = "选项ID")
|
@Schema(description = "选项ID")
|
||||||
private String id;
|
private String id;
|
||||||
@Schema(description = "选项名称")
|
@Schema(description = "选项名称")
|
||||||
|
|
Loading…
Reference in New Issue