feat(用例评审): 新增删除用例评审接口

This commit is contained in:
guoyuqi 2023-12-05 19:40:34 +08:00 committed by Craftsman
parent 7e74da5316
commit 3a42e95796
10 changed files with 101 additions and 24 deletions

View File

@ -112,9 +112,18 @@ public class CaseReviewController {
} }
@PostMapping("batch/move") @PostMapping("batch/move")
@Operation(summary = "用例管理-用例评审-复制用例评审") @Operation(summary = "用例管理-用例评审-批量移动用例评审")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_UPDATE) @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_UPDATE)
public void batchMoveCaseReview(@Validated @RequestBody CaseReviewBatchRequest request) { public void batchMoveCaseReview(@Validated @RequestBody CaseReviewBatchRequest request) {
caseReviewService.batchMoveCaseReview(request, SessionUtils.getUserId()); caseReviewService.batchMoveCaseReview(request, SessionUtils.getUserId());
} }
@GetMapping("/delete/{reviewId}/{projectId}")
@Operation(summary = "用例管理-用例评审-删除用例评审")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_DELETE)
@SendNotice(taskType = NoticeConstants.TaskType.CASE_REVIEW_TASK, event = NoticeConstants.Event.DELETE, target = "#targetClass.getMainCaseReview(#reviewId)", targetClass = CaseReviewNoticeService.class)
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteFunctionalCaseLog(#reviewId)", msClass = CaseReviewLogService.class)
public void deleteCaseReview(@PathVariable String reviewId, @PathVariable String projectId) {
caseReviewService.deleteCaseReview(reviewId, projectId);
}
} }

View File

@ -103,6 +103,32 @@ public class CaseReviewLogService {
return dto; return dto;
} }
/**
* 删除用例 日志
*
* @param reviewId reviewId
* @return LogDTO
*/
public LogDTO deleteFunctionalCaseLog(String reviewId) {
CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(reviewId);
if (caseReview != null) {
LogDTO dto = new LogDTO(
caseReview.getProjectId(),
null,
caseReview.getId(),
null,
OperationLogType.DELETE.name(),
OperationLogModule.CASE_REVIEW,
caseReview.getName());
dto.setPath("/case/review/delete");
dto.setMethod(HttpMethodConstants.DELETE.name());
dto.setOriginalValue(JSON.toJSONBytes(caseReview));
return dto;
}
return null;
}
public List<LogDTO> associateCaseLog(CaseReviewAssociateRequest request){ public List<LogDTO> associateCaseLog(CaseReviewAssociateRequest request){
CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(request.getReviewId()); CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(request.getReviewId());
if (caseReview ==null) { if (caseReview ==null) {

View File

@ -141,7 +141,7 @@ public class CaseReviewModuleService extends ModuleTreeService {
operationLogService.batchAdd(dtoList); operationLogService.batchAdd(dtoList);
} }
public List<CaseReview> deleteModuleByIds(List<String>deleteIds, List<CaseReview>caseReviews, String projectId){ public List<CaseReview> deleteModuleByIds(List<String> deleteIds, List<CaseReview> caseReviews, String projectId) {
if (CollectionUtils.isEmpty(deleteIds)) { if (CollectionUtils.isEmpty(deleteIds)) {
return caseReviews; return caseReviews;
} }
@ -152,7 +152,7 @@ public class CaseReviewModuleService extends ModuleTreeService {
if (CollectionUtils.isNotEmpty(caseReviewList)) { if (CollectionUtils.isNotEmpty(caseReviewList)) {
caseReviews.addAll(caseReviewList); caseReviews.addAll(caseReviewList);
} }
deleteCaseReviewService.deleteCaseReviewResource(deleteIds, projectId); deleteCaseReviewService.deleteCaseReviewResource(deleteIds, projectId, false);
List<String> childrenIds = extCaseReviewModuleMapper.selectChildrenIdsByParentIds(deleteIds); List<String> childrenIds = extCaseReviewModuleMapper.selectChildrenIdsByParentIds(deleteIds);
if (CollectionUtils.isNotEmpty(childrenIds)) { if (CollectionUtils.isNotEmpty(childrenIds)) {
deleteModuleByIds(childrenIds, caseReviews, projectId); deleteModuleByIds(childrenIds, caseReviews, projectId);
@ -171,7 +171,6 @@ public class CaseReviewModuleService extends ModuleTreeService {
/** /**
* 查找当前项目下模块每个节点对应的资源统计 * 查找当前项目下模块每个节点对应的资源统计
*
*/ */
public Map<String, Long> getModuleCountMap(String projectId, List<ModuleCountDTO> moduleCountDTOList) { public Map<String, Long> getModuleCountMap(String projectId, List<ModuleCountDTO> moduleCountDTOList) {

View File

@ -49,6 +49,10 @@ public class CaseReviewNoticeService {
return caseReview; return caseReview;
} }
public CaseReview getMainCaseReview(String reviewId){
return caseReviewMapper.selectByPrimaryKey(reviewId);
}
public Long getNextPos(String projectId) { public Long getNextPos(String projectId) {
Long pos = extCaseReviewMapper.getPos(projectId); Long pos = extCaseReviewMapper.getPos(projectId);
return (pos == null ? 0 : pos) + 5000; return (pos == null ? 0 : pos) + 5000;

View File

@ -69,6 +69,8 @@ public class CaseReviewService {
private ExtCaseReviewUserMapper extCaseReviewUserMapper; private ExtCaseReviewUserMapper extCaseReviewUserMapper;
@Resource @Resource
private FunctionalCaseMapper functionalCaseMapper; private FunctionalCaseMapper functionalCaseMapper;
@Resource
private DeleteCaseReviewService deleteCaseReviewService;
/** /**
@ -516,4 +518,9 @@ public class CaseReviewService {
extCaseReviewMapper.batchMoveModule(request, ids, userId); extCaseReviewMapper.batchMoveModule(request, ids, userId);
} }
} }
public void deleteCaseReview(String reviewId, String projectId) {
deleteCaseReviewService.deleteCaseReviewResource(List.of(reviewId), projectId, false);
}
} }

View File

@ -30,7 +30,7 @@ public class CleanupCaseReviewResourceService implements CleanupProjectResourceS
List<CaseReview> caseReviews = caseReviewMapper.selectByExample(caseReviewExample); List<CaseReview> caseReviews = caseReviewMapper.selectByExample(caseReviewExample);
List<String> ids = caseReviews.stream().map(CaseReview::getId).toList(); List<String> ids = caseReviews.stream().map(CaseReview::getId).toList();
if (CollectionUtils.isNotEmpty(ids)) { if (CollectionUtils.isNotEmpty(ids)) {
deleteCaseReviewService.deleteCaseReviewResource(ids, projectId); deleteCaseReviewService.deleteCaseReviewResource(ids, projectId, true);
} }
//删除模块 //删除模块
CaseReviewModuleExample caseReviewModuleExample = new CaseReviewModuleExample(); CaseReviewModuleExample caseReviewModuleExample = new CaseReviewModuleExample();

View File

@ -28,28 +28,31 @@ public class DeleteCaseReviewService {
@Resource @Resource
private CaseReviewHistoryMapper caseReviewHistoryMapper; private CaseReviewHistoryMapper caseReviewHistoryMapper;
public void deleteCaseReviewResource(List<String> ids, String projectId) { public void deleteCaseReviewResource(List<String> ids, String projectId, boolean deleteAll) {
//TODO 删除各种关联关系 1.关联用例(功能/接口/场景/ui/性能) 2.评审和评审人 3. 归档的用例 4. 关注人 5.评审历史 6. 操作记录 //TODO 删除各种关联关系 1.关联用例(功能/接口/场景/ui/性能) 2.评审和评审人 3. 归档的用例 4. 关注人 5.评审历史 6. 操作记录
//1.刪除评审与功能用例关联关系 //1.刪除评审与功能用例关联关系
CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample(); if (deleteAll) {
caseReviewFunctionalCaseExample.createCriteria().andReviewIdIn(ids); CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseMapper.deleteByExample(caseReviewFunctionalCaseExample); caseReviewFunctionalCaseExample.createCriteria().andReviewIdIn(ids);
//2. 删除评审和评审人 caseReviewFunctionalCaseMapper.deleteByExample(caseReviewFunctionalCaseExample);
CaseReviewUserExample caseReviewUserExample = new CaseReviewUserExample(); //2. 删除评审和评审人
caseReviewUserExample.createCriteria().andReviewIdIn(ids); CaseReviewUserExample caseReviewUserExample = new CaseReviewUserExample();
caseReviewUserMapper.deleteByExample(caseReviewUserExample); caseReviewUserExample.createCriteria().andReviewIdIn(ids);
//3. 删除归档的用例 caseReviewUserMapper.deleteByExample(caseReviewUserExample);
CaseReviewFunctionalCaseArchiveExample archiveExample = new CaseReviewFunctionalCaseArchiveExample(); //3. 删除归档的用例
archiveExample.createCriteria().andReviewIdIn(ids); CaseReviewFunctionalCaseArchiveExample archiveExample = new CaseReviewFunctionalCaseArchiveExample();
caseReviewFunctionalCaseArchiveMapper.deleteByExample(archiveExample); archiveExample.createCriteria().andReviewIdIn(ids);
caseReviewFunctionalCaseArchiveMapper.deleteByExample(archiveExample);
//5.删除评审历史
CaseReviewHistoryExample caseReviewHistoryExample = new CaseReviewHistoryExample();
caseReviewHistoryExample.createCriteria().andReviewIdIn(ids);
caseReviewHistoryMapper.deleteByExample(caseReviewHistoryExample);
}
//4.删除关注人 //4.删除关注人
CaseReviewFollowerExample caseReviewFollowerExample = new CaseReviewFollowerExample(); CaseReviewFollowerExample caseReviewFollowerExample = new CaseReviewFollowerExample();
caseReviewFollowerExample.createCriteria().andReviewIdIn(ids); caseReviewFollowerExample.createCriteria().andReviewIdIn(ids);
caseReviewFollowerMapper.deleteByExample(caseReviewFollowerExample); caseReviewFollowerMapper.deleteByExample(caseReviewFollowerExample);
//5.删除评审历史
CaseReviewHistoryExample caseReviewHistoryExample = new CaseReviewHistoryExample();
caseReviewHistoryExample.createCriteria().andReviewIdIn(ids);
caseReviewHistoryMapper.deleteByExample(caseReviewHistoryExample);
//TODO: 6.删除操作记录 //TODO: 6.删除操作记录
//删除评审 //删除评审
CaseReviewExample caseReviewExample = new CaseReviewExample(); CaseReviewExample caseReviewExample = new CaseReviewExample();

View File

@ -22,12 +22,14 @@ import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@Transactional(rollbackFor = Exception.class)
public class FunctionalCaseNoticeService { public class FunctionalCaseNoticeService {
@Resource @Resource

View File

@ -10,6 +10,7 @@ import io.metersphere.functional.result.CaseManagementResultCode;
import io.metersphere.project.domain.Notification; import io.metersphere.project.domain.Notification;
import io.metersphere.project.domain.NotificationExample; import io.metersphere.project.domain.NotificationExample;
import io.metersphere.project.mapper.NotificationMapper; import io.metersphere.project.mapper.NotificationMapper;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest; import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder; import io.metersphere.system.controller.handler.ResultHolder;
@ -23,16 +24,19 @@ import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils; import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ -55,6 +59,8 @@ public class CaseReviewControllerTests extends BaseTest {
private static final String FOLLOW_CASE_REVIEW = "/case/review/edit/follower"; private static final String FOLLOW_CASE_REVIEW = "/case/review/edit/follower";
private static final String CASE_REVIEWER_LIST = "/case/review/user-option/"; private static final String CASE_REVIEWER_LIST = "/case/review/user-option/";
private static final String DETAIL_CASE_REVIEW = "/case/review/detail/"; private static final String DETAIL_CASE_REVIEW = "/case/review/detail/";
private static final String DELETE_CASE_REVIEW = "/case/review/delete/";
@Resource @Resource
@ -464,7 +470,6 @@ public class CaseReviewControllerTests extends BaseTest {
Assertions.assertNotNull(resultHolder); Assertions.assertNotNull(resultHolder);
} }
@Test @Test
@Order(15) @Order(15)
public void testBatchMove() throws Exception { public void testBatchMove() throws Exception {
@ -489,8 +494,17 @@ public class CaseReviewControllerTests extends BaseTest {
caseReviews = getCaseReviews("创建评审更新1"); caseReviews = getCaseReviews("创建评审更新1");
String moduleIdNewOne = caseReviews.get(0).getModuleId(); String moduleIdNewOne = caseReviews.get(0).getModuleId();
Assertions.assertTrue(StringUtils.equals(moduleIdNewOne, moduleIdNew)); Assertions.assertTrue(StringUtils.equals(moduleIdNewOne, moduleIdNew));
}
@Test
@Order(16)
public void testDelete() throws Exception {
List<CaseReview> caseReviews = getCaseReviews("创建评审更新2");
delCaseReview(caseReviews.get(0).getId());
NotificationExample notificationExample = new NotificationExample();
notificationExample.createCriteria().andResourceTypeEqualTo(NoticeConstants.TaskType.CASE_REVIEW_TASK).andResourceIdEqualTo(caseReviews.get(0).getId()).andOperationEqualTo("DELETE");
List<Notification> notifications = notificationMapper.selectByExampleWithBLOBs(notificationExample);
Assertions.assertEquals(1, notifications.size());
} }
/** /**
@ -503,4 +517,13 @@ public class CaseReviewControllerTests extends BaseTest {
map.put("reviewers", Map.of("operator", "in", "value", List.of("admin"))); map.put("reviewers", Map.of("operator", "in", "value", List.of("admin")));
return map; return map;
} }
private void delCaseReview(String reviewId) throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get(DELETE_CASE_REVIEW+reviewId+"/"+projectId).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();
}
} }

View File

@ -92,6 +92,10 @@ Insert into message_task(id, event, receiver, project_robot_id, task_type, test_
VALUES ('case-review_message3', 'DELETE', 'CREATE_USER', 'test_case_review_message_robot1', 'CASE_REVIEW_TASK', 'NONE', 'project-gyq-case-review-test', true, 'admin', unix_timestamp() * 1000, 'admin', unix_timestamp() * 1000, true, true, 'message.title.case_review_task_delete'); VALUES ('case-review_message3', 'DELETE', 'CREATE_USER', 'test_case_review_message_robot1', 'CASE_REVIEW_TASK', 'NONE', 'project-gyq-case-review-test', true, 'admin', unix_timestamp() * 1000, 'admin', unix_timestamp() * 1000, true, true, 'message.title.case_review_task_delete');
INSERT INTO message_task_blob(id, template) VALUES ('case-review_message3', 'message.case_review_task_delete'); INSERT INTO message_task_blob(id, template) VALUES ('case-review_message3', 'message.case_review_task_delete');
Insert into message_task(id, event, receiver, project_robot_id, task_type, test_id, project_id, enable, create_user, create_time, update_user, update_time, use_default_template, use_default_subject, subject)
VALUES ('case-review_message7', 'DELETE', 'gyq_review_test2', 'test_case_review_message_robot1', 'CASE_REVIEW_TASK', 'NONE', 'project-gyq-case-review-test', true, 'admin', unix_timestamp() * 1000, 'admin', unix_timestamp() * 1000, true, true, 'message.title.case_review_task_delete');
INSERT INTO message_task_blob(id, template) VALUES ('case-review_message7', 'message.case_review_task_delete');
Insert into message_task(id, event, receiver, project_robot_id, task_type, test_id, project_id, enable, create_user, create_time, update_user, update_time, use_default_template, use_default_subject, subject) Insert into message_task(id, event, receiver, project_robot_id, task_type, test_id, project_id, enable, create_user, create_time, update_user, update_time, use_default_template, use_default_subject, subject)
VALUES ('case-review_message4', 'REVIEW_COMPLETED', 'CREATE_USER', 'test_case_review_message_robot1', 'CASE_REVIEW_TASK', 'NONE', 'project-gyq-case-review-test', true, 'admin', unix_timestamp() * 1000, 'admin', unix_timestamp() * 1000, true, true, 'message.title.case_review_task_review_completed'); VALUES ('case-review_message4', 'REVIEW_COMPLETED', 'CREATE_USER', 'test_case_review_message_robot1', 'CASE_REVIEW_TASK', 'NONE', 'project-gyq-case-review-test', true, 'admin', unix_timestamp() * 1000, 'admin', unix_timestamp() * 1000, true, true, 'message.title.case_review_task_review_completed');