feat(功能用例): 附件接口

This commit is contained in:
WangXu10 2023-11-30 18:35:24 +08:00 committed by Craftsman
parent e6f1fcb7ab
commit a90a8a0865
7 changed files with 157 additions and 7 deletions

View File

@ -1,6 +1,8 @@
package io.metersphere.functional.controller;
import io.metersphere.functional.domain.FunctionalCaseAttachment;
import io.metersphere.functional.request.FunctionalCaseAssociationFileRequest;
import io.metersphere.functional.request.FunctionalCaseDeleteFileRequest;
import io.metersphere.functional.request.FunctionalCaseFileRequest;
import io.metersphere.functional.service.FunctionalCaseAttachmentService;
import io.metersphere.project.dto.filemanagement.FileLogRecord;
@ -22,6 +24,7 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.Arrays;
import java.util.List;
@ -124,4 +127,21 @@ public class FunctionalCaseAttachmentController {
}
@PostMapping("/upload/file")
@Operation(summary = "用例管理-功能用例-上传文件并关联用例")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE)
public void uploadFile(@Validated @RequestPart("request") FunctionalCaseAssociationFileRequest request, @RequestPart(value = "file", required = false) MultipartFile file) {
String userId = SessionUtils.getUserId();
functionalCaseAttachmentService.uploadOrAssociationFile(request, file, userId);
}
@PostMapping("/delete/file")
@Operation(summary = "用例管理-功能用例-删除文件并取消关联用例")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE)
public void deleteFile(@Validated @RequestBody FunctionalCaseDeleteFileRequest request) {
String userId = SessionUtils.getUserId();
functionalCaseAttachmentService.deleteFile(request, userId);
}
}

View File

@ -0,0 +1,26 @@
package io.metersphere.functional.request;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* @author wx
*/
@Data
public class FunctionalCaseAssociationFileRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "文件id列表")
private List<String> fileIds;
@Schema(description = "用例id", requiredMode = Schema.RequiredMode.REQUIRED)
private String caseId;
@Schema(description = "项目id", requiredMode = Schema.RequiredMode.REQUIRED)
private String projectId;
}

View File

@ -0,0 +1,26 @@
package io.metersphere.functional.request;
import io.metersphere.functional.dto.FunctionalCaseAttachmentDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author wx
*/
@Data
public class FunctionalCaseDeleteFileRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "附件信息", requiredMode = Schema.RequiredMode.REQUIRED)
private FunctionalCaseAttachmentDTO attachment;
@Schema(description = "用例id", requiredMode = Schema.RequiredMode.REQUIRED)
private String caseId;
@Schema(description = "项目id", requiredMode = Schema.RequiredMode.REQUIRED)
private String projectId;
}

View File

@ -7,7 +7,8 @@ import io.metersphere.functional.domain.FunctionalCaseAttachmentExample;
import io.metersphere.functional.dto.FunctionalCaseAttachmentDTO;
import io.metersphere.functional.dto.FunctionalCaseDetailDTO;
import io.metersphere.functional.mapper.FunctionalCaseAttachmentMapper;
import io.metersphere.functional.request.FunctionalCaseAddRequest;
import io.metersphere.functional.request.FunctionalCaseAssociationFileRequest;
import io.metersphere.functional.request.FunctionalCaseDeleteFileRequest;
import io.metersphere.functional.request.FunctionalCaseFileRequest;
import io.metersphere.project.domain.FileAssociation;
import io.metersphere.project.dto.filemanagement.FileInfo;
@ -24,6 +25,7 @@ import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@ -52,6 +54,9 @@ public class FunctionalCaseAttachmentService {
@Resource
private FileAssociationService fileAssociationService;
private static final String UPLOAD_FILE = "/attachment/upload/file";
private static final String DELETED_FILE = "/attachment/delete/file";
/**
* 保存本地上传文件和用例关联关系
*
@ -70,16 +75,16 @@ public class FunctionalCaseAttachmentService {
/**
* 功能用例上传附件
*
* @param request request
* @param files files
* @param projectId projectId
* @param files files
*/
public void uploadFile(FunctionalCaseAddRequest request, String caseId, List<MultipartFile> files, Boolean isLocal, String userId) {
public void uploadFile(String projectId, String caseId, List<MultipartFile> files, Boolean isLocal, String userId) {
if (CollectionUtils.isNotEmpty(files)) {
files.forEach(file -> {
String fileId = IDGenerator.nextStr();
FileRequest fileRequest = new FileRequest();
fileRequest.setFileName(file.getOriginalFilename());
fileRequest.setFolder(DefaultRepositoryDir.getFunctionalCaseDir(request.getProjectId(), caseId) + "/" + fileId);
fileRequest.setFolder(DefaultRepositoryDir.getFunctionalCaseDir(projectId, caseId) + "/" + fileId);
fileRequest.setStorage(StorageType.MINIO.name());
try {
fileService.upload(file, fileRequest);
@ -289,4 +294,21 @@ public class FunctionalCaseAttachmentService {
}
return fileAssociationMap;
}
public void uploadOrAssociationFile(FunctionalCaseAssociationFileRequest request, MultipartFile file, String userId) {
Optional.ofNullable(file).ifPresent(item -> this.uploadFile(request.getProjectId(), request.getCaseId(), Arrays.asList(file), Boolean.TRUE, userId));
if (CollectionUtils.isNotEmpty(request.getFileIds())) {
this.association(request.getFileIds(), request.getCaseId(), userId, UPLOAD_FILE, request.getProjectId());
}
}
public void deleteFile(FunctionalCaseDeleteFileRequest request, String userId) {
if (BooleanUtils.isTrue(request.getAttachment().getLocal())) {
this.deleteCaseAttachment(Arrays.asList(request.getAttachment().getId()), request.getCaseId(), userId);
}
if (BooleanUtils.isFalse(request.getAttachment().getLocal())) {
this.unAssociation(Arrays.asList(request.getAttachment().getId()), DELETED_FILE, userId, request.getProjectId());
}
}
}

View File

@ -95,7 +95,7 @@ public class FunctionalCaseService {
FunctionalCase functionalCase = addCase(caseId, request, userId);
//上传文件
functionalCaseAttachmentService.uploadFile(request, caseId, files, true, userId);
functionalCaseAttachmentService.uploadFile(request.getProjectId(), caseId, files, true, userId);
//关联附件
if (CollectionUtils.isNotEmpty(request.getRelateFileMetaIds())) {
@ -275,7 +275,7 @@ public class FunctionalCaseService {
}
//上传新文件
functionalCaseAttachmentService.uploadFile(request, request.getId(), files, true, userId);
functionalCaseAttachmentService.uploadFile(request.getProjectId(), request.getId(), files, true, userId);
//关联新附件
if (CollectionUtils.isNotEmpty(request.getRelateFileMetaIds())) {

View File

@ -1,5 +1,8 @@
package io.metersphere.functional.controller;
import io.metersphere.functional.dto.FunctionalCaseAttachmentDTO;
import io.metersphere.functional.request.FunctionalCaseAssociationFileRequest;
import io.metersphere.functional.request.FunctionalCaseDeleteFileRequest;
import io.metersphere.functional.request.FunctionalCaseFileRequest;
import io.metersphere.functional.utils.FileBaseUtils;
import io.metersphere.project.dto.filemanagement.request.FileMetadataTableRequest;
@ -23,6 +26,7 @@ import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.util.LinkedMultiValueMap;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
@ -50,6 +54,9 @@ public class FunctionalCaseAttachmentControllerTests extends BaseTest {
public static final String ATTACHMENT_CHECK_UPDATE_URL = "/attachment/check-update";
public static final String ATTACHMENT_UPDATE_URL = "/attachment/update/";
public static final String ATTACHMENT_TRANSFER_URL = "/attachment/transfer";
public static final String UPLOAD_FILE_URL = "/attachment/upload/file";
public static final String DELETE_FILE_URL = "/attachment/delete/file";
@Test
@Order(1)
@ -171,4 +178,49 @@ public class FunctionalCaseAttachmentControllerTests extends BaseTest {
this.requestPost(ATTACHMENT_TRANSFER_URL, request);
}
@Test
@Order(7)
public void testUploadFile() throws Exception {
String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.JPG")).getPath();
MockMultipartFile file = new MockMultipartFile("file", "file_re-upload.JPG", MediaType.APPLICATION_OCTET_STREAM_VALUE, FileBaseUtils.getFileBytes(filePath));
LinkedMultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
FunctionalCaseAssociationFileRequest request = new FunctionalCaseAssociationFileRequest();
request.setCaseId("TEST_FUNCTIONAL_CASE_ATTACHMENT_ID_1");
request.setProjectId("WX_TEST_PROJECT_ID");
paramMap.add("request", JSON.toJSONString(request));
paramMap.add("file", file);
this.requestMultipart(UPLOAD_FILE_URL, paramMap);
request.setFileIds(Arrays.asList("wx_test_file_association_1"));
paramMap = new LinkedMultiValueMap<>();
paramMap.add("request", JSON.toJSONString(request));
paramMap.add("file", file);
this.requestMultipart(UPLOAD_FILE_URL, paramMap);
}
@Test
@Order(8)
public void testDeleteFile() throws Exception {
FunctionalCaseDeleteFileRequest request = new FunctionalCaseDeleteFileRequest();
FunctionalCaseAttachmentDTO attachmentDTO = new FunctionalCaseAttachmentDTO();
//覆盖率
request.setCaseId("TEST_FUNCTIONAL_CASE_ATTACHMENT_ID_1");
request.setProjectId("WX_TEST_PROJECT_ID");
request.setAttachment(attachmentDTO);
this.requestPost(DELETE_FILE_URL, request);
attachmentDTO.setId("wx_test_file_association_1");
attachmentDTO.setLocal(false);
this.requestPost(DELETE_FILE_URL, request);
attachmentDTO.setId("TEST_ATTACHMENT_ID");
attachmentDTO.setLocal(true);
this.requestPost(DELETE_FILE_URL, request);
}
}

View File

@ -19,3 +19,7 @@ INSERT INTO functional_case_attachment(id, case_id, file_id, file_name, size, lo
INSERT INTO file_association(id, source_type, source_id, file_id, file_ref_id, file_version, create_time, update_user, update_time, create_user) VALUES ('wx_test_file_association', 'functional_case', 'WX_TEST_FUNCTIONAL_CASE_ID', 'wx_file_id', '1', '1', 1698983271536, 'admin', 1698983271536, 'admin');
INSERT INTO file_metadata(id, name, type, size, create_time, update_time, project_id, storage, create_user, update_user, tags, description, module_id, path, latest, ref_id, file_version) VALUES ('wx_file_id', 'formItem', 'ts', 2502, 1698058347559, 1698058347559, '100001100001', 'MINIO', 'admin', 'admin', NULL, NULL, 'root', '100001100001/1127016598347779', b'1', '1127016598347779', '1127016598347779');
INSERT INTO file_association(id, source_type, source_id, file_id, file_ref_id, file_version, create_time, update_user, update_time, create_user) VALUES ('wx_test_file_association_1', 'functional_case', 'WX_TEST_FUNCTIONAL_CASE_ID', 'wx_file_id_1', '1', '1', 1698983271536, 'admin', 1698983271536, 'admin');
INSERT INTO file_metadata(id, name, type, size, create_time, update_time, project_id, storage, create_user, update_user, tags, description, module_id, path, latest, ref_id, file_version) VALUES ('wx_file_id_1', 'formItem', 'ts', 2502, 1698058347559, 1698058347559, '100001100001', 'MINIO', 'admin', 'admin', NULL, NULL, 'root', '100001100001/1127016598347779', b'1', '1127016598347779', '1127016598347779');