From 7844e3365cd61b5d19297c5d020c798dc4c9597a Mon Sep 17 00:00:00 2001 From: song-cc-rock Date: Thu, 2 Nov 2023 11:40:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E9=A1=B9=E7=9B=AE=E8=AE=BE=E7=BD=AE):=20?= =?UTF-8?q?=E7=BC=BA=E9=99=B7=E5=88=97=E8=A1=A8=E6=89=B9=E9=87=8F=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/i18n/bug.properties | 4 +- .../main/resources/i18n/bug_en_US.properties | 2 + .../main/resources/i18n/bug_zh_CN.properties | 4 +- .../main/resources/i18n/bug_zh_TW.properties | 2 + .../bug/controller/BugController.java | 16 +++ .../bug/controller/BugHistoryController.java | 4 - .../io/metersphere/bug/dto/BugTagEditDTO.java | 16 +++ .../bug/dto/request/BugBatchRequest.java | 22 +++ .../dto/request/BugBatchUpdateRequest.java | 23 +++ .../bug/dto/request/BugEditRequest.java | 2 + .../metersphere/bug/mapper/ExtBugMapper.java | 16 +++ .../metersphere/bug/mapper/ExtBugMapper.xml | 24 ++++ .../metersphere/bug/service/BugService.java | 123 ++++++++++++++-- .../bug/utils/CustomFieldUtils.java | 17 +++ .../bug/controller/BugControllerTests.java | 132 +++++++++++++++--- .../src/test/resources/dml/init_bug.sql | 7 +- 16 files changed, 381 insertions(+), 33 deletions(-) delete mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugHistoryController.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugTagEditDTO.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugBatchRequest.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugBatchUpdateRequest.java diff --git a/backend/framework/sdk/src/main/resources/i18n/bug.properties b/backend/framework/sdk/src/main/resources/i18n/bug.properties index 17899ecd4f..d3af0fa09f 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug.properties @@ -87,4 +87,6 @@ bug_not_exist=缺陷不存在 not_local_bug_error=非本地缺陷,无法操作 third_party_not_config=项目未配置第三方平台 bug_attachment_upload_error=缺陷附件上传失败 -bug_attachment_delete_error=缺陷附件删除失败 \ No newline at end of file +bug_attachment_delete_error=缺陷附件删除失败 +no_bug_select=未勾选缺陷 +bug_select_not_found=未查询到勾选的缺陷 \ No newline at end of file diff --git a/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties b/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties index f92a20550d..f6a1bdd3a2 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug_en_US.properties @@ -88,3 +88,5 @@ not_local_bug_error=Not local bug, error third_party_not_config=The project third-party platform not configured bug_attachment_upload_error=Bug attachment upload error bug_attachment_delete_error=Bug attachment delete error +no_bug_select=No bug selected +bug_select_not_found=Selected bug not found diff --git a/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties b/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties index 17899ecd4f..d3af0fa09f 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug_zh_CN.properties @@ -87,4 +87,6 @@ bug_not_exist=缺陷不存在 not_local_bug_error=非本地缺陷,无法操作 third_party_not_config=项目未配置第三方平台 bug_attachment_upload_error=缺陷附件上传失败 -bug_attachment_delete_error=缺陷附件删除失败 \ No newline at end of file +bug_attachment_delete_error=缺陷附件删除失败 +no_bug_select=未勾选缺陷 +bug_select_not_found=未查询到勾选的缺陷 \ No newline at end of file diff --git a/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties b/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties index 8e7d0daf55..557e50aa89 100644 --- a/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties +++ b/backend/framework/sdk/src/main/resources/i18n/bug_zh_TW.properties @@ -88,4 +88,6 @@ not_local_bug_error=非本地缺陷,無法操作 third_party_not_config=項目未配置第三方平台 bug_attachment_upload_error=缺陷附件上傳失敗 bug_attachment_delete_error=缺陷附件刪除失敗 +no_bug_select=未勾選缺陷 +bug_select_not_found=未查詢到勾選的缺陷 diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugController.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugController.java index ec2adfe963..f7699becfc 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugController.java +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugController.java @@ -3,6 +3,8 @@ package io.metersphere.bug.controller; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.metersphere.bug.dto.BugDTO; +import io.metersphere.bug.dto.request.BugBatchRequest; +import io.metersphere.bug.dto.request.BugBatchUpdateRequest; import io.metersphere.bug.dto.request.BugEditRequest; import io.metersphere.bug.dto.request.BugPageRequest; import io.metersphere.bug.service.BugService; @@ -86,4 +88,18 @@ public class BugController { public TemplateDTO getTemplateField(@PathVariable String id, @RequestParam(value = "projectId") String projectId) { return bugService.getTemplate(id, projectId); } + + @PostMapping("/batch-delete") + @Operation(summary = "缺陷管理-批量删除缺陷") + @RequiresPermissions(PermissionConstants.BUG_DELETE) + public void batchDelete(@Validated @RequestBody BugBatchRequest request) { + bugService.batchDelete(request); + } + + @PostMapping("/batch-update") + @Operation(summary = "缺陷管理-批量编辑缺陷") + @RequiresPermissions(PermissionConstants.BUG_UPDATE) + public void batchUpdate(@Validated @RequestBody BugBatchUpdateRequest request) { + bugService.batchUpdate(request); + } } diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugHistoryController.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugHistoryController.java deleted file mode 100644 index 4a69bc4cc7..0000000000 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugHistoryController.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.metersphere.bug.controller; - -public class BugHistoryController { -} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugTagEditDTO.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugTagEditDTO.java new file mode 100644 index 0000000000..7eba702cc6 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugTagEditDTO.java @@ -0,0 +1,16 @@ +package io.metersphere.bug.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class BugTagEditDTO { + + @Schema(description = "缺陷ID") + private String bugId; + + @Schema(description = "标签值") + private String tag; +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugBatchRequest.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugBatchRequest.java new file mode 100644 index 0000000000..127efa58f1 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugBatchRequest.java @@ -0,0 +1,22 @@ +package io.metersphere.bug.dto.request; + +import io.metersphere.system.dto.sdk.BaseCondition; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@Data +@EqualsAndHashCode(callSuper = false) +public class BugBatchRequest extends BaseCondition { + + @Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String projectId; + + @Schema(description = "是否全选", requiredMode = Schema.RequiredMode.REQUIRED) + private boolean selectAll; + + @Schema(description = "缺陷ID勾选集合") + private List includeBugIds; +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugBatchUpdateRequest.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugBatchUpdateRequest.java new file mode 100644 index 0000000000..82c8f44a04 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugBatchUpdateRequest.java @@ -0,0 +1,23 @@ +package io.metersphere.bug.dto.request; + +import io.metersphere.bug.dto.BugCustomFieldDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class BugBatchUpdateRequest extends BugBatchRequest{ + + @Schema(description = "处理人") + private String handleUser; + + @Schema(description = "标签") + private String tag; + + @Schema(description = "自定义字段") + private BugCustomFieldDTO customField; + + @Schema(description = "是否追加", requiredMode = Schema.RequiredMode.REQUIRED) + private boolean append; +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugEditRequest.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugEditRequest.java index bb6fab4a02..d975400168 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugEditRequest.java +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugEditRequest.java @@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; import lombok.Data; +import lombok.EqualsAndHashCode; import java.util.List; import java.util.Map; @@ -14,6 +15,7 @@ import java.util.Map; * @author song-cc-rock */ @Data +@EqualsAndHashCode(callSuper = false) public class BugEditRequest { @Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.java index 12a74c8786..ba4711accd 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.java +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.java @@ -1,6 +1,8 @@ package io.metersphere.bug.mapper; import io.metersphere.bug.dto.BugDTO; +import io.metersphere.bug.dto.BugTagEditDTO; +import io.metersphere.bug.dto.request.BugBatchUpdateRequest; import io.metersphere.bug.dto.request.BugPageRequest; import org.apache.ibatis.annotations.Param; @@ -23,4 +25,18 @@ public interface ExtBugMapper { * @return 最大的业务ID */ Long getMaxNum(String projectId); + + /** + * 获取缺陷标签列表 + * @param ids 缺陷ID集合 + * @return 缺陷标签列表 + */ + List getBugTagList(@Param("ids") List ids); + + /** + * 批量更新缺陷 + * @param request 请求参数 + * @param ids 缺陷ID集合 + */ + void batchUpdate(@Param("request") BugBatchUpdateRequest request, @Param("ids") List ids); } diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.xml b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.xml index cac097357a..d99c77513e 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.xml +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.xml @@ -11,6 +11,30 @@ select max(num) from bug where project_id = #{projectId} + + + + update bug + + + handle_user = #{request.handleUser}, + handle_users = handle_users + concat(',', #{request.handleUser}), + + + tag = #{request.tag}, + + + where id in + + #{id} + + + diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugService.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugService.java index 539cbd162d..9d8796a04f 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugService.java +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugService.java @@ -4,6 +4,9 @@ import io.metersphere.bug.domain.*; import io.metersphere.bug.dto.BugCustomFieldDTO; import io.metersphere.bug.dto.BugDTO; import io.metersphere.bug.dto.BugRelationCaseCountDTO; +import io.metersphere.bug.dto.BugTagEditDTO; +import io.metersphere.bug.dto.request.BugBatchRequest; +import io.metersphere.bug.dto.request.BugBatchUpdateRequest; import io.metersphere.bug.dto.request.BugEditRequest; import io.metersphere.bug.dto.request.BugPageRequest; import io.metersphere.bug.enums.BugPlatform; @@ -29,7 +32,6 @@ import io.metersphere.system.file.FileRequest; import io.metersphere.system.mapper.BaseUserMapper; import io.metersphere.system.mapper.TemplateMapper; import io.metersphere.system.service.BaseTemplateService; -import io.metersphere.system.service.PlatformPluginService; import io.metersphere.system.uid.IDGenerator; import io.metersphere.system.uid.NumGenerator; import jakarta.annotation.Resource; @@ -69,8 +71,6 @@ public class BugService { @Resource private SqlSessionFactory sqlSessionFactory; @Resource - private PlatformPluginService platformPluginService; - @Resource private ProjectTemplateService projectTemplateService; @Resource private BugCustomFieldMapper bugCustomFieldMapper; @@ -141,7 +141,7 @@ public class BugService { // 缺陷基础字段 handleAndSaveBug(request, currentUser, BugPlatform.LOCAL.getName()); // 自定义字段 - handleAndSaveCustomFields(request, false); + handleAndSaveCustomFields(request, false, false); // 附件 handleAndSaveAttachments(request, files, currentUser); } @@ -163,7 +163,7 @@ public class BugService { // 缺陷 handleAndSaveBug(request, currentUser, BugPlatform.LOCAL.getName()); // 自定义字段 - handleAndSaveCustomFields(request, true); + handleAndSaveCustomFields(request, true, false); // 附件 handleAndSaveAttachments(request, files, currentUser); } @@ -214,6 +214,106 @@ public class BugService { } } + /** + * 批量删除缺陷 + * @param request 请求参数 + */ + public void batchDelete(BugBatchRequest request) { + // 非Local直接删除, Local移入回收站 + if (request.isSelectAll()) { + // 全选 + BugPageRequest bugPageRequest = new BugPageRequest(); + BeanUtils.copyBean(bugPageRequest, request); + bugPageRequest.setUseTrash(false); + CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(bugPageRequest); + List bugs = extBugMapper.list(bugPageRequest); + if (CollectionUtils.isNotEmpty(bugs)) { + List deleteIds = bugs.stream().filter(bug -> !StringUtils.equals(BugPlatform.LOCAL.getName(), bug.getPlatform())).map(BugDTO::getId).toList(); + if (CollectionUtils.isNotEmpty(deleteIds)) { + BugExample bugExample = new BugExample(); + bugExample.createCriteria().andIdIn(deleteIds); + bugMapper.deleteByExample(bugExample); + } + bugs.stream().filter(bug -> StringUtils.equals(bug.getPlatform(), BugPlatform.LOCAL.getName())).forEach(bug -> { + Bug record = new Bug(); + record.setId(bug.getId()); + record.setTrash(true); + bugMapper.updateByPrimaryKeySelective(record); + }); + } + } else { + // 勾选部分 + if (CollectionUtils.isEmpty(request.getIncludeBugIds())) { + throw new MSException(Translator.get("no_bug_select")); + } + // 勾选操作数据较少, 可逐条删除 + request.getIncludeBugIds().forEach(this::delete); + } + } + + /** + * 批量编辑缺陷 + * @param request 请求参数 + */ + public void batchUpdate(BugBatchUpdateRequest request) { + List handleIds = new ArrayList<>(); + if (request.isSelectAll()) { + // 全选 + BugPageRequest bugPageRequest = new BugPageRequest(); + BeanUtils.copyBean(bugPageRequest, request); + bugPageRequest.setUseTrash(false); + CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(bugPageRequest); + List bugs = extBugMapper.list(bugPageRequest); + if (CollectionUtils.isNotEmpty(bugs)) { + handleIds = bugs.stream().map(BugDTO::getId).toList(); + } + } else { + // 勾选部分 + if (CollectionUtils.isEmpty(request.getIncludeBugIds())) { + throw new MSException(Translator.get("no_bug_select")); + } + handleIds = request.getIncludeBugIds(); + } + if (CollectionUtils.isEmpty(handleIds)) { + throw new MSException(Translator.get("no_bug_select")); + } + if (request.getCustomField() == null) { + // 系统字段处理, TAG需单独处理追加的问题 + if (StringUtils.isNotEmpty(request.getTag()) && request.isAppend()) { + // 标签(追加) + List bugTagList = extBugMapper.getBugTagList(handleIds); + if (CollectionUtils.isEmpty(bugTagList)) { + throw new MSException(Translator.get("bug_select_not_found")); + } + Map bugTagMap = bugTagList.stream().collect(Collectors.toMap(BugTagEditDTO::getBugId, b -> Optional.ofNullable(b.getTag()).orElse(StringUtils.EMPTY))); + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + BugMapper batchMapper = sqlSession.getMapper(BugMapper.class); + bugTagMap.forEach((k, v) -> { + Bug record = new Bug(); + record.setId(k); + record.setTag(CustomFieldUtils.appendToMultipleCustomField(v, request.getTag())); + batchMapper.updateByPrimaryKeySelective(record); + }); + sqlSession.flushStatements(); + SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); + } else { + extBugMapper.batchUpdate(request, handleIds); + } + } else { + // 自定义字段处理 (第三方模板字段暂时不支持批量编辑, 涉及到同步) + BugCustomFieldDTO customField = request.getCustomField(); + Map customFieldMap = new HashMap<>(1); + customFieldMap.put(customField.getId(), customField.getValue()); + handleIds.forEach(id -> { + BugEditRequest bugEditRequest = new BugEditRequest(); + BeanUtils.copyBean(bugEditRequest, request); + bugEditRequest.setId(id); + bugEditRequest.setCustomFieldMap(customFieldMap); + handleAndSaveCustomFields(bugEditRequest, true, request.isAppend()); + }); + } + } + /** * 处理保存缺陷基础信息 * @@ -283,7 +383,7 @@ public class BugService { * * @param request 请求参数 */ - private void handleAndSaveCustomFields(BugEditRequest request, boolean merge) { + private void handleAndSaveCustomFields(BugEditRequest request, boolean merge, boolean append) { Map customFieldMap = request.getCustomFieldMap(); if (MapUtils.isEmpty(customFieldMap)) { return; @@ -306,7 +406,12 @@ public class BugService { // 已存在的缺陷字段关系 bugCustomField.setBugId(request.getId()); bugCustomField.setFieldId(fieldId); - bugCustomField.setValue(customFieldMap.get(fieldId)); + if (append) { + // 追加处理只存在多选类型的自定义字段 + bugCustomField.setValue(CustomFieldUtils.appendToMultipleCustomField(originalFieldMap.get(fieldId), customFieldMap.get(fieldId))); + } else { + bugCustomField.setValue(customFieldMap.get(fieldId)); + } updateFields.add(bugCustomField); } }); @@ -409,7 +514,9 @@ public class BugService { addFiles.add(bugAttachment); }); } - extBugAttachmentMapper.batchInsert(addFiles); + if (CollectionUtils.isNotEmpty(addFiles)) { + extBugAttachmentMapper.batchInsert(addFiles); + } // TODO: 如果是第三方平台, 需调用平台插件同步上传附件 uploadMinioFiles.forEach((fileId, file) -> { FileRequest fileRequest = new FileRequest(); diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/utils/CustomFieldUtils.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/utils/CustomFieldUtils.java index 513ec98505..f9e9eb990a 100644 --- a/backend/services/bug-management/src/main/java/io/metersphere/bug/utils/CustomFieldUtils.java +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/utils/CustomFieldUtils.java @@ -60,4 +60,21 @@ public class CustomFieldUtils { }); } } + + /** + * 多选字段追加值 + * @param originalVal 原始值 + * @param appendVal 追加值 + * @return 追加后的值 + */ + public static String appendToMultipleCustomField(String originalVal, String appendVal) { + if (StringUtils.isEmpty(originalVal)) { + return appendVal; + } + List orignalList = JSON.parseArray(originalVal, String.class); + List appendList = JSON.parseArray(appendVal, String.class); + orignalList.addAll(appendList); + // 追加后需去重 + return JSON.toJSONString(orignalList.stream().distinct().toList()); + } } diff --git a/backend/services/bug-management/src/test/java/io/metersphere/bug/controller/BugControllerTests.java b/backend/services/bug-management/src/test/java/io/metersphere/bug/controller/BugControllerTests.java index 72ccf6ca6e..f3184b1997 100644 --- a/backend/services/bug-management/src/test/java/io/metersphere/bug/controller/BugControllerTests.java +++ b/backend/services/bug-management/src/test/java/io/metersphere/bug/controller/BugControllerTests.java @@ -1,6 +1,9 @@ package io.metersphere.bug.controller; +import io.metersphere.bug.dto.BugCustomFieldDTO; import io.metersphere.bug.dto.BugDTO; +import io.metersphere.bug.dto.request.BugBatchRequest; +import io.metersphere.bug.dto.request.BugBatchUpdateRequest; import io.metersphere.bug.dto.request.BugEditRequest; import io.metersphere.bug.dto.request.BugPageRequest; import io.metersphere.project.dto.ProjectTemplateOptionDTO; @@ -16,6 +19,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.SqlConfig; import org.springframework.test.web.servlet.MvcResult; +import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import java.io.File; @@ -35,6 +39,8 @@ public class BugControllerTests extends BaseTest { public static final String BUG_DELETE = "/bug/delete"; public static final String BUG_TEMPLATE_OPTION = "/bug/template/option"; public static final String BUG_TEMPLATE_DETAIL = "/bug/template"; + public static final String BUG_BATCH_DELETE = "/bug/batch-delete"; + public static final String BUG_BATCH_UPDATE = "/bug/batch-update"; @Test @Order(0) @@ -165,6 +171,11 @@ public class BugControllerTests extends BaseTest { File file = new File(filePath); MultiValueMap paramMap = getDefaultMultiPartParam(request, file); this.requestMultipartWithOkAndReturn(BUG_UPDATE, paramMap); + // 第二次更新, no-file + MultiValueMap noFileParamMap = new LinkedMultiValueMap<>(); + request.setLinkFileIds(null); + noFileParamMap.add("request", JSON.toJSONString(request)); + this.requestMultipartWithOkAndReturn(BUG_UPDATE, noFileParamMap); } @Test @@ -191,20 +202,6 @@ public class BugControllerTests extends BaseTest { @Test @Order(8) - public void testDeleteBugSuccess() throws Exception { - this.requestGet(BUG_DELETE + "/default-bug-id", status().isOk()); - // 非Local缺陷 - this.requestGet(BUG_DELETE + "/default-bug-id-tapd", status().isOk()); - } - - @Test - @Order(9) - public void testDeleteBugError() throws Exception { - this.requestGet(BUG_DELETE + "/default-bug-id-not-exist", status().is5xxServerError()); - } - - @Test - @Order(10) public void testGetBugTemplateOption() throws Exception { MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_TEMPLATE_OPTION + "?projectId=default-project-for-bug"); String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); @@ -215,7 +212,7 @@ public class BugControllerTests extends BaseTest { } @Test - @Order(11) + @Order(9) public void testGetBugTemplateDetailSuccess() throws Exception { MvcResult mvcResult = this.requestGetWithOkAndReturn(BUG_TEMPLATE_DETAIL + "/default-bug-template-id" + "?projectId=default-project-for-bug"); String sortData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); @@ -232,6 +229,108 @@ public class BugControllerTests extends BaseTest { Assertions.assertEquals("default-bug-template-id", defaultTemplate.getId()); } + @Test + @Order(10) + public void testBatchUpdateBugSuccess() throws Exception { + BugBatchUpdateRequest request = new BugBatchUpdateRequest(); + request.setProjectId("default-project-for-bug"); + // 全选, 编辑所有数据 + request.setSelectAll(true); + // TAG追加 + request.setTag(JSON.toJSONString(List.of("TAG", "TEST_TAG"))); + request.setAppend(true); + this.requestPost(BUG_BATCH_UPDATE, request, status().isOk()); + // TAG覆盖 + request.setTag(JSON.toJSONString(List.of("A", "B"))); + request.setAppend(false); + this.requestPost(BUG_BATCH_UPDATE, request, status().isOk()); + // TAG追加 + request.setTag(JSON.toJSONString(List.of("C", "D"))); + request.setAppend(true); + this.requestPost(BUG_BATCH_UPDATE, request, status().isOk()); + // 处理人修改 + request.setTag(null); + request.setHandleUser("default-admin"); + this.requestPost(BUG_BATCH_UPDATE, request, status().isOk()); + // 自定义字段追加 + BugCustomFieldDTO field = new BugCustomFieldDTO(); + field.setId("test_field"); + field.setValue(JSON.toJSONString(List.of("test1"))); + request.setCustomField(field); + this.requestPost(BUG_BATCH_UPDATE, request, status().isOk()); + // 自定义字段覆盖 + request.setAppend(false); + this.requestPost(BUG_BATCH_UPDATE, request, status().isOk()); + // 勾选部分 + request.setSelectAll(false); + request.setIncludeBugIds(List.of("default-bug-id")); + this.requestPost(BUG_BATCH_UPDATE, request, status().isOk()); + } + + @Test + @Order(11) + public void testBatchUpdateEmptyBugSuccess() throws Exception { + BugBatchUpdateRequest request = new BugBatchUpdateRequest(); + request.setProjectId("default-project-for-bug"); + request.setCombine(buildRequestCombine()); + // 全选, 空数据 + request.setSelectAll(true); + request.setTag(JSON.toJSONString(List.of("TAG", "TEST_TAG"))); + request.setAppend(true); + this.requestPost(BUG_BATCH_UPDATE, request, status().is5xxServerError()); + request.setSelectAll(false); + request.setIncludeBugIds(List.of("not-exist-bug-id")); + this.requestPost(BUG_BATCH_UPDATE, request, status().is5xxServerError()); + request.setSelectAll(false); + request.setIncludeBugIds(null); + this.requestPost(BUG_BATCH_UPDATE, request, status().is5xxServerError()); + } + + @Test + @Order(12) + public void testDeleteBugSuccess() throws Exception { + this.requestGet(BUG_DELETE + "/default-bug-id", status().isOk()); + // 非Local缺陷 + this.requestGet(BUG_DELETE + "/default-bug-id-tapd1", status().isOk()); + } + + @Test + @Order(13) + public void testDeleteBugError() throws Exception { + this.requestGet(BUG_DELETE + "/default-bug-id-not-exist", status().is5xxServerError()); + } + + @Test + @Order(14) + public void testBatchDeleteEmptyBugSuccess() throws Exception { + BugBatchRequest request = new BugBatchRequest(); + request.setProjectId("default-project-for-bug"); + request.setCombine(buildRequestCombine()); + // 全选, 空数据 + request.setSelectAll(true); + this.requestPost(BUG_BATCH_DELETE, request, status().isOk()); + // 勾选部分, 空数据 + request.setSelectAll(false); + this.requestPost(BUG_BATCH_DELETE, request, status().is5xxServerError()); + } + + @Test + @Order(20) + public void testBatchDeleteBugSuccess() throws Exception { + BugBatchRequest request = new BugBatchRequest(); + request.setProjectId("default-project-for-bug"); + // 全选, 删除所有 + request.setSelectAll(true); + this.requestPost(BUG_BATCH_DELETE, request, status().isOk()); + // 非Local的缺陷删除 + request.setProjectId("default-project-for-bug-no-local"); + this.requestPost(BUG_BATCH_DELETE, request, status().isOk()); + // 勾选部分 + request.setSelectAll(false); + request.setIncludeBugIds(List.of("default-bug-id-single")); + this.requestPost(BUG_BATCH_DELETE, request, status().isOk()); + } + /** * 生成请求过滤参数 * @return filter param @@ -272,16 +371,15 @@ public class BugControllerTests extends BaseTest { request.setHandleUser("admin"); request.setTemplateId("default-bug-template"); request.setStatus("prepare"); - request.setTag(JSON.toJSONString(List.of("TAG", "DEFAULT-TAG"))); request.setLinkFileIds(List.of("default-bug-file-id-1", "default-bug-file-id-3")); Map customFieldMap = new HashMap<>(); customFieldMap.put("custom-field", "oasis"); + customFieldMap.put("test_field", JSON.toJSONString(List.of("test"))); if (isUpdate) { request.setId("default-bug-id"); request.setUnLinkFileIds(List.of("default-bug-file-id-1")); request.setDeleteLocalFileIds(List.of("default-bug-file-id")); request.setLinkFileIds(List.of("default-bug-file-id-2")); - customFieldMap.put("test_field", JSON.toJSONString(List.of("test"))); } request.setCustomFieldMap(customFieldMap); return request; diff --git a/backend/services/bug-management/src/test/resources/dml/init_bug.sql b/backend/services/bug-management/src/test/resources/dml/init_bug.sql index 6a30c8b7fe..7b33c32217 100644 --- a/backend/services/bug-management/src/test/resources/dml/init_bug.sql +++ b/backend/services/bug-management/src/test/resources/dml/init_bug.sql @@ -7,12 +7,15 @@ INSERT INTO project (id, num, organization_id, name, description, create_user, u INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time, update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tag, platform_bug_id, trash) VALUES ('default-bug-id', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'bug-template-id', 'Local', 'open', 'default-tag', null, 0), - ('default-bug-id-tapd', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'default-bug-template-id', 'Tapd', 'open', 'default-tag', null, 0); + ('default-bug-id-tapd1', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'default-bug-template-id', 'Tapd', 'open', 'default-tag', null, 0), + ('default-bug-id-tapd2', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug-no-local', 'default-bug-template-id', 'Tapd', 'open', 'default-tag', null, 0), + ('default-bug-id-single', 100000, 'default-bug', 'oasis', 'oasis', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'default-project-for-bug-single', 'default-bug-template-id', 'Tapd', 'open', 'default-tag', null, 0); INSERT INTO bug_custom_field (bug_id, field_id, value) VALUE ('default-bug-id', 'test_field', '["default", "default-1"]'); INSERT INTO custom_field (id, name, scene, type, remark, internal, scope_type, create_time, update_time, create_user, scope_id) VALUE - ('test_field', '测试字段', 'BUG', 'MULTIPLE_SELECT', '', 0, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'default-project-for-bug'); + ('test_field', '测试字段', 'BUG', 'MULTIPLE_SELECT', '', 0, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'default-project-for-bug'), + ('custom-field', '测试字段', 'BUG', 'SELECT', '', 0, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'default-project-for-bug'); INSERT INTO template (id, name, remark, internal, update_time, create_time, create_user, scope_type, scope_id, enable_third_part, scene) VALUES ('bug-template-id', 'bug-template', '', 0, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', 'default-project-for-bug', 0, 'BUG'),