feat(用例管理): 新增用例评审权限以及新增功能用例取消关联需求的日志

This commit is contained in:
guoyuqi 2023-11-22 19:09:30 +08:00 committed by 刘瑞斌
parent 2a51b922c6
commit 87c905e46b
11 changed files with 112 additions and 31 deletions

View File

@ -225,13 +225,9 @@ public class PermissionConstants {
public static final String CASE_REVIEW_READ_ADD = "CASE_REVIEW:READ+ADD";
public static final String CASE_REVIEW_READ_UPDATE = "CASE_REVIEW:READ+UPDATE";
public static final String CASE_REVIEW_READ_DELETE = "CASE_REVIEW:READ+DELETE";
public static final String CASE_REVIEW_READ_COMMENT = "CASE_REVIEW:READ+COMMENT";
public static final String CASE_REVIEW_READ_EXPORT = "CASE_REVIEW:READ+EXPORT";
public static final String CASE_REVIEW_READ_IMPORT = "CASE_REVIEW:READ+IMPORT";
/*------ end: FUNCTIONAL_CASE ------*/
public static final String CASE_REVIEW_REVIEW = "CASE_REVIEW:READ+REVIEW";
public static final String CASE_REVIEW_RELEVANCE = "CASE_REVIEW:READ+RELEVANCE";
/*------ end: CASE_REVIEW ------*/
/*------ start: API_DEBUG ------*/
public static final String PROJECT_API_DEBUG_READ = "PROJECT_API_DEBUG:READ";

View File

@ -2,6 +2,9 @@
permission.case_management.name=用例管理
permission.functional_case.name=功能用例
permission.functional_case.comment=评论
permission.case_review.name=用例评审
permission.case_review.review=评审
permission.case_review.relevance=关联/取消关联
#moduleFunctionalCase
functional_case.id.not_blank=ID不能为空
functional_case.num.not_blank=业务ID不能为空

View File

@ -2,6 +2,10 @@
permission.case_management.name=Case management
permission.functional_case.name=Functional case
permission.functional_case.comment=Comment
permission.case_review.name=Case review
permission.case_review.review=Review
permission.case_review.relevance=Associate/Disassociate
#moduleFunctionalCase
functional_case.id.not_blank=ID cannot be empty
functional_case.num.not_blank=Business ID cannot be empty

View File

@ -2,6 +2,9 @@
permission.case_management.name=用例管理
permission.functional_case.name=功能用例
permission.functional_case.comment=评论
permission.case_review.name=用例评审
permission.case_review.review=评审
permission.case_review.relevance=关联/取消关联
#moduleFunctionalCase
functional_case.id.not_blank=ID不能为空
functional_case.num.not_blank=业务ID不能为空

View File

@ -2,6 +2,10 @@
permission.case_management.name=用例管理
permission.functional_case.name=功能用例
permission.functional_case.comment=評論
permission.case_review.name=用例評審
permission.case_review.review=評審
permission.case_review.relevance=關聯/取消關聯
#moduleFunctionalCase
functional_case.id.not_blank=ID不能為空
functional_case.num.not_blank=业务ID不能為空

View File

@ -6,7 +6,10 @@ import io.metersphere.functional.domain.FunctionalCaseDemand;
import io.metersphere.functional.request.FunctionalCaseDemandRequest;
import io.metersphere.functional.request.QueryDemandListRequest;
import io.metersphere.functional.service.FunctionalCaseDemandService;
import io.metersphere.functional.service.FunctionalCaseLogService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.log.annotation.Log;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager;
import io.metersphere.system.utils.SessionUtils;
@ -53,6 +56,7 @@ public class FunctionalCaseDemandController {
@GetMapping("/cancel/{id}")
@Operation(summary = "用例管理-功能用例-关联需求-取消关联需求")
@Log(type = OperationLogType.DISASSOCIATE, expression = "#msClass.disassociateLog(#id)", msClass = FunctionalCaseLogService.class)
@RequiresPermissions(value = {PermissionConstants.FUNCTIONAL_CASE_READ_ADD, PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE, PermissionConstants.FUNCTIONAL_CASE_READ_DELETE}, logical = Logical.OR)
public void deleteDemand(@PathVariable @NotBlank(message = "{functional_case.id.not_blank}") String id) {
functionalCaseDemandService.deleteDemand(id);

View File

@ -1,8 +1,10 @@
package io.metersphere.functional.service;
import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.domain.FunctionalCaseDemand;
import io.metersphere.functional.dto.BaseFunctionalCaseBatchDTO;
import io.metersphere.functional.mapper.ExtFunctionalCaseMapper;
import io.metersphere.functional.mapper.FunctionalCaseDemandMapper;
import io.metersphere.functional.mapper.FunctionalCaseMapper;
import io.metersphere.functional.request.*;
import io.metersphere.sdk.constants.HttpMethodConstants;
@ -36,6 +38,8 @@ public class FunctionalCaseLogService {
private FunctionalCaseService functionalCaseService;
@Resource
private ExtFunctionalCaseMapper extFunctionalCaseMapper;
@Resource
private FunctionalCaseDemandMapper functionalCaseDemandMapper;
//TODO 日志(需要修改)
@ -115,27 +119,6 @@ public class FunctionalCaseLogService {
return null;
}
public void batchDelLog(List<FunctionalCase> functionalCases, String projectId) {
List<LogDTO> dtoList = new ArrayList<>();
functionalCases.forEach(item -> {
LogDTO dto = new LogDTO(
projectId,
"",
item.getId(),
item.getCreateUser(),
OperationLogType.DELETE.name(),
OperationLogModule.FUNCTIONAL_CASE,
item.getName());
dto.setPath("/functional/case/module/delete/");
dto.setMethod(HttpMethodConstants.GET.name());
dto.setOriginalValue(JSON.toJSONBytes(item));
dtoList.add(dto);
});
operationLogService.batchAdd(dtoList);
}
public List<LogDTO> batchDeleteFunctionalCaseLog(FunctionalCaseBatchRequest request) {
List<String> ids = functionalCaseService.doSelectIds(request, request.getProjectId());
List<LogDTO> dtoList = new ArrayList<>();
@ -240,6 +223,37 @@ public class FunctionalCaseLogService {
}
/**
* 取消关联
*
* @param id ID
* @return 日志详情
*/
public LogDTO disassociateLog(String id) {
FunctionalCaseDemand functionalCaseDemand = functionalCaseDemandMapper.selectByPrimaryKey(id);
if (functionalCaseDemand == null) {
return null;
}
FunctionalCase functionalCase = functionalCaseMapper.selectByPrimaryKey(functionalCaseDemand.getCaseId());
if (functionalCase != null) {
LogDTO dto = new LogDTO(
functionalCase.getProjectId(),
null,
functionalCase.getId(),
functionalCase.getCreateUser(),
OperationLogType.DISASSOCIATE.name(),
OperationLogModule.FUNCTIONAL_CASE,
functionalCase.getName());
dto.setPath("/functional/case/demand/cancel/");
dto.setMethod(HttpMethodConstants.GET.name());
dto.setOriginalValue(JSON.toJSONBytes(functionalCaseDemand));
return dto;
}
return null;
}
public List<LogDTO> batchEditFunctionalCaseLog(FunctionalCaseBatchEditRequest request) {
List<String> ids = functionalCaseService.doSelectIds(request, request.getProjectId());
List<LogDTO> dtoList = new ArrayList<>();

View File

@ -31,6 +31,32 @@
"id": "FUNCTIONAL_CASE:READ+IMPORT"
}
]
},
{
"id": "CASE_REVIEW",
"name": "permission.case_review.name",
"permissions": [
{
"id": "CASE_REVIEW:READ"
},
{
"id": "CASE_REVIEW:READ+ADD"
},
{
"id": "CASE_REVIEW:READ+UPDATE"
},
{
"id": "CASE_REVIEW:READ+DELETE"
},
{
"id": "CASE_REVIEW:READ+REVIEW",
"name": "permission.case_review.review"
},
{
"id": "CASE_REVIEW:READ+RELEVANCE",
"name": "permission.case_review.relevance"
}
]
}
]
}

View File

@ -7,9 +7,13 @@ import io.metersphere.functional.mapper.FunctionalCaseDemandMapper;
import io.metersphere.functional.request.FunctionalCaseDemandRequest;
import io.metersphere.functional.request.QueryDemandListRequest;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.domain.OperationLog;
import io.metersphere.sdk.domain.OperationLogExample;
import io.metersphere.sdk.mapper.OperationLogMapper;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
@ -36,7 +40,8 @@ public class FunctionalCaseDemandControllerTests extends BaseTest {
@Resource
private FunctionalCaseDemandMapper functionalCaseDemandMapper;
@Resource
private OperationLogMapper operationLogMapper;
private static final String URL_DEMAND_PAGE = "/functional/case/demand/page";
private static final String URL_DEMAND_ADD = "/functional/case/demand/add";
@ -231,6 +236,7 @@ public class FunctionalCaseDemandControllerTests extends BaseTest {
functionalCaseDemandExample.createCriteria().andCaseIdEqualTo("DEMAND_TEST_FUNCTIONAL_CASE_ID");
List<FunctionalCaseDemand> functionalCaseDemands = functionalCaseDemandMapper.selectByExample(functionalCaseDemandExample);
Assertions.assertTrue(CollectionUtils.isEmpty(functionalCaseDemands));
checkLog("DEMAND_TEST_FUNCTIONAL_CASE_ID", OperationLogType.DISASSOCIATE);
}
@Test
@ -301,4 +307,22 @@ public class FunctionalCaseDemandControllerTests extends BaseTest {
List<FunctionalCaseDemand> functionalCaseDemands = functionalCaseDemandMapper.selectByExample(functionalCaseDemandExample);
Assertions.assertTrue(CollectionUtils.isEmpty(functionalCaseDemands));
}
@Test
@Order(12)
public void cancelDemandNoLog() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get(URL_DEMAND_CANCEL+"DEMAND_TEST_FUNCTIONAL_CASE_X").header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
FunctionalCaseDemandExample functionalCaseDemandExample = new FunctionalCaseDemandExample();
functionalCaseDemandExample.createCriteria().andCaseIdEqualTo("DEMAND_TEST_FUNCTIONAL_CASE_X");
List<FunctionalCaseDemand> functionalCaseDemands = functionalCaseDemandMapper.selectByExample(functionalCaseDemandExample);
Assertions.assertTrue(CollectionUtils.isEmpty(functionalCaseDemands));
OperationLogExample example = new OperationLogExample();
example.createCriteria().andSourceIdEqualTo("DEMAND_TEST_FUNCTIONAL_CASE_X").andTypeEqualTo(OperationLogType.DISASSOCIATE.name());
List<OperationLog> operationLogs = operationLogMapper.selectByExample(example);
Assertions.assertTrue(CollectionUtils.isEmpty(operationLogs));
}
}

View File

@ -64,7 +64,8 @@ public class OperationLogAspect {
private final ThreadLocal<String> localProjectId = new ThreadLocal<>();
// 此方法随时补充类型需要在内容变更前执行的类型都可以加入
private final OperationLogType[] beforeMethodNames = new OperationLogType[]{OperationLogType.UPDATE, OperationLogType.DELETE, OperationLogType.RECOVER};
private final OperationLogType[] beforeMethodNames = new OperationLogType[]{OperationLogType.UPDATE, OperationLogType.DELETE
, OperationLogType.RECOVER, OperationLogType.DISASSOCIATE, OperationLogType.ARCHIVED};
// 需要后置执行合并内容的
private final OperationLogType[] postMethodNames = new OperationLogType[]{OperationLogType.ADD, OperationLogType.UPDATE};

View File

@ -15,7 +15,9 @@ public enum OperationLogType {
LOGIN,
SELECT,
RECOVER,
LOGOUT;
LOGOUT,
DISASSOCIATE,
ARCHIVED;
public boolean contains(OperationLogType keyword) {
return this.name().contains(keyword.name());