diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiDefinitionModuleController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiDefinitionModuleController.java index f45eee10ef..6859feda6d 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiDefinitionModuleController.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiDefinitionModuleController.java @@ -80,6 +80,6 @@ public class ApiDefinitionModuleController { @Operation(summary = "接口测试-接口管理-模块-查找模块") @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ) public List getTrashTree(@RequestBody @Validated ApiModuleRequest request) { - return apiDefinitionModuleService.getTree(request, true); + return apiDefinitionModuleService.getTrashTree(request, true); } } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiTestCaseController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiTestCaseController.java index 4fa325f36f..4aa0cdb3ea 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiTestCaseController.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiTestCaseController.java @@ -6,6 +6,7 @@ import io.metersphere.api.domain.ApiTestCase; import io.metersphere.api.dto.definition.*; import io.metersphere.api.service.definition.ApiTestCaseLogService; import io.metersphere.api.service.definition.ApiTestCaseNoticeService; +import io.metersphere.api.service.definition.ApiTestCaseRecoverService; import io.metersphere.api.service.definition.ApiTestCaseService; import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.system.dto.sdk.request.PosRequest; @@ -35,6 +36,8 @@ import java.util.List; public class ApiTestCaseController { @Resource private ApiTestCaseService apiTestCaseService; + @Resource + private ApiTestCaseRecoverService apiTestCaseRecoverService; @PostMapping(value = "/add") @Operation(summary = "接口测试-接口管理-接口用例-新增") @@ -118,23 +121,33 @@ public class ApiTestCaseController { } @PostMapping("/batch/delete") + @Operation(summary = "接口测试-接口管理-接口用例-批量删除") @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_CASE_DELETE) public void deleteBatchByParam(@RequestBody ApiTestCaseBatchRequest request) { apiTestCaseService.batchDelete(request, SessionUtils.getUserId()); } @PostMapping("/batch/move-gc") + @Operation(summary = "接口测试-接口管理-接口用例-批量移动到回收站") @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_CASE_DELETE) public void deleteToGcByParam(@RequestBody ApiTestCaseBatchRequest request) { apiTestCaseService.batchMoveGc(request, SessionUtils.getUserId()); } @PostMapping("/batch/edit") + @Operation(summary = "接口测试-接口管理-接口用例-批量编辑") @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_CASE_UPDATE) public void batchUpdate(@Validated @RequestBody ApiCaseBatchEditRequest request) { apiTestCaseService.batchEdit(request, SessionUtils.getUserId()); } + @PostMapping("/batch/recover") + @Operation(summary = "接口测试-接口管理-接口用例-批量恢复") + @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_CASE_RECOVER) + public void batchRecover(@Validated @RequestBody ApiTestCaseBatchRequest request) { + apiTestCaseRecoverService.batchRecover(request, SessionUtils.getUserId()); + } + @PostMapping(value = "/trash/page") @Operation(summary = "接口测试-接口管理-接口用例-回收站-分页查询") @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ) diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/definition/ApiTestCaseDTO.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/definition/ApiTestCaseDTO.java index a3aeea77de..28dc81c46c 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/definition/ApiTestCaseDTO.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/definition/ApiTestCaseDTO.java @@ -87,4 +87,10 @@ public class ApiTestCaseDTO { @Schema(description = "请求内容") private AbstractMsTestElement request; + @Schema(description = "所属模块") + private String modulePath; + + @Schema(description = "模块id") + private String moduleId; + } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/importdto/ApiDefinitionImportDTO.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/importdto/ApiDefinitionImportDTO.java new file mode 100644 index 0000000000..f9093adf70 --- /dev/null +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/importdto/ApiDefinitionImportDTO.java @@ -0,0 +1,25 @@ +package io.metersphere.api.dto.importdto; + +import io.metersphere.api.domain.ApiDefinition; +import io.metersphere.api.dto.definition.HttpResponse; +import io.metersphere.plugin.api.spi.AbstractMsTestElement; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@Data +@EqualsAndHashCode(callSuper = false) +public class ApiDefinitionImportDTO extends ApiDefinition { + + @Schema(description = "请求内容") + private AbstractMsTestElement request; + + @Schema(description = "响应内容") + private List response; + + @Schema(description = "模块path") + private String modulePath; + +} diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMapper.java b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMapper.java index d943333957..862a3582a9 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMapper.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMapper.java @@ -2,6 +2,7 @@ package io.metersphere.api.mapper; import io.metersphere.api.domain.ApiDefinition; import io.metersphere.api.dto.definition.*; +import io.metersphere.api.dto.importdto.ApiDefinitionImportDTO; import io.metersphere.system.dto.table.TableBatchProcessDTO; import org.apache.ibatis.annotations.Param; @@ -40,4 +41,7 @@ public interface ExtApiDefinitionMapper { void updateLatestVersion(@Param("id") String id, @Param("projectId") String projectId); + List importList(@Param("request") ApiDefinitionPageRequest request); + + List selectIdsByIdsAndDeleted(@Param("ids")List ids, @Param("deleted") boolean deleted); } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMapper.xml b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMapper.xml index 47e6dd674f..350e662770 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMapper.xml +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMapper.xml @@ -129,7 +129,24 @@ and deleted = #{deleted} - + + update api_definition diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionModuleMapper.java b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionModuleMapper.java index b0a78e4052..b2b06b7bc4 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionModuleMapper.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionModuleMapper.java @@ -32,4 +32,6 @@ public interface ExtApiDefinitionModuleMapper { List countModuleIdByRequest(@Param("request") ApiModuleRequest request, @Param("deleted") boolean deleted); List selectNodeByIds(@Param("ids") List ids); + + List selectBaseByIds(@Param("ids") List ids); } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionModuleMapper.xml b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionModuleMapper.xml index beabaf49dd..cacf48f78c 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionModuleMapper.xml +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionModuleMapper.xml @@ -115,6 +115,17 @@ ORDER BY pos + + + api_definition.deleted = #{deleted} diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.java b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.java index 2e9360531a..68f5f4ee3f 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.java @@ -24,8 +24,7 @@ public interface ExtApiTestCaseMapper { List getIds(@Param("request") ApiTestCaseBatchRequest request, @Param("deleted") boolean deleted); - - void batchMoveGc(@Param("ids") List ids, @Param("userId") String userId); + void batchMoveGc(@Param("ids") List ids, @Param("userId") String userId, @Param("deleteTime") long deleteTime); List getCaseInfoByApiIds(@Param("ids") List apiIds, @Param("deleted") boolean deleted); @@ -36,4 +35,8 @@ public interface ExtApiTestCaseMapper { Long getLastPos(@Param("projectId") String projectId, @Param("basePos") Long basePos); List findPassRateByIds(@Param("ids") List ids); + + List selectIdsByCaseIds(@Param("ids") List ids); + + List getCaseIds(@Param("ids")List ids, @Param("deleted")boolean deleted); } \ No newline at end of file diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.xml b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.xml index 747c82efa6..d2051b1d7b 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.xml +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiTestCaseMapper.xml @@ -5,7 +5,7 @@ UPDATE api_test_case SET deleted = 1, - delete_time = UNIX_TIMESTAMP()*1000, + delete_time = #{deleteTime}, delete_user = #{userId} WHERE id in @@ -38,7 +38,8 @@ t1.num, t1.last_report_status, t1.last_report_id, - t1.environment_id + t1.environment_id, + a.module_id FROM api_test_case t1 LEFT JOIN api_report t3 ON t1.last_report_id = t3.id @@ -116,6 +117,30 @@ GROUP BY t2.resource_id + + diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionModuleService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionModuleService.java index d5dca31f8b..df85bfd5ef 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionModuleService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionModuleService.java @@ -27,6 +27,7 @@ import org.mybatis.spring.SqlSessionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -81,7 +82,7 @@ public class ApiDefinitionModuleService extends ModuleTreeService { this.checkDataValidity(module); module.setCreateTime(System.currentTimeMillis()); module.setUpdateTime(module.getCreateTime()); - module.setPos(this.countPos(request.getParentId())); + module.setPos(this.getNextOrder(request.getParentId())); module.setUpdateUser(operator); apiDefinitionModuleMapper.insert(module); //记录日志 @@ -89,7 +90,7 @@ public class ApiDefinitionModuleService extends ModuleTreeService { return module.getId(); } - private Long countPos(String parentId) { + public Long getNextOrder(String parentId) { Long maxPos = extApiDefinitionModuleMapper.getMaxPosByParentId(parentId); if (maxPos == null) { return LIMIT_POS; @@ -255,4 +256,17 @@ public class ApiDefinitionModuleService extends ModuleTreeService { return moduleCountMap; } + public List getTrashTree(ApiModuleRequest request, boolean deleted) { + ApiDefinitionExample example = new ApiDefinitionExample(); + example.createCriteria().andProjectIdEqualTo(request.getProjectId()).andDeletedEqualTo(true).andProtocolEqualTo(request.getProtocol()); + List apiDefinitions = apiDefinitionMapper.selectByExample(example); + if (CollectionUtils.isEmpty(apiDefinitions)) { + return new ArrayList<>(); + } + List moduleIds = apiDefinitions.stream().map(ApiDefinition::getModuleId).distinct().toList(); + List baseTreeNodes = extApiDefinitionModuleMapper.selectBaseByIds(moduleIds); + super.buildTreeAndCountResource(baseTreeNodes, true, Translator.get(UNPLANNED_API)); + List apiTreeNodeList = extApiDefinitionModuleMapper.selectApiDataByRequest(request, deleted); + return apiDebugModuleService.getBaseTreeNodes(apiTreeNodeList, baseTreeNodes); + } } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionService.java index ca38ec2897..086dbbcbb9 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionService.java @@ -652,7 +652,7 @@ public class ApiDefinitionService { // 恢复接口到接口列表 handleRestoreApiDefinition(Collections.singletonList(request.getId()), userId, request.getProjectId(), false); } - private void handleRestoreApiDefinition(List ids, String userId, String projectId, boolean isBatch){ + public void handleRestoreApiDefinition(List ids, String userId, String projectId, boolean isBatch){ if (CollectionUtils.isNotEmpty(ids)) { SubListUtils.dealForSubList(ids, 2000, subList -> doRestore(subList, userId, projectId, isBatch)); } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiTestCaseRecoverService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiTestCaseRecoverService.java new file mode 100644 index 0000000000..97021b409f --- /dev/null +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiTestCaseRecoverService.java @@ -0,0 +1,68 @@ +package io.metersphere.api.service.definition; + +import io.metersphere.api.domain.ApiTestCase; +import io.metersphere.api.domain.ApiTestCaseExample; +import io.metersphere.api.dto.definition.ApiTestCaseBatchRequest; +import io.metersphere.api.mapper.ApiTestCaseMapper; +import io.metersphere.api.mapper.ExtApiDefinitionMapper; +import io.metersphere.api.mapper.ExtApiTestCaseMapper; +import jakarta.annotation.Resource; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional(rollbackFor = Exception.class) +public class ApiTestCaseRecoverService { + + @Resource + private ApiTestCaseMapper apiTestCaseMapper; + @Resource + private ExtApiTestCaseMapper extApiTestCaseMapper; + @Resource + private ExtApiDefinitionMapper extApiDefinitionMapper; + @Resource + private ApiDefinitionService apiDefinitionService; + @Resource + private ApiTestCaseService apiTestCaseService; + + public void batchRecover(ApiTestCaseBatchRequest request, String userId) { + List ids = doSelectIds(request, true); + if (CollectionUtils.isEmpty(ids)) { + return; + } + //检查用例的接口是否存在 需要分开两批处理 一个是接口被删的 一个是只恢复用例的 + List definitionIds = extApiTestCaseMapper.selectIdsByCaseIds(ids); + if (CollectionUtils.isNotEmpty(definitionIds)) { + List apiIds = extApiDefinitionMapper.selectIdsByIdsAndDeleted(definitionIds, true); + apiDefinitionService.handleRestoreApiDefinition(apiIds, userId, request.getProjectId(), true); + definitionIds.removeAll(apiIds); + if (CollectionUtils.isNotEmpty(definitionIds)) { + //接口被删的用例 + List caseIds = extApiTestCaseMapper.getCaseIds(definitionIds, true); + ids.retainAll(caseIds); + } + } + if (CollectionUtils.isNotEmpty(ids)) { + ApiTestCaseExample example = new ApiTestCaseExample(); + example.createCriteria().andIdIn(ids).andDeletedEqualTo(true); + List caseList = apiTestCaseMapper.selectByExample(example); + apiTestCaseService.batchRecover(caseList, userId, request.getProjectId()); + } + + } + + public List doSelectIds(ApiTestCaseBatchRequest request, boolean deleted) { + if (request.isSelectAll()) { + List ids = extApiTestCaseMapper.getIds(request, deleted); + if (CollectionUtils.isNotEmpty(request.getExcludeIds())) { + ids.removeAll(request.getExcludeIds()); + } + return ids; + } else { + return request.getSelectIds(); + } + } +} diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiTestCaseService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiTestCaseService.java index 458f493804..b5cb8bf3ba 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiTestCaseService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiTestCaseService.java @@ -73,6 +73,8 @@ public class ApiTestCaseService { private SqlSessionFactory sqlSessionFactory; @Resource private ApiFileResourceService apiFileResourceService; + @Resource + private ApiDefinitionModuleMapper apiDefinitionModuleMapper; private void checkProjectExist(String projectId) { Project project = projectMapper.selectByPrimaryKey(projectId); @@ -196,14 +198,6 @@ public class ApiTestCaseService { apiTestCaseMapper.updateByPrimaryKeySelective(apiTestCase); } - private void checkApiExist(String id) { - ApiDefinitionExample example = new ApiDefinitionExample(); - example.createCriteria().andIdEqualTo(id).andDeletedEqualTo(false); - if (apiDefinitionMapper.countByExample(example) == 0) { - throw new MSException(Translator.get("please_recover_the_interface_data_first")); - } - } - public void follow(String id, String userId) { checkResourceExist(id); ApiTestCaseFollowerExample example = new ApiTestCaseFollowerExample(); @@ -281,11 +275,19 @@ public class ApiTestCaseService { List ids = apiCaseLists.stream().map(ApiTestCaseDTO::getId).collect(Collectors.toList()); List passRateList = extApiTestCaseMapper.findPassRateByIds(ids); Map passRates = passRateList.stream().collect(Collectors.toMap(CasePassDTO::getId, CasePassDTO::getValue)); + //取模块id为新的set + List moduleIds = apiCaseLists.stream().map(ApiTestCaseDTO::getModuleId).distinct().toList(); + ApiDefinitionModuleExample moduleExample = new ApiDefinitionModuleExample(); + moduleExample.createCriteria().andIdIn(moduleIds); + List modules = apiDefinitionModuleMapper.selectByExample(moduleExample); + //生成map key为id value为name + Map moduleMap = modules.stream().collect(Collectors.toMap(ApiDefinitionModule::getId, ApiDefinitionModule::getName)); apiCaseLists.forEach(apiCase -> { apiCase.setPassRate(passRates.get(apiCase.getId())); apiCase.setCreateName(userMap.get(apiCase.getCreateUser())); apiCase.setUpdateName(userMap.get(apiCase.getUpdateUser())); apiCase.setDeleteName(userMap.get(apiCase.getDeleteUser())); + apiCase.setModulePath(StringUtils.isNotBlank(moduleMap.get(apiCase.getModuleId())) ? moduleMap.get(apiCase.getModuleId()) : Translator.get("api_unplanned_request")); if (StringUtils.isNotBlank(apiCase.getEnvironmentId()) && MapUtils.isNotEmpty(envMap) && envMap.containsKey(apiCase.getEnvironmentId())) { @@ -301,17 +303,18 @@ public class ApiTestCaseService { } public void batchRecover(List apiTestCases, String userId, String projectId) { - apiTestCases.forEach(apiTestCase -> { - checkResourceExist(apiTestCase.getId()); - checkApiExist(apiTestCase.getApiDefinitionId()); - checkNameExist(apiTestCase); - apiTestCase.setDeleted(false); - apiTestCase.setDeleteUser(null); - apiTestCase.setDeleteTime(null); - apiTestCaseMapper.updateByPrimaryKeySelective(apiTestCase); - }); - //记录恢复日志 - apiTestCaseLogService.batchRecoverLog(apiTestCases, userId, projectId); + if (CollectionUtils.isNotEmpty(apiTestCases)) { + apiTestCases.forEach(apiTestCase -> { + checkResourceExist(apiTestCase.getId()); + checkNameExist(apiTestCase); + apiTestCase.setDeleted(false); + apiTestCase.setDeleteUser(null); + apiTestCase.setDeleteTime(null); + apiTestCaseMapper.updateByPrimaryKeySelective(apiTestCase); + }); + //记录恢复日志 + apiTestCaseLogService.batchRecoverLog(apiTestCases, userId, projectId); + } } public void delete(String id, String userId) { @@ -375,11 +378,12 @@ public class ApiTestCaseService { if (CollectionUtils.isEmpty(ids)) { return; } - SubListUtils.dealForSubList(ids, 2000, subList -> batchMoveToGc(subList, userId, projectId, saveLog)); + long deleteTime = System.currentTimeMillis(); + SubListUtils.dealForSubList(ids, 2000, subList -> batchMoveToGc(subList, userId, projectId, saveLog, deleteTime)); } - private void batchMoveToGc(List ids, String userId, String projectId, boolean saveLog) { - extApiTestCaseMapper.batchMoveGc(ids, userId); + private void batchMoveToGc(List ids, String userId, String projectId, boolean saveLog, long deleteTime) { + extApiTestCaseMapper.batchMoveGc(ids, userId, deleteTime); if (saveLog) { List apiTestCases = extApiTestCaseMapper.getCaseInfoByIds(ids, true); apiTestCaseLogService.batchToGcLog(apiTestCases, userId, projectId); @@ -485,4 +489,5 @@ public class ApiTestCaseService { public String uploadTempFile(MultipartFile file) { return apiFileResourceService.uploadTempFile(file); } + } diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDefinitionModuleControllerTests.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDefinitionModuleControllerTests.java index 6af8fff063..a80a1a4de2 100644 --- a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDefinitionModuleControllerTests.java +++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDefinitionModuleControllerTests.java @@ -786,6 +786,7 @@ public class ApiDefinitionModuleControllerTests extends BaseTest { @Order(10) public void deleteModuleTestSuccess() throws Exception { this.preliminaryData(); + this.getModuleTrashTreeNode(); // 删除没有文件的节点a1-b1-c1 检查是否级联删除根节点 BaseTreeNode a1b1Node = getNodeByName(this.getModuleTreeNode(), "a1-b1"); diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestCaseControllerTests.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestCaseControllerTests.java index d7fbdae2b0..e5e8a8ded0 100644 --- a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestCaseControllerTests.java +++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestCaseControllerTests.java @@ -79,6 +79,7 @@ public class ApiTestCaseControllerTests extends BaseTest { private static final String BATCH_EDIT = BASE_PATH + "batch/edit"; private static final String BATCH_DELETE = BASE_PATH + "batch/delete"; private static final String BATCH_MOVE_GC = BASE_PATH + "batch/move-gc"; + private static final String BATCH_RECOVER = BASE_PATH + "batch/recover"; private static final String POS_URL = BASE_PATH + "/edit/pos"; private static final String UPLOAD_TEMP_FILE = BASE_PATH + "/upload/temp/file"; @@ -151,8 +152,8 @@ public class ApiTestCaseControllerTests extends BaseTest { apiDefinitionMapper.insertSelective(apiDefinition); ApiDefinitionBlob apiDefinitionBlob = new ApiDefinitionBlob(); apiDefinitionBlob.setId(apiDefinition.getId()); - apiDefinitionBlob.setRequest(new byte[0]); - apiDefinitionBlob.setResponse(new byte[0]); + MsHTTPElement msHttpElement = MsHTTPElementTest.getMsHttpElement(); + apiDefinitionBlob.setRequest(JSON.toJSONBytes(msHttpElement)); apiDefinitionBlobMapper.insertSelective(apiDefinitionBlob); apiDefinition.setId("apiDefinitionId1"); apiDefinition.setModuleId("moduleId1"); @@ -772,6 +773,7 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setSelectAll(true); request.setExcludeIds(new ArrayList<>()); + request.setApiDefinitionId("apiDefinitionId"); request.setModuleIds(List.of("case-moduleId")); responsePost(BATCH_MOVE_GC, request); ApiTestCaseExample example = new ApiTestCaseExample(); @@ -839,6 +841,42 @@ public class ApiTestCaseControllerTests extends BaseTest { requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ, TRASH_PAGE, pageRequest); } + @Test + @Order(14) + public void batchRecover() throws Exception { + // @@请求成功 + ApiTestCaseBatchRequest request = new ApiTestCaseBatchRequest(); + request.setProjectId(DEFAULT_PROJECT_ID); + request.setSelectAll(false); + request.setSelectIds(List.of(apiTestCase.getId())); + request.setExcludeIds(List.of(apiTestCase.getId())); + responsePost(BATCH_RECOVER, request); + + ApiDefinition apiDefinition = new ApiDefinition(); + apiDefinition.setId("apiDefinitionId"); + apiDefinition.setDeleted(true); + apiDefinitionMapper.updateByPrimaryKeySelective(apiDefinition); + request.setSelectAll(true); + request.setSelectIds(List.of(apiTestCase.getId())); + request.setExcludeIds(List.of(apiTestCase.getId())); + request.setModuleIds(List.of("case-moduleId")); + responsePost(BATCH_RECOVER, request); + ApiTestCaseExample example = new ApiTestCaseExample(); + example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andApiDefinitionIdEqualTo("apiDefinitionId").andDeletedEqualTo(false); + List caseList = apiTestCaseMapper.selectByExample(example); + caseList.forEach(apiTestCase -> Assertions.assertFalse(apiTestCase.getDeleted())); + + request.setSelectAll(true); + request.setExcludeIds(new ArrayList<>()); + request.setModuleIds(List.of("case-moduleId")); + responsePost(BATCH_RECOVER, request); + //校验日志 + checkLog(apiTestCase.getId(), OperationLogType.DELETE); + //校验权限 + requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_RECOVER, BATCH_RECOVER, request); + this.batchMoveGc(); + } + @Test @Order(20) @@ -880,6 +918,7 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setProjectId(DEFAULT_PROJECT_ID); request.setSelectAll(true); request.setModuleIds(List.of("case-moduleId")); + request.setApiDefinitionId("apiDefinitionId"); responsePost(BATCH_DELETE, request); ApiTestCaseExample example = new ApiTestCaseExample(); example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andApiDefinitionIdEqualTo("apiDefinitionId"); diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/controller/EnvironmentController.java b/backend/services/project-management/src/main/java/io/metersphere/project/controller/EnvironmentController.java index 21ff0c3ed1..1e2ebafafd 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/controller/EnvironmentController.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/controller/EnvironmentController.java @@ -1,9 +1,6 @@ package io.metersphere.project.controller; -import io.metersphere.project.dto.environment.EnvironmentExportRequest; -import io.metersphere.project.dto.environment.EnvironmentFilterRequest; -import io.metersphere.project.dto.environment.EnvironmentImportRequest; -import io.metersphere.project.dto.environment.EnvironmentRequest; +import io.metersphere.project.dto.environment.*; import io.metersphere.project.dto.environment.datasource.DataSource; import io.metersphere.project.dto.environment.ssl.KeyStoreEntry; import io.metersphere.project.service.CommandService; @@ -50,7 +47,7 @@ public class EnvironmentController { @GetMapping("/get/{environmentId}") @Operation(summary = "项目管理-环境-环境目录-详情") @RequiresPermissions(PermissionConstants.PROJECT_ENVIRONMENT_READ) - public EnvironmentRequest get(@PathVariable String environmentId) { + public EnvironmentInfoDTO get(@PathVariable String environmentId) { return environmentService.get(environmentId); } @@ -59,7 +56,7 @@ public class EnvironmentController { @Operation(summary = "项目管理-环境-环境目录-新增") @RequiresPermissions(PermissionConstants.PROJECT_ENVIRONMENT_READ_ADD) @Log(type = OperationLogType.ADD, expression = "#msClass.addLog(#request)", msClass = EnvironmentLogService.class) - public EnvironmentRequest add(@Validated({Created.class}) @RequestPart(value = "request") EnvironmentRequest request, + public Environment add(@Validated({Created.class}) @RequestPart(value = "request") EnvironmentRequest request, @RequestPart(value = "file", required = false) List sslFiles) { return environmentService.add(request, SessionUtils.getUserId(), sslFiles); } @@ -68,7 +65,7 @@ public class EnvironmentController { @RequiresPermissions(PermissionConstants.PROJECT_ENVIRONMENT_READ_UPDATE) @Operation(summary = "项目管理-环境-环境目录-修改") @Log(type = OperationLogType.UPDATE, expression = "#msClass.updateLog(#request)", msClass = EnvironmentLogService.class) - public EnvironmentRequest update(@Validated({Updated.class}) @RequestPart("request") EnvironmentRequest request, + public Environment update(@Validated({Updated.class}) @RequestPart("request") EnvironmentRequest request, @RequestPart(value = "file", required = false) List sslFiles) { return environmentService.update(request, SessionUtils.getUserId(), sslFiles); } diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/dto/environment/EnvironmentInfoDTO.java b/backend/services/project-management/src/main/java/io/metersphere/project/dto/environment/EnvironmentInfoDTO.java new file mode 100644 index 0000000000..6e79ead8ac --- /dev/null +++ b/backend/services/project-management/src/main/java/io/metersphere/project/dto/environment/EnvironmentInfoDTO.java @@ -0,0 +1,37 @@ +package io.metersphere.project.dto.environment; + +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 jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +public class EnvironmentInfoDTO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + @Schema(description = "ID") + @NotBlank(message = "{project_parameters.id.not_blank}", groups = {Updated.class}) + @Size(min = 1, max = 50, message = "{project_parameters.id.length_range}", groups = {Updated.class}) + private String id; + @Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "{project_application.project_id.not_blank}", groups = {Created.class, Updated.class}) + @Size(min = 1, max = 50, message = "{project_parameters.project_id.length_range}", groups = {Created.class, Updated.class}) + private String projectId; + @Schema(description = "环境名称") + @NotBlank(message = "{environment_name_is_null}", groups = {Created.class, Updated.class}) + private String name; + @Schema(description = "环境配置") + @NotNull(message = "{environment_config_is_null}", groups = {Created.class, Updated.class}) + private EnvironmentConfig config; + @Schema(description = "是否是mock环境") + private Boolean mock; + @Schema(description = "描述") + private String description; + +} diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/service/EnvironmentService.java b/backend/services/project-management/src/main/java/io/metersphere/project/service/EnvironmentService.java index 29d0926aa1..263e39daa7 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/service/EnvironmentService.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/service/EnvironmentService.java @@ -114,7 +114,7 @@ public class EnvironmentService { return extEnvironmentMapper.selectByKeyword(request.getKeyword(), false, request.getProjectId()); } - public EnvironmentRequest add(EnvironmentRequest request, String userId, List sslFiles) { + public Environment add(EnvironmentRequest request, String userId, List sslFiles) { Environment environment = new Environment(); environment.setId(IDGenerator.nextStr()); environment.setCreateUser(userId); @@ -134,7 +134,7 @@ public class EnvironmentService { environmentBlob.setConfig(JSON.toJSONBytes(request.getConfig())); environmentBlobMapper.insert(environmentBlob); uploadFileToMinio(sslFiles, environment); - return request; + return environment; } private void uploadFileToMinio(List sslFiles, Environment environment) { @@ -153,20 +153,20 @@ public class EnvironmentService { } } - public EnvironmentRequest get(String environmentId) { - EnvironmentRequest environmentRequest = new EnvironmentRequest(); + public EnvironmentInfoDTO get(String environmentId) { + EnvironmentInfoDTO environmentInfoDTO = new EnvironmentInfoDTO(); Environment environment = environmentMapper.selectByPrimaryKey(environmentId); if (environment == null) { return null; } - environmentRequest.setProjectId(environment.getProjectId()); - environmentRequest.setName(environment.getName()); - environmentRequest.setId(environment.getId()); + environmentInfoDTO.setProjectId(environment.getProjectId()); + environmentInfoDTO.setName(environment.getName()); + environmentInfoDTO.setId(environment.getId()); EnvironmentBlob environmentBlob = environmentBlobMapper.selectByPrimaryKey(environmentId); if (environmentBlob == null) { - environmentRequest.setConfig(new EnvironmentConfig()); + environmentInfoDTO.setConfig(new EnvironmentConfig()); } else { - environmentRequest.setConfig(JSON.parseObject(new String(environmentBlob.getConfig()), EnvironmentConfig.class)); + environmentInfoDTO.setConfig(JSON.parseObject(new String(environmentBlob.getConfig()), EnvironmentConfig.class)); } if (BooleanUtils.isTrue(environment.getMock())) { SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class); @@ -175,11 +175,11 @@ public class EnvironmentService { String baseUrl = baseSystemConfigDTO.getUrl(); if (StringUtils.isNotEmpty(baseUrl)) { Project project = projectMapper.selectByPrimaryKey(environment.getProjectId()); - environmentRequest.getConfig().getHttpConfig().get(0).setUrl(StringUtils.join(baseUrl, MOCK_EVN_SOCKET, project.getNum())); + environmentInfoDTO.getConfig().getHttpConfig().get(0).setUrl(StringUtils.join(baseUrl, MOCK_EVN_SOCKET, project.getNum())); } } - return environmentRequest; + return environmentInfoDTO; } public Long getNextOrder(String projectId) { @@ -294,7 +294,7 @@ public class EnvironmentService { return null; } - public EnvironmentRequest update(EnvironmentRequest request, String userId, List sslFiles) { + public Environment update(EnvironmentRequest request, String userId, List sslFiles) { Environment environment = new Environment(); environment.setId(request.getId()); environment.setUpdateUser(userId); @@ -308,7 +308,7 @@ public class EnvironmentService { environmentBlob.setConfig(JSON.toJSONBytes(request.getConfig())); environmentBlobMapper.updateByPrimaryKeySelective(environmentBlob); uploadFileToMinio(sslFiles, environment); - return request; + return environment; } public void create(EnvironmentImportRequest request, MultipartFile file, String userId, String currentProjectId) { diff --git a/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java b/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java index 61426fb1ea..54a3939071 100644 --- a/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java +++ b/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java @@ -370,7 +370,7 @@ public class EnvironmentControllerTests extends BaseTest { MultiValueMap paramMap = new LinkedMultiValueMap<>(); paramMap.add("request", JSON.toJSONString(request)); MvcResult mvcResult = this.requestMultipartWithOkAndReturn(add, paramMap); - EnvironmentRequest response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + Environment response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); Environment environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertNotNull(environment); @@ -394,7 +394,7 @@ public class EnvironmentControllerTests extends BaseTest { request.setConfig(envConfig); paramMap.set("request", JSON.toJSONString(request)); mvcResult = this.requestMultipartWithOkAndReturn(add, paramMap); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertNotNull(environment); @@ -419,7 +419,7 @@ public class EnvironmentControllerTests extends BaseTest { request.setConfig(envConfig); paramMap.set("request", JSON.toJSONString(request)); mvcResult = this.requestMultipartWithOkAndReturn(add, paramMap); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertNotNull(environment); @@ -444,7 +444,7 @@ public class EnvironmentControllerTests extends BaseTest { request.setConfig(envConfig); paramMap.set("request", JSON.toJSONString(request)); mvcResult = this.requestMultipartWithOkAndReturn(add, paramMap); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertNotNull(environment); @@ -469,7 +469,7 @@ public class EnvironmentControllerTests extends BaseTest { request.setConfig(envConfig); paramMap.set("request", JSON.toJSONString(request)); mvcResult = this.requestMultipartWithOkAndReturn(add, paramMap); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertNotNull(environment); @@ -494,7 +494,7 @@ public class EnvironmentControllerTests extends BaseTest { request.setConfig(envConfig); paramMap.set("request", JSON.toJSONString(request)); mvcResult = this.requestMultipartWithOkAndReturn(add, paramMap); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertNotNull(environment); @@ -519,7 +519,7 @@ public class EnvironmentControllerTests extends BaseTest { request.setConfig(envConfig); paramMap.set("request", JSON.toJSONString(request)); mvcResult = this.requestMultipartWithOkAndReturn(add, paramMap); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertNotNull(environment); @@ -546,7 +546,7 @@ public class EnvironmentControllerTests extends BaseTest { request.setConfig(envConfig); paramMap.set("request", JSON.toJSONString(request)); mvcResult = this.requestMultipartWithOkAndReturn(add, paramMap); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertNotNull(environment); @@ -571,7 +571,7 @@ public class EnvironmentControllerTests extends BaseTest { request.setConfig(envConfig); paramMap.set("request", JSON.toJSONString(request)); mvcResult = this.requestMultipartWithOkAndReturn(add, paramMap); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertNotNull(environment); @@ -596,7 +596,7 @@ public class EnvironmentControllerTests extends BaseTest { request.setConfig(envConfig); paramMap.set("request", JSON.toJSONString(request)); mvcResult = this.requestMultipartWithOkAndReturn(add, paramMap); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertNotNull(environment); @@ -622,7 +622,7 @@ public class EnvironmentControllerTests extends BaseTest { request.setConfig(envConfig); paramMap.set("request", JSON.toJSONString(request)); mvcResult = this.requestMultipartWithOkAndReturn(add, paramMap); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertEquals(response.getName(), environment.getName()); @@ -652,7 +652,7 @@ public class EnvironmentControllerTests extends BaseTest { paramMap.add("file", List.of(file, file11)); paramMap.set("request", JSON.toJSONString(request)); mvcResult = requestMultipartWithOk(add, paramMap, DEFAULT_PROJECT_ID); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertEquals(response.getName(), environment.getName()); @@ -703,7 +703,7 @@ public class EnvironmentControllerTests extends BaseTest { List environments = environmentMapper.selectByExample(example); String id = environments.get(0).getId(); MvcResult mvcResult = this.responseGet(get + id); - EnvironmentRequest response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + EnvironmentInfoDTO response = parseObjectFromMvcResult(mvcResult, EnvironmentInfoDTO.class); Assertions.assertNotNull(response); Assertions.assertEquals(id, response.getId()); Assertions.assertEquals("name", response.getName()); @@ -724,7 +724,7 @@ public class EnvironmentControllerTests extends BaseTest { environmentBlob.setConfig(JSON.toJSONBytes(new EnvironmentConfig())); environmentBlobMapper.insert(environmentBlob); mvcResult = this.responseGet(get + "environmentId1"); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, EnvironmentInfoDTO.class); Assertions.assertNotNull(response); Assertions.assertEquals("environmentId1", response.getId()); //校验权限 @@ -817,7 +817,7 @@ public class EnvironmentControllerTests extends BaseTest { MultiValueMap paramMap = new LinkedMultiValueMap<>(); paramMap.set("request", JSON.toJSONString(request)); MvcResult mvcResult = requestMultipartWithOkAndReturn(update, paramMap, ERROR_REQUEST_MATCHER); - EnvironmentRequest response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + Environment response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); Environment environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertNotNull(environment); @@ -838,7 +838,7 @@ public class EnvironmentControllerTests extends BaseTest { paramMap.add("file", List.of(file, file11)); paramMap.set("request", JSON.toJSONString(request)); mvcResult = requestMultipartWithOk(update, paramMap, DEFAULT_PROJECT_ID); - response = parseObjectFromMvcResult(mvcResult, EnvironmentRequest.class); + response = parseObjectFromMvcResult(mvcResult, Environment.class); Assertions.assertNotNull(response); environment = environmentMapper.selectByPrimaryKey(response.getId()); Assertions.assertEquals(response.getName(), environment.getName());