From 8de0d13870a7aa4468b84a4f9bcfc30faaa8790f Mon Sep 17 00:00:00 2001 From: song-cc-rock Date: Fri, 3 Nov 2023 18:40:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=BC=BA=E9=99=B7=E7=AE=A1=E7=90=86):=20?= =?UTF-8?q?=E7=BC=BA=E9=99=B7=E8=AF=84=E8=AE=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/i18n/bug.properties | 7 +- .../main/resources/i18n/bug_en_US.properties | 5 + .../main/resources/i18n/bug_zh_CN.properties | 7 +- .../main/resources/i18n/bug_zh_TW.properties | 5 + .../bug/controller/BugCommentController.java | 47 +++ .../io/metersphere/bug/dto/BugCommentDTO.java | 22 ++ .../bug/dto/BugCommentNoticeDTO.java | 19 ++ .../bug/dto/BugCommentUserInfo.java | 14 + .../dto/request/BugCommentEditRequest.java | 36 ++ .../bug/service/BugCommentNoticeService.java | 132 ++++++++ .../bug/service/BugCommentService.java | 291 ++++++++++++++++ .../metersphere/bug/service/BugService.java | 3 +- .../bug/controller/BugCommentTests.java | 312 ++++++++++++++++++ .../test/resources/dml/init_bug_comment.sql | 25 ++ .../metersphere/system/dto/sdk/OptionDTO.java | 4 +- 15 files changed, 924 insertions(+), 5 deletions(-) create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugCommentController.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentDTO.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentNoticeDTO.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentUserInfo.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugCommentEditRequest.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommentNoticeService.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommentService.java create mode 100644 backend/services/bug-management/src/test/java/io/metersphere/bug/controller/BugCommentTests.java create mode 100644 backend/services/bug-management/src/test/resources/dml/init_bug_comment.sql diff --git a/backend/framework/sdk/src/main/resources/i18n/bug.properties b/backend/framework/sdk/src/main/resources/i18n/bug.properties index c3243beda8..8dd7016459 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug.properties @@ -89,4 +89,9 @@ third_party_not_config=项目未配置第三方平台 bug_attachment_upload_error=缺陷附件上传失败 bug_attachment_delete_error=缺陷附件删除失败 no_bug_select=未勾选缺陷 -bug_select_not_found=未查询到勾选的缺陷 \ No newline at end of file +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=缺陷评论不存在 diff --git a/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties b/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties index 1cf56fce39..55b39e8da5 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties @@ -90,3 +90,8 @@ bug_attachment_upload_error=Bug attachment upload error bug_attachment_delete_error=Bug attachment delete error no_bug_select=No bug selected 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 diff --git a/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties b/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties index c3243beda8..8dd7016459 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties @@ -89,4 +89,9 @@ third_party_not_config=项目未配置第三方平台 bug_attachment_upload_error=缺陷附件上传失败 bug_attachment_delete_error=缺陷附件删除失败 no_bug_select=未勾选缺陷 -bug_select_not_found=未查询到勾选的缺陷 \ No newline at end of file +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=缺陷评论不存在 diff --git a/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties b/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties index 8d85ed69e3..95488267d1 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties @@ -90,4 +90,9 @@ bug_attachment_upload_error=缺陷附件上傳失敗 bug_attachment_delete_error=缺陷附件刪除失敗 no_bug_select=未勾選缺陷 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=缺陷評論不存在 diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugCommentController.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugCommentController.java new file mode 100644 index 0000000000..aef8d4678c --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugCommentController.java @@ -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 get(@PathVariable String bugId) { + return bugCommentService.getComments(bugId); + } + + @GetMapping("/user-extra/{bugId}") + public List 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); + } +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentDTO.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentDTO.java new file mode 100644 index 0000000000..6c122c9c47 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentDTO.java @@ -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 childComments; +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentNoticeDTO.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentNoticeDTO.java new file mode 100644 index 0000000000..419ebce139 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentNoticeDTO.java @@ -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 fields; +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentUserInfo.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentUserInfo.java new file mode 100644 index 0000000000..e754fd6bae --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugCommentUserInfo.java @@ -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; +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugCommentEditRequest.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugCommentEditRequest.java new file mode 100644 index 0000000000..76edb15a50 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugCommentEditRequest.java @@ -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; +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommentNoticeService.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommentNoticeService.java new file mode 100644 index 0000000000..0ff443dd6c --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommentNoticeService.java @@ -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 defaultTemplateMap = MessageTemplateUtils.getDefaultTemplateMap(); + String template = defaultTemplateMap.get(NoticeConstants.TaskType.BUG_TASK + "_" + request.getEvent()); + Map 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 bugCustomFields = extBugCustomFieldMapper.getBugCustomFields(List.of(bugCommentNoticeDTO.getId()), bugCommentNoticeDTO.getProjectId()); + if (CollectionUtils.isNotEmpty(bugCustomFields)) { + List 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 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 getRelateUser(String notifier) { + if (StringUtils.isBlank(notifier)) { + return null; + } + return Arrays.asList(notifier.split(";")); + } +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommentService.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommentService.java new file mode 100644 index 0000000000..acb2776187 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugCommentService.java @@ -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 getComments(String bugId) { + BugCommentExample example = new BugCommentExample(); + example.createCriteria().andBugIdEqualTo(bugId); + List bugComments = bugCommentMapper.selectByExample(example); + if (CollectionUtils.isEmpty(bugComments)) { + return new ArrayList<>(); + } + + // BugComment -> BugCommentDTO + Map userMap = getUserMap(bugComments); + List 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 parentComments = bugCommentDTOList.stream().filter(bugCommentDTO -> StringUtils.isEmpty(bugCommentDTO.getParentId())) + .sorted(Comparator.comparing(BugCommentDTO::getCreateTime, Comparator.reverseOrder())).toList(); + parentComments.forEach(parentComment -> { + // 子级评论 + List 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 getUserExtra(String bugId) { + BugCommentExample example = new BugCommentExample(); + example.createCriteria().andBugIdEqualTo(bugId); + List bugComments = bugCommentMapper.selectByExample(example); + if (CollectionUtils.isEmpty(bugComments)) { + return new ArrayList<>(); + } + + List 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 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 getUserMap(List bugComments) { + List userIds = new ArrayList<>(); + userIds.addAll(bugComments.stream().map(BugComment::getCreateUser).toList()); + userIds.addAll(bugComments.stream().map(BugComment::getReplyUser).toList()); + List options = baseUserMapper.selectUserOptionByIds(userIds.stream().distinct().toList()); + return options.stream().collect(Collectors.toMap(OptionDTO::getId, OptionDTO::getName)); + } +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugService.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugService.java index 541aa2fe4f..0d78a9bbbe 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugService.java +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugService.java @@ -552,8 +552,7 @@ public class BugService { */ private List buildExtraInfo(List bugs) { // 获取用户集合 - List userIds = new ArrayList<>(); - userIds.addAll(bugs.stream().map(BugDTO::getCreateUser).toList()); + List userIds = new ArrayList<>(bugs.stream().map(BugDTO::getCreateUser).toList()); userIds.addAll(bugs.stream().map(BugDTO::getUpdateUser).toList()); userIds.addAll(bugs.stream().map(BugDTO::getDeleteUser).toList()); userIds.addAll(bugs.stream().map(BugDTO::getHandleUser).toList()); diff --git a/backend/services/bug-management/src/test/java/io/metersphere/bug/controller/BugCommentTests.java b/backend/services/bug-management/src/test/java/io/metersphere/bug/controller/BugCommentTests.java new file mode 100644 index 0000000000..fd6b9bce5d --- /dev/null +++ b/backend/services/bug-management/src/test/java/io/metersphere/bug/controller/BugCommentTests.java @@ -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 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 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 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 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 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 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 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 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 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 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 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 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); + } +} diff --git a/backend/services/bug-management/src/test/resources/dml/init_bug_comment.sql b/backend/services/bug-management/src/test/resources/dml/init_bug_comment.sql new file mode 100644 index 0000000000..0191c9b18e --- /dev/null +++ b/backend/services/bug-management/src/test/resources/dml/init_bug_comment.sql @@ -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'); diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/dto/sdk/OptionDTO.java b/backend/services/system-setting/src/main/java/io/metersphere/system/dto/sdk/OptionDTO.java index 241879eca7..f0fc437f62 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/dto/sdk/OptionDTO.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/dto/sdk/OptionDTO.java @@ -5,10 +5,12 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import java.io.Serializable; + @Data @AllArgsConstructor @NoArgsConstructor -public class OptionDTO { +public class OptionDTO implements Serializable { @Schema(description = "选项ID") private String id; @Schema(description = "选项名称")