feat(功能用例): 获取评论接口

This commit is contained in:
guoyuqi 2023-10-30 16:03:54 +08:00 committed by Craftsman
parent 588da5a530
commit 7eabb3fe89
9 changed files with 178 additions and 11 deletions

View File

@ -213,6 +213,7 @@ public class PermissionConstants {
/*------ start: FUNCTIONAL_CASE ------*/ /*------ start: FUNCTIONAL_CASE ------*/
public static final String FUNCTIONAL_CASE_READ = "FUNCTIONAL_CASE:READ"; public static final String FUNCTIONAL_CASE_READ = "FUNCTIONAL_CASE:READ";
public static final String FUNCTIONAL_CASE_READ_ADD = "FUNCTIONAL_CASE:READ+ADD"; public static final String FUNCTIONAL_CASE_READ_ADD = "FUNCTIONAL_CASE:READ+ADD";
public static final String FUNCTIONAL_CASE_COMMENT_READ = "FUNCTIONAL_CASE_COMMENT:READ";
public static final String FUNCTIONAL_CASE_READ_UPDATE = "FUNCTIONAL_CASE:READ+UPDATE"; public static final String FUNCTIONAL_CASE_READ_UPDATE = "FUNCTIONAL_CASE:READ+UPDATE";
public static final String FUNCTIONAL_CASE_COMMENT_READ_ADD = "FUNCTIONAL_CASE_COMMENT:READ+ADD"; public static final String FUNCTIONAL_CASE_COMMENT_READ_ADD = "FUNCTIONAL_CASE_COMMENT:READ+ADD";
public static final String FUNCTIONAL_CASE_COMMENT_READ_DELETE = "FUNCTIONAL_CASE_COMMENT:READ+DELETE"; public static final String FUNCTIONAL_CASE_COMMENT_READ_DELETE = "FUNCTIONAL_CASE_COMMENT:READ+DELETE";

View File

@ -1,6 +1,6 @@
package io.metersphere.functional.controller; package io.metersphere.functional.controller;
import io.metersphere.functional.dto.CaseReviewDto; import io.metersphere.functional.dto.CaseReviewDTO;
import io.metersphere.functional.service.CaseReviewService; import io.metersphere.functional.service.CaseReviewService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -18,7 +18,7 @@ public class CaseReviewController {
@GetMapping("/get/{id}") @GetMapping("/get/{id}")
public CaseReviewDto get(@PathVariable String id) { public CaseReviewDTO get(@PathVariable String id) {
return caseReviewService.get(id); return caseReviewService.get(id);
} }
} }

View File

@ -1,6 +1,7 @@
package io.metersphere.functional.controller; package io.metersphere.functional.controller;
import io.metersphere.functional.domain.FunctionalCaseComment; import io.metersphere.functional.domain.FunctionalCaseComment;
import io.metersphere.functional.dto.FunctionalCaseCommentDTO;
import io.metersphere.functional.request.FunctionalCaseCommentRequest; import io.metersphere.functional.request.FunctionalCaseCommentRequest;
import io.metersphere.functional.service.FunctionalCaseCommentService; import io.metersphere.functional.service.FunctionalCaseCommentService;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
@ -13,6 +14,8 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "用例管理-功能用例-用例评论") @Tag(name = "用例管理-功能用例-用例评论")
@RestController @RestController
@RequestMapping("/functional/case/comment") @RequestMapping("/functional/case/comment")
@ -34,4 +37,11 @@ public class FunctionalCaseCommentController {
public void deleteComment(@PathVariable String commentId) { public void deleteComment(@PathVariable String commentId) {
functionalCaseCommentService.deleteComment(commentId); functionalCaseCommentService.deleteComment(commentId);
} }
@GetMapping("/get/list/{caseId}")
@Operation(summary = "用例管理-功能用例-用例评论-获取用例评论")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_COMMENT_READ)
public List<FunctionalCaseCommentDTO> getCommentList(@PathVariable String caseId) {
return functionalCaseCommentService.getCommentList(caseId);
}
} }

View File

@ -2,5 +2,5 @@ package io.metersphere.functional.dto;
import io.metersphere.functional.domain.CaseReview; import io.metersphere.functional.domain.CaseReview;
public class CaseReviewDto extends CaseReview { public class CaseReviewDTO extends CaseReview {
} }

View File

@ -0,0 +1,24 @@
package io.metersphere.functional.dto;
import io.metersphere.functional.domain.FunctionalCaseComment;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class FunctionalCaseCommentDTO extends FunctionalCaseComment {
@Schema(description = "评论的人名")
private String userName;
@Schema(description = "被回复的人名")
private String replyUserName;
@Schema(description = "被回复的人头像")
private String replyUserLogo;
@Schema(description = "该条评论下的所有回复数据")
private List<FunctionalCaseCommentDTO> replies;
}

View File

@ -1,7 +1,7 @@
package io.metersphere.functional.service; package io.metersphere.functional.service;
import io.metersphere.functional.dto.CaseReviewDto; import io.metersphere.functional.dto.CaseReviewDTO;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
@ -13,8 +13,8 @@ import org.springframework.stereotype.Service;
public class CaseReviewService { public class CaseReviewService {
public CaseReviewDto get(String id) { public CaseReviewDTO get(String id) {
CaseReviewDto caseReviewDto = new CaseReviewDto(); CaseReviewDTO caseReviewDto = new CaseReviewDTO();
return caseReviewDto; return caseReviewDto;
} }
} }

View File

@ -1,16 +1,20 @@
package io.metersphere.functional.service; package io.metersphere.functional.service;
import io.metersphere.functional.domain.FunctionalCase; import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.domain.FunctionalCaseComment; import io.metersphere.functional.domain.FunctionalCaseComment;
import io.metersphere.functional.domain.FunctionalCaseCommentExample; import io.metersphere.functional.domain.FunctionalCaseCommentExample;
import io.metersphere.functional.dto.CommentEnum; import io.metersphere.functional.dto.CommentEnum;
import io.metersphere.functional.dto.FunctionalCaseCommentDTO;
import io.metersphere.functional.dto.FunctionalCaseDTO; import io.metersphere.functional.dto.FunctionalCaseDTO;
import io.metersphere.functional.mapper.FunctionalCaseCommentMapper; import io.metersphere.functional.mapper.FunctionalCaseCommentMapper;
import io.metersphere.functional.mapper.FunctionalCaseMapper; import io.metersphere.functional.mapper.FunctionalCaseMapper;
import io.metersphere.functional.request.FunctionalCaseCommentRequest; import io.metersphere.functional.request.FunctionalCaseCommentRequest;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.User; import io.metersphere.system.domain.User;
import io.metersphere.system.domain.UserExample;
import io.metersphere.system.mapper.UserMapper; import io.metersphere.system.mapper.UserMapper;
import io.metersphere.system.notice.NoticeModel; import io.metersphere.system.notice.NoticeModel;
import io.metersphere.system.notice.constants.NoticeConstants; import io.metersphere.system.notice.constants.NoticeConstants;
@ -22,8 +26,13 @@ import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.apache.commons.collections.CollectionUtils;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* @author guoyuqi * @author guoyuqi
@ -55,7 +64,7 @@ public class FunctionalCaseCommentService {
* @return FunctionalCaseComment * @return FunctionalCaseComment
*/ */
public FunctionalCaseComment saveComment(FunctionalCaseCommentRequest functionalCaseCommentRequest, String userId) { public FunctionalCaseComment saveComment(FunctionalCaseCommentRequest functionalCaseCommentRequest, String userId) {
checkCase(functionalCaseCommentRequest); checkCase(functionalCaseCommentRequest.getCaseId());
FunctionalCaseComment functionalCaseComment = getFunctionalCaseComment(functionalCaseCommentRequest, userId); FunctionalCaseComment functionalCaseComment = getFunctionalCaseComment(functionalCaseCommentRequest, userId);
if (StringUtils.equals(functionalCaseCommentRequest.getEvent(), NoticeConstants.Event.REPLY)) { if (StringUtils.equals(functionalCaseCommentRequest.getEvent(), NoticeConstants.Event.REPLY)) {
return saveCommentWidthNotice(functionalCaseCommentRequest, functionalCaseComment, userId); return saveCommentWidthNotice(functionalCaseCommentRequest, functionalCaseComment, userId);
@ -85,8 +94,8 @@ public class FunctionalCaseCommentService {
return functionalCaseComment; return functionalCaseComment;
} }
private void checkCase(FunctionalCaseCommentRequest functionalCaseCommentRequest) { private void checkCase(String caseId) {
FunctionalCase functionalCase = functionalCaseMapper.selectByPrimaryKey(functionalCaseCommentRequest.getCaseId()); FunctionalCase functionalCase = functionalCaseMapper.selectByPrimaryKey(caseId);
if (functionalCase == null) { if (functionalCase == null) {
throw new MSException(Translator.get("case_comment.case_is_null")); throw new MSException(Translator.get("case_comment.case_is_null"));
} }
@ -198,4 +207,84 @@ public class FunctionalCaseCommentService {
functionalCaseCommentExample.createCriteria().andIdIn(commentIds); functionalCaseCommentExample.createCriteria().andIdIn(commentIds);
functionalCaseCommentMapper.deleteByExample(functionalCaseCommentExample); functionalCaseCommentMapper.deleteByExample(functionalCaseCommentExample);
} }
public List<FunctionalCaseCommentDTO> getCommentList(String caseId) {
checkCase(caseId);
//查询出当前用例下的所有数据
FunctionalCaseCommentExample functionalCaseCommentExample = new FunctionalCaseCommentExample();
functionalCaseCommentExample.createCriteria().andCaseIdEqualTo(caseId);
List<FunctionalCaseComment> functionalCaseComments = functionalCaseCommentMapper.selectByExampleWithBLOBs(functionalCaseCommentExample);
List<String> userIds = getUserIds(functionalCaseComments);
Map<String, User> userMap = getUserMap(userIds);
return buildData(functionalCaseComments, userMap);
}
/**
* 组装需要返回前端的数据结构
* @param functionalCaseComments 查出来的所有当前用例的评论信息
* @param userMap 用户信息
*/
private List<FunctionalCaseCommentDTO> buildData(List<FunctionalCaseComment> functionalCaseComments, Map<String, User> userMap) {
List<FunctionalCaseCommentDTO>list = new ArrayList<>();
List<FunctionalCaseComment> rootList = functionalCaseComments.stream().filter(t -> StringUtils.isBlank(t.getParentId())).toList();
List<FunctionalCaseComment> replyList = functionalCaseComments.stream().filter(t -> StringUtils.isNotBlank(t.getParentId())).toList();
Map<String, List<FunctionalCaseComment>> commentMap = replyList.stream().collect(Collectors.groupingBy(FunctionalCaseComment::getParentId));
for (FunctionalCaseComment functionalCaseComment : rootList) {
FunctionalCaseCommentDTO functionalCaseCommentDTO = new FunctionalCaseCommentDTO();
BeanUtils.copyBean(functionalCaseCommentDTO,functionalCaseComment);
functionalCaseCommentDTO.setUserName(userMap.get(functionalCaseComment.getCreateUser()).getName());
List<FunctionalCaseComment> replyComments = commentMap.get(functionalCaseComment.getId());
if (CollectionUtils.isNotEmpty(replyComments)) {
List<FunctionalCaseCommentDTO> replies = getReplies(userMap, functionalCaseComment, replyComments);
functionalCaseCommentDTO.setReplies(replies);
}
list.add(functionalCaseCommentDTO);
}
return list;
}
private List<FunctionalCaseCommentDTO> getReplies(Map<String, User> userMap, FunctionalCaseComment functionalCaseComment, List<FunctionalCaseComment> replyComments) {
List<FunctionalCaseCommentDTO> replies = new ArrayList<>();
for (FunctionalCaseComment replyComment : replyComments) {
FunctionalCaseCommentDTO functionalCaseCommentDTOReply = new FunctionalCaseCommentDTO();
BeanUtils.copyBean(functionalCaseCommentDTOReply,replyComment);
functionalCaseCommentDTOReply.setUserName(userMap.get(replyComment.getCreateUser()).getName());
if (StringUtils.isBlank(replyComment.getReplyUser())) {
functionalCaseCommentDTOReply.setReplyUserName(userMap.get(functionalCaseComment.getCreateUser()).getName());
} else {
functionalCaseCommentDTOReply.setReplyUserName(userMap.get(replyComment.getReplyUser()).getName());
}
replies.add(functionalCaseCommentDTOReply);
}
return replies.stream().sorted(Comparator.comparing(FunctionalCaseComment::getCreateTime).reversed()).toList();
}
/**
* 根据userIds 获取user信息
* @param userIds userIds
* @return Map<String, User>
*/
private Map<String, User> getUserMap(List<String> userIds) {
UserExample userExample = new UserExample();
userExample.createCriteria().andIdIn(userIds);
List<User> users = userMapper.selectByExample(userExample);
return users.stream().collect(Collectors.toMap(User::getId, item -> item));
}
/**
* 获取评论里所有人员信息
* @param functionalCaseComments 评论集合
* @return List<String>userIds
*/
private static List<String> getUserIds(List<FunctionalCaseComment> functionalCaseComments) {
List<String> userIds = new ArrayList<>(functionalCaseComments.stream().flatMap(functionalCaseComment -> Stream.of(functionalCaseComment.getCreateUser(), functionalCaseComment.getReplyUser())).toList());
List<String> notifierList = functionalCaseComments.stream().map(FunctionalCaseComment::getNotifier).filter(StringUtils::isNotBlank).toList();
for (String notifierStr : notifierList) {
List<String> notifiers = Arrays.asList(notifierStr.split(";"));
userIds.addAll(notifiers);
}
userIds = userIds.stream().distinct().toList();
return userIds;
}
} }

View File

@ -4,6 +4,7 @@ import com.jayway.jsonpath.JsonPath;
import io.metersphere.functional.domain.FunctionalCaseComment; import io.metersphere.functional.domain.FunctionalCaseComment;
import io.metersphere.functional.domain.FunctionalCaseCommentExample; import io.metersphere.functional.domain.FunctionalCaseCommentExample;
import io.metersphere.functional.domain.FunctionalCaseCustomField; import io.metersphere.functional.domain.FunctionalCaseCustomField;
import io.metersphere.functional.dto.FunctionalCaseCommentDTO;
import io.metersphere.functional.mapper.FunctionalCaseCommentMapper; import io.metersphere.functional.mapper.FunctionalCaseCommentMapper;
import io.metersphere.functional.mapper.FunctionalCaseCustomFieldMapper; import io.metersphere.functional.mapper.FunctionalCaseCustomFieldMapper;
import io.metersphere.functional.request.FunctionalCaseCommentRequest; import io.metersphere.functional.request.FunctionalCaseCommentRequest;
@ -61,6 +62,7 @@ public class FunctionalCaseCommentControllerTests {
public static final String SAVE_URL = "/functional/case/comment/save"; public static final String SAVE_URL = "/functional/case/comment/save";
public static final String DELETE_URL = "/functional/case/comment/delete/"; public static final String DELETE_URL = "/functional/case/comment/delete/";
public static final String GET_URL = "/functional/case/comment/get/list/";
private static String sessionId; private static String sessionId;
@ -345,6 +347,33 @@ public class FunctionalCaseCommentControllerTests {
@Test @Test
@Order(13) @Order(13)
public void getCommentSuccess() throws Exception {
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get(GET_URL + "xiaomeinvGTest").header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(SessionConstants.CURRENT_PROJECT, projectId)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
String contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
List<FunctionalCaseCommentDTO> list = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), FunctionalCaseCommentDTO.class);
System.out.println(JSON.toJSONString(list));
}
@Test
@Order(14)
public void getCommentFalse() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get(GET_URL + "xiaomeinvGTestNo").header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(SessionConstants.CURRENT_PROJECT, projectId)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().is5xxServerError())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
}
@Test
@Order(15)
public void deleteCommentSuccess() throws Exception { public void deleteCommentSuccess() throws Exception {
FunctionalCaseCommentExample functionalCaseCommentExample = new FunctionalCaseCommentExample(); FunctionalCaseCommentExample functionalCaseCommentExample = new FunctionalCaseCommentExample();
functionalCaseCommentExample.createCriteria().andCaseIdEqualTo("xiaomeinvGTest").andNotifierEqualTo("default-project-member-user-guo;default-project-member-user-guo-4;"); functionalCaseCommentExample.createCriteria().andCaseIdEqualTo("xiaomeinvGTest").andNotifierEqualTo("default-project-member-user-guo;default-project-member-user-guo-4;");
@ -363,7 +392,7 @@ public class FunctionalCaseCommentControllerTests {
} }
@Test @Test
@Order(14) @Order(16)
public void deleteNoCommentSuccess() throws Exception { public void deleteNoCommentSuccess() throws Exception {
delFunctionalCaseComment("no_comment"); delFunctionalCaseComment("no_comment");
FunctionalCaseCommentExample functionalCaseCommentExample = new FunctionalCaseCommentExample(); FunctionalCaseCommentExample functionalCaseCommentExample = new FunctionalCaseCommentExample();
@ -375,6 +404,19 @@ public class FunctionalCaseCommentControllerTests {
} }
@Test
@Order(17)
public void deleteCommentFirstSuccess() throws Exception {
delFunctionalCaseComment("xiaomeinvGTest");
FunctionalCaseCommentExample functionalCaseCommentExample = new FunctionalCaseCommentExample();
functionalCaseCommentExample.createCriteria().andParentIdEqualTo("xiaomeinvGTest");
List<FunctionalCaseComment> functionalCaseComments1 = functionalCaseCommentMapper.selectByExample(functionalCaseCommentExample);
Assertions.assertTrue(functionalCaseComments1.isEmpty());
FunctionalCaseComment functionalCaseComment = functionalCaseCommentMapper.selectByPrimaryKey("xiaomeinvGTest");
Assertions.assertNull(functionalCaseComment);
}
private FunctionalCaseComment getFunctionalCaseComment(FunctionalCaseCommentRequest functionalCaseCommentRequest) throws Exception { private FunctionalCaseComment getFunctionalCaseComment(FunctionalCaseCommentRequest functionalCaseCommentRequest) throws Exception {
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post(SAVE_URL).header(SessionConstants.HEADER_TOKEN, sessionId) MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post(SAVE_URL).header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken) .header(SessionConstants.CSRF_TOKEN, csrfToken)

View File

@ -70,6 +70,7 @@ VALUES (UUID(), 'default-project-member-user-guo', 'project_admin', '10000110000
INSERT INTO user_role_permission(id, role_id, permission_id) INSERT INTO user_role_permission(id, role_id, permission_id)
VALUES ('user_role_guo_permission1', 'project_admin', 'FUNCTIONAL_CASE_COMMENT:READ+ADD'), VALUES ('user_role_guo_permission1', 'project_admin', 'FUNCTIONAL_CASE_COMMENT:READ+ADD'),
('user_role_guo_permission2', 'project_admin', 'FUNCTIONAL_CASE_COMMENT:READ+DELETE'), ('user_role_guo_permission2', 'project_admin', 'FUNCTIONAL_CASE_COMMENT:READ+DELETE'),
('user_role_guo_permission3', 'project_admin', 'FUNCTIONAL_CASE:READ+ADD'); ('user_role_guo_permission3', 'project_admin', 'FUNCTIONAL_CASE:READ+ADD'),
('user_role_guo_permission4', 'project_admin', 'FUNCTIONAL_CASE_COMMENT:READ');