From 3dab64d0f0e332b3911ce46134b18d35357251dc Mon Sep 17 00:00:00 2001 From: song-cc-rock Date: Mon, 16 Oct 2023 11:32:29 +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=E5=9F=BA=E7=A1=80=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/metersphere/bug/domain/Bug.java | 18 +- .../metersphere/bug/domain/BugAttachment.java | 8 +- .../bug/domain/BugAttachmentExample.java | 48 +- .../io/metersphere/bug/domain/BugComment.java | 8 +- .../io/metersphere/bug/domain/BugExample.java | 126 ++++- .../io/metersphere/bug/domain/BugHistory.java | 8 + .../bug/domain/BugHistoryExample.java | 140 +++++ .../bug/domain/BugRelationCase.java | 4 +- .../bug/mapper/BugAttachmentMapper.xml | 40 +- .../bug/mapper/BugCommentMapper.xml | 73 ++- .../bug/mapper/BugHistoryMapper.xml | 56 +- .../io/metersphere/bug/mapper/BugMapper.xml | 89 +-- .../3.0.0/ddl/V3.0.0_7__bug_management.sql | 48 +- .../migration/3.0.0/dml/V3.0.0_11_1__data.sql | 4 + .../dto/SyncAttachmentToPlatformRequest.java | 24 + .../dto/SyncBugAttachmentRequest.java | 24 - .../platform/enums/SyncAttachmentType.java | 24 + .../plugin/platform/spi/Platform.java | 61 +- .../sdk/constants/CustomFieldType.java | 35 +- .../sdk/constants/PermissionConstants.java | 7 + .../io/metersphere/sdk/util/MsFileUtils.java | 8 +- .../src/main/resources/i18n/bug.properties | 15 +- .../main/resources/i18n/bug_en_US.properties | 15 +- .../main/resources/i18n/bug_zh_CN.properties | 15 +- .../main/resources/i18n/bug_zh_TW.properties | 12 +- .../resources/i18n/project_en_US.properties | 1 + .../resources/i18n/project_zh_CN.properties | 1 + .../resources/i18n/project_zh_TW.properties | 3 +- backend/services/bug-management/pom.xml | 8 + .../bug/controller/BugController.java | 89 +++ .../bug/controller/BugHistoryController.java | 4 + .../bug/dto/BugCustomFieldDTO.java | 18 + .../java/io/metersphere/bug/dto/BugDTO.java | 32 ++ .../bug/dto/BugHistoryContentDTO.java | 24 + .../bug/dto/BugRelationCaseCountDTO.java | 17 + .../bug/dto/BugStatusOptionDTO.java | 10 + .../bug/dto/request/BugEditRequest.java | 66 +++ .../bug/dto/request/BugPageRequest.java | 17 + .../io/metersphere/bug/enums/BugPlatform.java | 39 ++ .../bug/enums/result/BugResultCode.java | 38 ++ .../bug/mapper/ExtBugAttachmentMapper.java | 15 + .../bug/mapper/ExtBugAttachmentMapper.xml | 11 + .../bug/mapper/ExtBugCustomFieldMapper.java | 24 + .../bug/mapper/ExtBugCustomFieldMapper.xml | 19 + .../metersphere/bug/mapper/ExtBugMapper.java | 26 + .../metersphere/bug/mapper/ExtBugMapper.xml | 143 +++++ .../bug/mapper/ExtBugRelationCaseMapper.java | 19 + .../bug/mapper/ExtBugRelationCaseMapper.xml | 12 + .../bug/service/BugHistoryService.java | 29 + .../metersphere/bug/service/BugService.java | 519 ++++++++++++++++++ .../bug/service/BugStatusService.java | 66 +++ .../service/CleanupBugResourceService.java | 19 + .../bug/utils/CustomFieldUtils.java | 63 +++ .../src/main/resources/bugGeneratorConfig.xml | 14 +- .../src/main/resources/permission.json | 27 + .../java/io/metersphere/bug/Application.java | 2 +- .../bug/controller/BugControllerTests.java | 289 ++++++++++ .../src/test/resources/application.properties | 6 +- .../src/test/resources/dml/init_bug.sql | 31 ++ .../src/test/resources/file/test.xlsx | Bin 0 -> 8861 bytes .../project/service/CommandService.java | 2 +- .../service/ProjectApplicationService.java | 14 +- .../service/ProjectTemplateService.java | 5 +- .../system/file/LocalFileRepository.java | 2 +- .../metersphere/system/mapper/BaseMapper.xml | 6 + .../system/service/BaseTemplateService.java | 16 +- 66 files changed, 2392 insertions(+), 264 deletions(-) create mode 100644 backend/framework/plugin/plugin-platform-sdk/src/main/java/io/metersphere/plugin/platform/dto/SyncAttachmentToPlatformRequest.java delete mode 100644 backend/framework/plugin/plugin-platform-sdk/src/main/java/io/metersphere/plugin/platform/dto/SyncBugAttachmentRequest.java create mode 100644 backend/framework/plugin/plugin-platform-sdk/src/main/java/io/metersphere/plugin/platform/enums/SyncAttachmentType.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/controller/BugController.java create 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/BugCustomFieldDTO.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugDTO.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugHistoryContentDTO.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugRelationCaseCountDTO.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/BugStatusOptionDTO.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugEditRequest.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/dto/request/BugPageRequest.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/enums/BugPlatform.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/enums/result/BugResultCode.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugAttachmentMapper.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugAttachmentMapper.xml create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugCustomFieldMapper.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugCustomFieldMapper.xml create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.xml create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelationCaseMapper.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelationCaseMapper.xml create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugHistoryService.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugService.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugStatusService.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/service/CleanupBugResourceService.java create mode 100644 backend/services/bug-management/src/main/java/io/metersphere/bug/utils/CustomFieldUtils.java create mode 100644 backend/services/bug-management/src/main/resources/permission.json create mode 100644 backend/services/bug-management/src/test/java/io/metersphere/bug/controller/BugControllerTests.java create mode 100644 backend/services/bug-management/src/test/resources/dml/init_bug.sql create mode 100644 backend/services/bug-management/src/test/resources/file/test.xlsx diff --git a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/Bug.java b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/Bug.java index 9ed6b7a85b..228ce0efa9 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/Bug.java +++ b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/Bug.java @@ -27,10 +27,13 @@ public class Bug implements Serializable { @Size(min = 1, max = 300, message = "{bug.title.length_range}", groups = {Created.class, Updated.class}) private String title; - @Schema(description = "指派人", requiredMode = Schema.RequiredMode.REQUIRED) - @NotBlank(message = "{bug.assign_user.not_blank}", groups = {Created.class}) - @Size(min = 1, max = 50, message = "{bug.assign_user.length_range}", groups = {Created.class, Updated.class}) - private String assignUser; + @Schema(description = "处理人集合;预留字段, 后续工作台统计可能需要") + private String handleUsers; + + @Schema(description = "处理人", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "{bug.handle_user.not_blank}", groups = {Created.class}) + @Size(min = 1, max = 50, message = "{bug.handle_user.length_range}", groups = {Created.class, Updated.class}) + private String handleUser; @Schema(description = "创建人") private String createUser; @@ -55,7 +58,9 @@ public class Bug implements Serializable { @Size(min = 1, max = 50, message = "{bug.project_id.length_range}", groups = {Created.class, Updated.class}) private String projectId; - @Schema(description = "模板ID") + @Schema(description = "模板ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "{bug.template_id.not_blank}", groups = {Created.class}) + @Size(min = 1, max = 50, message = "{bug.template_id.length_range}", groups = {Created.class, Updated.class}) private String templateId; @Schema(description = "缺陷平台", requiredMode = Schema.RequiredMode.REQUIRED) @@ -84,7 +89,8 @@ public class Bug implements Serializable { id("id", "id", "VARCHAR", false), num("num", "num", "INTEGER", false), title("title", "title", "VARCHAR", false), - assignUser("assign_user", "assignUser", "VARCHAR", false), + handleUsers("handle_users", "handleUsers", "VARCHAR", false), + handleUser("handle_user", "handleUser", "VARCHAR", false), createUser("create_user", "createUser", "VARCHAR", false), createTime("create_time", "createTime", "BIGINT", false), updateUser("update_user", "updateUser", "VARCHAR", false), diff --git a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugAttachment.java b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugAttachment.java index d4295cf5f7..af3589d0f3 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugAttachment.java +++ b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugAttachment.java @@ -38,9 +38,9 @@ public class BugAttachment implements Serializable { @NotNull(message = "{bug_attachment.size.not_blank}", groups = {Created.class}) private Long size; - @Schema(description = "是否关联", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "{bug_attachment.association.not_blank}", groups = {Created.class}) - private Boolean association; + @Schema(description = "是否本地", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "{bug_attachment.local.not_blank}", groups = {Created.class}) + private Boolean local; @Schema(description = "创建人") private String createUser; @@ -56,7 +56,7 @@ public class BugAttachment implements Serializable { fileId("file_id", "fileId", "VARCHAR", false), fileName("file_name", "fileName", "VARCHAR", false), size("size", "size", "BIGINT", true), - association("association", "association", "BIT", false), + local("local", "local", "BIT", true), createUser("create_user", "createUser", "VARCHAR", false), createTime("create_time", "createTime", "BIGINT", false); diff --git a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugAttachmentExample.java b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugAttachmentExample.java index 436f387932..16e7844168 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugAttachmentExample.java +++ b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugAttachmentExample.java @@ -444,63 +444,63 @@ public class BugAttachmentExample { return (Criteria) this; } - public Criteria andAssociationIsNull() { - addCriterion("association is null"); + public Criteria andLocalIsNull() { + addCriterion("`local` is null"); return (Criteria) this; } - public Criteria andAssociationIsNotNull() { - addCriterion("association is not null"); + public Criteria andLocalIsNotNull() { + addCriterion("`local` is not null"); return (Criteria) this; } - public Criteria andAssociationEqualTo(Boolean value) { - addCriterion("association =", value, "association"); + public Criteria andLocalEqualTo(Boolean value) { + addCriterion("`local` =", value, "local"); return (Criteria) this; } - public Criteria andAssociationNotEqualTo(Boolean value) { - addCriterion("association <>", value, "association"); + public Criteria andLocalNotEqualTo(Boolean value) { + addCriterion("`local` <>", value, "local"); return (Criteria) this; } - public Criteria andAssociationGreaterThan(Boolean value) { - addCriterion("association >", value, "association"); + public Criteria andLocalGreaterThan(Boolean value) { + addCriterion("`local` >", value, "local"); return (Criteria) this; } - public Criteria andAssociationGreaterThanOrEqualTo(Boolean value) { - addCriterion("association >=", value, "association"); + public Criteria andLocalGreaterThanOrEqualTo(Boolean value) { + addCriterion("`local` >=", value, "local"); return (Criteria) this; } - public Criteria andAssociationLessThan(Boolean value) { - addCriterion("association <", value, "association"); + public Criteria andLocalLessThan(Boolean value) { + addCriterion("`local` <", value, "local"); return (Criteria) this; } - public Criteria andAssociationLessThanOrEqualTo(Boolean value) { - addCriterion("association <=", value, "association"); + public Criteria andLocalLessThanOrEqualTo(Boolean value) { + addCriterion("`local` <=", value, "local"); return (Criteria) this; } - public Criteria andAssociationIn(List values) { - addCriterion("association in", values, "association"); + public Criteria andLocalIn(List values) { + addCriterion("`local` in", values, "local"); return (Criteria) this; } - public Criteria andAssociationNotIn(List values) { - addCriterion("association not in", values, "association"); + public Criteria andLocalNotIn(List values) { + addCriterion("`local` not in", values, "local"); return (Criteria) this; } - public Criteria andAssociationBetween(Boolean value1, Boolean value2) { - addCriterion("association between", value1, value2, "association"); + public Criteria andLocalBetween(Boolean value1, Boolean value2) { + addCriterion("`local` between", value1, value2, "local"); return (Criteria) this; } - public Criteria andAssociationNotBetween(Boolean value1, Boolean value2) { - addCriterion("association not between", value1, value2, "association"); + public Criteria andLocalNotBetween(Boolean value1, Boolean value2) { + addCriterion("`local` not between", value1, value2, "local"); return (Criteria) this; } diff --git a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugComment.java b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugComment.java index 724320e309..6af27e2fd2 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugComment.java +++ b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugComment.java @@ -45,9 +45,9 @@ public class BugComment implements Serializable { private Long updateTime; @Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED) - @NotBlank(message = "{bug_comment.description.not_blank}", groups = {Created.class}) - @Size(min = 1, max = 65535, message = "{bug_comment.description.length_range}", groups = {Created.class, Updated.class}) - private String description; + @NotBlank(message = "{bug_comment.content.not_blank}", groups = {Created.class}) + @Size(min = 1, max = 65535, message = "{bug_comment.content.length_range}", groups = {Created.class, Updated.class}) + private String content; private static final long serialVersionUID = 1L; @@ -61,7 +61,7 @@ public class BugComment implements Serializable { createTime("create_time", "createTime", "BIGINT", false), updateUser("update_user", "updateUser", "VARCHAR", false), updateTime("update_time", "updateTime", "BIGINT", false), - description("description", "description", "LONGVARCHAR", false); + content("content", "content", "LONGVARCHAR", false); private static final String BEGINNING_DELIMITER = "`"; diff --git a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugExample.java b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugExample.java index 56a3932d9f..850624bac9 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugExample.java +++ b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugExample.java @@ -304,73 +304,143 @@ public class BugExample { return (Criteria) this; } - public Criteria andAssignUserIsNull() { - addCriterion("assign_user is null"); + public Criteria andHandleUsersIsNull() { + addCriterion("handle_users is null"); return (Criteria) this; } - public Criteria andAssignUserIsNotNull() { - addCriterion("assign_user is not null"); + public Criteria andHandleUsersIsNotNull() { + addCriterion("handle_users is not null"); return (Criteria) this; } - public Criteria andAssignUserEqualTo(String value) { - addCriterion("assign_user =", value, "assignUser"); + public Criteria andHandleUsersEqualTo(String value) { + addCriterion("handle_users =", value, "handleUsers"); return (Criteria) this; } - public Criteria andAssignUserNotEqualTo(String value) { - addCriterion("assign_user <>", value, "assignUser"); + public Criteria andHandleUsersNotEqualTo(String value) { + addCriterion("handle_users <>", value, "handleUsers"); return (Criteria) this; } - public Criteria andAssignUserGreaterThan(String value) { - addCriterion("assign_user >", value, "assignUser"); + public Criteria andHandleUsersGreaterThan(String value) { + addCriterion("handle_users >", value, "handleUsers"); return (Criteria) this; } - public Criteria andAssignUserGreaterThanOrEqualTo(String value) { - addCriterion("assign_user >=", value, "assignUser"); + public Criteria andHandleUsersGreaterThanOrEqualTo(String value) { + addCriterion("handle_users >=", value, "handleUsers"); return (Criteria) this; } - public Criteria andAssignUserLessThan(String value) { - addCriterion("assign_user <", value, "assignUser"); + public Criteria andHandleUsersLessThan(String value) { + addCriterion("handle_users <", value, "handleUsers"); return (Criteria) this; } - public Criteria andAssignUserLessThanOrEqualTo(String value) { - addCriterion("assign_user <=", value, "assignUser"); + public Criteria andHandleUsersLessThanOrEqualTo(String value) { + addCriterion("handle_users <=", value, "handleUsers"); return (Criteria) this; } - public Criteria andAssignUserLike(String value) { - addCriterion("assign_user like", value, "assignUser"); + public Criteria andHandleUsersLike(String value) { + addCriterion("handle_users like", value, "handleUsers"); return (Criteria) this; } - public Criteria andAssignUserNotLike(String value) { - addCriterion("assign_user not like", value, "assignUser"); + public Criteria andHandleUsersNotLike(String value) { + addCriterion("handle_users not like", value, "handleUsers"); return (Criteria) this; } - public Criteria andAssignUserIn(List values) { - addCriterion("assign_user in", values, "assignUser"); + public Criteria andHandleUsersIn(List values) { + addCriterion("handle_users in", values, "handleUsers"); return (Criteria) this; } - public Criteria andAssignUserNotIn(List values) { - addCriterion("assign_user not in", values, "assignUser"); + public Criteria andHandleUsersNotIn(List values) { + addCriterion("handle_users not in", values, "handleUsers"); return (Criteria) this; } - public Criteria andAssignUserBetween(String value1, String value2) { - addCriterion("assign_user between", value1, value2, "assignUser"); + public Criteria andHandleUsersBetween(String value1, String value2) { + addCriterion("handle_users between", value1, value2, "handleUsers"); return (Criteria) this; } - public Criteria andAssignUserNotBetween(String value1, String value2) { - addCriterion("assign_user not between", value1, value2, "assignUser"); + public Criteria andHandleUsersNotBetween(String value1, String value2) { + addCriterion("handle_users not between", value1, value2, "handleUsers"); + return (Criteria) this; + } + + public Criteria andHandleUserIsNull() { + addCriterion("handle_user is null"); + return (Criteria) this; + } + + public Criteria andHandleUserIsNotNull() { + addCriterion("handle_user is not null"); + return (Criteria) this; + } + + public Criteria andHandleUserEqualTo(String value) { + addCriterion("handle_user =", value, "handleUser"); + return (Criteria) this; + } + + public Criteria andHandleUserNotEqualTo(String value) { + addCriterion("handle_user <>", value, "handleUser"); + return (Criteria) this; + } + + public Criteria andHandleUserGreaterThan(String value) { + addCriterion("handle_user >", value, "handleUser"); + return (Criteria) this; + } + + public Criteria andHandleUserGreaterThanOrEqualTo(String value) { + addCriterion("handle_user >=", value, "handleUser"); + return (Criteria) this; + } + + public Criteria andHandleUserLessThan(String value) { + addCriterion("handle_user <", value, "handleUser"); + return (Criteria) this; + } + + public Criteria andHandleUserLessThanOrEqualTo(String value) { + addCriterion("handle_user <=", value, "handleUser"); + return (Criteria) this; + } + + public Criteria andHandleUserLike(String value) { + addCriterion("handle_user like", value, "handleUser"); + return (Criteria) this; + } + + public Criteria andHandleUserNotLike(String value) { + addCriterion("handle_user not like", value, "handleUser"); + return (Criteria) this; + } + + public Criteria andHandleUserIn(List values) { + addCriterion("handle_user in", values, "handleUser"); + return (Criteria) this; + } + + public Criteria andHandleUserNotIn(List values) { + addCriterion("handle_user not in", values, "handleUser"); + return (Criteria) this; + } + + public Criteria andHandleUserBetween(String value1, String value2) { + addCriterion("handle_user between", value1, value2, "handleUser"); + return (Criteria) this; + } + + public Criteria andHandleUserNotBetween(String value1, String value2) { + addCriterion("handle_user not between", value1, value2, "handleUser"); return (Criteria) this; } diff --git a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugHistory.java b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugHistory.java index f24cad2d00..619ae89605 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugHistory.java +++ b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugHistory.java @@ -27,6 +27,12 @@ public class BugHistory implements Serializable { @Schema(description = "变更记录批次号") private Integer num; + @Schema(description = "变更类型; IMPORT/EDIT/ROLLBACK") + private String type; + + @Schema(description = "回退来源") + private String rollbackSourceId; + @Schema(description = "操作人") private String createUser; @@ -43,6 +49,8 @@ public class BugHistory implements Serializable { id("id", "id", "VARCHAR", false), bugId("bug_id", "bugId", "VARCHAR", false), num("num", "num", "INTEGER", false), + type("type", "type", "VARCHAR", true), + rollbackSourceId("rollback_source_id", "rollbackSourceId", "VARCHAR", false), createUser("create_user", "createUser", "VARCHAR", false), createTime("create_time", "createTime", "BIGINT", false), content("content", "content", "LONGVARBINARY", false); diff --git a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugHistoryExample.java b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugHistoryExample.java index 577e10072f..7f22e284b3 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugHistoryExample.java +++ b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugHistoryExample.java @@ -304,6 +304,146 @@ public class BugHistoryExample { return (Criteria) this; } + public Criteria andTypeIsNull() { + addCriterion("`type` is null"); + return (Criteria) this; + } + + public Criteria andTypeIsNotNull() { + addCriterion("`type` is not null"); + return (Criteria) this; + } + + public Criteria andTypeEqualTo(String value) { + addCriterion("`type` =", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotEqualTo(String value) { + addCriterion("`type` <>", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeGreaterThan(String value) { + addCriterion("`type` >", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeGreaterThanOrEqualTo(String value) { + addCriterion("`type` >=", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeLessThan(String value) { + addCriterion("`type` <", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeLessThanOrEqualTo(String value) { + addCriterion("`type` <=", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeLike(String value) { + addCriterion("`type` like", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotLike(String value) { + addCriterion("`type` not like", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeIn(List values) { + addCriterion("`type` in", values, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotIn(List values) { + addCriterion("`type` not in", values, "type"); + return (Criteria) this; + } + + public Criteria andTypeBetween(String value1, String value2) { + addCriterion("`type` between", value1, value2, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotBetween(String value1, String value2) { + addCriterion("`type` not between", value1, value2, "type"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdIsNull() { + addCriterion("rollback_source_id is null"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdIsNotNull() { + addCriterion("rollback_source_id is not null"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdEqualTo(String value) { + addCriterion("rollback_source_id =", value, "rollbackSourceId"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdNotEqualTo(String value) { + addCriterion("rollback_source_id <>", value, "rollbackSourceId"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdGreaterThan(String value) { + addCriterion("rollback_source_id >", value, "rollbackSourceId"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdGreaterThanOrEqualTo(String value) { + addCriterion("rollback_source_id >=", value, "rollbackSourceId"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdLessThan(String value) { + addCriterion("rollback_source_id <", value, "rollbackSourceId"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdLessThanOrEqualTo(String value) { + addCriterion("rollback_source_id <=", value, "rollbackSourceId"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdLike(String value) { + addCriterion("rollback_source_id like", value, "rollbackSourceId"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdNotLike(String value) { + addCriterion("rollback_source_id not like", value, "rollbackSourceId"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdIn(List values) { + addCriterion("rollback_source_id in", values, "rollbackSourceId"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdNotIn(List values) { + addCriterion("rollback_source_id not in", values, "rollbackSourceId"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdBetween(String value1, String value2) { + addCriterion("rollback_source_id between", value1, value2, "rollbackSourceId"); + return (Criteria) this; + } + + public Criteria andRollbackSourceIdNotBetween(String value1, String value2) { + addCriterion("rollback_source_id not between", value1, value2, "rollbackSourceId"); + return (Criteria) this; + } + public Criteria andCreateUserIsNull() { addCriterion("create_user is null"); return (Criteria) this; diff --git a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugRelationCase.java b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugRelationCase.java index 59b5cae9de..29278f0cf4 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugRelationCase.java +++ b/backend/framework/domain/src/main/java/io/metersphere/bug/domain/BugRelationCase.java @@ -18,9 +18,7 @@ public class BugRelationCase implements Serializable { @Size(min = 1, max = 50, message = "{bug_relation_case.id.length_range}", groups = {Created.class, Updated.class}) private String id; - @Schema(description = "关联功能用例ID", requiredMode = Schema.RequiredMode.REQUIRED) - @NotBlank(message = "{bug_relation_case.case_id.not_blank}", groups = {Created.class}) - @Size(min = 1, max = 50, message = "{bug_relation_case.case_id.length_range}", groups = {Created.class, Updated.class}) + @Schema(description = "关联功能用例ID") private String caseId; @Schema(description = "缺陷ID", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugAttachmentMapper.xml b/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugAttachmentMapper.xml index 4c6ca52ec8..ac626d64d0 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugAttachmentMapper.xml +++ b/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugAttachmentMapper.xml @@ -7,7 +7,7 @@ - + @@ -70,7 +70,7 @@ - id, bug_id, file_id, file_name, `size`, association, create_user, create_time + id, bug_id, file_id, file_name, `size`, `local`, create_user, create_time select @@ -128,13 +130,13 @@ insert into bug_comment (id, bug_id, reply_user, - parent_id, create_user, create_time, - update_user, update_time, description - ) + notifier, parent_id, create_user, + create_time, update_user, update_time, + content) values (#{id,jdbcType=VARCHAR}, #{bugId,jdbcType=VARCHAR}, #{replyUser,jdbcType=VARCHAR}, - #{parentId,jdbcType=VARCHAR}, #{createUser,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, - #{updateUser,jdbcType=VARCHAR}, #{updateTime,jdbcType=BIGINT}, #{description,jdbcType=LONGVARCHAR} - ) + #{notifier,jdbcType=VARCHAR}, #{parentId,jdbcType=VARCHAR}, #{createUser,jdbcType=VARCHAR}, + #{createTime,jdbcType=BIGINT}, #{updateUser,jdbcType=VARCHAR}, #{updateTime,jdbcType=BIGINT}, + #{content,jdbcType=LONGVARCHAR}) insert into bug_comment @@ -148,6 +150,9 @@ reply_user, + + notifier, + parent_id, @@ -163,8 +168,8 @@ update_time, - - description, + + content, @@ -177,6 +182,9 @@ #{replyUser,jdbcType=VARCHAR}, + + #{notifier,jdbcType=VARCHAR}, + #{parentId,jdbcType=VARCHAR}, @@ -192,8 +200,8 @@ #{updateTime,jdbcType=BIGINT}, - - #{description,jdbcType=LONGVARCHAR}, + + #{content,jdbcType=LONGVARCHAR}, @@ -215,6 +223,9 @@ reply_user = #{record.replyUser,jdbcType=VARCHAR}, + + notifier = #{record.notifier,jdbcType=VARCHAR}, + parent_id = #{record.parentId,jdbcType=VARCHAR}, @@ -230,8 +241,8 @@ update_time = #{record.updateTime,jdbcType=BIGINT}, - - description = #{record.description,jdbcType=LONGVARCHAR}, + + content = #{record.content,jdbcType=LONGVARCHAR}, @@ -243,12 +254,13 @@ set id = #{record.id,jdbcType=VARCHAR}, bug_id = #{record.bugId,jdbcType=VARCHAR}, reply_user = #{record.replyUser,jdbcType=VARCHAR}, + notifier = #{record.notifier,jdbcType=VARCHAR}, parent_id = #{record.parentId,jdbcType=VARCHAR}, create_user = #{record.createUser,jdbcType=VARCHAR}, create_time = #{record.createTime,jdbcType=BIGINT}, update_user = #{record.updateUser,jdbcType=VARCHAR}, update_time = #{record.updateTime,jdbcType=BIGINT}, - description = #{record.description,jdbcType=LONGVARCHAR} + content = #{record.content,jdbcType=LONGVARCHAR} @@ -258,6 +270,7 @@ set id = #{record.id,jdbcType=VARCHAR}, bug_id = #{record.bugId,jdbcType=VARCHAR}, reply_user = #{record.replyUser,jdbcType=VARCHAR}, + notifier = #{record.notifier,jdbcType=VARCHAR}, parent_id = #{record.parentId,jdbcType=VARCHAR}, create_user = #{record.createUser,jdbcType=VARCHAR}, create_time = #{record.createTime,jdbcType=BIGINT}, @@ -276,6 +289,9 @@ reply_user = #{replyUser,jdbcType=VARCHAR}, + + notifier = #{notifier,jdbcType=VARCHAR}, + parent_id = #{parentId,jdbcType=VARCHAR}, @@ -291,8 +307,8 @@ update_time = #{updateTime,jdbcType=BIGINT}, - - description = #{description,jdbcType=LONGVARCHAR}, + + content = #{content,jdbcType=LONGVARCHAR}, where id = #{id,jdbcType=VARCHAR} @@ -301,18 +317,20 @@ update bug_comment set bug_id = #{bugId,jdbcType=VARCHAR}, reply_user = #{replyUser,jdbcType=VARCHAR}, + notifier = #{notifier,jdbcType=VARCHAR}, parent_id = #{parentId,jdbcType=VARCHAR}, create_user = #{createUser,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT}, update_user = #{updateUser,jdbcType=VARCHAR}, update_time = #{updateTime,jdbcType=BIGINT}, - description = #{description,jdbcType=LONGVARCHAR} + content = #{content,jdbcType=LONGVARCHAR} where id = #{id,jdbcType=VARCHAR} update bug_comment set bug_id = #{bugId,jdbcType=VARCHAR}, reply_user = #{replyUser,jdbcType=VARCHAR}, + notifier = #{notifier,jdbcType=VARCHAR}, parent_id = #{parentId,jdbcType=VARCHAR}, create_user = #{createUser,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT}, @@ -322,14 +340,14 @@ insert into bug_comment - (id, bug_id, reply_user, parent_id, create_user, create_time, update_user, update_time, - description) + (id, bug_id, reply_user, notifier, parent_id, create_user, create_time, update_user, + update_time, content) values (#{item.id,jdbcType=VARCHAR}, #{item.bugId,jdbcType=VARCHAR}, #{item.replyUser,jdbcType=VARCHAR}, - #{item.parentId,jdbcType=VARCHAR}, #{item.createUser,jdbcType=VARCHAR}, #{item.createTime,jdbcType=BIGINT}, - #{item.updateUser,jdbcType=VARCHAR}, #{item.updateTime,jdbcType=BIGINT}, #{item.description,jdbcType=LONGVARCHAR} - ) + #{item.notifier,jdbcType=VARCHAR}, #{item.parentId,jdbcType=VARCHAR}, #{item.createUser,jdbcType=VARCHAR}, + #{item.createTime,jdbcType=BIGINT}, #{item.updateUser,jdbcType=VARCHAR}, #{item.updateTime,jdbcType=BIGINT}, + #{item.content,jdbcType=LONGVARCHAR}) @@ -351,6 +369,9 @@ #{item.replyUser,jdbcType=VARCHAR} + + #{item.notifier,jdbcType=VARCHAR} + #{item.parentId,jdbcType=VARCHAR} @@ -366,8 +387,8 @@ #{item.updateTime,jdbcType=BIGINT} - - #{item.description,jdbcType=LONGVARCHAR} + + #{item.content,jdbcType=LONGVARCHAR} ) diff --git a/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugHistoryMapper.xml b/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugHistoryMapper.xml index e23b80309c..555ccfd1f5 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugHistoryMapper.xml +++ b/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugHistoryMapper.xml @@ -5,6 +5,8 @@ + + @@ -70,7 +72,7 @@ - id, bug_id, num, create_user, create_time + id, bug_id, num, `type`, rollback_source_id, create_user, create_time content @@ -125,11 +127,11 @@ insert into bug_history (id, bug_id, num, - create_user, create_time, content - ) + `type`, rollback_source_id, create_user, + create_time, content) values (#{id,jdbcType=VARCHAR}, #{bugId,jdbcType=VARCHAR}, #{num,jdbcType=INTEGER}, - #{createUser,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{content,jdbcType=LONGVARBINARY} - ) + #{type,jdbcType=VARCHAR}, #{rollbackSourceId,jdbcType=VARCHAR}, #{createUser,jdbcType=VARCHAR}, + #{createTime,jdbcType=BIGINT}, #{content,jdbcType=LONGVARBINARY}) insert into bug_history @@ -143,6 +145,12 @@ num, + + `type`, + + + rollback_source_id, + create_user, @@ -163,6 +171,12 @@ #{num,jdbcType=INTEGER}, + + #{type,jdbcType=VARCHAR}, + + + #{rollbackSourceId,jdbcType=VARCHAR}, + #{createUser,jdbcType=VARCHAR}, @@ -192,6 +206,12 @@ num = #{record.num,jdbcType=INTEGER}, + + `type` = #{record.type,jdbcType=VARCHAR}, + + + rollback_source_id = #{record.rollbackSourceId,jdbcType=VARCHAR}, + create_user = #{record.createUser,jdbcType=VARCHAR}, @@ -211,6 +231,8 @@ set id = #{record.id,jdbcType=VARCHAR}, bug_id = #{record.bugId,jdbcType=VARCHAR}, num = #{record.num,jdbcType=INTEGER}, + `type` = #{record.type,jdbcType=VARCHAR}, + rollback_source_id = #{record.rollbackSourceId,jdbcType=VARCHAR}, create_user = #{record.createUser,jdbcType=VARCHAR}, create_time = #{record.createTime,jdbcType=BIGINT}, content = #{record.content,jdbcType=LONGVARBINARY} @@ -223,6 +245,8 @@ set id = #{record.id,jdbcType=VARCHAR}, bug_id = #{record.bugId,jdbcType=VARCHAR}, num = #{record.num,jdbcType=INTEGER}, + `type` = #{record.type,jdbcType=VARCHAR}, + rollback_source_id = #{record.rollbackSourceId,jdbcType=VARCHAR}, create_user = #{record.createUser,jdbcType=VARCHAR}, create_time = #{record.createTime,jdbcType=BIGINT} @@ -238,6 +262,12 @@ num = #{num,jdbcType=INTEGER}, + + `type` = #{type,jdbcType=VARCHAR}, + + + rollback_source_id = #{rollbackSourceId,jdbcType=VARCHAR}, + create_user = #{createUser,jdbcType=VARCHAR}, @@ -254,6 +284,8 @@ update bug_history set bug_id = #{bugId,jdbcType=VARCHAR}, num = #{num,jdbcType=INTEGER}, + `type` = #{type,jdbcType=VARCHAR}, + rollback_source_id = #{rollbackSourceId,jdbcType=VARCHAR}, create_user = #{createUser,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT}, content = #{content,jdbcType=LONGVARBINARY} @@ -263,18 +295,20 @@ update bug_history set bug_id = #{bugId,jdbcType=VARCHAR}, num = #{num,jdbcType=INTEGER}, + `type` = #{type,jdbcType=VARCHAR}, + rollback_source_id = #{rollbackSourceId,jdbcType=VARCHAR}, create_user = #{createUser,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT} where id = #{id,jdbcType=VARCHAR} insert into bug_history - (id, bug_id, num, create_user, create_time, content) + (id, bug_id, num, `type`, rollback_source_id, create_user, create_time, content) values (#{item.id,jdbcType=VARCHAR}, #{item.bugId,jdbcType=VARCHAR}, #{item.num,jdbcType=INTEGER}, - #{item.createUser,jdbcType=VARCHAR}, #{item.createTime,jdbcType=BIGINT}, #{item.content,jdbcType=LONGVARBINARY} - ) + #{item.type,jdbcType=VARCHAR}, #{item.rollbackSourceId,jdbcType=VARCHAR}, #{item.createUser,jdbcType=VARCHAR}, + #{item.createTime,jdbcType=BIGINT}, #{item.content,jdbcType=LONGVARBINARY}) @@ -296,6 +330,12 @@ #{item.num,jdbcType=INTEGER} + + #{item.type,jdbcType=VARCHAR} + + + #{item.rollbackSourceId,jdbcType=VARCHAR} + #{item.createUser,jdbcType=VARCHAR} diff --git a/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugMapper.xml b/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugMapper.xml index 711a892d47..be21d1ee70 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugMapper.xml +++ b/backend/framework/domain/src/main/java/io/metersphere/bug/mapper/BugMapper.xml @@ -5,7 +5,8 @@ - + + @@ -79,9 +80,9 @@ - id, num, title, assign_user, create_user, create_time, update_user, update_time, - delete_user, delete_time, project_id, template_id, platform, `status`, tag, platform_bug_id, - trash + 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 + select cf.*, bcf.value, bcf.bug_id from bug_custom_field bcf join custom_field cf on bcf.field_id = cf.id + where cf.scene = 'BUG' and cf.scope_type = 'PROJECT' and scope_id = #{projectId} + and bug_id in + + #{id} + + + + + insert into bug_custom_field (bug_id, field_id, value) values + + (#{field.bugId}, #{field.fieldId}, #{field.value}) + + + \ No newline at end of file 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 new file mode 100644 index 0000000000..12a74c8786 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.java @@ -0,0 +1,26 @@ +package io.metersphere.bug.mapper; + +import io.metersphere.bug.dto.BugDTO; +import io.metersphere.bug.dto.request.BugPageRequest; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface ExtBugMapper { + + /** + * 缺陷列表查询 + * + * @param request 请求查询参数 + * @return 缺陷列表 + */ + List list(@Param("request") BugPageRequest request); + + /** + * 获取缺陷业务ID + * + * @param projectId 项目ID + * @return 最大的业务ID + */ + Long getMaxNum(String projectId); +} 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 new file mode 100644 index 0000000000..cac097357a --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugMapper.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + b.trash = 1 + + + b.trash = 0 + + + and b.project_id = #{request.projectId} + + + and ( + b.title like concat('%', #{request.keyword},'%') + or b.num like concat('%', #{request.keyword},'%') + ) + + + + + + + + + + + + + + + and b.handle_user in + + + + and b.create_user in + + + + and b.platform in + + + + and b.status in + + + + and b.id in ( + select bug_id from bug_custom_field where concat('custom_single_', field_id) = #{key} + and trim(both '"' from `value`) in + + ) + + + and b.id in ( + select bug_id from bug_custom_field where concat('custom_multiple_', field_id) = #{key} + and + + ) + + + + + + + + + + + and b.handle_user + + + + + + and b.create_user + + + + + + and b.platform + + + + + + and b.status + + + + + + + + and b.id not in ( + + + and b.id in ( + + select bug_id from bug_custom_field where field_id = #{custom.id} + + + and ${custom.value} + + + and left(replace(unix_timestamp(trim(both '"' from `value`)), '.', ''), 13) + + + + + + and `value` + + + + + + and trim(both '"' from `value`) + + + + + + ) + + + + + + diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelationCaseMapper.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelationCaseMapper.java new file mode 100644 index 0000000000..789c4677b7 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelationCaseMapper.java @@ -0,0 +1,19 @@ +package io.metersphere.bug.mapper; + +import io.metersphere.bug.dto.BugRelationCaseCountDTO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * @author song-cc-rock + */ +public interface ExtBugRelationCaseMapper { + + /** + * 统计缺陷关联的用例数量 + * @param bugIds 缺陷ID集合 + * @return 缺陷关联DTO + */ + List countRelationCases(@Param("ids") List bugIds); +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelationCaseMapper.xml b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelationCaseMapper.xml new file mode 100644 index 0000000000..e05f0a83d1 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/mapper/ExtBugRelationCaseMapper.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugHistoryService.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugHistoryService.java new file mode 100644 index 0000000000..2b6681efb5 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugHistoryService.java @@ -0,0 +1,29 @@ +//package io.metersphere.bug.service; +// +//import io.metersphere.bug.mapper.BugAttachmentMapper; +//import io.metersphere.bug.mapper.BugMapper; +//import jakarta.annotation.Resource; +//import org.springframework.stereotype.Service; +// +//@Service +//public class BugHistoryService { +// +// @Resource +// private BugMapper bugMapper; +// @Resource +// private BugAttachmentMapper bugAttachmentMapper; +// +// public void save(String bugId) { +// /* +// * 变更历史内容: BUG信息(基础字段, 自定义字段, 缺陷内容大字段, 附件) +// */ +// } +// +// public void compare() { +// // 对比变更历史 +// } +// +// public void rollback() { +// // 回退变更历史 +// } +//} 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 new file mode 100644 index 0000000000..539cbd162d --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugService.java @@ -0,0 +1,519 @@ +package io.metersphere.bug.service; + +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.request.BugEditRequest; +import io.metersphere.bug.dto.request.BugPageRequest; +import io.metersphere.bug.enums.BugPlatform; +import io.metersphere.bug.mapper.*; +import io.metersphere.bug.utils.CustomFieldUtils; +import io.metersphere.project.domain.FileMetadata; +import io.metersphere.project.domain.FileMetadataExample; +import io.metersphere.project.dto.ProjectTemplateOptionDTO; +import io.metersphere.project.mapper.FileMetadataMapper; +import io.metersphere.project.service.FileService; +import io.metersphere.project.service.ProjectTemplateService; +import io.metersphere.sdk.constants.ApplicationNumScope; +import io.metersphere.sdk.constants.StorageType; +import io.metersphere.sdk.constants.TemplateScene; +import io.metersphere.sdk.exception.MSException; +import io.metersphere.sdk.util.BeanUtils; +import io.metersphere.sdk.util.MsFileUtils; +import io.metersphere.sdk.util.Translator; +import io.metersphere.system.domain.Template; +import io.metersphere.system.dto.sdk.OptionDTO; +import io.metersphere.system.dto.sdk.TemplateDTO; +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; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.session.ExecutorType; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.util.*; +import java.util.stream.Collectors; + +import static io.metersphere.bug.enums.result.BugResultCode.BUG_NOT_EXIST; + +/** + * @author song-cc-rock + */ +@Service +@Transactional(rollbackFor = Exception.class) +public class BugService { + + @Resource + private BugMapper bugMapper; + @Resource + private ExtBugMapper extBugMapper; + @Resource + private BugContentMapper bugContentMapper; + @Resource + private BaseUserMapper baseUserMapper; + @Resource + protected TemplateMapper templateMapper; + @Resource + private SqlSessionFactory sqlSessionFactory; + @Resource + private PlatformPluginService platformPluginService; + @Resource + private ProjectTemplateService projectTemplateService; + @Resource + private BugCustomFieldMapper bugCustomFieldMapper; + @Resource + private ExtBugCustomFieldMapper extBugCustomFieldMapper; + @Resource + private ExtBugRelationCaseMapper extBugRelationCaseMapper; + @Resource + private FileMetadataMapper fileMetadataMapper; + @Resource + private BugAttachmentMapper bugAttachmentMapper; + @Resource + private ExtBugAttachmentMapper extBugAttachmentMapper; + @Resource + private FileService fileService; + @Resource + private BaseTemplateService baseTemplateService; + + /** + * 缺陷列表查询 + * + * @param request 列表请求参数 + * @return 缺陷列表 + */ + public List list(BugPageRequest request) { + CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(request); + List bugs = extBugMapper.list(request); + if (CollectionUtils.isEmpty(bugs)) { + return new ArrayList<>(); + } + // 处理自定义字段及状态字段 + List bugList = handleCustomFieldsAndStatus(bugs, request.getProjectId()); + return buildExtraInfo(bugList); + } + + /** + * 创建缺陷 + * + * @param request 缺陷请求参数 + * @param files 附件集合 + * @param currentUser 当前用户 + */ + public void add(BugEditRequest request, List files, String currentUser) { + /* + * 缺陷创建逻辑 + * 1. 判断所属项目是否关联第三方平台; + * 2. 根据模板自定义字段保存缺陷, 附件一起保存; + * 3. 第三方平台需调用插件同步缺陷至其他平台(API字段, 附件需处理); + * 4. 变更历史, 操作记录; + */ + // TODO: 后续补充第三方平台同步逻辑(缺陷, 附件) +// String platformName = projectApplicationService.getPlatformName(request.getProjectId()); +// request.setPlatform(platformName); +// if (!StringUtils.equals(platformName, BugPlatform.LOCAL.getName())) { +// // 关联第三方平台 +// ServiceIntegration serviceIntegration = projectTemplateService.getServiceIntegration(request.getProjectId()); +// if (serviceIntegration == null) { +// // 项目未配置第三方平台 +// throw new MSException(Translator.get("third_party_not_config")); +// } +// // 获取配置平台, 插入平台缺陷 +// Platform platform = platformPluginService.getPlatform(serviceIntegration.getPluginId(), serviceIntegration.getOrganizationId(), +// new String(serviceIntegration.getConfiguration())); +// PlatformBugUpdateRequest platformRequest = buildPlatformBugRequest(request); +// String platformBugId = platform.addBug(platformRequest); +// request.setPlatformBugId(platformBugId); +// } + // 缺陷基础字段 + handleAndSaveBug(request, currentUser, BugPlatform.LOCAL.getName()); + // 自定义字段 + handleAndSaveCustomFields(request, false); + // 附件 + handleAndSaveAttachments(request, files, currentUser); + } + + /** + * 更新缺陷 + * + * @param request 缺陷请求参数 + * @param files 附件集合 + * @param currentUser 当前用户 + */ + public void update(BugEditRequest request, List files, String currentUser) { + /* + * 缺陷更新逻辑 + * 1. 保存逻辑与创建(1, 2, 3, 4)一致. + * 2. 需校验状态流 + */ + // TODO: 后续补充第三方平台同步逻辑(缺陷, 附件) + // 缺陷 + handleAndSaveBug(request, currentUser, BugPlatform.LOCAL.getName()); + // 自定义字段 + handleAndSaveCustomFields(request, true); + // 附件 + handleAndSaveAttachments(request, files, currentUser); + } + + /** + * 删除缺陷 + * + * @param id 缺陷ID + */ + public void delete(String id) { + Bug bug = bugMapper.selectByPrimaryKey(id); + if (bug == null) { + throw new MSException(BUG_NOT_EXIST); + } + if (StringUtils.equals(bug.getPlatform(), BugPlatform.LOCAL.getName())) { + Bug record = new Bug(); + record.setId(id); + record.setTrash(true); + bugMapper.updateByPrimaryKeySelective(record); + } else { + bugMapper.deleteByPrimaryKey(id); + } + } + + /** + * 获取缺陷模板详情 + * + * @param templateId 模板ID + * @param projectId 项目ID + * @return 模板详情 + */ + public TemplateDTO getTemplate(String templateId, String projectId) { + Template template = templateMapper.selectByPrimaryKey(templateId); + if (template != null) { + // 属于系统模板 + return baseTemplateService.getTemplateDTO(template); + } else { + // 不属于系统模板 + List option = projectTemplateService.getOption(projectId, TemplateScene.BUG.name()); + Optional isThirdPartyDefaultTemplate = option.stream().filter(projectTemplateOptionDTO -> StringUtils.equals(projectTemplateOptionDTO.getId(), templateId)).findFirst(); + if (isThirdPartyDefaultTemplate.isPresent()) { + // TODO: 获取第三方平台模板 + return null; + } else { + // 不属于系统模板&&不属于第三方平台默认模板, 则该模板已被删除 + return projectTemplateService.getDefaultTemplateDTO(projectId, TemplateScene.BUG.name()); + } + } + } + + /** + * 处理保存缺陷基础信息 + * + * @param request 请求参数 + * @param currentUser 当前用户ID + * @param platformName 第三方平台名称 + */ + private void handleAndSaveBug(BugEditRequest request, String currentUser, String platformName) { + Bug bug = new Bug(); + BeanUtils.copyBean(bug, request); + bug.setPlatform(platformName); + // TODO: 关于平台, 后续补充, 暂保留 +// if (StringUtils.equalsIgnoreCase(BugPlatform.LOCAL.getName(), platformName)) { +// bug.setPlatformBugId(null); +// } else { +// bug.setPlatformBugId(platformBugId); +// } + if (StringUtils.isEmpty(bug.getId())) { + bug.setId(IDGenerator.nextStr()); + // TODO: 业务ID生成规则, 暂保留, 后续补充 + bug.setNum(Long.valueOf(NumGenerator.nextNum(request.getProjectId(), ApplicationNumScope.BUG_MANAGEMENT)).intValue()); + bug.setHandleUsers(request.getHandleUser()); + bug.setCreateUser(currentUser); + bug.setCreateTime(System.currentTimeMillis()); + bug.setUpdateUser(currentUser); + bug.setUpdateTime(System.currentTimeMillis()); + bug.setDeleteUser(currentUser); + bug.setDeleteTime(System.currentTimeMillis()); + bug.setTrash(false); + bugMapper.insert(bug); + request.setId(bug.getId()); + BugContent bugContent = new BugContent(); + bugContent.setBugId(bug.getId()); + bugContent.setDescription(request.getDescription()); + bugContentMapper.insert(bugContent); + } else { + Bug orignalBug = checkBugExist(request.getId()); + // 追加处理人 + bug.setHandleUsers(orignalBug.getHandleUsers() + "," + request.getHandleUser()); + bug.setUpdateUser(currentUser); + bug.setUpdateTime(System.currentTimeMillis()); + bugMapper.updateByPrimaryKeySelective(bug); + BugContent bugContent = new BugContent(); + bugContent.setBugId(bug.getId()); + bugContent.setDescription(request.getDescription()); + bugContentMapper.updateByPrimaryKeySelective(bugContent); + } + } + + /** + * 校验缺陷是否存在 + * @param id 缺陷ID + * @return 缺陷 + */ + private Bug checkBugExist(String id) { + BugExample bugExample = new BugExample(); + bugExample.createCriteria().andIdEqualTo(id).andTrashEqualTo(false); + List bugs = bugMapper.selectByExample(bugExample); + if (CollectionUtils.isEmpty(bugs)) { + throw new MSException(BUG_NOT_EXIST); + } + return bugs.get(0); + } + + /** + * 处理保存自定义字段信息 + * + * @param request 请求参数 + */ + private void handleAndSaveCustomFields(BugEditRequest request, boolean merge) { + Map customFieldMap = request.getCustomFieldMap(); + if (MapUtils.isEmpty(customFieldMap)) { + return; + } + List addFields = new ArrayList<>(); + List updateFields = new ArrayList<>(); + if (merge) { + // 编辑缺陷需合并原有自定义字段 + List originalFields = extBugCustomFieldMapper.getBugCustomFields(List.of(request.getId()), request.getProjectId()); + Map originalFieldMap = originalFields.stream().collect(Collectors.toMap(BugCustomFieldDTO::getId, BugCustomFieldDTO::getValue)); + customFieldMap.keySet().forEach(fieldId -> { + BugCustomField bugCustomField = new BugCustomField(); + if (!originalFieldMap.containsKey(fieldId)) { + // 新的缺陷字段关系 + bugCustomField.setBugId(request.getId()); + bugCustomField.setFieldId(fieldId); + bugCustomField.setValue(customFieldMap.get(fieldId)); + addFields.add(bugCustomField); + } else { + // 已存在的缺陷字段关系 + bugCustomField.setBugId(request.getId()); + bugCustomField.setFieldId(fieldId); + bugCustomField.setValue(customFieldMap.get(fieldId)); + updateFields.add(bugCustomField); + } + }); + } else { + // 新增缺陷不需要合并自定义字段 + customFieldMap.keySet().forEach(fieldId -> { + BugCustomField bugCustomField = new BugCustomField(); + bugCustomField.setBugId(request.getId()); + bugCustomField.setFieldId(fieldId); + bugCustomField.setValue(customFieldMap.get(fieldId)); + addFields.add(bugCustomField); + }); + } + if (CollectionUtils.isNotEmpty(addFields)) { + bugCustomFieldMapper.batchInsert(addFields); + } + if (CollectionUtils.isNotEmpty(updateFields)) { + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + BugCustomFieldMapper bugCustomFieldMapper = sqlSession.getMapper(BugCustomFieldMapper.class); + for (BugCustomField bugCustomField : updateFields) { + BugCustomFieldExample bugCustomFieldExample = new BugCustomFieldExample(); + bugCustomFieldExample.createCriteria().andBugIdEqualTo(bugCustomField.getBugId()).andFieldIdEqualTo(bugCustomField.getFieldId()); + bugCustomFieldMapper.updateByExample(bugCustomField, bugCustomFieldExample); + } + sqlSession.flushStatements(); + SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); + } + } + + /** + * 处理保存附件信息 + * @param request 请求参数 + * @param files 上传附件集合 + */ + private void handleAndSaveAttachments(BugEditRequest request, List files, String currentUser) { + Map uploadMinioFiles = new HashMap<>(16); + List addFiles = new ArrayList<>(); + // 处理删除的本地上传附件及取消关联的附件 + List deleteIds = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(request.getDeleteLocalFileIds())) { + deleteIds.addAll(request.getDeleteLocalFileIds()); + request.getDeleteLocalFileIds().forEach(deleteFileId -> { + FileRequest fileRequest = new FileRequest(); + fileRequest.setProjectId(request.getProjectId()); + fileRequest.setFileName(deleteFileId); + fileRequest.setStorage(StorageType.MINIO.name()); + try { + fileService.deleteFile(fileRequest); + } catch (Exception e) { + throw new MSException(Translator.get("bug_attachment_delete_error")); + } + }); + } + if (CollectionUtils.isNotEmpty(request.getUnLinkFileIds())) { + deleteIds.addAll(request.getUnLinkFileIds()); + } + if (CollectionUtils.isNotEmpty(deleteIds)) { + BugAttachmentExample example = new BugAttachmentExample(); + example.createCriteria().andBugIdEqualTo(request.getId()).andFileIdIn(deleteIds); + bugAttachmentMapper.deleteByExample(example); + // TODO: 如果是第三方平台, 需调用平台插件同步删除附件 + } + // 新本地上传的附件 + if (CollectionUtils.isNotEmpty(files)) { + files.forEach(file -> { + BugAttachment bugAttachment = new BugAttachment(); + bugAttachment.setId(IDGenerator.nextStr()); + bugAttachment.setBugId(request.getId()); + bugAttachment.setFileId(IDGenerator.nextStr()); + bugAttachment.setFileName(file.getOriginalFilename()); + bugAttachment.setSize(file.getSize()); + bugAttachment.setLocal(true); + bugAttachment.setCreateTime(System.currentTimeMillis()); + bugAttachment.setCreateUser(currentUser); + addFiles.add(bugAttachment); + uploadMinioFiles.put(bugAttachment.getFileId(), file); + }); + } + // 新关联的附件 + List linkIds = request.getLinkFileIds(); + if (CollectionUtils.isNotEmpty(linkIds)) { + FileMetadataExample example = new FileMetadataExample(); + example.createCriteria().andIdIn(linkIds); + List linkFiles = fileMetadataMapper.selectByExample(example); + Map linkFileMap = linkFiles.stream().collect(Collectors.toMap(FileMetadata::getId, v -> v)); + linkIds.forEach(fileId -> { + FileMetadata fileMetadata = linkFileMap.get(fileId); + if (fileMetadata == null) { + return; + } + BugAttachment bugAttachment = new BugAttachment(); + bugAttachment.setId(IDGenerator.nextStr()); + bugAttachment.setBugId(request.getId()); + bugAttachment.setFileId(fileId); + bugAttachment.setFileName(fileMetadata.getName()); + bugAttachment.setSize(fileMetadata.getSize()); + bugAttachment.setLocal(false); + bugAttachment.setCreateTime(System.currentTimeMillis()); + bugAttachment.setCreateUser(currentUser); + addFiles.add(bugAttachment); + }); + } + extBugAttachmentMapper.batchInsert(addFiles); + // TODO: 如果是第三方平台, 需调用平台插件同步上传附件 + uploadMinioFiles.forEach((fileId, file) -> { + FileRequest fileRequest = new FileRequest(); + fileRequest.setFileName(file.getOriginalFilename()); + fileRequest.setResourceId("/" + MsFileUtils.BUG_MANAGEMENT_DIR + "/" + request.getProjectId() + "/" + fileId); + fileRequest.setStorage(StorageType.MINIO.name()); + try { + fileService.upload(file, fileRequest); + } catch (Exception e) { + throw new MSException(Translator.get("bug_attachment_upload_error")); + } + }); + } + +// /** +// * 封装缺陷平台请求参数 +// * @param request 缺陷请求参数 +// */ +// private PlatformBugUpdateRequest buildPlatformBugRequest(BugEditRequest request) { +// /* +// * TODO: 封装缺陷平台请求参数 +// * 如果是系统默认模板, 只需获取模板中有配置API的字段并处理 +// * 如果是平台默认模板, 则处理参数中全部自定义字段 +// */ +// return new PlatformBugUpdateRequest(); +// } + + /** + * 封装缺陷其他字段 + * + * @param bugs 缺陷集合 + * @return 缺陷DTO集合 + */ + private List buildExtraInfo(List bugs) { + // 获取用户集合 + List userIds = new ArrayList<>(); + userIds.addAll(bugs.stream().map(BugDTO::getCreateUser).toList()); + userIds.addAll(bugs.stream().map(BugDTO::getHandleUser).toList()); + List distinctUserIds = userIds.stream().distinct().toList(); + List userOptions = baseUserMapper.selectUserOptionByIds(distinctUserIds); + Map userMap = userOptions.stream().collect(Collectors.toMap(OptionDTO::getId, OptionDTO::getName)); + // 根据缺陷ID获取关联用例数 + List ids = bugs.stream().map(BugDTO::getId).toList(); + List relationCaseCount = extBugRelationCaseMapper.countRelationCases(ids); + Map countMap = relationCaseCount.stream().collect(Collectors.toMap(BugRelationCaseCountDTO::getBugId, BugRelationCaseCountDTO::getRelationCaseCount)); + bugs.forEach(bug -> { + bug.setRelationCaseCount(countMap.get(bug.getId())); + bug.setCreateUserName(userMap.get(bug.getCreateUser())); + bug.setAssignUserName(userMap.get(bug.getHandleUser())); + }); + return bugs; + } + + /** + * 处理自定义字段及状态字段 + * + * @param bugs 缺陷集合 + * @return 缺陷DTO集合 + */ + private List handleCustomFieldsAndStatus(List bugs, String projectId) { + List ids = bugs.stream().map(BugDTO::getId).toList(); + List customFields = extBugCustomFieldMapper.getBugCustomFields(ids, projectId); + Map> customFieldMap = customFields.stream().collect(Collectors.groupingBy(BugCustomFieldDTO::getBugId)); + bugs.forEach(bug -> { + bug.setCustomFields(customFieldMap.get(bug.getId())); + // 缺陷状态选项值不存在时不展示 暂时保留, 项目插件同步配置开发后补充 +// List statusOption = bugStatusService.getProjectStatusOption(bug.getProjectId()); +// if (CollectionUtils.isNotEmpty(statusOption)) { +// Optional statusOpt = statusOption.stream().filter(optionDTO -> optionDTO.getId().equals(bug.getStatus())).findFirst(); +// statusOpt.ifPresent(optionDTO -> bug.setStatusName(optionDTO.getName())); +// } + }); + return bugs; + } + +// /** +// * 获取第三方平台模板 +// * +// * @param projectId 项目ID +// * @return 第三方平台模板 +// */ +// private TemplateDTO getPluginBugTemplate(String projectId) { +// ServiceIntegration serviceIntegration = projectTemplateService.getServiceIntegration(projectId); +// if (serviceIntegration == null) { +// return null; +// } +// TemplateDTO template = new TemplateDTO(); +// Template pluginTemplate = projectTemplateService.getPluginBugTemplate(projectId); +// BeanUtils.copyBean(template, pluginTemplate); +// Platform platform = platformPluginService.getPlatform(serviceIntegration.getPluginId(), serviceIntegration.getOrganizationId(), +// new String(serviceIntegration.getConfiguration())); +// // TODO: 插件平台获取自定义字段, 并针对特殊字段单独处理 +// List platformCustomFields = platform.getThirdPartCustomField(""); +// if (CollectionUtils.isNotEmpty(platformCustomFields)) { +// List customFields = platformCustomFields.stream().map(platformCustomField -> { +// TemplateCustomFieldDTO customField = new TemplateCustomFieldDTO(); +// customField.setFieldId(platformCustomField.getId()); +// customField.setFieldName(platformCustomField.getName()); +// customField.setDefaultValue(platformCustomField.getDefaultValue()); +// customField.setRequired(platformCustomField.getRequired()); +// return customField; +// }).toList(); +// template.setCustomFields(customFields); +// } +// return template; +// } +} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugStatusService.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugStatusService.java new file mode 100644 index 0000000000..5d5ca0cc8b --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/BugStatusService.java @@ -0,0 +1,66 @@ +//package io.metersphere.bug.service; +// +//import io.metersphere.bug.dto.BugStatusOptionDTO; +//import io.metersphere.bug.enums.BugPlatform; +//import io.metersphere.plugin.platform.spi.Platform; +//import io.metersphere.project.service.ProjectApplicationService; +//import io.metersphere.project.service.ProjectTemplateService; +//import io.metersphere.sdk.exception.MSException; +//import io.metersphere.sdk.util.Translator; +//import io.metersphere.system.domain.ServiceIntegration; +//import io.metersphere.system.service.PlatformPluginService; +//import jakarta.annotation.Resource; +//import org.apache.commons.lang3.StringUtils; +//import org.springframework.stereotype.Service; +//import org.springframework.transaction.annotation.Transactional; +// +//import java.util.List; +// +//@Service +//@Transactional(rollbackFor = Exception.class) +//public class BugStatusService { +// +// @Resource +// private ProjectApplicationService projectApplicationService; +// @Resource +// private ProjectTemplateService projectTemplateService; +// @Resource +// private PlatformPluginService platformPluginService; +// +// /** +// * 获取状态下拉选项 +// * @param projectId 项目ID +// * @return 选项集合 +// */ +// public List getProjectStatusOption(String projectId) { +// // TODO: 获取状态下拉选项 {Local平台: 直接取状态流中的选项, 第三方平台: 取第三方插件平台的状态和状态流中的选项} +// String platformName = projectApplicationService.getPlatformName(projectId); +// if (StringUtils.equals(platformName, BugPlatform.LOCAL.getName())) { +// return getProjectStatusItemOption(projectId); +// } else { +// // 状态流 && 第三方平台状态流 +// ServiceIntegration serviceIntegration = projectTemplateService.getServiceIntegration(projectId); +// if (serviceIntegration == null) { +// // 项目未配置第三方平台 +// throw new MSException(Translator.get("third_party_not_config")); +// } +// // 获取配置平台, 获取第三方平台状态流 +// Platform platform = platformPluginService.getPlatform(serviceIntegration.getPluginId(), serviceIntegration.getOrganizationId(), +// new String(serviceIntegration.getConfiguration())); +//// List statusList = platform.getStatusList(); +// // 获取项目状态流 +//// List projectStatusItemOption = getProjectStatusItemOption(projectId); +// } +// return null; +// } +// +// /** +// * 获取项目状态流选项 +// * @param projectId 项目ID +// * @return 选项集合 +// */ +// public List getProjectStatusItemOption(String projectId) { +// // TODO: 获取项目状态流选项 +// return null; +// } +//} diff --git a/backend/services/bug-management/src/main/java/io/metersphere/bug/service/CleanupBugResourceService.java b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/CleanupBugResourceService.java new file mode 100644 index 0000000000..431916093b --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/service/CleanupBugResourceService.java @@ -0,0 +1,19 @@ +//package io.metersphere.bug.service; +// +//import io.metersphere.sdk.util.LogUtils; +//import io.metersphere.system.service.CleanupProjectResourceService; +//import org.springframework.stereotype.Component; +// +//@Component +//public class CleanupBugResourceService implements CleanupProjectResourceService { +// +// @Override +// public void deleteResources(String projectId) { +// LogUtils.info("删除当前项目[" + projectId + "]相关缺陷资源"); +// } +// +// @Override +// public void cleanReportResources(String projectId) { +// LogUtils.info("清理当前项目[" + projectId + "]相关缺陷报告资源"); +// } +//} 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 new file mode 100644 index 0000000000..513ec98505 --- /dev/null +++ b/backend/services/bug-management/src/main/java/io/metersphere/bug/utils/CustomFieldUtils.java @@ -0,0 +1,63 @@ +package io.metersphere.bug.utils; + +import io.metersphere.sdk.constants.CustomFieldType; +import io.metersphere.sdk.util.JSON; +import io.metersphere.system.dto.sdk.BasePageRequest; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 字段处理工具类 + * @author song-cc-rock + */ +public class CustomFieldUtils { + + public static final String COMBINE_CUSTOM = "customs"; + public static final String COMBINE_CUSTOM_FIELD_TYPE = "type"; + public static final String COMBINE_CUSTOM_FIELD_VALUE = "value"; +// public static final String COMBINE_CUSTOM_FIELD_OPERATOR = "operator"; +// public static final String IS_CURRENT_USER = "current user"; + public static final String CUSTOM_MULTIPLE_PREFIX = "custom_multiple"; + + /** + * 设置列表查询的多选字段参数 + * @param request 请求参数 + */ + public static void setBaseQueryRequestCustomMultipleFields(BasePageRequest request) { + // handle filter custom multiple fields + if (MapUtils.isNotEmpty(request.getFilter())) { + request.getFilter().entrySet().forEach(entry -> { + if (entry.getKey().startsWith(CUSTOM_MULTIPLE_PREFIX) && CollectionUtils.isNotEmpty(entry.getValue())) { + List jsonValues = entry.getValue().stream().map(item -> "[\"".concat(item).concat("\"]")).collect(Collectors.toList()); + entry.setValue(jsonValues); + } + }); + } + + // handle combine custom multiple fields + if (MapUtils.isNotEmpty(request.getCombine()) && ObjectUtils.isNotEmpty((request.getCombine().get(COMBINE_CUSTOM)))) { + //noinspection unchecked + List> customs = (List>) request.getCombine().get(COMBINE_CUSTOM); + customs.forEach(custom -> { + // when member select or member multipart select support current user, open it +// if(StringUtils.equalsIgnoreCase(custom.get(COMBINE_CUSTOM_FIELD_OPERATOR).toString(), IS_CURRENT_USER)){ +// String userId = SessionUtils.getUserId(); +// custom.put(COMBINE_CUSTOM_FIELD_VALUE, userId); +// } + if (StringUtils.equalsAny(custom.get(COMBINE_CUSTOM_FIELD_TYPE).toString(), CustomFieldType.MULTIPLE_MEMBER.getType(), + CustomFieldType.CHECKBOX.getType(), CustomFieldType.MULTIPLE_SELECT.getType()) + && StringUtils.isNotEmpty(custom.get(COMBINE_CUSTOM_FIELD_VALUE).toString())) { + List customValues = JSON.parseArray(custom.get(COMBINE_CUSTOM_FIELD_VALUE).toString(), String.class); + List jsonValues = customValues.stream().map(item -> "JSON_CONTAINS(`value`, '[\"".concat(item).concat("\"]')")).toList(); + custom.put(COMBINE_CUSTOM_FIELD_VALUE, "(".concat(StringUtils.join(jsonValues, " OR ")).concat(")")); + } + }); + } + } +} diff --git a/backend/services/bug-management/src/main/resources/bugGeneratorConfig.xml b/backend/services/bug-management/src/main/resources/bugGeneratorConfig.xml index 62507f6eda..ac2cada802 100644 --- a/backend/services/bug-management/src/main/resources/bugGeneratorConfig.xml +++ b/backend/services/bug-management/src/main/resources/bugGeneratorConfig.xml @@ -71,13 +71,13 @@ -
-
-
-
-
-
-
+ + + + + + + diff --git a/backend/services/bug-management/src/main/resources/permission.json b/backend/services/bug-management/src/main/resources/permission.json new file mode 100644 index 0000000000..6bcb2c84bf --- /dev/null +++ b/backend/services/bug-management/src/main/resources/permission.json @@ -0,0 +1,27 @@ +[ + { + "id": "BUG", + "name": "permission.bug.name", + "type": "BUG", + "children": [ + { + "id": "BUG", + "name": "permission.bug.name", + "permissions": [ + { + "id": "BUG:READ" + }, + { + "id": "BUG:READ+ADD" + }, + { + "id": "BUG:READ+UPDATE" + }, + { + "id": "BUG:READ+DELETE" + } + ] + } + ] + } +] \ No newline at end of file diff --git a/backend/services/bug-management/src/test/java/io/metersphere/bug/Application.java b/backend/services/bug-management/src/test/java/io/metersphere/bug/Application.java index 8394eb791f..83f3e98ec8 100644 --- a/backend/services/bug-management/src/test/java/io/metersphere/bug/Application.java +++ b/backend/services/bug-management/src/test/java/io/metersphere/bug/Application.java @@ -19,7 +19,7 @@ import org.springframework.context.annotation.ComponentScan; MinioProperties.class }) @ServletComponentScan -@ComponentScan(basePackages = {"io.metersphere.sdk", "io.metersphere.bug", "io.metersphere.system"}) +@ComponentScan(basePackages = {"io.metersphere.sdk", "io.metersphere.system", "io.metersphere.project", "io.metersphere.bug"}) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); 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 new file mode 100644 index 0000000000..72ccf6ca6e --- /dev/null +++ b/backend/services/bug-management/src/test/java/io/metersphere/bug/controller/BugControllerTests.java @@ -0,0 +1,289 @@ +package io.metersphere.bug.controller; + +import io.metersphere.bug.dto.BugDTO; +import io.metersphere.bug.dto.request.BugEditRequest; +import io.metersphere.bug.dto.request.BugPageRequest; +import io.metersphere.project.dto.ProjectTemplateOptionDTO; +import io.metersphere.sdk.util.JSON; +import io.metersphere.system.base.BaseTest; +import io.metersphere.system.controller.handler.ResultHolder; +import io.metersphere.system.dto.sdk.TemplateDTO; +import io.metersphere.system.utils.Pager; +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.*; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +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.MultiValueMap; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.*; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class BugControllerTests extends BaseTest { + + public static final String BUG_PAGE = "/bug/page"; + public static final String BUG_ADD = "/bug/add"; + public static final String BUG_UPDATE = "/bug/update"; + 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"; + + @Test + @Order(0) + @Sql(scripts = {"/dml/init_bug.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED)) + public void testBugPageSuccess() throws Exception { + BugPageRequest bugRequest = new BugPageRequest(); + bugRequest.setCurrent(1); + bugRequest.setPageSize(10); + bugRequest.setKeyword("default"); + bugRequest.setProjectId("default-project-for-bug"); + bugRequest.setFilter(buildRequestFilter()); + bugRequest.setCombine(buildRequestCombine()); + MvcResult mvcResult = this.requestPostWithOkAndReturn(BUG_PAGE, bugRequest); + // 获取返回值 + String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); + // 返回请求正常 + Assertions.assertNotNull(resultHolder); + Pager pageData = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class); + // 返回值不为空 + Assertions.assertNotNull(pageData); + // 返回值的页码和当前页码相同 + Assertions.assertEquals(pageData.getCurrent(), bugRequest.getCurrent()); + // 返回的数据量不超过规定要返回的数据量相同 + Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= bugRequest.getPageSize()); + // 返回值中取出第一条数据, 并判断是否包含关键字default + BugDTO bugDTO = JSON.parseArray(JSON.toJSONString(pageData.getList()), BugDTO.class).get(0); + Assertions.assertTrue(StringUtils.contains(bugDTO.getTitle(), bugRequest.getKeyword()) + || StringUtils.contains(bugDTO.getId(), bugRequest.getKeyword())); + + // sort不为空 + Map sort = new HashMap<>(); + sort.put("id", "desc"); + bugRequest.setSort(sort); + MvcResult sortResult = this.requestPostWithOkAndReturn(BUG_PAGE, bugRequest); + String sortData = sortResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder sortHolder = JSON.parseObject(sortData, ResultHolder.class); + Pager sortPageData = JSON.parseObject(JSON.toJSONString(sortHolder.getData()), Pager.class); + // 返回值中取出第一条ID最大的数据, 并判断是否是default-bug + BugDTO maxBugDTO = JSON.parseArray(JSON.toJSONString(sortPageData.getList()), BugDTO.class).get(0); + Assertions.assertTrue(maxBugDTO.getId().contains("default")); + } + + @Test + @Order(1) + public void testBugPageEmptySuccess() throws Exception { + BugPageRequest bugPageRequest = new BugPageRequest(); + bugPageRequest.setCurrent(1); + bugPageRequest.setPageSize(10); + bugPageRequest.setKeyword("default-x"); + MvcResult mvcResult = this.requestPostWithOkAndReturn(BUG_PAGE, bugPageRequest); + // 获取返回值 + String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); + // 返回请求正常 + Assertions.assertNotNull(resultHolder); + Pager pageData = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class); + // 返回值不为空 + Assertions.assertNotNull(pageData); + // 返回值的页码和当前页码相同 + Assertions.assertEquals(pageData.getCurrent(), bugPageRequest.getCurrent()); + // 返回的数据量为0条 + Assertions.assertEquals(0, pageData.getTotal()); + } + + @Test + @Order(2) + public void testBugPageError() throws Exception { + // 页码有误 + BugPageRequest bugPageRequest = new BugPageRequest(); + bugPageRequest.setCurrent(0); + bugPageRequest.setPageSize(10); + this.requestPost(BUG_PAGE, bugPageRequest, status().isBadRequest()); + // 页数有误 + bugPageRequest = new BugPageRequest(); + bugPageRequest.setCurrent(1); + bugPageRequest.setPageSize(1); + this.requestPost(BUG_PAGE, bugPageRequest, status().isBadRequest()); + } + + @Test + @Order(3) + public void testAddBugSuccess() throws Exception { + BugEditRequest request = buildRequest(false); + String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.xlsx")).getPath(); + File file = new File(filePath); + MultiValueMap paramMap = getDefaultMultiPartParam(request, file); + this.requestMultipartWithOkAndReturn(BUG_ADD, paramMap); + } + + @Test + @Order(4) + public void testAddBugError() throws Exception { + BugEditRequest request = buildRequest(false); + String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.xlsx")).getPath(); + File file = new File(filePath); + // 项目ID为空 + request.setProjectId(null); + MultiValueMap paramMap = getDefaultMultiPartParam(request, file); + this.requestMultipart(BUG_ADD, paramMap).andExpect(status().isBadRequest()); + // 标题为空 + request.setProjectId("default-project-for-bug"); + request.setTitle(null); + paramMap = getDefaultMultiPartParam(request, file); + this.requestMultipart(BUG_ADD, paramMap).andExpect(status().isBadRequest()); + // 处理人为空 + request.setTitle("default-bug-title"); + request.setHandleUser(null); + paramMap = getDefaultMultiPartParam(request, file); + this.requestMultipart(BUG_ADD, paramMap).andExpect(status().isBadRequest()); + // 模板为空 + request.setHandleUser("admin"); + request.setTemplateId(null); + paramMap = getDefaultMultiPartParam(request, file); + this.requestMultipart(BUG_ADD, paramMap).andExpect(status().isBadRequest()); + // 状态为空 + request.setTemplateId("default-bug-template"); + request.setStatus(null); + paramMap = getDefaultMultiPartParam(request, file); + this.requestMultipart(BUG_ADD, paramMap).andExpect(status().isBadRequest()); + } + + @Test + @Order(5) + public void testUpdateBugSuccess() throws Exception { + BugEditRequest request = buildRequest(true); + String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.xlsx")).getPath(); + File file = new File(filePath); + MultiValueMap paramMap = getDefaultMultiPartParam(request, file); + this.requestMultipartWithOkAndReturn(BUG_UPDATE, paramMap); + } + + @Test + @Order(6) + public void testUpdateBugError() throws Exception { + BugEditRequest request = buildRequest(true); + request.setId("default-bug-id-not-exist"); + String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.xlsx")).getPath(); + File file = new File(filePath); + MultiValueMap paramMap = getDefaultMultiPartParam(request, file); + this.requestMultipart(BUG_UPDATE, paramMap).andExpect(status().is5xxServerError()); + } + + @Test + @Order(7) + public void testUpdateBugWithEmptyField() throws Exception { + BugEditRequest request = buildRequest(true); + request.setCustomFieldMap(null); + String filePath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/test.xlsx")).getPath(); + File file = new File(filePath); + MultiValueMap paramMap = getDefaultMultiPartParam(request, file); + this.requestMultipartWithOkAndReturn(BUG_UPDATE, paramMap); + } + + @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); + ResultHolder resultHolder = JSON.parseObject(sortData, ResultHolder.class); + List templateOptionDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), ProjectTemplateOptionDTO.class); + // 默认模板断言 + Assertions.assertTrue(templateOptionDTOS.stream().anyMatch(ProjectTemplateOptionDTO::getEnableDefault)); + } + + @Test + @Order(11) + 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); + ResultHolder resultHolder = JSON.parseObject(sortData, ResultHolder.class); + TemplateDTO templateDTO = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TemplateDTO.class); + Assertions.assertNotNull(templateDTO); + Assertions.assertEquals("default-bug-template-id", templateDTO.getId()); + // 获取默认模板 + MvcResult defaultResult = this.requestGetWithOkAndReturn(BUG_TEMPLATE_DETAIL + "/default-bug-template-id-not-exist" + "?projectId=default-project-for-bug"); + String defaultData = defaultResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder defaultResultHolder = JSON.parseObject(defaultData, ResultHolder.class); + TemplateDTO defaultTemplate = JSON.parseObject(JSON.toJSONString(defaultResultHolder.getData()), TemplateDTO.class); + Assertions.assertNotNull(defaultTemplate); + Assertions.assertEquals("default-bug-template-id", defaultTemplate.getId()); + } + + /** + * 生成请求过滤参数 + * @return filter param + */ + private Map> buildRequestFilter() { + Map> filter = new HashMap<>(); + filter.put("custom_multiple_test_field", List.of("default", "default1")); + return filter; + } + + /** + * 生成高级搜索参数 + * @return combine param + */ + private Map buildRequestCombine() { + Map combine = new HashMap<>(); + List> customs = new ArrayList<>(); + Map custom = new HashMap<>(); + custom.put("id", "test_field"); + custom.put("operator", "in"); + custom.put("type", "multipleSelect"); + custom.put("value", JSON.toJSONString(List.of("default", "default1"))); + customs.add(custom); + combine.put("customs", customs); + return combine; + } + + /** + * 生成请求参数 + * @param isUpdate 是否更新操作 + * @return 请求参数 + */ + private BugEditRequest buildRequest(boolean isUpdate) { + BugEditRequest request = new BugEditRequest(); + request.setProjectId("default-project-for-bug"); + request.setTitle("default-bug-title"); + request.setDescription("default-bug-description"); + 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"); + 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/application.properties b/backend/services/bug-management/src/test/resources/application.properties index 7ec051882b..13f5364f31 100644 --- a/backend/services/bug-management/src/test/resources/application.properties +++ b/backend/services/bug-management/src/test/resources/application.properties @@ -6,14 +6,14 @@ server.compression.enabled=true server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css,text/javascript,image/jpeg server.compression.min-response-size=2048 # -quartz.enabled=false +quartz.enabled=true quartz.scheduler-name=msScheduler quartz.thread-count=10 quartz.properties.org.quartz.jobStore.acquireTriggersWithinLock=true # logging.file.path=/opt/metersphere/logs/metersphere # Hikari -spring.datasource.url=jdbc:mysql://${embedded.mysql.host}:${embedded.mysql.port}/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8 +spring.datasource.url=jdbc:mysql://${embedded.mysql.host}:${embedded.mysql.port}/test?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&allowPublicKeyRetrieval=true&useSSL=false&sessionVariables=sql_mode=%27STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION%27 spring.datasource.username=${embedded.mysql.user} spring.datasource.password=${embedded.mysql.password} spring.datasource.type=com.zaxxer.hikari.HikariDataSource @@ -80,4 +80,4 @@ minio.secret-key=${embedded.minio.secretKey} logging.level.org.springframework.jdbc.core=info logging.level.io.metersphere.sdk.mapper=info -logging.level.io.metersphere.system.mapper=info +logging.level.io.metersphere.bug.mapper=info 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 new file mode 100644 index 0000000000..6a30c8b7fe --- /dev/null +++ b/backend/services/bug-management/src/test/resources/dml/init_bug.sql @@ -0,0 +1,31 @@ +INSERT INTO project (id, num, organization_id, name, description, create_user, update_user, create_time, update_time) VALUE + ('default-project-for-bug-tmp', null, '100001', '测试项目(缺陷)', '系统默认创建的项目(缺陷)', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000); + +INSERT INTO project (id, num, organization_id, name, description, create_user, update_user, create_time, update_time) VALUE + ('default-project-for-bug', null, '100001', '测试项目(缺陷)', '系统默认创建的项目(缺陷)', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000); + +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); + +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'); + +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'), + ('default-bug-template-id', 'bug-default-template', '', 0, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', 'default-project-for-bug', 0, 'BUG'); + +INSERT INTO bug_relation_case (id, case_id, bug_id, case_type, test_plan_id, test_plan_case_id, create_user, create_time, update_time) VALUE + (UUID_SHORT(), UUID_SHORT(), 'default-bug-id', 'functional', null, null, 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000); + +INSERT INTO file_metadata (id, name, type, size, create_time, update_time, project_id, storage, create_user, update_user, + tags, description, module_id, path, latest, ref_id, file_version) VALUES + ('default-bug-file-id-1', 'test-file', 'xlsx', 100, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'MINIO', 'admin', 'admin', + '["default-tag"]', 'test-file', null, 'test-file', 1, 'default-bug-id', 1), + ('default-bug-file-id-2', 'test-file', 'xlsx', 100, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'default-project-for-bug', 'MINIO', 'admin', 'admin', + '["default-tag"]', 'test-file', null, 'test-file', 1, 'default-bug-id', 1); + +INSERT INTO project_application (project_id, type, type_value) VALUES ('default-project-for-bug', 'BUG_DEFAULT_TEMPLATE', 'default-bug-template-id'); \ No newline at end of file diff --git a/backend/services/bug-management/src/test/resources/file/test.xlsx b/backend/services/bug-management/src/test/resources/file/test.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..732067f6ecdc90d81f4972e2cea2d76c4657c202 GIT binary patch literal 8861 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 M8IrR-NPm9&F96-r`Tzg` literal 0 HcmV?d00001 diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/service/CommandService.java b/backend/services/project-management/src/main/java/io/metersphere/project/service/CommandService.java index b3e0a824e2..5732a15dc6 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/service/CommandService.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/service/CommandService.java @@ -24,7 +24,7 @@ public class CommandService { public static String createFile(MultipartFile bodyFile) { MsFileUtils.validateFileName(bodyFile.getOriginalFilename()); - String dir = MsFileUtils.DATE_ROOT_DIR + "/body/environment/tmp"; + String dir = MsFileUtils.DATA_ROOT_DIR + "/body/environment/tmp"; File fileDir = new File(dir); if (!fileDir.exists()) { fileDir.mkdirs(); diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/service/ProjectApplicationService.java b/backend/services/project-management/src/main/java/io/metersphere/project/service/ProjectApplicationService.java index 8737455e9b..08cf373429 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/service/ProjectApplicationService.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/service/ProjectApplicationService.java @@ -18,13 +18,13 @@ import io.metersphere.project.utils.ModuleSortUtils; import io.metersphere.sdk.constants.OperationLogConstants; import io.metersphere.sdk.constants.ProjectApplicationType; import io.metersphere.sdk.constants.ScheduleType; -import io.metersphere.system.log.dto.LogDTO; -import io.metersphere.system.dto.sdk.OptionDTO; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.util.JSON; import io.metersphere.system.domain.*; +import io.metersphere.system.dto.sdk.OptionDTO; 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.mapper.PluginMapper; import io.metersphere.system.mapper.ServiceIntegrationMapper; import io.metersphere.system.sechedule.ScheduleService; @@ -568,4 +568,14 @@ public class ProjectApplicationService { List projectApplications = projectApplicationMapper.selectByExample(example); return CollectionUtils.isEmpty(projectApplications) ? null : projectApplications.get(0); } + +// /** +// * 获取项目所属平台 +// * @param projectId 项目ID +// * @return 项目所属平台 +// */ +// public String getPlatformName(String projectId) { +// // TODO 需调用项目平台配置接口, 获取项目所属平台名称 +// return null; +// } } diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/service/ProjectTemplateService.java b/backend/services/project-management/src/main/java/io/metersphere/project/service/ProjectTemplateService.java index ced2b3407d..3926e1bf7a 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/service/ProjectTemplateService.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/service/ProjectTemplateService.java @@ -223,7 +223,7 @@ public class ProjectTemplateService extends BaseTemplateService { * @param projectId * @return */ - private Template getPluginBugTemplate(String projectId) { + public Template getPluginBugTemplate(String projectId) { ServiceIntegration serviceIntegration = getServiceIntegration(projectId); if (serviceIntegration == null) { return null; @@ -240,6 +240,7 @@ public class ProjectTemplateService extends BaseTemplateService { PluginWrapper pluginWrapper = pluginLoadService.getPluginWrapper(pluginId); Template template = new Template(); template.setId(pluginWrapper.getPluginId()); + template.setName(((MsPlugin) pluginWrapper.getPlugin()).getName() + Translator.get("default_template")); template.setCreateUser(InternalUser.ADMIN.getValue()); template.setScene(TemplateScene.BUG.name()); template.setEnableThirdPart(true); @@ -257,7 +258,7 @@ public class ProjectTemplateService extends BaseTemplateService { * @param projectId * @return */ - private ServiceIntegration getServiceIntegration(String projectId) { + public ServiceIntegration getServiceIntegration(String projectId) { // 判断项目是否开启集成缺陷 ProjectApplication syncEnableConfig = projectApplicationService.getByType(projectId, ProjectApplicationType.BUG_SYNC_CONFIG.SYNC_ENABLE.name()); boolean isSyncEnable = syncEnableConfig != null && Boolean.parseBoolean(syncEnableConfig.getTypeValue()); diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/file/LocalFileRepository.java b/backend/services/system-setting/src/main/java/io/metersphere/system/file/LocalFileRepository.java index 8c76922628..79eeadaf40 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/file/LocalFileRepository.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/file/LocalFileRepository.java @@ -94,6 +94,6 @@ public class LocalFileRepository implements FileRepository { private String getFileDir(FileRequest request) { MsFileUtils.validateFileName(request.getProjectId(), request.getFileName()); - return StringUtils.join(MsFileUtils.DATE_ROOT_DIR, "/", request.getProjectId()); + return StringUtils.join(MsFileUtils.DATA_ROOT_DIR, "/", request.getProjectId()); } } diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/BaseMapper.xml b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/BaseMapper.xml index b571dedb9d..6ac1e62448 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/BaseMapper.xml +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/mapper/BaseMapper.xml @@ -47,4 +47,10 @@ #{value} + + + + JSON_CONTAINS(value, #{value}) + + \ No newline at end of file diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/service/BaseTemplateService.java b/backend/services/system-setting/src/main/java/io/metersphere/system/service/BaseTemplateService.java index 947747860f..195499fb72 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/service/BaseTemplateService.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/service/BaseTemplateService.java @@ -2,21 +2,22 @@ package io.metersphere.system.service; import io.metersphere.sdk.constants.TemplateScene; import io.metersphere.sdk.constants.TemplateScopeType; -import io.metersphere.system.dto.sdk.TemplateCustomFieldDTO; -import io.metersphere.system.dto.sdk.TemplateDTO; -import io.metersphere.system.dto.sdk.request.TemplateCustomFieldRequest; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.LogUtils; -import io.metersphere.system.resolver.field.AbstractCustomFieldResolver; -import io.metersphere.system.resolver.field.CustomFieldResolverFactory; -import io.metersphere.system.utils.ServiceUtils; import io.metersphere.sdk.util.Translator; import io.metersphere.system.domain.CustomField; import io.metersphere.system.domain.Template; import io.metersphere.system.domain.TemplateCustomField; import io.metersphere.system.domain.TemplateExample; +import io.metersphere.system.dto.sdk.TemplateCustomFieldDTO; +import io.metersphere.system.dto.sdk.TemplateDTO; +import io.metersphere.system.dto.sdk.request.TemplateCustomFieldRequest; import io.metersphere.system.mapper.TemplateMapper; +import io.metersphere.system.resolver.field.AbstractCustomFieldResolver; +import io.metersphere.system.resolver.field.CustomFieldResolverFactory; +import io.metersphere.system.uid.IDGenerator; +import io.metersphere.system.utils.ServiceUtils; import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -26,7 +27,6 @@ import org.springframework.transaction.annotation.Transactional; import java.util.Arrays; import java.util.List; import java.util.Map; -import io.metersphere.system.uid.IDGenerator; import java.util.stream.Collectors; import static io.metersphere.system.controller.handler.result.CommonResultCode.*; @@ -94,7 +94,7 @@ public class BaseTemplateService { return templateMapper.selectByPrimaryKey(id); } - protected TemplateDTO getTemplateDTO(Template template) { + public TemplateDTO getTemplateDTO(Template template) { List templateCustomFields = baseTemplateCustomFieldService.getByTemplateId(template.getId()); // 查找字段名称