diff --git a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseAttachment.java b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseAttachment.java index 629ab703ad..8fe8b18142 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseAttachment.java +++ b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseAttachment.java @@ -12,6 +12,11 @@ import lombok.Data; @Data public class FunctionalCaseAttachment implements Serializable { + @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "{functional_case_attachment.id.not_blank}", groups = {Updated.class}) + @Size(min = 1, max = 50, message = "{functional_case_attachment.id.length_range}", groups = {Created.class, Updated.class}) + private String id; + @Schema(description = "功能用例ID", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "{functional_case_attachment.case_id.not_blank}", groups = {Created.class}) @Size(min = 1, max = 50, message = "{functional_case_attachment.case_id.length_range}", groups = {Created.class, Updated.class}) @@ -22,11 +27,6 @@ public class FunctionalCaseAttachment implements Serializable { @Size(min = 1, max = 50, message = "{functional_case_attachment.file_id.length_range}", groups = {Created.class, Updated.class}) private String fileId; - @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED) - @NotBlank(message = "{functional_case_attachment.id.not_blank}", groups = {Updated.class}) - @Size(min = 1, max = 50, message = "{functional_case_attachment.id.length_range}", groups = {Created.class, Updated.class}) - private String id; - @Schema(description = "文件名称", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "{functional_case_attachment.file_name.not_blank}", groups = {Created.class}) @Size(min = 1, max = 255, message = "{functional_case_attachment.file_name.length_range}", groups = {Created.class, Updated.class}) @@ -51,9 +51,9 @@ public class FunctionalCaseAttachment implements Serializable { private static final long serialVersionUID = 1L; public enum Column { + id("id", "id", "VARCHAR", false), caseId("case_id", "caseId", "VARCHAR", false), fileId("file_id", "fileId", "VARCHAR", false), - id("id", "id", "VARCHAR", false), fileName("file_name", "fileName", "VARCHAR", false), size("size", "size", "BIGINT", true), local("local", "local", "BIT", true), diff --git a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseAttachmentExample.java b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseAttachmentExample.java index 5ae31977f6..c8394f86b9 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseAttachmentExample.java +++ b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/FunctionalCaseAttachmentExample.java @@ -104,6 +104,76 @@ public class FunctionalCaseAttachmentExample { criteria.add(new Criterion(condition, value1, value2)); } + public Criteria andIdIsNull() { + addCriterion("id is null"); + return (Criteria) this; + } + + public Criteria andIdIsNotNull() { + addCriterion("id is not null"); + return (Criteria) this; + } + + public Criteria andIdEqualTo(String value) { + addCriterion("id =", value, "id"); + return (Criteria) this; + } + + public Criteria andIdNotEqualTo(String value) { + addCriterion("id <>", value, "id"); + return (Criteria) this; + } + + public Criteria andIdGreaterThan(String value) { + addCriterion("id >", value, "id"); + return (Criteria) this; + } + + public Criteria andIdGreaterThanOrEqualTo(String value) { + addCriterion("id >=", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLessThan(String value) { + addCriterion("id <", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLessThanOrEqualTo(String value) { + addCriterion("id <=", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLike(String value) { + addCriterion("id like", value, "id"); + return (Criteria) this; + } + + public Criteria andIdNotLike(String value) { + addCriterion("id not like", value, "id"); + return (Criteria) this; + } + + public Criteria andIdIn(List values) { + addCriterion("id in", values, "id"); + return (Criteria) this; + } + + public Criteria andIdNotIn(List values) { + addCriterion("id not in", values, "id"); + return (Criteria) this; + } + + public Criteria andIdBetween(String value1, String value2) { + addCriterion("id between", value1, value2, "id"); + return (Criteria) this; + } + + public Criteria andIdNotBetween(String value1, String value2) { + addCriterion("id not between", value1, value2, "id"); + return (Criteria) this; + } + public Criteria andCaseIdIsNull() { addCriterion("case_id is null"); return (Criteria) this; @@ -244,76 +314,6 @@ public class FunctionalCaseAttachmentExample { return (Criteria) this; } - public Criteria andIdIsNull() { - addCriterion("id is null"); - return (Criteria) this; - } - - public Criteria andIdIsNotNull() { - addCriterion("id is not null"); - return (Criteria) this; - } - - public Criteria andIdEqualTo(String value) { - addCriterion("id =", value, "id"); - return (Criteria) this; - } - - public Criteria andIdNotEqualTo(String value) { - addCriterion("id <>", value, "id"); - return (Criteria) this; - } - - public Criteria andIdGreaterThan(String value) { - addCriterion("id >", value, "id"); - return (Criteria) this; - } - - public Criteria andIdGreaterThanOrEqualTo(String value) { - addCriterion("id >=", value, "id"); - return (Criteria) this; - } - - public Criteria andIdLessThan(String value) { - addCriterion("id <", value, "id"); - return (Criteria) this; - } - - public Criteria andIdLessThanOrEqualTo(String value) { - addCriterion("id <=", value, "id"); - return (Criteria) this; - } - - public Criteria andIdLike(String value) { - addCriterion("id like", value, "id"); - return (Criteria) this; - } - - public Criteria andIdNotLike(String value) { - addCriterion("id not like", value, "id"); - return (Criteria) this; - } - - public Criteria andIdIn(List values) { - addCriterion("id in", values, "id"); - return (Criteria) this; - } - - public Criteria andIdNotIn(List values) { - addCriterion("id not in", values, "id"); - return (Criteria) this; - } - - public Criteria andIdBetween(String value1, String value2) { - addCriterion("id between", value1, value2, "id"); - return (Criteria) this; - } - - public Criteria andIdNotBetween(String value1, String value2) { - addCriterion("id not between", value1, value2, "id"); - return (Criteria) this; - } - public Criteria andFileNameIsNull() { addCriterion("file_name is null"); return (Criteria) this; diff --git a/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseAttachmentMapper.java b/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseAttachmentMapper.java index e0d9b880ed..25c4d4d059 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseAttachmentMapper.java +++ b/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseAttachmentMapper.java @@ -10,7 +10,7 @@ public interface FunctionalCaseAttachmentMapper { int deleteByExample(FunctionalCaseAttachmentExample example); - int deleteByPrimaryKey(@Param("caseId") String caseId, @Param("fileId") String fileId); + int deleteByPrimaryKey(String id); int insert(FunctionalCaseAttachment record); @@ -18,7 +18,7 @@ public interface FunctionalCaseAttachmentMapper { List selectByExample(FunctionalCaseAttachmentExample example); - FunctionalCaseAttachment selectByPrimaryKey(@Param("caseId") String caseId, @Param("fileId") String fileId); + FunctionalCaseAttachment selectByPrimaryKey(String id); int updateByExampleSelective(@Param("record") FunctionalCaseAttachment record, @Param("example") FunctionalCaseAttachmentExample example); diff --git a/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseAttachmentMapper.xml b/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseAttachmentMapper.xml index b1b4169374..6134d7579b 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseAttachmentMapper.xml +++ b/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/FunctionalCaseAttachmentMapper.xml @@ -2,9 +2,9 @@ - - - + + + @@ -70,7 +70,7 @@ - case_id, file_id, id, file_name, `size`, `local`, create_user, create_time + id, case_id, file_id, file_name, `size`, `local`, create_user, create_time - select from functional_case_attachment - where case_id = #{caseId,jdbcType=VARCHAR} - and file_id = #{fileId,jdbcType=VARCHAR} + where id = #{id,jdbcType=VARCHAR} - + delete from functional_case_attachment - where case_id = #{caseId,jdbcType=VARCHAR} - and file_id = #{fileId,jdbcType=VARCHAR} + where id = #{id,jdbcType=VARCHAR} delete from functional_case_attachment @@ -105,25 +103,25 @@ - insert into functional_case_attachment (case_id, file_id, id, + insert into functional_case_attachment (id, case_id, file_id, file_name, `size`, `local`, create_user, create_time) - values (#{caseId,jdbcType=VARCHAR}, #{fileId,jdbcType=VARCHAR}, #{id,jdbcType=VARCHAR}, + values (#{id,jdbcType=VARCHAR}, #{caseId,jdbcType=VARCHAR}, #{fileId,jdbcType=VARCHAR}, #{fileName,jdbcType=VARCHAR}, #{size,jdbcType=BIGINT}, #{local,jdbcType=BIT}, #{createUser,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}) insert into functional_case_attachment + + id, + case_id, file_id, - - id, - file_name, @@ -141,15 +139,15 @@ + + #{id,jdbcType=VARCHAR}, + #{caseId,jdbcType=VARCHAR}, #{fileId,jdbcType=VARCHAR}, - - #{id,jdbcType=VARCHAR}, - #{fileName,jdbcType=VARCHAR}, @@ -176,15 +174,15 @@ update functional_case_attachment + + id = #{record.id,jdbcType=VARCHAR}, + case_id = #{record.caseId,jdbcType=VARCHAR}, file_id = #{record.fileId,jdbcType=VARCHAR}, - - id = #{record.id,jdbcType=VARCHAR}, - file_name = #{record.fileName,jdbcType=VARCHAR}, @@ -207,9 +205,9 @@ update functional_case_attachment - set case_id = #{record.caseId,jdbcType=VARCHAR}, + set id = #{record.id,jdbcType=VARCHAR}, + case_id = #{record.caseId,jdbcType=VARCHAR}, file_id = #{record.fileId,jdbcType=VARCHAR}, - id = #{record.id,jdbcType=VARCHAR}, file_name = #{record.fileName,jdbcType=VARCHAR}, `size` = #{record.size,jdbcType=BIGINT}, `local` = #{record.local,jdbcType=BIT}, @@ -222,8 +220,11 @@ update functional_case_attachment - - id = #{id,jdbcType=VARCHAR}, + + case_id = #{caseId,jdbcType=VARCHAR}, + + + file_id = #{fileId,jdbcType=VARCHAR}, file_name = #{fileName,jdbcType=VARCHAR}, @@ -241,26 +242,25 @@ create_time = #{createTime,jdbcType=BIGINT}, - where case_id = #{caseId,jdbcType=VARCHAR} - and file_id = #{fileId,jdbcType=VARCHAR} + where id = #{id,jdbcType=VARCHAR} update functional_case_attachment - set id = #{id,jdbcType=VARCHAR}, + set case_id = #{caseId,jdbcType=VARCHAR}, + file_id = #{fileId,jdbcType=VARCHAR}, file_name = #{fileName,jdbcType=VARCHAR}, `size` = #{size,jdbcType=BIGINT}, `local` = #{local,jdbcType=BIT}, create_user = #{createUser,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT} - where case_id = #{caseId,jdbcType=VARCHAR} - and file_id = #{fileId,jdbcType=VARCHAR} + where id = #{id,jdbcType=VARCHAR} insert into functional_case_attachment - (case_id, file_id, id, file_name, `size`, `local`, create_user, create_time) + (id, case_id, file_id, file_name, `size`, `local`, create_user, create_time) values - (#{item.caseId,jdbcType=VARCHAR}, #{item.fileId,jdbcType=VARCHAR}, #{item.id,jdbcType=VARCHAR}, + (#{item.id,jdbcType=VARCHAR}, #{item.caseId,jdbcType=VARCHAR}, #{item.fileId,jdbcType=VARCHAR}, #{item.fileName,jdbcType=VARCHAR}, #{item.size,jdbcType=BIGINT}, #{item.local,jdbcType=BIT}, #{item.createUser,jdbcType=VARCHAR}, #{item.createTime,jdbcType=BIGINT}) @@ -275,15 +275,15 @@ ( + + #{item.id,jdbcType=VARCHAR} + #{item.caseId,jdbcType=VARCHAR} #{item.fileId,jdbcType=VARCHAR} - - #{item.id,jdbcType=VARCHAR} - #{item.fileName,jdbcType=VARCHAR} diff --git a/backend/framework/domain/src/main/resources/migration/3.0.0/ddl/V3.0.0_10__functional_case.sql b/backend/framework/domain/src/main/resources/migration/3.0.0/ddl/V3.0.0_10__functional_case.sql index 3b33967846..57fd57996f 100644 --- a/backend/framework/domain/src/main/resources/migration/3.0.0/ddl/V3.0.0_10__functional_case.sql +++ b/backend/framework/domain/src/main/resources/migration/3.0.0/ddl/V3.0.0_10__functional_case.sql @@ -108,7 +108,7 @@ CREATE TABLE IF NOT EXISTS functional_case_attachment( `local` BIT(1) NOT NULL COMMENT '是否本地' , `create_user` VARCHAR(50) NOT NULL COMMENT '创建人' , `create_time` BIGINT NOT NULL COMMENT '创建时间' , - PRIMARY KEY (case_id,file_id) + PRIMARY KEY (id) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '功能用例和附件的中间表'; diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java index 08eaf33c77..61193562a3 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java @@ -213,6 +213,7 @@ public class PermissionConstants { /*------ start: FUNCTIONAL_CASE ------*/ public static final String FUNCTIONAL_CASE_READ = "FUNCTIONAL_CASE:READ"; public static final String FUNCTIONAL_CASE_READ_ADD = "FUNCTIONAL_CASE:READ+ADD"; + public static final String FUNCTIONAL_CASE_READ_UPDATE = "FUNCTIONAL_CASE:READ+UPDATE"; public static final String FUNCTIONAL_CASE_COMMENT_READ_ADD = "FUNCTIONAL_CASE_COMMENT:READ+ADD"; /*------ end: FUNCTIONAL_CASE ------*/ diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalCaseController.java b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalCaseController.java index 6cfabe25e6..8013269c81 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalCaseController.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalCaseController.java @@ -3,6 +3,7 @@ package io.metersphere.functional.controller; import io.metersphere.functional.domain.FunctionalCase; import io.metersphere.functional.dto.FunctionalCaseDetailDTO; import io.metersphere.functional.request.FunctionalCaseAddRequest; +import io.metersphere.functional.request.FunctionalCaseEditRequest; import io.metersphere.functional.service.FunctionalCaseService; import io.metersphere.project.service.ProjectTemplateService; import io.metersphere.sdk.constants.PermissionConstants; @@ -62,4 +63,14 @@ public class FunctionalCaseController { public FunctionalCaseDetailDTO getFunctionalCaseDetail(@PathVariable String functionalCaseId) { return functionalCaseService.getFunctionalCaseDetail(functionalCaseId); } + + + @PostMapping("/update") + @Operation(summary = "功能用例-更新用例") + @RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_UPDATE) + @Log(type = OperationLogType.UPDATE, expression = "#msClass.updateFunctionalCaseLog(#request, #files)", msClass = FunctionalCaseService.class) + public FunctionalCase updateFunctionalCase(@Validated @RequestPart("request") FunctionalCaseEditRequest request, @RequestPart(value = "files", required = false) List files) { + String userId = SessionUtils.getUserId(); + return functionalCaseService.updateFunctionalCase(request, files, userId); + } } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/dto/FunctionalCaseAttachmentDTO.java b/backend/services/case-management/src/main/java/io/metersphere/functional/dto/FunctionalCaseAttachmentDTO.java new file mode 100644 index 0000000000..5ed609e9ba --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/dto/FunctionalCaseAttachmentDTO.java @@ -0,0 +1,36 @@ +package io.metersphere.functional.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * @author wx + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class FunctionalCaseAttachmentDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @Schema(description = "文件ID") + private String fileId; + + @Schema(description = "文件名称") + private String fileName; + + @Schema(description = "文件大小") + private Long size; + + @Schema(description = "是否本地") + private Boolean local; + + @Schema(description = "创建人") + private String createUser; + + @Schema(description = "创建时间") + private Long createTime; +} diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/dto/FunctionalCaseDetailDTO.java b/backend/services/case-management/src/main/java/io/metersphere/functional/dto/FunctionalCaseDetailDTO.java index 98fe0c2d92..6362202dd0 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/dto/FunctionalCaseDetailDTO.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/dto/FunctionalCaseDetailDTO.java @@ -74,5 +74,6 @@ public class FunctionalCaseDetailDTO implements Serializable { @Schema(description = "自定义字段属性") private List customFields; - + @Schema(description = "附件信息") + private List attachments; } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/request/FunctionalCaseAddRequest.java b/backend/services/case-management/src/main/java/io/metersphere/functional/request/FunctionalCaseAddRequest.java index b266602ab6..7481866662 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/request/FunctionalCaseAddRequest.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/request/FunctionalCaseAddRequest.java @@ -7,7 +7,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; import java.io.Serializable; -import java.util.ArrayList; import java.util.List; /** @@ -31,23 +30,23 @@ public class FunctionalCaseAddRequest implements Serializable { @NotBlank(message = "{functional_case.name.not_blank}") private String name; - @Schema(description = "前置条件") + @Schema(description = "前置条件", defaultValue = "") private String prerequisite; @Schema(description = "编辑模式", allowableValues = {"STEP", "TEXT"}) @NotBlank(message = "{functional_case.case_edit_type.not_blank}") private String caseEditType; - @Schema(description = "用例步骤") + @Schema(description = "用例步骤", defaultValue = "") private String steps; - @Schema(description = "步骤描述") + @Schema(description = "步骤描述", defaultValue = "") private String textDescription; - @Schema(description = "预期结果") + @Schema(description = "预期结果", defaultValue = "") private String expectedResult; - @Schema(description = "备注") + @Schema(description = "备注", defaultValue = "") private String description; @Schema(description = "是否公共用例库") @@ -70,7 +69,7 @@ public class FunctionalCaseAddRequest implements Serializable { @Schema(description = "关联文件ID集合") - private List relateFileMetaIds = new ArrayList<>(); + private List relateFileMetaIds; } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/request/FunctionalCaseEditRequest.java b/backend/services/case-management/src/main/java/io/metersphere/functional/request/FunctionalCaseEditRequest.java new file mode 100644 index 0000000000..19e7a00133 --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/request/FunctionalCaseEditRequest.java @@ -0,0 +1,23 @@ +package io.metersphere.functional.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * @author wx + */ +@Data +@EqualsAndHashCode(callSuper = false) +public class FunctionalCaseEditRequest extends FunctionalCaseAddRequest{ + + @Schema(description = "用例id") + @NotBlank(message = "{functional_case.id.not_blank}") + private String id; + + @Schema(description = "取消关联id") + private List deleteFileMetaIds; +} diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseAttachmentService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseAttachmentService.java index 8964cbab72..07ca259772 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseAttachmentService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseAttachmentService.java @@ -1,12 +1,18 @@ package io.metersphere.functional.service; +import com.google.common.collect.Lists; import io.metersphere.functional.domain.FunctionalCaseAttachment; +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.project.domain.FileMetadata; import io.metersphere.project.mapper.FileMetadataMapper; +import io.metersphere.sdk.util.BeanUtils; import io.metersphere.system.uid.IDGenerator; import jakarta.annotation.Resource; +import org.apache.commons.collections.CollectionUtils; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; @@ -57,16 +63,18 @@ public class FunctionalCaseAttachmentService { * @param userId */ public void relateFileMeta(List relateFileMetaIds, String caseId, String userId) { - SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); - FunctionalCaseAttachmentMapper sessionMapper = sqlSession.getMapper(FunctionalCaseAttachmentMapper.class); - relateFileMetaIds.forEach(fileMetaId -> { - FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileMetaId); - FunctionalCaseAttachment caseAttachment = creatModule(fileMetadata.getId(), fileMetadata.getName(), fileMetadata.getSize(), caseId, false, userId); - sessionMapper.insertSelective(caseAttachment); - }); - sqlSession.flushStatements(); - if (sqlSession != null && sqlSessionFactory != null) { - SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); + if (CollectionUtils.isNotEmpty(relateFileMetaIds)) { + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + FunctionalCaseAttachmentMapper sessionMapper = sqlSession.getMapper(FunctionalCaseAttachmentMapper.class); + relateFileMetaIds.forEach(fileMetaId -> { + FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(fileMetaId); + FunctionalCaseAttachment caseAttachment = creatModule(fileMetadata.getId(), fileMetadata.getName(), fileMetadata.getSize(), caseId, false, userId); + sessionMapper.insertSelective(caseAttachment); + }); + sqlSession.flushStatements(); + if (sqlSession != null && sqlSessionFactory != null) { + SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); + } } } @@ -82,4 +90,44 @@ public class FunctionalCaseAttachmentService { caseAttachment.setCreateTime(System.currentTimeMillis()); return caseAttachment; } + + + /** + * 获取附件信息 + * + * @param functionalCaseDetailDTO + */ + public void getAttachmentInfo(FunctionalCaseDetailDTO functionalCaseDetailDTO) { + FunctionalCaseAttachmentExample example = new FunctionalCaseAttachmentExample(); + example.createCriteria().andCaseIdEqualTo(functionalCaseDetailDTO.getId()); + List caseAttachments = functionalCaseAttachmentMapper.selectByExample(example); + if (CollectionUtils.isNotEmpty(caseAttachments)) { + caseAttachments.stream().filter(caseAttachment -> !caseAttachment.getLocal()).forEach(caseAttachment -> { + FileMetadata fileMetadata = fileMetadataMapper.selectByPrimaryKey(caseAttachment.getFileId()); + caseAttachment.setFileName(fileMetadata.getName()); + }); + } + List attachmentDTOs = Lists.transform(caseAttachments, (functionalCaseAttachment) -> { + FunctionalCaseAttachmentDTO attachmentDTO = new FunctionalCaseAttachmentDTO(); + BeanUtils.copyBean(attachmentDTO, functionalCaseAttachment); + return attachmentDTO; + }); + functionalCaseDetailDTO.setAttachments(attachmentDTOs); + } + + + /** + * 更新用例时删除文件 取消关联关系 + * + * @param deleteFileMetaIds + */ + public List deleteCaseAttachment(List deleteFileMetaIds, String caseId) { + FunctionalCaseAttachmentExample example = new FunctionalCaseAttachmentExample(); + example.createCriteria().andFileIdIn(deleteFileMetaIds).andCaseIdEqualTo(caseId).andLocalEqualTo(true); + List delAttachment = functionalCaseAttachmentMapper.selectByExample(example); + example.clear(); + example.createCriteria().andFileIdIn(deleteFileMetaIds).andCaseIdEqualTo(caseId); + functionalCaseAttachmentMapper.deleteByExample(example); + return delAttachment; + } } \ No newline at end of file diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseCustomFieldService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseCustomFieldService.java index 43a6417292..a199bced77 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseCustomFieldService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseCustomFieldService.java @@ -10,7 +10,10 @@ import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** @@ -55,4 +58,45 @@ public class FunctionalCaseCustomFieldService { } return null; } + + + /** + * 更新自定义字段 + * + * @param caseId + * @param customsFields + */ + public void updateCustomField(String caseId, List customsFields) { + List fieldIds = customsFields.stream().map(CaseCustomsFieldDTO::getFieldId).collect(Collectors.toList()); + FunctionalCaseCustomFieldExample example = new FunctionalCaseCustomFieldExample(); + example.createCriteria().andFieldIdIn(fieldIds).andCaseIdEqualTo(caseId); + List defaultFields = functionalCaseCustomFieldMapper.selectByExample(example); + Map collect = defaultFields.stream().collect(Collectors.toMap(FunctionalCaseCustomField::getFieldId, (item) -> item)); + List addFields = new ArrayList<>(); + List updateFields = new ArrayList<>(); + customsFields.forEach(customsField -> { + if (collect.containsKey(customsField.getFieldId())) { + updateFields.add(customsField); + } else { + addFields.add(customsField); + } + }); + if (CollectionUtils.isNotEmpty(addFields)) { + saveCustomField(caseId, addFields); + } + ; + if (CollectionUtils.isNotEmpty(updateFields)) { + updateField(caseId, updateFields); + } + } + + private void updateField(String caseId, List updateFields) { + updateFields.forEach(customsField -> { + FunctionalCaseCustomField customField = new FunctionalCaseCustomField(); + customField.setCaseId(caseId); + customField.setFieldId(customsField.getFieldId()); + customField.setValue(customsField.getValue()); + functionalCaseCustomFieldMapper.updateByPrimaryKeySelective(customField); + }); + } } \ No newline at end of file diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseService.java index 5700008aaf..e1acb85e5f 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseService.java @@ -1,6 +1,7 @@ package io.metersphere.functional.service; import io.metersphere.functional.domain.FunctionalCase; +import io.metersphere.functional.domain.FunctionalCaseAttachment; import io.metersphere.functional.domain.FunctionalCaseBlob; import io.metersphere.functional.domain.FunctionalCaseCustomField; import io.metersphere.functional.dto.CaseCustomsFieldDTO; @@ -9,20 +10,21 @@ import io.metersphere.functional.mapper.ExtFunctionalCaseMapper; import io.metersphere.functional.mapper.FunctionalCaseBlobMapper; import io.metersphere.functional.mapper.FunctionalCaseMapper; import io.metersphere.functional.request.FunctionalCaseAddRequest; +import io.metersphere.functional.request.FunctionalCaseEditRequest; import io.metersphere.functional.result.FunctionalCaseResultCode; import io.metersphere.project.service.ProjectTemplateService; import io.metersphere.sdk.constants.*; -import io.metersphere.system.log.dto.LogDTO; -import io.metersphere.system.dto.sdk.TemplateCustomFieldDTO; -import io.metersphere.system.dto.sdk.TemplateDTO; import io.metersphere.sdk.exception.MSException; -import io.metersphere.system.file.FileRequest; -import io.metersphere.system.file.MinioRepository; import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.MsFileUtils; +import io.metersphere.system.dto.sdk.TemplateCustomFieldDTO; +import io.metersphere.system.dto.sdk.TemplateDTO; +import io.metersphere.system.file.FileRequest; +import io.metersphere.system.file.MinioRepository; import io.metersphere.system.log.constants.OperationLogModule; import io.metersphere.system.log.constants.OperationLogType; +import io.metersphere.system.log.dto.LogDTO; import io.metersphere.system.uid.IDGenerator; import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; @@ -68,17 +70,13 @@ public class FunctionalCaseService { public FunctionalCase addFunctionalCase(FunctionalCaseAddRequest request, List files, String userId) { String caseId = IDGenerator.nextStr(); //添加功能用例 - FunctionalCase functionalCase = addTestCase(caseId, request, userId); + FunctionalCase functionalCase = addCase(caseId, request, userId); //上传文件 - if (CollectionUtils.isNotEmpty(files)) { - uploadFile(request, caseId, files, true, userId); - } + uploadFile(request, caseId, files, true, userId); //关联附件 - if (CollectionUtils.isNotEmpty(request.getRelateFileMetaIds())) { - functionalCaseAttachmentService.relateFileMeta(request.getRelateFileMetaIds(), caseId, userId); - } + functionalCaseAttachmentService.relateFileMeta(request.getRelateFileMetaIds(), caseId, userId); return functionalCase; } @@ -87,7 +85,7 @@ public class FunctionalCaseService { * * @param request */ - private FunctionalCase addTestCase(String caseId, FunctionalCaseAddRequest request, String userId) { + private FunctionalCase addCase(String caseId, FunctionalCaseAddRequest request, String userId) { FunctionalCase functionalCase = new FunctionalCase(); BeanUtils.copyBean(functionalCase, request); functionalCase.setId(caseId); @@ -137,21 +135,22 @@ public class FunctionalCaseService { * @param files */ public void uploadFile(FunctionalCaseAddRequest request, String caseId, List files, Boolean isLocal, String userId) { - files.forEach(file -> { - String fileId = IDGenerator.nextStr(); - FileRequest fileRequest = new FileRequest(); - fileRequest.setFileName(file.getName()); - fileRequest.setProjectId(request.getProjectId()); - fileRequest.setResourceId(MsFileUtils.FUNCTIONAL_CASE_ATTACHMENT_DIR + fileId); - fileRequest.setStorage(StorageType.MINIO.name()); - try { - minioRepository.saveFile(file, fileRequest); - } catch (Exception e) { - throw new MSException("save file error"); - } - functionalCaseAttachmentService.saveCaseAttachment(fileId, file, caseId, isLocal, userId); - }); - + if (CollectionUtils.isNotEmpty(files)) { + files.forEach(file -> { + String fileId = IDGenerator.nextStr(); + FileRequest fileRequest = new FileRequest(); + fileRequest.setFileName(file.getName()); + fileRequest.setProjectId(request.getProjectId()); + fileRequest.setResourceId(MsFileUtils.FUNCTIONAL_CASE_ATTACHMENT_DIR + "/" + fileId); + fileRequest.setStorage(StorageType.MINIO.name()); + try { + minioRepository.saveFile(file, fileRequest); + } catch (Exception e) { + throw new MSException("save file error"); + } + functionalCaseAttachmentService.saveCaseAttachment(fileId, file, caseId, isLocal, userId); + }); + } } @@ -174,6 +173,9 @@ public class FunctionalCaseService { //模板校验 获取自定义字段 functionalCaseDetailDTO = checkTemplateCustomField(functionalCaseDetailDTO, functionalCase); + //获取附件信息 + functionalCaseAttachmentService.getAttachmentInfo(functionalCaseDetailDTO); + return functionalCaseDetailDTO; } @@ -201,6 +203,72 @@ public class FunctionalCaseService { } + /** + * 更新用例 基本信息 + * + * @param request + * @param files + * @param userId + * @return + */ + public FunctionalCase updateFunctionalCase(FunctionalCaseEditRequest request, List files, String userId) { + //基本信息 + FunctionalCase functionalCase = new FunctionalCase(); + BeanUtils.copyBean(functionalCase, request); + updateCase(request, userId, functionalCase); + + //处理删除文件id + if (CollectionUtils.isNotEmpty(request.getDeleteFileMetaIds())) { + this.deleteFile(request.getDeleteFileMetaIds(), request); + } + + //上传新文件 + uploadFile(request, request.getId(), files, true, userId); + + //关联新附件 + functionalCaseAttachmentService.relateFileMeta(request.getRelateFileMetaIds(), request.getId(), userId); + return functionalCase; + + } + + private void deleteFile(List deleteFileMetaIds, FunctionalCaseEditRequest request) { + List caseAttachments = functionalCaseAttachmentService.deleteCaseAttachment(deleteFileMetaIds, request.getId()); + if (CollectionUtils.isNotEmpty(caseAttachments)) { + //删除本地上传的minio文件 + deleteMinioFile(caseAttachments, request.getProjectId()); + } + } + + private void deleteMinioFile(List files, String projectId) { + files.forEach(file -> { + FileRequest fileRequest = new FileRequest(); + fileRequest.setFileName(file.getFileName()); + fileRequest.setProjectId(projectId); + fileRequest.setResourceId(MsFileUtils.FUNCTIONAL_CASE_ATTACHMENT_DIR + "/" + file.getFileId()); + fileRequest.setStorage(StorageType.MINIO.name()); + try { + minioRepository.delete(fileRequest); + } catch (Exception e) { + throw new MSException("delete file error"); + } + }); + } + + private void updateCase(FunctionalCaseEditRequest request, String userId, FunctionalCase functionalCase) { + //更新用例 + functionalCaseMapper.updateByPrimaryKeySelective(functionalCase); + //更新附属表信息 + FunctionalCaseBlob functionalCaseBlob = new FunctionalCaseBlob(); + BeanUtils.copyBean(functionalCaseBlob, request); + functionalCaseBlobMapper.updateByPrimaryKeySelective(functionalCaseBlob); + + //更新自定义字段 + functionalCaseCustomFieldService.updateCustomField(request.getId(), request.getCustomsFields()); + } + + + + //TODO 日志 /** * 新增用例 日志 * @@ -223,4 +291,29 @@ public class FunctionalCaseService { dto.setOriginalValue(JSON.toJSONBytes(requests)); return dto; } + + + /** + * 更新用例 日志 + * + * @param requests + * @param files + * @return + */ + public LogDTO updateFunctionalCaseLog(FunctionalCaseAddRequest requests, List files) { + //TODO 获取原值 + LogDTO dto = new LogDTO( + requests.getProjectId(), + null, + null, + null, + OperationLogType.UPDATE.name(), + OperationLogModule.FUNCTIONAL_CASE, + requests.getName()); + + dto.setPath("/functional/case/update"); + dto.setMethod(HttpMethodConstants.POST.name()); + dto.setModifiedValue(JSON.toJSONBytes(requests)); + return dto; + } } diff --git a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseControllerTests.java b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseControllerTests.java index 6e7ea2050d..335f319e94 100644 --- a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseControllerTests.java +++ b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseControllerTests.java @@ -2,6 +2,7 @@ package io.metersphere.functional.controller; import io.metersphere.functional.dto.CaseCustomsFieldDTO; import io.metersphere.functional.request.FunctionalCaseAddRequest; +import io.metersphere.functional.request.FunctionalCaseEditRequest; import io.metersphere.functional.result.FunctionalCaseResultCode; import io.metersphere.functional.utils.FileBaseUtils; import io.metersphere.sdk.util.JSON; @@ -30,7 +31,8 @@ public class FunctionalCaseControllerTests extends BaseTest { public static final String FUNCTIONAL_CASE_ADD_URL = "/functional/case/add"; public static final String DEFAULT_TEMPLATE_FIELD_URL = "/functional/case/default/template/field/"; - public static final String FUNCTIONAL_CASE_DETAIL_URL = "/functional/case//detail/"; + public static final String FUNCTIONAL_CASE_DETAIL_URL = "/functional/case/detail/"; + public static final String FUNCTIONAL_CASE_UPDATE_URL = "/functional/case/update"; @Test @Order(1) @@ -112,4 +114,57 @@ public class FunctionalCaseControllerTests extends BaseTest { } + @Test + @Order(3) + public void testUpdateFunctionalCase() throws Exception { + FunctionalCaseEditRequest request = creatEditRequest(); + //设置自定义字段 + List list = updateCustomsFields(request); + request.setCustomsFields(list); + LinkedMultiValueMap paramMap = new LinkedMultiValueMap<>(); + List files = new ArrayList<>(); + paramMap.add("request", JSON.toJSONString(request)); + paramMap.add("files", files); + MvcResult mvcResult = this.requestMultipartWithOkAndReturn(FUNCTIONAL_CASE_UPDATE_URL, paramMap); + String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); + Assertions.assertNotNull(resultHolder); + + //设置删除文件id + request.setDeleteFileMetaIds(Arrays.asList("delete_file_meta_id_1")); + paramMap = new LinkedMultiValueMap<>(); + paramMap.add("request", JSON.toJSONString(request)); + paramMap.add("files", files); + MvcResult updateResult = this.requestMultipartWithOkAndReturn(FUNCTIONAL_CASE_UPDATE_URL, paramMap); + String updateReturnData = updateResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder updateResultHolder = JSON.parseObject(updateReturnData, ResultHolder.class); + Assertions.assertNotNull(updateResultHolder); + + } + + private List updateCustomsFields(FunctionalCaseEditRequest editRequest) { + List list = new ArrayList<>() {{ + add(new CaseCustomsFieldDTO() {{ + setFieldId("customs_field_id_1"); + setValue("测试更新"); + }}); + add(new CaseCustomsFieldDTO() {{ + setFieldId("customs_field_id_2"); + setValue("更新时存在新字段"); + }}); + }}; + return list; + } + + private FunctionalCaseEditRequest creatEditRequest() { + FunctionalCaseEditRequest editRequest = new FunctionalCaseEditRequest(); + editRequest.setProjectId(DEFAULT_PROJECT_ID); + editRequest.setTemplateId("default_template_id"); + editRequest.setName("测试用例编辑"); + editRequest.setCaseEditType("STEP"); + editRequest.setModuleId("default_module_id"); + editRequest.setId("TEST_FUNCTIONAL_CASE_ID"); + editRequest.setSteps(""); + return editRequest; + } } diff --git a/backend/services/case-management/src/test/resources/dml/init_file_metadata_test.sql b/backend/services/case-management/src/test/resources/dml/init_file_metadata_test.sql index 7d5463e95d..ae9660c261 100644 --- a/backend/services/case-management/src/test/resources/dml/init_file_metadata_test.sql +++ b/backend/services/case-management/src/test/resources/dml/init_file_metadata_test.sql @@ -9,3 +9,9 @@ INSERT INTO functional_case_blob(id, steps, text_description, expected_result, p INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('TEST_FUNCTIONAL_CASE_ID', '100548878725546079', '22'); + + +INSERT INTO functional_case_attachment(id, case_id, file_id, file_name, size, local, create_user, create_time) VALUES ('TEST_CASE_ATTACHMENT_ID', 'TEST_FUNCTIONAL_CASE_ID', '100548878725546079', '测试', 1, b'1', 'admin', 1698058347559); +INSERT INTO functional_case_attachment(id, case_id, file_id, file_name, size, local, create_user, create_time) VALUES ('TEST_CASE_ATTACHMENT_ID_1', 'TEST_FUNCTIONAL_CASE_ID', 'relate_file_meta_id_1', '测试1', 1, b'0', 'admin', 1698058347559); +INSERT INTO functional_case_attachment(id, case_id, file_id, file_name, size, local, create_user, create_time) VALUES ('TEST_CASE_ATTACHMENT_ID_2', 'TEST_FUNCTIONAL_CASE_ID', 'delete_file_meta_id_1', '测试删除', 1, b'1', 'admin', 1698058347559); +