feat(功能用例): 功能用例详情副文本增加文件

This commit is contained in:
guoyuqi 2024-01-12 13:18:53 +08:00 committed by 刘瑞斌
parent c76e081451
commit ab9ffc61ce
9 changed files with 113 additions and 12 deletions

View File

@ -2,10 +2,7 @@ package io.metersphere.functional.constants;
public enum CaseFileSourceType { public enum CaseFileSourceType {
ATTACHMENT,//附件 ATTACHMENT,//附件
PREREQUISITE,//前置条件 CASE_DETAIL,//功能用例详情
TEXT_DESCRIPTION,//步骤描述
EXPECTED_RESULT,//预期结果
DESCRIPTION,//备注
CASE_COMMENT,//用例评论 CASE_COMMENT,//用例评论
REVIEW_COMMENT//评审评论 REVIEW_COMMENT//评审评论
} }

View File

@ -13,6 +13,7 @@ import io.metersphere.project.dto.filemanagement.response.FileInformationRespons
import io.metersphere.project.service.FileAssociationService; import io.metersphere.project.service.FileAssociationService;
import io.metersphere.project.service.FileMetadataService; import io.metersphere.project.service.FileMetadataService;
import io.metersphere.project.service.FileModuleService; import io.metersphere.project.service.FileModuleService;
import io.metersphere.project.service.PermissionCheckService;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.FileAssociationSourceUtil; import io.metersphere.sdk.util.FileAssociationSourceUtil;
@ -50,9 +51,13 @@ public class FunctionalCaseAttachmentController {
@Resource @Resource
private FileAssociationService fileAssociationService; private FileAssociationService fileAssociationService;
@Resource @Resource
private FileModuleService fileModuleService; private FileModuleService fileModuleService;
@Resource
private PermissionCheckService permissionCheckService;
@PostMapping("/page") @PostMapping("/page")
@Operation(summary = "用例管理-功能用例-附件-关联文件列表分页接口") @Operation(summary = "用例管理-功能用例-附件-关联文件列表分页接口")
@ -64,7 +69,7 @@ public class FunctionalCaseAttachmentController {
@PostMapping("/preview") @PostMapping("/preview")
@Operation(summary = "用例管理-功能用例-附件-文件预览") @Operation(summary = "用例管理-功能用例-附件/副文本(原图/文件)-文件预览")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ) @RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public ResponseEntity<byte[]> preview(@Validated @RequestBody FunctionalCaseFileRequest request) throws Exception { public ResponseEntity<byte[]> preview(@Validated @RequestBody FunctionalCaseFileRequest request) throws Exception {
@ -78,8 +83,17 @@ public class FunctionalCaseAttachmentController {
} }
@PostMapping(value = "/preview/compressed")
@Operation(summary = "用例管理-功能用例-显示详情(副文本)图片缩略图")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public ResponseEntity<byte[]> compressedImg(@Validated @RequestBody FunctionalCaseFileRequest request) throws Exception {
return functionalCaseAttachmentService.downloadPreviewCompressedImg(request);
}
@PostMapping("/download") @PostMapping("/download")
@Operation(summary = "用例管理-功能用例-附件-文件下载") @Operation(summary = "用例管理-功能用例-附件/副文本(原图/文件)-文件下载")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ) @RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public ResponseEntity<byte[]> download(@Validated @RequestBody FunctionalCaseFileRequest request) throws Exception { public ResponseEntity<byte[]> download(@Validated @RequestBody FunctionalCaseFileRequest request) throws Exception {

View File

@ -27,6 +27,9 @@ public class FunctionalCaseAttachmentDTO implements Serializable {
@Schema(description = "文件大小") @Schema(description = "文件大小")
private Long size; private Long size;
@Schema(description = "文件来源")
private String fileSource;
@Schema(description = "是否本地") @Schema(description = "是否本地")
private Boolean local; private Boolean local;

View File

@ -52,7 +52,6 @@ public class FunctionalCaseAddRequest implements Serializable {
@Schema(description = "是否公共用例库") @Schema(description = "是否公共用例库")
private String publicCase; private String publicCase;
@Schema(description = "模块id", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "模块id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{functional_case.module_id.not_blank}") @NotBlank(message = "{functional_case.module_id.not_blank}")
private String moduleId; private String moduleId;
@ -63,14 +62,15 @@ public class FunctionalCaseAddRequest implements Serializable {
@Schema(description = "标签") @Schema(description = "标签")
private List<String> tags; private List<String> tags;
@Schema(description = "自定义字段集合") @Schema(description = "自定义字段集合")
private Map<String, Object> customFields; private Map<String, Object> customFields;
@Schema(description = "附件关联文件ID集合")
@Schema(description = "关联文件ID集合")
private List<String> relateFileMetaIds; private List<String> relateFileMetaIds;
@Schema(description = "攻能用例详情(前置条件/步骤描述/预期结果/备注上传的文件id集合")
private List<String> caseDetailFileIds;
@Schema(description = "评审id") @Schema(description = "评审id")
private String reviewId; private String reviewId;

View File

@ -16,7 +16,7 @@ public class FunctionalCaseEditRequest extends FunctionalCaseAddRequest {
@NotBlank(message = "{functional_case.id.not_blank}") @NotBlank(message = "{functional_case.id.not_blank}")
private String id; private String id;
@Schema(description = "删除本地上传的文件id") @Schema(description = "删除本地上传(副文本里)的文件id")
private List<String> deleteFileMetaIds; private List<String> deleteFileMetaIds;
@Schema(description = "取消关联的文件id") @Schema(description = "取消关联的文件id")

View File

@ -2,6 +2,10 @@ package io.metersphere.functional.service;
import io.metersphere.functional.domain.*; import io.metersphere.functional.domain.*;
import io.metersphere.functional.mapper.*; import io.metersphere.functional.mapper.*;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.file.FileCenter;
import io.metersphere.sdk.file.FileRequest;
import io.metersphere.sdk.util.LogUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -26,7 +30,13 @@ public class DeleteFunctionalCaseService {
@Resource @Resource
private FunctionalCaseCommentMapper functionalCaseCommentMapper; private FunctionalCaseCommentMapper functionalCaseCommentMapper;
@Resource @Resource
private FunctionalCaseDemandMapper functionalCaseDemandMapper;
@Resource
private CaseReviewHistoryMapper caseReviewHistoryMapper; private CaseReviewHistoryMapper caseReviewHistoryMapper;
@Resource
private CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper;
@Resource
private FunctionalCaseAttachmentMapper functionalCaseAttachmentMapper;
public void deleteFunctionalCaseResource(List<String> ids, String projectId) { public void deleteFunctionalCaseResource(List<String> ids, String projectId) {
@ -35,11 +45,36 @@ public class DeleteFunctionalCaseService {
FunctionalCaseTestExample caseTestExample = new FunctionalCaseTestExample(); FunctionalCaseTestExample caseTestExample = new FunctionalCaseTestExample();
caseTestExample.createCriteria().andCaseIdIn(ids); caseTestExample.createCriteria().andCaseIdIn(ids);
functionalCaseTestMapper.deleteByExample(caseTestExample); functionalCaseTestMapper.deleteByExample(caseTestExample);
//3.删除关联需求
FunctionalCaseDemandExample functionalCaseDemandExample = new FunctionalCaseDemandExample();
functionalCaseDemandExample.createCriteria().andCaseIdIn(ids);
functionalCaseDemandMapper.deleteByExample(functionalCaseDemandExample);
//5.删除关联评审
CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseExample.createCriteria().andCaseIdIn(ids);
caseReviewFunctionalCaseMapper.deleteByExample(caseReviewFunctionalCaseExample);
//8.评论 //8.评论
FunctionalCaseCommentExample functionalCaseCommentExample = new FunctionalCaseCommentExample(); FunctionalCaseCommentExample functionalCaseCommentExample = new FunctionalCaseCommentExample();
functionalCaseCommentExample.createCriteria().andCaseIdIn(ids); functionalCaseCommentExample.createCriteria().andCaseIdIn(ids);
functionalCaseCommentMapper.deleteByExample(functionalCaseCommentExample); functionalCaseCommentMapper.deleteByExample(functionalCaseCommentExample);
//9.附件 todo 删除关联关系 //9.附件 todo 删除关联关系
FunctionalCaseAttachmentExample functionalCaseAttachmentExample = new FunctionalCaseAttachmentExample();
functionalCaseAttachmentExample.createCriteria().andCaseIdIn(ids);
functionalCaseAttachmentMapper.deleteByExample(functionalCaseAttachmentExample);
//删除文件
FileRequest request = new FileRequest();
// 删除文件所在目录
for (String id : ids) {
request.setFolder(DefaultRepositoryDir.getFunctionalCaseDir(projectId, id));
try {
FileCenter.getDefaultRepository().deleteFolder(request);
request.setFolder(DefaultRepositoryDir.getFunctionalCasePreviewDir(projectId, id));
FileCenter.getDefaultRepository().deleteFolder(request);
} catch (Exception e) {
LogUtils.error("彻底删除功能用例,文件删除失败",e);
}
}
//10.自定义字段 //10.自定义字段
FunctionalCaseCustomFieldExample fieldExample = new FunctionalCaseCustomFieldExample(); FunctionalCaseCustomFieldExample fieldExample = new FunctionalCaseCustomFieldExample();
fieldExample.createCriteria().andCaseIdIn(ids); fieldExample.createCriteria().andCaseIdIn(ids);

View File

@ -177,6 +177,15 @@ public class FunctionalCaseAttachmentService {
fileRequest.setStorage(StorageType.MINIO.name()); fileRequest.setStorage(StorageType.MINIO.name());
try { try {
fileService.deleteFile(fileRequest); fileService.deleteFile(fileRequest);
String fileType = StringUtils.substring(file.getFileName(), file.getFileName().lastIndexOf(".") + 1);
if (TempFileUtils.isImage(fileType)) {
//删除预览图
fileRequest = new FileRequest();
fileRequest.setFileName(file.getFileName());
fileRequest.setFolder(DefaultRepositoryDir.getFunctionalCasePreviewDir(projectId, caseId) + "/" + file.getFileId());
fileRequest.setStorage(StorageType.MINIO.name());
fileService.deleteFile(fileRequest);
}
} catch (Exception e) { } catch (Exception e) {
throw new MSException("delete file error"); throw new MSException("delete file error");
} }
@ -271,6 +280,36 @@ public class FunctionalCaseAttachmentService {
return ResponseEntity.ok().contentType(MediaType.parseMediaType("application/octet-stream")).body(null); return ResponseEntity.ok().contentType(MediaType.parseMediaType("application/octet-stream")).body(null);
} }
/**
* 预览压缩图片
*
* @param request request
*/
public ResponseEntity<byte[]> downloadPreviewCompressedImg(FunctionalCaseFileRequest request) {
FunctionalCaseAttachmentExample example = new FunctionalCaseAttachmentExample();
example.createCriteria().andFileIdEqualTo(request.getFileId()).andCaseIdEqualTo(request.getCaseId()).andFileSourceEqualTo(CaseFileSourceType.CASE_DETAIL.toString());
List<FunctionalCaseAttachment> caseAttachments = functionalCaseAttachmentMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(caseAttachments)) {
FunctionalCaseAttachment attachment = caseAttachments.get(0);
FileRequest fileRequest = new FileRequest();
fileRequest.setFileName(attachment.getFileName());
fileRequest.setFolder(DefaultRepositoryDir.getFunctionalCasePreviewDir(request.getProjectId(), request.getCaseId()) + "/" + attachment.getFileId());
fileRequest.setStorage(StorageType.MINIO.name());
byte[] bytes = null;
try {
bytes = fileService.download(fileRequest);
} catch (Exception e) {
throw new MSException("get file error");
}
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + attachment.getFileName() + "\"")
.body(bytes);
}
return ResponseEntity.ok().contentType(MediaType.parseMediaType("application/octet-stream")).body(null);
}
public byte[] getFileByte(FunctionalCaseFileRequest request) { public byte[] getFileByte(FunctionalCaseFileRequest request) {
FunctionalCaseAttachmentExample example = new FunctionalCaseAttachmentExample(); FunctionalCaseAttachmentExample example = new FunctionalCaseAttachmentExample();
example.createCriteria().andFileIdEqualTo(request.getFileId()).andCaseIdEqualTo(request.getCaseId()); example.createCriteria().andFileIdEqualTo(request.getFileId()).andCaseIdEqualTo(request.getCaseId());

View File

@ -1,6 +1,7 @@
package io.metersphere.functional.service; package io.metersphere.functional.service;
import io.metersphere.functional.constants.CaseEvent; import io.metersphere.functional.constants.CaseEvent;
import io.metersphere.functional.constants.CaseFileSourceType;
import io.metersphere.functional.constants.FunctionalCaseReviewStatus; import io.metersphere.functional.constants.FunctionalCaseReviewStatus;
import io.metersphere.functional.domain.*; import io.metersphere.functional.domain.*;
import io.metersphere.functional.dto.*; import io.metersphere.functional.dto.*;
@ -111,6 +112,8 @@ public class FunctionalCaseService {
//上传文件 //上传文件
functionalCaseAttachmentService.uploadFile(request.getProjectId(), caseId, files, true, userId); functionalCaseAttachmentService.uploadFile(request.getProjectId(), caseId, files, true, userId);
functionalCaseAttachmentService.uploadMinioFile(caseId,request.getProjectId(),request.getCaseDetailFileIds(),userId, CaseFileSourceType.CASE_DETAIL.toString());
//关联附件 //关联附件
if (CollectionUtils.isNotEmpty(request.getRelateFileMetaIds())) { if (CollectionUtils.isNotEmpty(request.getRelateFileMetaIds())) {
functionalCaseAttachmentService.association(request.getRelateFileMetaIds(), caseId, userId, ADD_FUNCTIONAL_CASE_FILE_LOG_URL, request.getProjectId()); functionalCaseAttachmentService.association(request.getRelateFileMetaIds(), caseId, userId, ADD_FUNCTIONAL_CASE_FILE_LOG_URL, request.getProjectId());
@ -316,6 +319,9 @@ public class FunctionalCaseService {
//上传新文件 //上传新文件
functionalCaseAttachmentService.uploadFile(request.getProjectId(), request.getId(), files, true, userId); functionalCaseAttachmentService.uploadFile(request.getProjectId(), request.getId(), files, true, userId);
//上传副文本文件
functionalCaseAttachmentService.uploadMinioFile(request.getId(),request.getProjectId(),request.getCaseDetailFileIds(),userId,CaseFileSourceType.CASE_DETAIL.toString());
//关联新附件 //关联新附件
if (CollectionUtils.isNotEmpty(request.getRelateFileMetaIds())) { if (CollectionUtils.isNotEmpty(request.getRelateFileMetaIds())) {
functionalCaseAttachmentService.association(request.getRelateFileMetaIds(), request.getId(), userId, UPDATE_FUNCTIONAL_CASE_FILE_LOG_URL, request.getProjectId()); functionalCaseAttachmentService.association(request.getRelateFileMetaIds(), request.getId(), userId, UPDATE_FUNCTIONAL_CASE_FILE_LOG_URL, request.getProjectId());
@ -324,7 +330,6 @@ public class FunctionalCaseService {
//处理评审状态 //处理评审状态
handleReviewStatus(request, functionalCaseBlob, checked.getName()); handleReviewStatus(request, functionalCaseBlob, checked.getName());
return functionalCase; return functionalCase;
} }

View File

@ -60,6 +60,7 @@ public class FunctionalCaseAttachmentControllerTests extends BaseTest {
public static final String ATTACHMENT_PAGE_URL = "/attachment/page"; public static final String ATTACHMENT_PAGE_URL = "/attachment/page";
public static final String ATTACHMENT_PREVIEW_URL = "/attachment/preview"; public static final String ATTACHMENT_PREVIEW_URL = "/attachment/preview";
public static final String ATTACHMENT_PREVIEW_COMPRESSED_URL = "/attachment/preview/compressed";
public static final String ATTACHMENT_DOWNLOAD_URL = "/attachment/download"; public static final String ATTACHMENT_DOWNLOAD_URL = "/attachment/download";
public static final String ATTACHMENT_CHECK_UPDATE_URL = "/attachment/check-update"; 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_UPDATE_URL = "/attachment/update/";
@ -247,6 +248,13 @@ public class FunctionalCaseAttachmentControllerTests extends BaseTest {
file = getNoNameMockMultipartFile(); file = getNoNameMockMultipartFile();
doUploadTempFileFalse(file); doUploadTempFileFalse(file);
functionalCaseAttachmentService.uploadMinioFile("TEST_FUNCTIONAL_CASE_ATTACHMENT_ID_1","WX_TEST_PROJECT_ID", List.of(fileId),"admin", CaseFileSourceType.CASE_COMMENT.toString()); functionalCaseAttachmentService.uploadMinioFile("TEST_FUNCTIONAL_CASE_ATTACHMENT_ID_1","WX_TEST_PROJECT_ID", List.of(fileId),"admin", CaseFileSourceType.CASE_COMMENT.toString());
FunctionalCaseFileRequest request = new FunctionalCaseFileRequest();
request.setProjectId("WX_TEST_PROJECT_ID");
request.setLocal(true);
request.setFileId("fileId");
request.setCaseId("TEST_FUNCTIONAL_CASE_ATTACHMENT_ID_1");
MvcResult mvcResult = this.downloadFile(ATTACHMENT_PREVIEW_COMPRESSED_URL, request);
Assertions.assertNotNull(mvcResult);
FunctionalCaseAttachmentExample functionalCaseAttachmentExample = new FunctionalCaseAttachmentExample(); FunctionalCaseAttachmentExample functionalCaseAttachmentExample = new FunctionalCaseAttachmentExample();
functionalCaseAttachmentExample.createCriteria().andCaseIdEqualTo("TEST_FUNCTIONAL_CASE_ATTACHMENT_ID_1").andFileIdEqualTo(fileId).andFileSourceEqualTo(CaseFileSourceType.CASE_COMMENT.toString()); functionalCaseAttachmentExample.createCriteria().andCaseIdEqualTo("TEST_FUNCTIONAL_CASE_ATTACHMENT_ID_1").andFileIdEqualTo(fileId).andFileSourceEqualTo(CaseFileSourceType.CASE_COMMENT.toString());
List<FunctionalCaseAttachment> functionalCaseAttachments = functionalCaseAttachmentMapper.selectByExample(functionalCaseAttachmentExample); List<FunctionalCaseAttachment> functionalCaseAttachments = functionalCaseAttachmentMapper.selectByExample(functionalCaseAttachmentExample);