feat(用例评审): 用例评审评论副文本文件上传

This commit is contained in:
guoyuqi 2024-01-12 18:33:55 +08:00 committed by 刘瑞斌
parent 9da60bcca2
commit 2438618c0c
13 changed files with 266 additions and 27 deletions

View File

@ -1,10 +1,7 @@
package io.metersphere.functional.controller; package io.metersphere.functional.controller;
import io.metersphere.functional.domain.FunctionalCaseAttachment; import io.metersphere.functional.domain.FunctionalCaseAttachment;
import io.metersphere.functional.request.AttachmentTransferRequest; import io.metersphere.functional.request.*;
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.functional.service.FunctionalCaseAttachmentService;
import io.metersphere.project.dto.filemanagement.FileAssociationDTO; import io.metersphere.project.dto.filemanagement.FileAssociationDTO;
import io.metersphere.project.dto.filemanagement.FileLogRecord; import io.metersphere.project.dto.filemanagement.FileLogRecord;
@ -13,7 +10,6 @@ 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;
@ -26,6 +22,7 @@ import io.metersphere.system.utils.SessionUtils;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -55,9 +52,6 @@ public class FunctionalCaseAttachmentController {
@Resource @Resource
private FileModuleService fileModuleService; private FileModuleService fileModuleService;
@Resource
private PermissionCheckService permissionCheckService;
@PostMapping("/page") @PostMapping("/page")
@Operation(summary = "用例管理-功能用例-附件-关联文件列表分页接口") @Operation(summary = "用例管理-功能用例-附件-关联文件列表分页接口")
@ -87,7 +81,7 @@ public class FunctionalCaseAttachmentController {
@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[]> compressedImg(@Validated @RequestBody FunctionalCaseFileRequest request) throws Exception { public ResponseEntity<byte[]> compressedImg(@Validated @RequestBody FunctionalCaseSourceFileRequest request) throws Exception {
return functionalCaseAttachmentService.downloadPreviewCompressedImg(request); return functionalCaseAttachmentService.downloadPreviewCompressedImg(request);
} }
@ -186,7 +180,7 @@ public class FunctionalCaseAttachmentController {
@PostMapping("/upload/temp/file") @PostMapping("/upload/temp/file")
@Operation(summary = "用例管理-功能用例-上传副文本里所需的文件资源并返回文件ID") @Operation(summary = "用例管理-功能用例-上传副文本里所需的文件资源并返回文件ID")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_COMMENT) @RequiresPermissions(logical = Logical.OR, value = {PermissionConstants.FUNCTIONAL_CASE_READ_ADD, PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE, PermissionConstants.FUNCTIONAL_CASE_READ_COMMENT})
public String upload(@RequestParam("file") MultipartFile file) throws Exception { public String upload(@RequestParam("file") MultipartFile file) throws Exception {
return functionalCaseAttachmentService.uploadTemp(file); return functionalCaseAttachmentService.uploadTemp(file);
} }

View File

@ -37,7 +37,7 @@ public class FunctionalCaseReviewController {
} }
@GetMapping("/comment/{caseId}") @GetMapping("/comment/{caseId}")
@Operation(summary = "用例管理-功能用例-评审-评论") @Operation(summary = "用例管理-功能用例-评审-获取评审评论历史")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ) @RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
@CheckOwner(resourceId = "#caseId", resourceType = "functional_case") @CheckOwner(resourceId = "#caseId", resourceType = "functional_case")
public List<CaseReviewHistoryDTO> getCaseReviewHistory(@PathVariable String caseId) { public List<CaseReviewHistoryDTO> getCaseReviewHistory(@PathVariable String caseId) {

View File

@ -1,7 +1,10 @@
package io.metersphere.functional.controller; package io.metersphere.functional.controller;
import io.metersphere.functional.dto.CaseReviewHistoryDTO; import io.metersphere.functional.dto.CaseReviewHistoryDTO;
import io.metersphere.functional.request.FunctionalCaseFileRequest;
import io.metersphere.functional.request.FunctionalCaseSourceFileRequest;
import io.metersphere.functional.request.ReviewFunctionalCaseRequest; import io.metersphere.functional.request.ReviewFunctionalCaseRequest;
import io.metersphere.functional.service.FunctionalCaseAttachmentService;
import io.metersphere.functional.service.ReviewFunctionalCaseService; import io.metersphere.functional.service.ReviewFunctionalCaseService;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.security.CheckOwner; import io.metersphere.system.security.CheckOwner;
@ -10,8 +13,10 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
@ -23,6 +28,9 @@ public class ReviewFunctionalCaseController {
@Resource @Resource
private ReviewFunctionalCaseService reviewFunctionalCaseService; private ReviewFunctionalCaseService reviewFunctionalCaseService;
@Resource
private FunctionalCaseAttachmentService functionalCaseAttachmentService;
@PostMapping("/save") @PostMapping("/save")
@Operation(summary = "用例管理-用例评审-评审功能用例-提交评审") @Operation(summary = "用例管理-用例评审-评审功能用例-提交评审")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_REVIEW) @RequiresPermissions(PermissionConstants.CASE_REVIEW_REVIEW)
@ -38,5 +46,36 @@ public class ReviewFunctionalCaseController {
return reviewFunctionalCaseService.getCaseReviewHistoryList(reviewId, caseId); return reviewFunctionalCaseService.getCaseReviewHistoryList(reviewId, caseId);
} }
@PostMapping("/upload/temp/file")
@Operation(summary = "用例管理-用例评审-上传副文本里所需的文件资源并返回文件ID")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_REVIEW)
public String upload(@RequestParam("file") MultipartFile file) throws Exception {
return functionalCaseAttachmentService.uploadTemp(file);
}
@PostMapping("/preview")
@Operation(summary = "用例管理-用例评审-附件/副文本(原图/文件)-文件预览")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_REVIEW)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public ResponseEntity<byte[]> preview(@Validated @RequestBody FunctionalCaseFileRequest request) throws Exception {
return functionalCaseAttachmentService.downloadPreviewImgById(request);
}
@PostMapping(value = "/preview/compressed")
@Operation(summary = "用例管理-功能用例-显示详情(副文本)图片缩略图")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_REVIEW)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public ResponseEntity<byte[]> compressedImg(@Validated @RequestBody FunctionalCaseSourceFileRequest request) throws Exception {
return functionalCaseAttachmentService.downloadPreviewCompressedImg(request);
}
@PostMapping("/download")
@Operation(summary = "用例管理-功能用例-附件/副文本(原图/文件)-文件下载")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_REVIEW)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
public ResponseEntity<byte[]> download(@Validated @RequestBody FunctionalCaseFileRequest request) throws Exception {
return functionalCaseAttachmentService.downloadPreviewImgById(request);
}
} }

View File

@ -27,7 +27,7 @@ public class FunctionalCaseAttachmentDTO implements Serializable {
@Schema(description = "文件大小") @Schema(description = "文件大小")
private Long size; private Long size;
@Schema(description = "文件来源") @Schema(description = "文件来源:附件(ATTACHMENT)/功能用例详情(CASE_DETAIL)/用例评论(CASE_COMMENT)/评审评论(REVIEW_COMMENT)")
private String fileSource; private String fileSource;
@Schema(description = "是否本地") @Schema(description = "是否本地")

View File

@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import java.util.List;
@Data @Data
public class BatchReviewFunctionalCaseRequest extends BaseReviewCaseBatchRequest{ public class BatchReviewFunctionalCaseRequest extends BaseReviewCaseBatchRequest{
@ -21,4 +23,7 @@ public class BatchReviewFunctionalCaseRequest extends BaseReviewCaseBatchRequest
@Schema(description = "评论@的人的Id, 多个以';'隔开") @Schema(description = "评论@的人的Id, 多个以';'隔开")
private String notifier; private String notifier;
@Schema(description = "用例评审评论副文本的文件id集合")
private List<String> reviewCommentFileIds;
} }

View File

@ -68,7 +68,7 @@ public class FunctionalCaseAddRequest implements Serializable {
@Schema(description = "附件关联文件ID集合") @Schema(description = "附件关联文件ID集合")
private List<String> relateFileMetaIds; private List<String> relateFileMetaIds;
@Schema(description = "能用例详情(前置条件/步骤描述/预期结果/备注上传的文件id集合") @Schema(description = "能用例详情(前置条件/步骤描述/预期结果/备注上传的文件id集合")
private List<String> caseDetailFileIds; private List<String> caseDetailFileIds;
@Schema(description = "评审id") @Schema(description = "评审id")

View File

@ -0,0 +1,35 @@
package io.metersphere.functional.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author wx
*/
@Data
public class FunctionalCaseSourceFileRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "项目id",requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{case_review.project_id.not_blank}")
private String projectId;
@Schema(description = "用例id",requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{case_review_functional_case.case_id.not_blank}")
private String caseId;
@Schema(description = "文件来源:附件(ATTACHMENT)/功能用例详情(CASE_DETAIL)/用例评论(CASE_COMMENT)/评审评论(REVIEW_COMMENT)")
@NotBlank(message = "{functional_case_source_file_request.file_source.not_blank}")
private String fileSource;
@Schema(description = "是否本地",requiredMode = Schema.RequiredMode.REQUIRED)
private Boolean local;
}

View File

@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import java.util.List;
@Data @Data
public class ReviewFunctionalCaseRequest { public class ReviewFunctionalCaseRequest {
@ -32,4 +34,7 @@ public class ReviewFunctionalCaseRequest {
@Schema(description = "评论@的人的Id, 多个以';'隔开") @Schema(description = "评论@的人的Id, 多个以';'隔开")
private String notifier; private String notifier;
@Schema(description = "用例评审评论副文本的文件id集合")
private List<String> reviewCommentFileIds;
} }

View File

@ -2,6 +2,7 @@ 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.CaseReviewPassRule; import io.metersphere.functional.constants.CaseReviewPassRule;
import io.metersphere.functional.constants.FunctionalCaseReviewStatus; import io.metersphere.functional.constants.FunctionalCaseReviewStatus;
import io.metersphere.functional.domain.*; import io.metersphere.functional.domain.*;
@ -75,6 +76,8 @@ public class CaseReviewFunctionalCaseService extends ModuleTreeService {
private BaseCaseProvider provider; private BaseCaseProvider provider;
@Resource @Resource
private ReviewSendNoticeService reviewSendNoticeService; private ReviewSendNoticeService reviewSendNoticeService;
@Resource
private FunctionalCaseAttachmentService functionalCaseAttachmentService;
private static final String CASE_MODULE_COUNT_ALL = "all"; private static final String CASE_MODULE_COUNT_ALL = "all";
@ -275,6 +278,11 @@ public class CaseReviewFunctionalCaseService extends ModuleTreeService {
List<CaseReviewFunctionalCaseUser> caseReviewFunctionalCaseUsers = caseReviewFunctionalCaseUserMapper.selectByExample(caseReviewFunctionalCaseUserExample); List<CaseReviewFunctionalCaseUser> caseReviewFunctionalCaseUsers = caseReviewFunctionalCaseUserMapper.selectByExample(caseReviewFunctionalCaseUserExample);
Map<String, List<CaseReviewFunctionalCaseUser>> reviewerMap = caseReviewFunctionalCaseUsers.stream().collect(Collectors.groupingBy(CaseReviewFunctionalCaseUser::getCaseId, Collectors.toList())); Map<String, List<CaseReviewFunctionalCaseUser>> reviewerMap = caseReviewFunctionalCaseUsers.stream().collect(Collectors.groupingBy(CaseReviewFunctionalCaseUser::getCaseId, Collectors.toList()));
FunctionalCaseExample functionalCaseExample = new FunctionalCaseExample();
functionalCaseExample.createCriteria().andIdIn(caseIds);
List<FunctionalCase> functionalCases = functionalCaseMapper.selectByExample(functionalCaseExample);
Map<String, String> caseProjectIdMap = functionalCases.stream().collect(Collectors.toMap(FunctionalCase::getId, FunctionalCase::getProjectId));
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
CaseReviewHistoryMapper caseReviewHistoryMapper = sqlSession.getMapper(CaseReviewHistoryMapper.class); CaseReviewHistoryMapper caseReviewHistoryMapper = sqlSession.getMapper(CaseReviewHistoryMapper.class);
CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper = sqlSession.getMapper(CaseReviewFunctionalCaseMapper.class); CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper = sqlSession.getMapper(CaseReviewFunctionalCaseMapper.class);
@ -307,6 +315,8 @@ public class CaseReviewFunctionalCaseService extends ModuleTreeService {
if (StringUtils.equalsIgnoreCase(request.getStatus(), FunctionalCaseReviewStatus.PASS.toString())) { if (StringUtils.equalsIgnoreCase(request.getStatus(), FunctionalCaseReviewStatus.PASS.toString())) {
reviewSendNoticeService.sendNoticeCase(new ArrayList<>(), userId, caseId, NoticeConstants.TaskType.FUNCTIONAL_CASE_TASK, NoticeConstants.Event.REVIEW_PASSED, reviewId); reviewSendNoticeService.sendNoticeCase(new ArrayList<>(), userId, caseId, NoticeConstants.TaskType.FUNCTIONAL_CASE_TASK, NoticeConstants.Event.REVIEW_PASSED, reviewId);
} }
functionalCaseAttachmentService.uploadMinioFile(caseId,caseProjectIdMap.get(caseId),request.getReviewCommentFileIds(),userId, CaseFileSourceType.REVIEW_COMMENT.toString());
} }
sqlSession.flushStatements(); sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);

View File

@ -11,6 +11,7 @@ import io.metersphere.functional.mapper.FunctionalCaseAttachmentMapper;
import io.metersphere.functional.request.FunctionalCaseAssociationFileRequest; import io.metersphere.functional.request.FunctionalCaseAssociationFileRequest;
import io.metersphere.functional.request.FunctionalCaseDeleteFileRequest; import io.metersphere.functional.request.FunctionalCaseDeleteFileRequest;
import io.metersphere.functional.request.FunctionalCaseFileRequest; import io.metersphere.functional.request.FunctionalCaseFileRequest;
import io.metersphere.functional.request.FunctionalCaseSourceFileRequest;
import io.metersphere.project.domain.FileAssociation; import io.metersphere.project.domain.FileAssociation;
import io.metersphere.project.dto.filemanagement.FileInfo; import io.metersphere.project.dto.filemanagement.FileInfo;
import io.metersphere.project.dto.filemanagement.FileLogRecord; import io.metersphere.project.dto.filemanagement.FileLogRecord;
@ -286,9 +287,9 @@ public class FunctionalCaseAttachmentService {
* *
* @param request request * @param request request
*/ */
public ResponseEntity<byte[]> downloadPreviewCompressedImg(FunctionalCaseFileRequest request) { public ResponseEntity<byte[]> downloadPreviewCompressedImg(FunctionalCaseSourceFileRequest request) {
FunctionalCaseAttachmentExample example = new FunctionalCaseAttachmentExample(); FunctionalCaseAttachmentExample example = new FunctionalCaseAttachmentExample();
example.createCriteria().andFileIdEqualTo(request.getFileId()).andCaseIdEqualTo(request.getCaseId()).andFileSourceEqualTo(CaseFileSourceType.CASE_DETAIL.toString()); example.createCriteria().andCaseIdEqualTo(request.getCaseId()).andFileSourceEqualTo(CaseFileSourceType.CASE_DETAIL.toString());
List<FunctionalCaseAttachment> caseAttachments = functionalCaseAttachmentMapper.selectByExample(example); List<FunctionalCaseAttachment> caseAttachments = functionalCaseAttachmentMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(caseAttachments)) { if (CollectionUtils.isNotEmpty(caseAttachments)) {
FunctionalCaseAttachment attachment = caseAttachments.get(0); FunctionalCaseAttachment attachment = caseAttachments.get(0);

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.CaseReviewPassRule; import io.metersphere.functional.constants.CaseReviewPassRule;
import io.metersphere.functional.constants.FunctionalCaseReviewStatus; import io.metersphere.functional.constants.FunctionalCaseReviewStatus;
import io.metersphere.functional.domain.CaseReviewFunctionalCaseUserExample; import io.metersphere.functional.domain.CaseReviewFunctionalCaseUserExample;
@ -43,6 +44,8 @@ public class ReviewFunctionalCaseService {
private ReviewSendNoticeService reviewSendNoticeService; private ReviewSendNoticeService reviewSendNoticeService;
@Resource @Resource
private BaseCaseProvider provider; private BaseCaseProvider provider;
@Resource
private FunctionalCaseAttachmentService functionalCaseAttachmentService;
/** /**
* 评审功能用例 * 评审功能用例
@ -69,6 +72,9 @@ public class ReviewFunctionalCaseService {
extCaseReviewFunctionalCaseMapper.updateStatus(caseId, reviewId, functionalCaseStatus); extCaseReviewFunctionalCaseMapper.updateStatus(caseId, reviewId, functionalCaseStatus);
caseReviewHistoryMapper.insert(caseReviewHistory); caseReviewHistoryMapper.insert(caseReviewHistory);
//保存副文本评论附件
functionalCaseAttachmentService.uploadMinioFile(caseId,request.getProjectId(),request.getReviewCommentFileIds(),userId, CaseFileSourceType.REVIEW_COMMENT.toString());
//检查是否有@发送@通知 //检查是否有@发送@通知
if (StringUtils.isNotBlank(request.getNotifier())) { if (StringUtils.isNotBlank(request.getNotifier())) {
List<String> relatedUsers = Arrays.asList(request.getNotifier().split(";")); List<String> relatedUsers = Arrays.asList(request.getNotifier().split(";"));

View File

@ -4,10 +4,7 @@ import io.metersphere.functional.constants.CaseFileSourceType;
import io.metersphere.functional.domain.FunctionalCaseAttachment; import io.metersphere.functional.domain.FunctionalCaseAttachment;
import io.metersphere.functional.domain.FunctionalCaseAttachmentExample; import io.metersphere.functional.domain.FunctionalCaseAttachmentExample;
import io.metersphere.functional.mapper.FunctionalCaseAttachmentMapper; import io.metersphere.functional.mapper.FunctionalCaseAttachmentMapper;
import io.metersphere.functional.request.AttachmentTransferRequest; import io.metersphere.functional.request.*;
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.functional.service.FunctionalCaseAttachmentService;
import io.metersphere.functional.utils.FileBaseUtils; import io.metersphere.functional.utils.FileBaseUtils;
import io.metersphere.project.dto.filemanagement.request.FileMetadataTableRequest; import io.metersphere.project.dto.filemanagement.request.FileMetadataTableRequest;
@ -248,10 +245,10 @@ 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_DETAIL.toString()); functionalCaseAttachmentService.uploadMinioFile("TEST_FUNCTIONAL_CASE_ATTACHMENT_ID_1","WX_TEST_PROJECT_ID", List.of(fileId),"admin", CaseFileSourceType.CASE_DETAIL.toString());
FunctionalCaseFileRequest request = new FunctionalCaseFileRequest(); FunctionalCaseSourceFileRequest request = new FunctionalCaseSourceFileRequest();
request.setProjectId("WX_TEST_PROJECT_ID"); request.setProjectId("WX_TEST_PROJECT_ID");
request.setLocal(true); request.setLocal(true);
request.setFileId(fileId); request.setFileSource(CaseFileSourceType.CASE_DETAIL.toString());
request.setCaseId("TEST_FUNCTIONAL_CASE_ATTACHMENT_ID_1"); request.setCaseId("TEST_FUNCTIONAL_CASE_ATTACHMENT_ID_1");
MvcResult mvcResult = this.downloadFile(ATTACHMENT_PREVIEW_COMPRESSED_URL, request); MvcResult mvcResult = this.downloadFile(ATTACHMENT_PREVIEW_COMPRESSED_URL, request);
Assertions.assertNotNull(mvcResult); Assertions.assertNotNull(mvcResult);

View File

@ -1,5 +1,6 @@
package io.metersphere.functional.controller; package io.metersphere.functional.controller;
import io.metersphere.functional.constants.CaseFileSourceType;
import io.metersphere.functional.constants.CaseReviewPassRule; import io.metersphere.functional.constants.CaseReviewPassRule;
import io.metersphere.functional.constants.CaseReviewStatus; import io.metersphere.functional.constants.CaseReviewStatus;
import io.metersphere.functional.constants.FunctionalCaseReviewStatus; import io.metersphere.functional.constants.FunctionalCaseReviewStatus;
@ -8,27 +9,36 @@ import io.metersphere.functional.dto.CaseReviewHistoryDTO;
import io.metersphere.functional.mapper.CaseReviewFunctionalCaseMapper; import io.metersphere.functional.mapper.CaseReviewFunctionalCaseMapper;
import io.metersphere.functional.mapper.CaseReviewHistoryMapper; import io.metersphere.functional.mapper.CaseReviewHistoryMapper;
import io.metersphere.functional.mapper.CaseReviewMapper; import io.metersphere.functional.mapper.CaseReviewMapper;
import io.metersphere.functional.request.BaseAssociateCaseRequest; import io.metersphere.functional.mapper.FunctionalCaseAttachmentMapper;
import io.metersphere.functional.request.CaseReviewRequest; import io.metersphere.functional.request.*;
import io.metersphere.functional.request.ReviewFunctionalCaseRequest; import io.metersphere.functional.service.FunctionalCaseAttachmentService;
import io.metersphere.functional.utils.FileBaseUtils;
import io.metersphere.project.dto.filemanagement.request.FileUploadRequest;
import io.metersphere.project.service.FileMetadataService;
import io.metersphere.project.service.FileService;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.SessionConstants; import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.constants.StorageType;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.file.FileRequest;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest; import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder; import io.metersphere.system.controller.handler.ResultHolder;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -44,13 +54,26 @@ public class ReviewFunctionalCaseControllerTests extends BaseTest {
private static final String ADD_CASE_REVIEW = "/case/review/add"; private static final String ADD_CASE_REVIEW = "/case/review/add";
private static final String REVIEW_LIST = "/review/functional/case/get/list/"; private static final String REVIEW_LIST = "/review/functional/case/get/list/";
public static final String ATTACHMENT_PREVIEW_COMPRESSED_URL = "/review/functional/case/preview/compressed";
public static final String ATTACHMENT_DOWNLOAD_URL = "/review/functional/case/download";
public static final String UPLOAD_TEMP = "/review/functional/case/upload/temp/file";
public static final String ATTACHMENT_PREVIEW_URL = "/review/functional/case/preview";
@Resource @Resource
private CaseReviewMapper caseReviewMapper; private CaseReviewMapper caseReviewMapper;
@Resource @Resource
private CaseReviewHistoryMapper caseReviewHistoryMapper; private CaseReviewHistoryMapper caseReviewHistoryMapper;
@Resource @Resource
private CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper; private CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper;
@Resource
private FileService fileService;
@Resource
private FileMetadataService fileMetadataService;
@Resource
private FunctionalCaseAttachmentService functionalCaseAttachmentService;
@Resource
private FunctionalCaseAttachmentMapper functionalCaseAttachmentMapper;
@Test @Test
@Order(0) @Order(0)
@ -250,6 +273,74 @@ public class ReviewFunctionalCaseControllerTests extends BaseTest {
System.out.println(JSON.toJSONString(gyqReviewCaseTest)); System.out.println(JSON.toJSONString(gyqReviewCaseTest));
} }
@Test
@Order(5)
public void testAttachmentPreview() throws Exception {
FunctionalCaseFileRequest request = new FunctionalCaseFileRequest();
request.setProjectId("project-review-case-test");
request.setLocal(true);
request.setFileId("TEST_REVIEW_COMMENT_FILE_ID");
request.setCaseId("gyqReviewCaseTest");
uploadLocalFile();
this.downloadFile(ATTACHMENT_PREVIEW_URL, request);
//覆盖controller
request.setLocal(false);
String fileId = uploadFile();
request.setFileId(fileId);
request.setProjectId(DEFAULT_PROJECT_ID);
this.downloadFile(ATTACHMENT_PREVIEW_URL, request);
//增加覆盖率
request.setLocal(true);
request.setProjectId("123213");
request.setFileId("123123");
request.setCaseId("123123");
this.downloadFile(ATTACHMENT_PREVIEW_URL, request);
}
@Test
@Order(6)
public void testUploadTemp() throws Exception {
//覆盖controller方法
MockMultipartFile file = getMockMultipartFile();
String fileId = doUploadTempFile(file);
Assertions.assertTrue(StringUtils.isNotBlank(fileId));
file = getNoNameMockMultipartFile();
doUploadTempFileFalse(file);
functionalCaseAttachmentService.uploadMinioFile("gyqReviewCaseTest","project-review-case-test", List.of(fileId),"admin", CaseFileSourceType.REVIEW_COMMENT.toString());
FunctionalCaseSourceFileRequest request = new FunctionalCaseSourceFileRequest();
request.setProjectId("project-review-case-test");
request.setLocal(true);
request.setFileSource(CaseFileSourceType.REVIEW_COMMENT.toString());
request.setCaseId("gyqReviewCaseTest");
MvcResult mvcResult = this.downloadFile(ATTACHMENT_PREVIEW_COMPRESSED_URL, request);
Assertions.assertNotNull(mvcResult);
FunctionalCaseAttachmentExample functionalCaseAttachmentExample = new FunctionalCaseAttachmentExample();
functionalCaseAttachmentExample.createCriteria().andCaseIdEqualTo("gyqReviewCaseTest").andFileIdEqualTo(fileId).andFileSourceEqualTo(CaseFileSourceType.REVIEW_COMMENT.toString());
List<FunctionalCaseAttachment> functionalCaseAttachments = functionalCaseAttachmentMapper.selectByExample(functionalCaseAttachmentExample);
Assertions.assertTrue(CollectionUtils.isNotEmpty(functionalCaseAttachments));
functionalCaseAttachmentService.uploadMinioFile("gyqReviewCaseTest","project-review-case-test",new ArrayList<>(),"admin", CaseFileSourceType.REVIEW_COMMENT.toString());
String functionalCaseDir = DefaultRepositoryDir.getFunctionalCaseDir("project-review-case-test", "gyqReviewCaseTest");
functionalCaseAttachmentService.uploadFileResource(functionalCaseDir,new HashMap<>(),"project-review-case-test", "gyqReviewCaseTest");
Map<String, String> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put(fileId,null);
functionalCaseAttachmentService.uploadFileResource(functionalCaseDir,objectObjectHashMap,"project-review-case-test", "gyqReviewCaseTest");
}
@Test
@Order(7)
public void testAttachmentDownload() throws Exception {
//覆盖controller
FunctionalCaseFileRequest request = new FunctionalCaseFileRequest();
request.setProjectId("project-review-case-test");
request.setFileId("TEST_REVIEW_COMMENT_FILE_ID");
request.setCaseId("gyqReviewCaseTest");
request.setLocal(true);
this.downloadFile(ATTACHMENT_DOWNLOAD_URL, request);
}
public List<CaseReviewHistoryDTO> getCaseReviewHistoryList(String caseId,String reviewId) throws Exception { public List<CaseReviewHistoryDTO> getCaseReviewHistoryList(String caseId,String reviewId) throws Exception {
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get(REVIEW_LIST +"/"+reviewId +"/"+ caseId).header(SessionConstants.HEADER_TOKEN, sessionId) MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get(REVIEW_LIST +"/"+reviewId +"/"+ caseId).header(SessionConstants.HEADER_TOKEN, sessionId)
@ -289,5 +380,61 @@ public class ReviewFunctionalCaseControllerTests extends BaseTest {
return caseReviewMapper.selectByExample(caseReviewExample); return caseReviewMapper.selectByExample(caseReviewExample);
} }
protected MvcResult downloadFile(String url, Object param, Object... uriVariables) throws Exception {
return mockMvc.perform(getPostRequestBuilder(url, param, uriVariables))
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM_VALUE))
.andExpect(status().isOk()).andReturn();
}
private void uploadLocalFile() {
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));
FileRequest fileRequest = new FileRequest();
fileRequest.setFileName("测试评审");
fileRequest.setFolder(DefaultRepositoryDir.getFunctionalCaseDir("project-review-case-test", "gyqReviewCaseTest") + "/" + "TEST_REVIEW_COMMENT_FILE_ID");
fileRequest.setStorage(StorageType.MINIO.name());
try {
fileService.upload(file, fileRequest);
} catch (Exception e) {
throw new MSException("save file error");
}
}
private String uploadFile() 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));
FileUploadRequest fileUploadRequest = new FileUploadRequest();
fileUploadRequest.setProjectId("project-review-case-test");
return fileMetadataService.upload(fileUploadRequest, "admin", file);
}
private static MockMultipartFile getMockMultipartFile() {
MockMultipartFile file = new MockMultipartFile(
"file",
"file_upload.JPG",
MediaType.APPLICATION_OCTET_STREAM_VALUE,
"Hello, World!".getBytes()
);
return file;
}
private String doUploadTempFile(MockMultipartFile file) throws Exception {
return JSON.parseObject(requestUploadFileWithOkAndReturn(UPLOAD_TEMP, file)
.getResponse()
.getContentAsString(), ResultHolder.class)
.getData().toString();
}
private void doUploadTempFileFalse(MockMultipartFile file) throws Exception {
this.requestUploadFile(UPLOAD_TEMP, file).andExpect(status().is5xxServerError());
}
private static MockMultipartFile getNoNameMockMultipartFile() {
MockMultipartFile file = new MockMultipartFile(
"file",
null,
MediaType.APPLICATION_OCTET_STREAM_VALUE,
"Hello, World!".getBytes()
);
return file;
}
} }