diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioController.java index a8b3396405..24cba4f84d 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioController.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioController.java @@ -47,6 +47,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.util.List; +import java.util.Map; @RestController @RequestMapping(value = "/api/scenario") @@ -159,8 +160,8 @@ public class ApiScenarioController { @Operation(summary = "接口测试-接口场景管理-获取未保存的场景步骤详情") @RequiresPermissions(value = {PermissionConstants.PROJECT_API_SCENARIO_UPDATE, PermissionConstants.PROJECT_API_SCENARIO_ADD}, logical = Logical.OR) - public ApiScenarioUnsavedStepDetailDTO getUnsavedStepDetail(@Validated @RequestBody ApiScenarioStepDetailRequest request) { - return apiScenarioService.getUnsavedStepDetail(request); + public Object getUnsavedStepDetail(@Validated @RequestBody ApiScenarioStepDetailRequest request) { + return JSON.parseObject(JSON.toJSONString(apiScenarioService.getUnsavedStepDetail(request))); } @GetMapping("/step/get/{stepId}") @@ -171,6 +172,14 @@ public class ApiScenarioController { return JSON.parseObject(JSON.toJSONString(apiScenarioService.getStepDetail(stepId))); } + @PostMapping("/step/file/copy") + @Operation(summary = "接口测试-接口场景管理-复制步骤时,复制步骤文件") + @RequiresPermissions(value = {PermissionConstants.PROJECT_API_SCENARIO_UPDATE, PermissionConstants.PROJECT_API_SCENARIO_ADD}, + logical = Logical.OR) + public Map copyStepFile(@Validated @RequestBody ApiScenarioStepFileCopyRequest request) { + return apiScenarioService.copyStepFile(request); + } + @GetMapping("/step/resource-info/{resourceId}") @Operation(summary = "接口测试-接口场景管理-获取步骤关联资源的信息") @RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ) diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioStepDetailRequest.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioStepDetailRequest.java index 217817c9f0..feec9b077c 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioStepDetailRequest.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioStepDetailRequest.java @@ -21,7 +21,6 @@ public class ApiScenarioStepDetailRequest { * 保存时需要根据这个字段查询原步骤详情保存 */ @Schema(description = "复制的目标步骤ID") - @NotBlank private String copyFromStepId; @Schema(description = "资源id") diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioStepFileCopyRequest.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioStepFileCopyRequest.java new file mode 100644 index 0000000000..6d0077b243 --- /dev/null +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioStepFileCopyRequest.java @@ -0,0 +1,39 @@ +package io.metersphere.api.dto.scenario; + +import io.metersphere.api.constants.ApiScenarioStepType; +import io.metersphere.sdk.valid.EnumValue; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +@Data +public class ApiScenarioStepFileCopyRequest { + /** + * 记录是从哪个步骤复制来的 + * 如果没有传步骤详情 + * 保存时需要根据这个字段查询原步骤详情保存 + */ + @Schema(description = "复制的目标步骤ID") + private String copyFromStepId; + + @Schema(description = "资源id") + private String resourceId; + + /** + * {@link ApiScenarioStepType} + */ + @Schema(description = "步骤类型/API/CASE等") + @EnumValue(enumClass = ApiScenarioStepType.class) + private String stepType; + + @Schema(description = "是否是临时文件") + @NotNull + private Boolean isTempFile; + + @Schema(description = "文件数组") + @NotEmpty + private List fileIds; +} diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioUnsavedStepDetailDTO.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioUnsavedStepDetailDTO.java deleted file mode 100644 index cf9e1bd1bc..0000000000 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioUnsavedStepDetailDTO.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.metersphere.api.dto.scenario; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.util.List; - -@Data -public class ApiScenarioUnsavedStepDetailDTO { - - @Schema(description = "步骤详情") - private Object detail; - - @Schema(description = "复制的步骤中的本地文件ID集合") - private List uploadIds; -} diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiFileResourceService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiFileResourceService.java index d8750820ba..e57e8ddb6e 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiFileResourceService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiFileResourceService.java @@ -65,6 +65,10 @@ public class ApiFileResourceService { return commonFileService.getTempFileNameByFileId(fileId); } + public String getFileNameByFileId(String fileId, String folder) { + return commonFileService.getFileNameByFileId(fileId, folder); + } + /** * 添加接口与文件的关联关系 */ diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java index 7b1cecfa5a..787d98376a 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java @@ -2983,73 +2983,58 @@ public class ApiScenarioService extends MoveNodeService { * @param request * @return */ - public ApiScenarioUnsavedStepDetailDTO getUnsavedStepDetail(ApiScenarioStepDetailRequest request) { + public Object getUnsavedStepDetail(ApiScenarioStepDetailRequest request) { ApiScenarioStep step = apiScenarioStepMapper.selectByPrimaryKey(request.getId()); if (step == null) { - ApiScenarioUnsavedStepDetailDTO result = new ApiScenarioUnsavedStepDetailDTO(); ApiScenarioStepDetailRequest getDetailRequest = BeanUtils.copyBean(new ApiScenarioStepDetailRequest(), request); if (StringUtils.isNotBlank(request.getCopyFromStepId())) { // 从已有步骤复制,则获取复制步骤的详情 ApiScenarioStep copyFromStep = apiScenarioStepMapper.selectByPrimaryKey(request.getCopyFromStepId()); getDetailRequest = BeanUtils.copyBean(new ApiScenarioStepDetailRequest(), copyFromStep); } - Object stepDetail = getStepDetail(getDetailRequest); - List uploadFileIds = uploadCopyStepLocalFiles(request, stepDetail); - result.setDetail(JSON.parseObject(JSON.toJSONString(stepDetail))); - result.setUploadIds(uploadFileIds); - return result; + return getStepDetail(getDetailRequest); } throw new MSException("步骤已存在,请调用 /api/scenario/step/get/{stepId} 接口获取详情"); } - /** - * 复制的步骤,将步骤中的文件上传 - * 并替换文件ID - * @param request - * @param stepDetail - * @return - */ - private List uploadCopyStepLocalFiles(ApiScenarioStepDetailRequest request, Object stepDetail) { - if (stepDetail instanceof AbstractMsTestElement stepMsTestElement) { - List localFiles = apiCommonService.getApiFiles(stepMsTestElement) - .stream() - .filter(file -> BooleanUtils.isTrue(file.getLocal())) - .collect(Collectors.toList()); - if (CollectionUtils.isNotEmpty(localFiles)) { - List uploadFileIds = new ArrayList<>(); - String sourceDir = null; - String stepType = request.getStepType(); - String resourceId = request.getResourceId(); - if (StringUtils.isNotBlank(request.getCopyFromStepId())) { - // 从已有步骤复制,则获取复制步骤的文件 - ApiScenarioStep copyFromStep = apiScenarioStepMapper.selectByPrimaryKey(request.getCopyFromStepId()); - sourceDir = DefaultRepositoryDir.getApiScenarioStepDir(copyFromStep.getProjectId(), - copyFromStep.getScenarioId(), copyFromStep.getId()); - } else if (StringUtils.equals(stepType, ApiScenarioStepType.API.name())) { - // 获取接口定义相关的文件 - ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(resourceId); - sourceDir = DefaultRepositoryDir.getApiDefinitionDir(apiDefinition.getProjectId(), - apiDefinition.getId()); - } else if (StringUtils.equals(stepType, ApiScenarioStepType.API_CASE.name())) { - // 获取接口用例相关的文件 - ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(resourceId); - sourceDir = DefaultRepositoryDir.getApiCaseDir(apiTestCase.getProjectId(), - apiTestCase.getId()); - } - // 复制的步骤将文件复制到临时目录,并且保存新的文件ID - for (ApiFile localFile : localFiles) { - String newFileId = IDGenerator.nextStr(); - String targetDir = DefaultRepositoryDir.getSystemTempDir(); - // 复制文件到临时目录 - apiFileResourceService.copyFile(sourceDir + "/" + localFile.getFileId(), - targetDir + "/" + newFileId, - localFile.getFileName()); - localFile.setFileId(newFileId); - uploadFileIds.add(newFileId); - } - return uploadFileIds; + public Map copyStepFile(ApiScenarioStepFileCopyRequest request) { + String sourceDir; + Map uploadFileMap = new HashMap<>(); + if (BooleanUtils.isTrue(request.getIsTempFile())) { + sourceDir = DefaultRepositoryDir.getSystemTempDir(); + } else { + String stepType = request.getStepType(); + String resourceId = request.getResourceId(); + if (StringUtils.isNotBlank(request.getCopyFromStepId())) { + // 从已有步骤复制 + ApiScenarioStep copyFromStep = apiScenarioStepMapper.selectByPrimaryKey(request.getCopyFromStepId()); + sourceDir = DefaultRepositoryDir.getApiScenarioStepDir(copyFromStep.getProjectId(), + copyFromStep.getScenarioId(), copyFromStep.getId()); + } else if (StringUtils.equals(stepType, ApiScenarioStepType.API.name())) { + // 从接口定义复制 + ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(resourceId); + sourceDir = DefaultRepositoryDir.getApiDefinitionDir(apiDefinition.getProjectId(), + apiDefinition.getId()); + } else if (StringUtils.equals(stepType, ApiScenarioStepType.API_CASE.name())) { + // 从接口用例复制 + ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(resourceId); + sourceDir = DefaultRepositoryDir.getApiCaseDir(apiTestCase.getProjectId(), + apiTestCase.getId()); + } else { + throw new MSException("不支持的步骤类型"); } } - return List.of(); + + for (String fileId : request.getFileIds()) { + String newFileId = IDGenerator.nextStr(); + String targetDir = DefaultRepositoryDir.getSystemTempDir(); + String fileName = apiFileResourceService.getFileNameByFileId(fileId, sourceDir); + // 复制文件到临时目录 + apiFileResourceService.copyFile(sourceDir + "/" + fileId, + targetDir + "/" + newFileId, + fileName); + uploadFileMap.put(fileId, newFileId); + } + return uploadFileMap; } }