From d1e36c20b97aa1ff96965e866d74f3a71471abf0 Mon Sep 17 00:00:00 2001 From: lan-yonghui Date: Thu, 11 Jan 2024 22:23:51 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E9=A1=B9=E7=9B=AE=E7=AE=A1=E7=90=86):=20?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=AE=A1=E7=90=86=E5=85=AC=E5=85=B1=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/domain/CustomFunction.java | 44 +- .../project/domain/CustomFunctionExample.java | 556 +++++++++++++++++- .../project/mapper/CustomFunctionMapper.xml | 211 ++++++- .../ddl/V3.0.0_4__project_management.sql | 9 +- .../sdk/constants/PermissionConstants.java | 7 + .../main/resources/i18n/project.properties | 4 + .../resources/i18n/project_en_US.properties | 9 +- .../resources/i18n/project_zh_CN.properties | 7 +- .../resources/i18n/project_zh_TW.properties | 7 +- .../api/mapper/ExtApiDefinitionMockMapper.xml | 26 +- .../definition/ApiDefinitionMockService.java | 4 +- .../controller/CustomFunctionController.java | 96 +++ .../dto/customfunction/CustomFunctionDTO.java | 26 + .../request/CustomFunctionPageRequest.java | 32 + .../request/CustomFunctionRequest.java | 63 ++ .../request/CustomFunctionUpdateRequest.java | 20 + .../enums/result/ProjectResultCode.java | 4 +- .../mapper/ExtCustomFunctionMapper.java | 16 + .../mapper/ExtCustomFunctionMapper.xml | 127 ++++ .../service/CustomFunctionLogService.java | 138 +++++ .../service/CustomFunctionService.java | 162 +++++ .../CustomFunctionControllerTests.java | 352 +++++++++++ .../EnvironmentControllerTests.java | 2 +- .../log/constants/OperationLogModule.java | 1 + 24 files changed, 1841 insertions(+), 82 deletions(-) create mode 100644 backend/services/project-management/src/main/java/io/metersphere/project/controller/CustomFunctionController.java create mode 100644 backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/CustomFunctionDTO.java create mode 100644 backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionPageRequest.java create mode 100644 backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionRequest.java create mode 100644 backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionUpdateRequest.java create mode 100644 backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtCustomFunctionMapper.java create mode 100644 backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtCustomFunctionMapper.xml create mode 100644 backend/services/project-management/src/main/java/io/metersphere/project/service/CustomFunctionLogService.java create mode 100644 backend/services/project-management/src/main/java/io/metersphere/project/service/CustomFunctionService.java create mode 100644 backend/services/project-management/src/test/java/io/metersphere/project/controller/CustomFunctionControllerTests.java diff --git a/backend/framework/domain/src/main/java/io/metersphere/project/domain/CustomFunction.java b/backend/framework/domain/src/main/java/io/metersphere/project/domain/CustomFunction.java index 69681481ef..d9983f6dbf 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/project/domain/CustomFunction.java +++ b/backend/framework/domain/src/main/java/io/metersphere/project/domain/CustomFunction.java @@ -6,33 +6,65 @@ import jakarta.validation.constraints.*; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; + import lombok.Data; @Data public class CustomFunction implements Serializable { - @Schema(description = "", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "{custom_function.id.not_blank}", groups = {Updated.class}) @Size(min = 1, max = 50, message = "{custom_function.id.length_range}", groups = {Created.class, Updated.class}) private String id; - @Schema(description = "函数名", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "{custom_function.project_id.not_blank}", groups = {Created.class}) + @Size(min = 1, max = 50, message = "{custom_function.project_id.length_range}", groups = {Created.class, Updated.class}) + private String projectId; + + @Schema(description = "函数名", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "{custom_function.name.not_blank}", groups = {Created.class}) @Size(min = 1, max = 255, message = "{custom_function.name.length_range}", groups = {Created.class, Updated.class}) private String name; - @Schema(description = "标签") - private String tags; + @Schema(description = "标签") + private List tags; - @Schema(description = "函数描述") + @Schema(description = "函数描述") private String description; + @Schema(description = "脚本语言类型") + private String type; + + @Schema(description = "脚本状态(进行中/已完成)") + private String status; + + @Schema(description = "创建时间") + private Long createTime; + + @Schema(description = "更新时间") + private Long updateTime; + + @Schema(description = "创建人") + private String createUser; + + @Schema(description = "更新人") + private String updateUser; + private static final long serialVersionUID = 1L; public enum Column { id("id", "id", "VARCHAR", false), + projectId("project_id", "projectId", "VARCHAR", false), name("name", "name", "VARCHAR", true), tags("tags", "tags", "VARCHAR", false), - description("description", "description", "VARCHAR", false); + description("description", "description", "VARCHAR", false), + type("type", "type", "VARCHAR", true), + status("status", "status", "VARCHAR", true), + createTime("create_time", "createTime", "BIGINT", false), + updateTime("update_time", "updateTime", "BIGINT", false), + createUser("create_user", "createUser", "VARCHAR", false), + updateUser("update_user", "updateUser", "VARCHAR", false); private static final String BEGINNING_DELIMITER = "`"; diff --git a/backend/framework/domain/src/main/java/io/metersphere/project/domain/CustomFunctionExample.java b/backend/framework/domain/src/main/java/io/metersphere/project/domain/CustomFunctionExample.java index a775ec10bf..e84288291f 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/project/domain/CustomFunctionExample.java +++ b/backend/framework/domain/src/main/java/io/metersphere/project/domain/CustomFunctionExample.java @@ -64,19 +64,50 @@ public class CustomFunctionExample { } protected abstract static class GeneratedCriteria { + protected List tagsCriteria; + + protected List allCriteria; + protected List criteria; protected GeneratedCriteria() { super(); criteria = new ArrayList(); + tagsCriteria = new ArrayList(); + } + + public List getTagsCriteria() { + return tagsCriteria; + } + + protected void addTagsCriterion(String condition, Object value, String property) { + if (value == null) { + throw new RuntimeException("Value for " + property + " cannot be null"); + } + tagsCriteria.add(new Criterion(condition, value, "io.metersphere.handler.ListTypeHandler")); + allCriteria = null; + } + + protected void addTagsCriterion(String condition, List value1, List value2, String property) { + if (value1 == null || value2 == null) { + throw new RuntimeException("Between values for " + property + " cannot be null"); + } + tagsCriteria.add(new Criterion(condition, value1, value2, "io.metersphere.handler.ListTypeHandler")); + allCriteria = null; } public boolean isValid() { - return criteria.size() > 0; + return criteria.size() > 0 + || tagsCriteria.size() > 0; } public List getAllCriteria() { - return criteria; + if (allCriteria == null) { + allCriteria = new ArrayList(); + allCriteria.addAll(criteria); + allCriteria.addAll(tagsCriteria); + } + return allCriteria; } public List getCriteria() { @@ -88,6 +119,7 @@ public class CustomFunctionExample { throw new RuntimeException("Value for condition cannot be null"); } criteria.add(new Criterion(condition)); + allCriteria = null; } protected void addCriterion(String condition, Object value, String property) { @@ -95,6 +127,7 @@ public class CustomFunctionExample { throw new RuntimeException("Value for " + property + " cannot be null"); } criteria.add(new Criterion(condition, value)); + allCriteria = null; } protected void addCriterion(String condition, Object value1, Object value2, String property) { @@ -102,6 +135,7 @@ public class CustomFunctionExample { throw new RuntimeException("Between values for " + property + " cannot be null"); } criteria.add(new Criterion(condition, value1, value2)); + allCriteria = null; } public Criteria andIdIsNull() { @@ -174,6 +208,76 @@ public class CustomFunctionExample { return (Criteria) this; } + public Criteria andProjectIdIsNull() { + addCriterion("project_id is null"); + return (Criteria) this; + } + + public Criteria andProjectIdIsNotNull() { + addCriterion("project_id is not null"); + return (Criteria) this; + } + + public Criteria andProjectIdEqualTo(String value) { + addCriterion("project_id =", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotEqualTo(String value) { + addCriterion("project_id <>", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdGreaterThan(String value) { + addCriterion("project_id >", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdGreaterThanOrEqualTo(String value) { + addCriterion("project_id >=", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLessThan(String value) { + addCriterion("project_id <", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLessThanOrEqualTo(String value) { + addCriterion("project_id <=", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdLike(String value) { + addCriterion("project_id like", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotLike(String value) { + addCriterion("project_id not like", value, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdIn(List values) { + addCriterion("project_id in", values, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotIn(List values) { + addCriterion("project_id not in", values, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdBetween(String value1, String value2) { + addCriterion("project_id between", value1, value2, "projectId"); + return (Criteria) this; + } + + public Criteria andProjectIdNotBetween(String value1, String value2) { + addCriterion("project_id not between", value1, value2, "projectId"); + return (Criteria) this; + } + public Criteria andNameIsNull() { addCriterion("`name` is null"); return (Criteria) this; @@ -254,63 +358,63 @@ public class CustomFunctionExample { return (Criteria) this; } - public Criteria andTagsEqualTo(String value) { - addCriterion("tags =", value, "tags"); + public Criteria andTagsEqualTo(List value) { + addTagsCriterion("tags =", value, "tags"); return (Criteria) this; } - public Criteria andTagsNotEqualTo(String value) { - addCriterion("tags <>", value, "tags"); + public Criteria andTagsNotEqualTo(List value) { + addTagsCriterion("tags <>", value, "tags"); return (Criteria) this; } - public Criteria andTagsGreaterThan(String value) { - addCriterion("tags >", value, "tags"); + public Criteria andTagsGreaterThan(List value) { + addTagsCriterion("tags >", value, "tags"); return (Criteria) this; } - public Criteria andTagsGreaterThanOrEqualTo(String value) { - addCriterion("tags >=", value, "tags"); + public Criteria andTagsGreaterThanOrEqualTo(List value) { + addTagsCriterion("tags >=", value, "tags"); return (Criteria) this; } - public Criteria andTagsLessThan(String value) { - addCriterion("tags <", value, "tags"); + public Criteria andTagsLessThan(List value) { + addTagsCriterion("tags <", value, "tags"); return (Criteria) this; } - public Criteria andTagsLessThanOrEqualTo(String value) { - addCriterion("tags <=", value, "tags"); + public Criteria andTagsLessThanOrEqualTo(List value) { + addTagsCriterion("tags <=", value, "tags"); return (Criteria) this; } - public Criteria andTagsLike(String value) { - addCriterion("tags like", value, "tags"); + public Criteria andTagsLike(List value) { + addTagsCriterion("tags like", value, "tags"); return (Criteria) this; } - public Criteria andTagsNotLike(String value) { - addCriterion("tags not like", value, "tags"); + public Criteria andTagsNotLike(List value) { + addTagsCriterion("tags not like", value, "tags"); return (Criteria) this; } - public Criteria andTagsIn(List values) { - addCriterion("tags in", values, "tags"); + public Criteria andTagsIn(List> values) { + addTagsCriterion("tags in", values, "tags"); return (Criteria) this; } - public Criteria andTagsNotIn(List values) { - addCriterion("tags not in", values, "tags"); + public Criteria andTagsNotIn(List> values) { + addTagsCriterion("tags not in", values, "tags"); return (Criteria) this; } - public Criteria andTagsBetween(String value1, String value2) { - addCriterion("tags between", value1, value2, "tags"); + public Criteria andTagsBetween(List value1, List value2) { + addTagsCriterion("tags between", value1, value2, "tags"); return (Criteria) this; } - public Criteria andTagsNotBetween(String value1, String value2) { - addCriterion("tags not between", value1, value2, "tags"); + public Criteria andTagsNotBetween(List value1, List value2) { + addTagsCriterion("tags not between", value1, value2, "tags"); return (Criteria) this; } @@ -383,6 +487,406 @@ public class CustomFunctionExample { addCriterion("description not between", value1, value2, "description"); 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 andStatusIsNull() { + addCriterion("`status` is null"); + return (Criteria) this; + } + + public Criteria andStatusIsNotNull() { + addCriterion("`status` is not null"); + return (Criteria) this; + } + + public Criteria andStatusEqualTo(String value) { + addCriterion("`status` =", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotEqualTo(String value) { + addCriterion("`status` <>", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusGreaterThan(String value) { + addCriterion("`status` >", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusGreaterThanOrEqualTo(String value) { + addCriterion("`status` >=", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusLessThan(String value) { + addCriterion("`status` <", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusLessThanOrEqualTo(String value) { + addCriterion("`status` <=", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusLike(String value) { + addCriterion("`status` like", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotLike(String value) { + addCriterion("`status` not like", value, "status"); + return (Criteria) this; + } + + public Criteria andStatusIn(List values) { + addCriterion("`status` in", values, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotIn(List values) { + addCriterion("`status` not in", values, "status"); + return (Criteria) this; + } + + public Criteria andStatusBetween(String value1, String value2) { + addCriterion("`status` between", value1, value2, "status"); + return (Criteria) this; + } + + public Criteria andStatusNotBetween(String value1, String value2) { + addCriterion("`status` not between", value1, value2, "status"); + return (Criteria) this; + } + + public Criteria andCreateTimeIsNull() { + addCriterion("create_time is null"); + return (Criteria) this; + } + + public Criteria andCreateTimeIsNotNull() { + addCriterion("create_time is not null"); + return (Criteria) this; + } + + public Criteria andCreateTimeEqualTo(Long value) { + addCriterion("create_time =", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotEqualTo(Long value) { + addCriterion("create_time <>", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeGreaterThan(Long value) { + addCriterion("create_time >", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeGreaterThanOrEqualTo(Long value) { + addCriterion("create_time >=", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeLessThan(Long value) { + addCriterion("create_time <", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeLessThanOrEqualTo(Long value) { + addCriterion("create_time <=", value, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeIn(List values) { + addCriterion("create_time in", values, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotIn(List values) { + addCriterion("create_time not in", values, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeBetween(Long value1, Long value2) { + addCriterion("create_time between", value1, value2, "createTime"); + return (Criteria) this; + } + + public Criteria andCreateTimeNotBetween(Long value1, Long value2) { + addCriterion("create_time not between", value1, value2, "createTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeIsNull() { + addCriterion("update_time is null"); + return (Criteria) this; + } + + public Criteria andUpdateTimeIsNotNull() { + addCriterion("update_time is not null"); + return (Criteria) this; + } + + public Criteria andUpdateTimeEqualTo(Long value) { + addCriterion("update_time =", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeNotEqualTo(Long value) { + addCriterion("update_time <>", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeGreaterThan(Long value) { + addCriterion("update_time >", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeGreaterThanOrEqualTo(Long value) { + addCriterion("update_time >=", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeLessThan(Long value) { + addCriterion("update_time <", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeLessThanOrEqualTo(Long value) { + addCriterion("update_time <=", value, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeIn(List values) { + addCriterion("update_time in", values, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeNotIn(List values) { + addCriterion("update_time not in", values, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeBetween(Long value1, Long value2) { + addCriterion("update_time between", value1, value2, "updateTime"); + return (Criteria) this; + } + + public Criteria andUpdateTimeNotBetween(Long value1, Long value2) { + addCriterion("update_time not between", value1, value2, "updateTime"); + return (Criteria) this; + } + + public Criteria andCreateUserIsNull() { + addCriterion("create_user is null"); + return (Criteria) this; + } + + public Criteria andCreateUserIsNotNull() { + addCriterion("create_user is not null"); + return (Criteria) this; + } + + public Criteria andCreateUserEqualTo(String value) { + addCriterion("create_user =", value, "createUser"); + return (Criteria) this; + } + + public Criteria andCreateUserNotEqualTo(String value) { + addCriterion("create_user <>", value, "createUser"); + return (Criteria) this; + } + + public Criteria andCreateUserGreaterThan(String value) { + addCriterion("create_user >", value, "createUser"); + return (Criteria) this; + } + + public Criteria andCreateUserGreaterThanOrEqualTo(String value) { + addCriterion("create_user >=", value, "createUser"); + return (Criteria) this; + } + + public Criteria andCreateUserLessThan(String value) { + addCriterion("create_user <", value, "createUser"); + return (Criteria) this; + } + + public Criteria andCreateUserLessThanOrEqualTo(String value) { + addCriterion("create_user <=", value, "createUser"); + return (Criteria) this; + } + + public Criteria andCreateUserLike(String value) { + addCriterion("create_user like", value, "createUser"); + return (Criteria) this; + } + + public Criteria andCreateUserNotLike(String value) { + addCriterion("create_user not like", value, "createUser"); + return (Criteria) this; + } + + public Criteria andCreateUserIn(List values) { + addCriterion("create_user in", values, "createUser"); + return (Criteria) this; + } + + public Criteria andCreateUserNotIn(List values) { + addCriterion("create_user not in", values, "createUser"); + return (Criteria) this; + } + + public Criteria andCreateUserBetween(String value1, String value2) { + addCriterion("create_user between", value1, value2, "createUser"); + return (Criteria) this; + } + + public Criteria andCreateUserNotBetween(String value1, String value2) { + addCriterion("create_user not between", value1, value2, "createUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserIsNull() { + addCriterion("update_user is null"); + return (Criteria) this; + } + + public Criteria andUpdateUserIsNotNull() { + addCriterion("update_user is not null"); + return (Criteria) this; + } + + public Criteria andUpdateUserEqualTo(String value) { + addCriterion("update_user =", value, "updateUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserNotEqualTo(String value) { + addCriterion("update_user <>", value, "updateUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserGreaterThan(String value) { + addCriterion("update_user >", value, "updateUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserGreaterThanOrEqualTo(String value) { + addCriterion("update_user >=", value, "updateUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserLessThan(String value) { + addCriterion("update_user <", value, "updateUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserLessThanOrEqualTo(String value) { + addCriterion("update_user <=", value, "updateUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserLike(String value) { + addCriterion("update_user like", value, "updateUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserNotLike(String value) { + addCriterion("update_user not like", value, "updateUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserIn(List values) { + addCriterion("update_user in", values, "updateUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserNotIn(List values) { + addCriterion("update_user not in", values, "updateUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserBetween(String value1, String value2) { + addCriterion("update_user between", value1, value2, "updateUser"); + return (Criteria) this; + } + + public Criteria andUpdateUserNotBetween(String value1, String value2) { + addCriterion("update_user not between", value1, value2, "updateUser"); + return (Criteria) this; + } } public static class Criteria extends GeneratedCriteria { diff --git a/backend/framework/domain/src/main/java/io/metersphere/project/mapper/CustomFunctionMapper.xml b/backend/framework/domain/src/main/java/io/metersphere/project/mapper/CustomFunctionMapper.xml index 578bc76760..4d607d4b5a 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/project/mapper/CustomFunctionMapper.xml +++ b/backend/framework/domain/src/main/java/io/metersphere/project/mapper/CustomFunctionMapper.xml @@ -3,9 +3,16 @@ + - + + + + + + + @@ -31,6 +38,25 @@ + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value,typeHandler=io.metersphere.handler.ListTypeHandler} + + + and ${criterion.condition} #{criterion.value,typeHandler=io.metersphere.handler.ListTypeHandler} and #{criterion.secondValue,typeHandler=io.metersphere.handler.ListTypeHandler} + + + and ${criterion.condition} + + #{listItem,typeHandler=io.metersphere.handler.ListTypeHandler} + + + + @@ -60,13 +86,33 @@ + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value,typeHandler=io.metersphere.handler.ListTypeHandler} + + + and ${criterion.condition} #{criterion.value,typeHandler=io.metersphere.handler.ListTypeHandler} and #{criterion.secondValue,typeHandler=io.metersphere.handler.ListTypeHandler} + + + and ${criterion.condition} + + #{listItem,typeHandler=io.metersphere.handler.ListTypeHandler} + + + + - id, `name`, tags, description + id, project_id, `name`, tags, description, `type`, `status`, create_time, update_time, + create_user, update_user @@ -147,15 +241,36 @@ id = #{record.id,jdbcType=VARCHAR}, + + project_id = #{record.projectId,jdbcType=VARCHAR}, + `name` = #{record.name,jdbcType=VARCHAR}, - tags = #{record.tags,jdbcType=VARCHAR}, + tags = #{record.tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler}, description = #{record.description,jdbcType=VARCHAR}, + + `type` = #{record.type,jdbcType=VARCHAR}, + + + `status` = #{record.status,jdbcType=VARCHAR}, + + + create_time = #{record.createTime,jdbcType=BIGINT}, + + + update_time = #{record.updateTime,jdbcType=BIGINT}, + + + create_user = #{record.createUser,jdbcType=VARCHAR}, + + + update_user = #{record.updateUser,jdbcType=VARCHAR}, + @@ -164,9 +279,16 @@ update custom_function set id = #{record.id,jdbcType=VARCHAR}, + project_id = #{record.projectId,jdbcType=VARCHAR}, `name` = #{record.name,jdbcType=VARCHAR}, - tags = #{record.tags,jdbcType=VARCHAR}, - description = #{record.description,jdbcType=VARCHAR} + tags = #{record.tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler}, + description = #{record.description,jdbcType=VARCHAR}, + `type` = #{record.type,jdbcType=VARCHAR}, + `status` = #{record.status,jdbcType=VARCHAR}, + create_time = #{record.createTime,jdbcType=BIGINT}, + update_time = #{record.updateTime,jdbcType=BIGINT}, + create_user = #{record.createUser,jdbcType=VARCHAR}, + update_user = #{record.updateUser,jdbcType=VARCHAR} @@ -174,32 +296,64 @@ update custom_function + + project_id = #{projectId,jdbcType=VARCHAR}, + `name` = #{name,jdbcType=VARCHAR}, - tags = #{tags,jdbcType=VARCHAR}, + tags = #{tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler}, description = #{description,jdbcType=VARCHAR}, + + `type` = #{type,jdbcType=VARCHAR}, + + + `status` = #{status,jdbcType=VARCHAR}, + + + create_time = #{createTime,jdbcType=BIGINT}, + + + update_time = #{updateTime,jdbcType=BIGINT}, + + + create_user = #{createUser,jdbcType=VARCHAR}, + + + update_user = #{updateUser,jdbcType=VARCHAR}, + where id = #{id,jdbcType=VARCHAR} update custom_function - set `name` = #{name,jdbcType=VARCHAR}, - tags = #{tags,jdbcType=VARCHAR}, - description = #{description,jdbcType=VARCHAR} + set project_id = #{projectId,jdbcType=VARCHAR}, + `name` = #{name,jdbcType=VARCHAR}, + tags = #{tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler}, + description = #{description,jdbcType=VARCHAR}, + `type` = #{type,jdbcType=VARCHAR}, + `status` = #{status,jdbcType=VARCHAR}, + create_time = #{createTime,jdbcType=BIGINT}, + update_time = #{updateTime,jdbcType=BIGINT}, + create_user = #{createUser,jdbcType=VARCHAR}, + update_user = #{updateUser,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR} insert into custom_function - (id, `name`, tags, description) + (id, project_id, `name`, tags, description, `type`, `status`, create_time, update_time, + create_user, update_user) values - (#{item.id,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR}, #{item.tags,jdbcType=VARCHAR}, - #{item.description,jdbcType=VARCHAR}) + (#{item.id,jdbcType=VARCHAR}, #{item.projectId,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR}, + #{item.tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler}, + #{item.description,jdbcType=VARCHAR}, #{item.type,jdbcType=VARCHAR}, #{item.status,jdbcType=VARCHAR}, + #{item.createTime,jdbcType=BIGINT}, #{item.updateTime,jdbcType=BIGINT}, #{item.createUser,jdbcType=VARCHAR}, + #{item.updateUser,jdbcType=VARCHAR}) @@ -215,15 +369,36 @@ #{item.id,jdbcType=VARCHAR} + + #{item.projectId,jdbcType=VARCHAR} + #{item.name,jdbcType=VARCHAR} - #{item.tags,jdbcType=VARCHAR} + #{item.tags,jdbcType=VARCHAR,typeHandler=io.metersphere.handler.ListTypeHandler} #{item.description,jdbcType=VARCHAR} + + #{item.type,jdbcType=VARCHAR} + + + #{item.status,jdbcType=VARCHAR} + + + #{item.createTime,jdbcType=BIGINT} + + + #{item.updateTime,jdbcType=BIGINT} + + + #{item.createUser,jdbcType=VARCHAR} + + + #{item.updateUser,jdbcType=VARCHAR} + ) diff --git a/backend/framework/domain/src/main/resources/migration/3.0.0/ddl/V3.0.0_4__project_management.sql b/backend/framework/domain/src/main/resources/migration/3.0.0/ddl/V3.0.0_4__project_management.sql index d8c62b7079..292bf5991d 100644 --- a/backend/framework/domain/src/main/resources/migration/3.0.0/ddl/V3.0.0_4__project_management.sql +++ b/backend/framework/domain/src/main/resources/migration/3.0.0/ddl/V3.0.0_4__project_management.sql @@ -3,10 +3,17 @@ SET SESSION innodb_lock_wait_timeout = 7200; CREATE TABLE IF NOT EXISTS custom_function ( - `id` VARCHAR(50) NOT NULL COMMENT '', + `id` VARCHAR(50) NOT NULL COMMENT '主键ID', + `project_id` VARCHAR(50) NOT NULL COMMENT '项目ID' , `name` VARCHAR(255) NOT NULL COMMENT '函数名', `tags` VARCHAR(1000) COMMENT '标签', `description` VARCHAR(500) COMMENT '函数描述', + `type` VARCHAR(50) DEFAULT NULL COMMENT '脚本语言类型', + `status` VARCHAR(50) COMMENT '脚本状态(进行中/已完成)' , + `create_time` BIGINT COMMENT '创建时间' , + `update_time` BIGINT COMMENT '更新时间' , + `create_user` VARCHAR(50) COMMENT '创建人' , + `update_user` VARCHAR(50) COMMENT '更新人' , PRIMARY KEY (id) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java index cde452bf4b..e77751e576 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java @@ -198,6 +198,13 @@ public class PermissionConstants { public static final String PROJECT_CUSTOM_FIELD_DELETE = "PROJECT_CUSTOM_FIELD:READ+DELETE"; /*------ end: PROJECT_CUSTOM_FIELD ------*/ + /*------ start: PROJECT_CUSTOM_FUNCTION------*/ + public static final String PROJECT_CUSTOM_FUNCTION_READ = "PROJECT_CUSTOM_FUNCTION:READ"; + public static final String PROJECT_CUSTOM_FUNCTION_ADD = "PROJECT_CUSTOM_FUNCTION:READ+ADD"; + public static final String PROJECT_CUSTOM_FUNCTION_UPDATE = "PROJECT_CUSTOM_FUNCTION:READ+UPDATE"; + public static final String PROJECT_CUSTOM_FUNCTION_DELETE = "PROJECT_CUSTOM_FUNCTION:READ+DELETE"; + /*------ end: PROJECT_CUSTOM_FUNCTION ------*/ + /*------ start: PROJECT_TEMPLATE ------*/ public static final String PROJECT_TEMPLATE_READ = "PROJECT_TEMPLATE:READ"; public static final String PROJECT_TEMPLATE_ADD = "PROJECT_TEMPLATE:READ+ADD"; diff --git a/backend/framework/sdk/src/main/resources/i18n/project.properties b/backend/framework/sdk/src/main/resources/i18n/project.properties index 1047c13929..18ead8249e 100644 --- a/backend/framework/sdk/src/main/resources/i18n/project.properties +++ b/backend/framework/sdk/src/main/resources/i18n/project.properties @@ -74,6 +74,8 @@ custom_function.name.length_range=名称长度必须在{min}-{max}之间 custom_function.name.not_blank=名称不能为空 custom_function.type.length_range=类型长度必须在{min}-{max}之间 custom_function.type.not_blank=类型不能为空 +custom_function.status.length_range=脚本状态长度必须在{min}-{max}之间 +custom_function.status.not_blank=脚本状态不能为空 custom_function.create_user.length_range=创建人长度必须在{min}-{max}之间 custom_function.create_user.not_blank=创建人不能为空 custom_function.project_id.length_range=项目ID长度必须在{min}-{max}之间 @@ -470,4 +472,6 @@ plugin_bug_template_remark=模板为系统自动获取,不支持编辑和查 global_params=全局参数.json env_info_all=环境信息(总).json +# custom_function +custom_function_already_exist= 脚本名称已存在 diff --git a/backend/framework/sdk/src/main/resources/i18n/project_en_US.properties b/backend/framework/sdk/src/main/resources/i18n/project_en_US.properties index 0c6ec9ab88..3bfdfe9ee6 100644 --- a/backend/framework/sdk/src/main/resources/i18n/project_en_US.properties +++ b/backend/framework/sdk/src/main/resources/i18n/project_en_US.properties @@ -86,6 +86,8 @@ custom_function.name.length_range=Name length must be between {min} and {max} custom_function.name.not_blank=Name is required custom_function.type.length_range=Type length must be between {min} and {max} custom_function.type.not_blank=Type is required +custom_function.status.length_range=Status length must be between {min} and {max} +custom_function.status.not_blank=Status is required custom_function.create_user.length_range=Create User length must be between {min} and {max} custom_function.create_user.not_blank=Create User is required custom_function.project_id.length_range=Project ID length must be between {min} and {max} @@ -338,7 +340,7 @@ message.title.schedule_task_open=Turn on scheduled task notifications message.title.schedule_task_close=Turn off scheduled task notifications -#功能case +#功能case message.domain.name=Name message.domain.test_plan_name=Test plan name message.domain.review_name=Review name @@ -351,7 +353,7 @@ message.domain.delete_user=Delete user message.domain.create_time=Create time message.domain.update_time=Update time message.domain.delete_time=Delete time -#接口定义和case +#接口定义和case message.domain.protocol=Interface Protocol message.domain.method=Http protocol type message.domain.path=Http protocol path/other protocols are empty @@ -507,3 +509,6 @@ default_template=default template global_params=Global params.json env_info_all=All environment info.json + +# custom_function +custom_function_already_exist= custom function name already exist diff --git a/backend/framework/sdk/src/main/resources/i18n/project_zh_CN.properties b/backend/framework/sdk/src/main/resources/i18n/project_zh_CN.properties index 5d83318c50..b2ca4f821a 100644 --- a/backend/framework/sdk/src/main/resources/i18n/project_zh_CN.properties +++ b/backend/framework/sdk/src/main/resources/i18n/project_zh_CN.properties @@ -86,6 +86,8 @@ custom_function.name.length_range=名称长度必须在{min}-{max}之间 custom_function.name.not_blank=名称不能为空 custom_function.type.length_range=类型长度必须在{min}-{max}之间 custom_function.type.not_blank=类型不能为空 +custom_function.status.length_range=脚本状态长度必须在{min}-{max}之间 +custom_function.status.not_blank=脚本状态不能为空 custom_function.create_user.length_range=创建人长度必须在{min}-{max}之间 custom_function.create_user.not_blank=创建人不能为空 custom_function.project_id.length_range=项目ID长度必须在{min}-{max}之间 @@ -505,4 +507,7 @@ plugin_bug_template_remark=模板为系统自动获取,不支持编辑和查 default_template=默认模板 global_params=全局参数.json -env_info_all=环境信息(总).json \ No newline at end of file +env_info_all=环境信息(总).json + +# custom_function +custom_function_already_exist= 脚本名称已存在 diff --git a/backend/framework/sdk/src/main/resources/i18n/project_zh_TW.properties b/backend/framework/sdk/src/main/resources/i18n/project_zh_TW.properties index a958b87297..a38b423743 100644 --- a/backend/framework/sdk/src/main/resources/i18n/project_zh_TW.properties +++ b/backend/framework/sdk/src/main/resources/i18n/project_zh_TW.properties @@ -86,6 +86,8 @@ custom_function.name.length_range=名稱長度必須在{min}-{max}之間 custom_function.name.not_blank=名稱不能為空 custom_function.type.length_range=類型長度必須在{min}-{max}之間 custom_function.type.not_blank=類型不能為空 +custom_function.status.length_range=腳本狀態長度必須在{min}-{max}之間 +custom_function.status.not_blank=腳本狀態不能為空 custom_function.create_user.length_range=創建人長度必須在{min}-{max}之間 custom_function.create_user.not_blank=創建人不能為空 custom_function.project_id.length_range=項目ID長度必須在{min}-{max}之間 @@ -506,4 +508,7 @@ plugin_bug_template_remark=模板為系統自動獲取,不支持編輯和查 default_template=默認模板 global_params=全局參數.json -env_info_all=環境信息(总).json \ No newline at end of file +env_info_all=環境信息(总).json + +# custom_function +custom_function_already_exist= 腳本名稱已存在 diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMockMapper.xml b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMockMapper.xml index fe405c56da..a3d4b0b58c 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMockMapper.xml +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiDefinitionMockMapper.xml @@ -11,6 +11,7 @@ m.id, m.create_time, m.update_time, m.create_user, m.`name`, m.tags, m.`enable`, m.expect_num, m.project_id, m.api_definition_id, u.name as create_user_name from api_definition_mock m + left join `api_definition` d on d.id = m.api_definition_id left join `user` u on u.id = m.create_user where m.api_definition_id = #{request.apiDefinitionId} @@ -31,7 +32,8 @@ and ( m.expect_num like concat('%', #{request.keyword},'%') or m.name like concat('%', #{request.keyword},'%') - or m.tags like JSON_CONTAINS(tags, concat('["',#{request.keyword},'"]')) + or d.path like concat('%', #{request.keyword},'%') + or m.tags like JSON_CONTAINS(m.tags, concat('["',#{request.keyword},'"]')) ) @@ -61,14 +63,6 @@ and m.enable in - - and m.api_method in - - - - and m.api_path in - - and m.create_user in @@ -115,20 +109,6 @@ - - and m.api_path - - - - - - - and m.api_method - - - - - and (m.tags is null or m.tags diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionMockService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionMockService.java index d383c76511..8f4841ecc9 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionMockService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionMockService.java @@ -114,7 +114,7 @@ public class ApiDefinitionMockService { } apiDefinitionMock.setEnable(true); ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiDefinitionMock.getApiDefinitionId()); - apiDefinitionMock.setExpectNum(String.valueOf(NumGenerator.nextNum(request.getProjectId() + "_" + apiDefinition.getNum(), ApplicationNumScope.API_TEST_CASE))); + apiDefinitionMock.setExpectNum(String.valueOf(NumGenerator.nextNum(request.getProjectId() + "_" + apiDefinition.getNum(), ApplicationNumScope.API_MOCK))); apiDefinitionMockMapper.insertSelective(apiDefinitionMock); ApiDefinitionMockConfig apiDefinitionMockConfig = new ApiDefinitionMockConfig(); @@ -208,7 +208,7 @@ public class ApiDefinitionMockService { apiDefinitionMock.setCreateUser(userId); apiDefinitionMock.setEnable(true); ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(apiDefinitionMock.getApiDefinitionId()); - apiDefinitionMock.setExpectNum(String.valueOf(NumGenerator.nextNum(request.getProjectId() + "_" + apiDefinition.getNum(), ApplicationNumScope.API_TEST_CASE))); + apiDefinitionMock.setExpectNum(String.valueOf(NumGenerator.nextNum(request.getProjectId() + "_" + apiDefinition.getNum(), ApplicationNumScope.API_MOCK))); apiDefinitionMockMapper.insertSelective(apiDefinitionMock); Optional apiDefinitionMockConfigOptional = Optional.ofNullable(apiDefinitionMockConfigMapper.selectByPrimaryKey(request.getId())); diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/controller/CustomFunctionController.java b/backend/services/project-management/src/main/java/io/metersphere/project/controller/CustomFunctionController.java new file mode 100644 index 0000000000..e685a1dd84 --- /dev/null +++ b/backend/services/project-management/src/main/java/io/metersphere/project/controller/CustomFunctionController.java @@ -0,0 +1,96 @@ +package io.metersphere.project.controller; + +import com.github.pagehelper.Page; +import com.github.pagehelper.page.PageMethod; +import io.metersphere.project.domain.CustomFunction; +import io.metersphere.project.dto.customfunction.CustomFunctionDTO; +import io.metersphere.project.dto.customfunction.request.CustomFunctionPageRequest; +import io.metersphere.project.dto.customfunction.request.CustomFunctionRequest; +import io.metersphere.project.dto.customfunction.request.CustomFunctionUpdateRequest; +import io.metersphere.project.service.CustomFunctionLogService; +import io.metersphere.project.service.CustomFunctionService; +import io.metersphere.sdk.constants.PermissionConstants; +import io.metersphere.system.log.annotation.Log; +import io.metersphere.system.log.constants.OperationLogType; +import io.metersphere.system.security.CheckOwner; +import io.metersphere.system.utils.PageUtils; +import io.metersphere.system.utils.Pager; +import io.metersphere.system.utils.SessionUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @author: LAN + * @date: 2024/1/9 19:19 + * @version: 1.0 + */ +@RestController +@RequestMapping(value = "/project/custom/func") +@Tag(name = "项目管理-公共脚本") +public class CustomFunctionController { + + @Resource + private CustomFunctionService customFunctionService; + @PostMapping("/page") + @Operation(summary = "项目管理-公共脚本-列表") + @RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FUNCTION_READ) + @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") + public Pager> query(@Validated @RequestBody CustomFunctionPageRequest request) { + Page page = PageMethod.startPage(request.getCurrent(), request.getPageSize(), + StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "create_time desc"); + return PageUtils.setPageInfo(page, customFunctionService.getPage(request)); + } + + @GetMapping("/detail/{id}") + @Operation(summary = "项目管理-公共脚本-脚本详情") + @RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FUNCTION_READ) + @CheckOwner(resourceId = "#id", resourceType = "custom_function") + public CustomFunctionDTO get(@PathVariable String id) { + return customFunctionService.get(id); + } + + @PostMapping("/add") + @Operation(summary = "项目管理-公共脚本-脚本添加") + @RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FUNCTION_ADD) + @Log(type = OperationLogType.ADD, expression = "#msClass.addLog(#request)", msClass = CustomFunctionLogService.class) + @CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project") + public CustomFunction add(@Validated @RequestBody CustomFunctionRequest request) { + return customFunctionService.add(request, SessionUtils.getUserId()); + } + + @PostMapping("/update") + @Operation(summary = "项目管理-公共脚本-脚本更新") + @RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FUNCTION_UPDATE) + @Log(type = OperationLogType.UPDATE, expression = "#msClass.updateLog(#request)", msClass = CustomFunctionLogService.class) + @CheckOwner(resourceId = "#request.getId()", resourceType = "custom_function") + public void update(@Validated @RequestBody CustomFunctionUpdateRequest request) { + customFunctionService.update(request, SessionUtils.getUserId()); + } + + @PostMapping("/status") + @Operation(summary = "项目管理-公共脚本-脚本更新状态") + @RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FUNCTION_UPDATE) + @Log(type = OperationLogType.UPDATE, expression = "#msClass.updateStatusLog(#request)", msClass = CustomFunctionLogService.class) + @CheckOwner(resourceId = "#request.getId()", resourceType = "custom_function") + public void updateStatus(@Validated @RequestBody CustomFunctionUpdateRequest request) { + customFunctionService.updateStatus(request, SessionUtils.getUserId()); + } + + @GetMapping("/delete/{id}") + @Operation(summary = "项目管理-公共脚本-脚本删除") + @RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FUNCTION_DELETE) + @Log(type = OperationLogType.DELETE, expression = "#msClass.delLog(#id)", msClass = CustomFunctionLogService.class) + @CheckOwner(resourceId = "#id", resourceType = "custom_function") + public void delete(@PathVariable String id) { + customFunctionService.delete(id); + } + + +} diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/CustomFunctionDTO.java b/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/CustomFunctionDTO.java new file mode 100644 index 0000000000..45431b0a31 --- /dev/null +++ b/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/CustomFunctionDTO.java @@ -0,0 +1,26 @@ +package io.metersphere.project.dto.customfunction; + +import io.metersphere.project.domain.CustomFunction; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author: LAN + * @date: 2024/1/9 19:42 + * @version: 1.0 + */ +@Data +public class CustomFunctionDTO extends CustomFunction { + + @Schema(description = "创建人名称") + private String createUserName; + + @Schema(description = "参数列表") + private String params; + + @Schema(description = "函数体") + private String script; + + @Schema(description = "执行结果") + private String result; +} diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionPageRequest.java b/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionPageRequest.java new file mode 100644 index 0000000000..d5aeee65ec --- /dev/null +++ b/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionPageRequest.java @@ -0,0 +1,32 @@ +package io.metersphere.project.dto.customfunction.request; + +import io.metersphere.system.dto.sdk.BasePageRequest; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author: LAN + * @date: 2024/1/9 19:43 + * @version: 1.0 + */ +@Data +public class CustomFunctionPageRequest extends BasePageRequest implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "项目ID") + @NotBlank(message = "{custom_function.project_id.not_blank}") + @Size(min = 1, max = 50, message = "{custom_function.project_id.length_range}") + private String projectId; + + @Schema(description = "脚本语言类型") + private String type; + + @Schema(description = "脚本状态(进行中/已完成)") + private String status; +} diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionRequest.java b/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionRequest.java new file mode 100644 index 0000000000..1e894045be --- /dev/null +++ b/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionRequest.java @@ -0,0 +1,63 @@ +package io.metersphere.project.dto.customfunction.request; + +import io.metersphere.validation.groups.Created; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; + +/** + * @author: LAN + * @date: 2024/1/9 19:51 + * @version: 1.0 + */ +@Data +public class CustomFunctionRequest implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "项目ID") + @NotBlank(message = "{custom_function.project_id.not_blank}") + @Size(min = 1, max = 50, message = "{custom_function.project_id.length_range}") + private String projectId; + + @Schema(description = "函数名") + @NotBlank(message = "{custom_function.name.not_blank}", groups = {Created.class}) + @Size(min = 1, max = 255, message = "{custom_function.name.length_range}") + private String name; + + @Schema(description = "脚本语言类型") + private String type; + + @Schema(description = "脚本状态(进行中/已完成)") + private String status; + + @Schema(description = "标签") + private LinkedHashSet<@NotBlank String> tags; + + @Schema(description = "函数描述") + private String description; + + @Schema(description = "参数列表") + private String params; + + @Schema(description = "函数体") + private String script; + + @Schema(description = "执行结果") + private String result; + + public List getTags() { + if (tags == null) { + return new ArrayList<>(0); + } else { + return new ArrayList<>(tags); + } + } +} diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionUpdateRequest.java b/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionUpdateRequest.java new file mode 100644 index 0000000000..c711158c28 --- /dev/null +++ b/backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionUpdateRequest.java @@ -0,0 +1,20 @@ +package io.metersphere.project.dto.customfunction.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +/** + * @author: LAN + * @date: 2024/1/9 19:51 + * @version: 1.0 + */ +@Data +public class CustomFunctionUpdateRequest extends CustomFunctionRequest { + + @Schema(description = "主键ID") + @NotBlank(message = "{custom_function.id.not_blank}") + @Size(min = 1, max = 50, message = "{custom_function.id.length_range}") + private String id; +} diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/enums/result/ProjectResultCode.java b/backend/services/project-management/src/main/java/io/metersphere/project/enums/result/ProjectResultCode.java index 7a6c57e8b2..366f3032e5 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/enums/result/ProjectResultCode.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/enums/result/ProjectResultCode.java @@ -14,7 +14,9 @@ public enum ProjectResultCode implements IResultCode { /** * 开启组织模板,操作项目模板时,会返回 */ - PROJECT_TEMPLATE_PERMISSION(102002, "project_template_permission_error"); + PROJECT_TEMPLATE_PERMISSION(102002, "project_template_permission_error"), + + CUSTOM_FUNCTION_ALREADY_EXIST(102003, "custom_function_already_exist"); private final int code; private final String message; diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtCustomFunctionMapper.java b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtCustomFunctionMapper.java new file mode 100644 index 0000000000..ef7e96b30c --- /dev/null +++ b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtCustomFunctionMapper.java @@ -0,0 +1,16 @@ +package io.metersphere.project.mapper; + +import io.metersphere.project.dto.customfunction.CustomFunctionDTO; +import io.metersphere.project.dto.customfunction.request.CustomFunctionPageRequest; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * @author: LAN + * @date: 2024/1/11 15:45 + * @version: 1.0 + */ +public interface ExtCustomFunctionMapper { + List list(@Param("request") CustomFunctionPageRequest request); +} diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtCustomFunctionMapper.xml b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtCustomFunctionMapper.xml new file mode 100644 index 0000000000..f03f81e3b4 --- /dev/null +++ b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtCustomFunctionMapper.xml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + and ( + c.name like concat('%', #{request.keyword},'%') + or c.tags like JSON_CONTAINS(tags, concat('["',#{request.keyword},'"]')) + ) + + + + and c.type = #{request.type} + + + + and c.status = #{request.status} + + + + + + + + + + + + + + + + + + + + + + + and c.status in + + + + + + + + + + + and c.name + + + + + + + and c.update_time + + + + + + + and c.create_time + + + + + + + and c.create_user + + + + + + + and c.status + + + + + + + and (c.tags is null or c.tags + + + + ) + + + + and c.tags + + + + + + + + diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/service/CustomFunctionLogService.java b/backend/services/project-management/src/main/java/io/metersphere/project/service/CustomFunctionLogService.java new file mode 100644 index 0000000000..7245633c12 --- /dev/null +++ b/backend/services/project-management/src/main/java/io/metersphere/project/service/CustomFunctionLogService.java @@ -0,0 +1,138 @@ +package io.metersphere.project.service; + +import io.metersphere.project.domain.CustomFunction; +import io.metersphere.project.dto.customfunction.CustomFunctionDTO; +import io.metersphere.project.dto.customfunction.request.CustomFunctionRequest; +import io.metersphere.project.dto.customfunction.request.CustomFunctionUpdateRequest; +import io.metersphere.project.mapper.CustomFunctionMapper; +import io.metersphere.sdk.constants.HttpMethodConstants; +import io.metersphere.sdk.util.BeanUtils; +import io.metersphere.sdk.util.JSON; +import io.metersphere.system.log.constants.OperationLogModule; +import io.metersphere.system.log.constants.OperationLogType; +import io.metersphere.system.log.dto.LogDTO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author: LAN + * @date: 2024/1/9 19:38 + * @version: 1.0 + */ +@Service +@Transactional(rollbackFor = Exception.class) +public class CustomFunctionLogService { + @Resource + private CustomFunctionMapper customFunctionMapper; + + @Resource + private CustomFunctionService customFunctionService; + + /** + * 添加日志 + * + * @param request + * @return + */ + public LogDTO addLog(CustomFunctionRequest request) { + LogDTO dto = new LogDTO( + request.getProjectId(), + null, + null, + null, + OperationLogType.ADD.name(), + OperationLogModule.PROJECT_CUSTOM_FUNCTION, + request.getName()); + dto.setHistory(true); + dto.setPath("/project/custom/func/add"); + dto.setMethod(HttpMethodConstants.POST.name()); + dto.setOriginalValue(JSON.toJSONBytes(request)); + return dto; + } + + /** + * 修改日志 + * + * @param request + * @return + */ + public LogDTO updateLog(CustomFunctionUpdateRequest request) { + CustomFunctionDTO customFunctionDTO= getOriginalValue(request.getId()); + if(customFunctionDTO.getId() != null){ + LogDTO dto = new LogDTO( + request.getProjectId(), + null, + request.getId(), + null, + OperationLogType.UPDATE.name(), + OperationLogModule.PROJECT_CUSTOM_FUNCTION, + request.getName()); + dto.setHistory(true); + dto.setPath("/project/custom/func/update"); + dto.setMethod(HttpMethodConstants.POST.name()); + dto.setOriginalValue(JSON.toJSONBytes(customFunctionDTO)); + return dto; + } + return null; + } + + public LogDTO updateStatusLog(CustomFunctionUpdateRequest request) { + CustomFunctionDTO customFunctionDTO= getOriginalValue(request.getId()); + if(customFunctionDTO.getId() != null){ + LogDTO dto = new LogDTO( + customFunctionDTO.getProjectId(), + null, + customFunctionDTO.getId(), + null, + OperationLogType.UPDATE.name(), + OperationLogModule.PROJECT_CUSTOM_FUNCTION, + customFunctionDTO.getName()); + dto.setHistory(true); + dto.setPath("/project/custom/func/status" ); + dto.setMethod(HttpMethodConstants.GET.name()); + dto.setOriginalValue(JSON.toJSONBytes(customFunctionDTO)); + return dto; + } + return null; + } + + /** + * 删除日志 + * + * @param id + * @return + */ + public LogDTO delLog(String id) { + CustomFunctionDTO customFunctionDTO = getOriginalValue(id); + if(customFunctionDTO.getId() != null){ + LogDTO dto = new LogDTO( + customFunctionDTO.getProjectId(), + null, + customFunctionDTO.getId(), + null, + OperationLogType.DELETE.name(), + OperationLogModule.PROJECT_CUSTOM_FUNCTION, + customFunctionDTO.getName()); + dto.setHistory(true); + dto.setPath("/project/custom/func/delete"); + dto.setMethod(HttpMethodConstants.POST.name()); + dto.setOriginalValue(JSON.toJSONBytes(customFunctionDTO)); + return dto; + } + + return null; + } + + + + private CustomFunctionDTO getOriginalValue(String id){ + CustomFunctionDTO customFunctionDTO = new CustomFunctionDTO(); + CustomFunction customFunction = customFunctionMapper.selectByPrimaryKey(id); + if(null != customFunction){ + customFunctionService.handleCustomFunctionBlob(id, customFunctionDTO); + BeanUtils.copyBean(customFunctionDTO, customFunction); + } + return customFunctionDTO; + } +} diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/service/CustomFunctionService.java b/backend/services/project-management/src/main/java/io/metersphere/project/service/CustomFunctionService.java new file mode 100644 index 0000000000..24cb99692e --- /dev/null +++ b/backend/services/project-management/src/main/java/io/metersphere/project/service/CustomFunctionService.java @@ -0,0 +1,162 @@ +package io.metersphere.project.service; + +import io.metersphere.project.domain.CustomFunction; +import io.metersphere.project.domain.CustomFunctionBlob; +import io.metersphere.project.domain.CustomFunctionExample; +import io.metersphere.project.dto.customfunction.CustomFunctionDTO; +import io.metersphere.project.dto.customfunction.request.CustomFunctionPageRequest; +import io.metersphere.project.dto.customfunction.request.CustomFunctionRequest; +import io.metersphere.project.dto.customfunction.request.CustomFunctionUpdateRequest; +import io.metersphere.project.enums.result.ProjectResultCode; +import io.metersphere.project.mapper.CustomFunctionBlobMapper; +import io.metersphere.project.mapper.CustomFunctionMapper; +import io.metersphere.project.mapper.ExtCustomFunctionMapper; +import io.metersphere.sdk.exception.MSException; +import io.metersphere.sdk.util.BeanUtils; +import io.metersphere.system.uid.IDGenerator; +import io.metersphere.system.utils.ServiceUtils; +import jakarta.annotation.Resource; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Optional; + +/** + * @author: LAN + * @date: 2024/1/9 19:38 + * @version: 1.0 + */ +@Service +@Transactional(rollbackFor = Exception.class) +public class CustomFunctionService { + + @Resource + CustomFunctionMapper customFunctionMapper; + + @Resource + CustomFunctionBlobMapper customFunctionBlobMapper; + + @Resource + ExtCustomFunctionMapper extCustomFunctionMapper; + + public List getPage(CustomFunctionPageRequest request) { + return extCustomFunctionMapper.list(request); + } + + public CustomFunctionDTO get(String id) { + CustomFunction customFunction = checkCustomFunction(id); + CustomFunctionDTO customFunctionDTO = new CustomFunctionDTO(); + handleCustomFunctionBlob(id, customFunctionDTO); + BeanUtils.copyBean(customFunctionDTO, customFunction); + return customFunctionDTO; + } + + public void handleCustomFunctionBlob(String id, CustomFunctionDTO customFunctionDTO) { + Optional customFunctionBlobOptional = Optional.ofNullable(customFunctionBlobMapper.selectByPrimaryKey(id)); + customFunctionBlobOptional.ifPresent(blob -> { + customFunctionDTO.setParams(new String(blob.getParams(), StandardCharsets.UTF_8)); + customFunctionDTO.setScript(new String(blob.getScript(), StandardCharsets.UTF_8)); + customFunctionDTO.setResult(new String(blob.getResult(), StandardCharsets.UTF_8)); + }); + } + + public CustomFunction add(CustomFunctionRequest request, String userId) { + ProjectService.checkResourceExist(request.getProjectId()); + + CustomFunction customFunction = new CustomFunction(); + BeanUtils.copyBean(customFunction, request); + checkAddExist(customFunction); + customFunction.setId(IDGenerator.nextStr()); + customFunction.setCreateTime(System.currentTimeMillis()); + customFunction.setUpdateTime(System.currentTimeMillis()); + customFunction.setCreateUser(userId); + customFunction.setUpdateUser(userId); + if (CollectionUtils.isNotEmpty(request.getTags())) { + customFunction.setTags(request.getTags()); + } + customFunctionMapper.insertSelective(customFunction); + CustomFunctionBlob customFunctionBlob = new CustomFunctionBlob(); + customFunctionBlob.setId(customFunction.getId()); + if(request.getParams() != null) { + customFunctionBlob.setParams(request.getParams().getBytes()); + } + if(request.getScript() != null) { + customFunctionBlob.setScript(request.getScript().getBytes()); + } + if(request.getResult() != null) { + customFunctionBlob.setResult(request.getResult().getBytes()); + } + customFunctionBlobMapper.insertSelective(customFunctionBlob); + + return customFunction; + } + + public void update(CustomFunctionUpdateRequest request, String userId) { + ProjectService.checkResourceExist(request.getProjectId()); + + CustomFunction customFunction = new CustomFunction(); + BeanUtils.copyBean(customFunction, request); + checkUpdateExist(customFunction); + customFunction.setUpdateTime(System.currentTimeMillis()); + customFunction.setUpdateUser(userId); + if (CollectionUtils.isNotEmpty(request.getTags())) { + customFunction.setTags(request.getTags()); + } + customFunctionMapper.updateByPrimaryKeySelective(customFunction); + CustomFunctionBlob customFunctionBlob = new CustomFunctionBlob(); + customFunctionBlob.setId(customFunction.getId()); + if(request.getParams() != null) { + customFunctionBlob.setParams(request.getParams().getBytes()); + } + if(request.getScript() != null) { + customFunctionBlob.setScript(request.getScript().getBytes()); + } + if(request.getResult() != null) { + customFunctionBlob.setResult(request.getResult().getBytes()); + } + customFunctionBlobMapper.updateByPrimaryKeySelective(customFunctionBlob); + } + + public void updateStatus(CustomFunctionUpdateRequest request, String userId) { + checkCustomFunction(request.getId()); + CustomFunction update = new CustomFunction(); + update.setId(request.getId()); + update.setStatus(request.getStatus()); + update.setUpdateTime(System.currentTimeMillis()); + update.setUpdateUser(userId); + customFunctionMapper.updateByPrimaryKeySelective(update); + } + + public void delete(String id) { + checkCustomFunction(id); + customFunctionMapper.deleteByPrimaryKey(id); + customFunctionBlobMapper.deleteByPrimaryKey(id); + } + + private CustomFunction checkCustomFunction(String id) { + return ServiceUtils.checkResourceExist(customFunctionMapper.selectByPrimaryKey(id), "resource_not_exist"); + } + + private void checkAddExist(CustomFunction customFunction) { + CustomFunctionExample example = new CustomFunctionExample(); + example.createCriteria() + .andNameEqualTo(customFunction.getName()); + if (customFunctionMapper.countByExample(example) > 0) { + throw new MSException(ProjectResultCode.CUSTOM_FUNCTION_ALREADY_EXIST); + } + } + + private void checkUpdateExist(CustomFunction customFunction) { + CustomFunctionExample example = new CustomFunctionExample(); + example.createCriteria() + .andIdNotEqualTo(customFunction.getId()) + .andNameEqualTo(customFunction.getName()); + if (customFunctionMapper.countByExample(example) > 0) { + throw new MSException(ProjectResultCode.CUSTOM_FUNCTION_ALREADY_EXIST); + } + } + +} diff --git a/backend/services/project-management/src/test/java/io/metersphere/project/controller/CustomFunctionControllerTests.java b/backend/services/project-management/src/test/java/io/metersphere/project/controller/CustomFunctionControllerTests.java new file mode 100644 index 0000000000..bee98de0c3 --- /dev/null +++ b/backend/services/project-management/src/test/java/io/metersphere/project/controller/CustomFunctionControllerTests.java @@ -0,0 +1,352 @@ +package io.metersphere.project.controller; + +import io.metersphere.project.domain.CustomFunction; +import io.metersphere.project.domain.CustomFunctionBlob; +import io.metersphere.project.dto.customfunction.CustomFunctionDTO; +import io.metersphere.project.dto.customfunction.request.CustomFunctionPageRequest; +import io.metersphere.project.dto.customfunction.request.CustomFunctionRequest; +import io.metersphere.project.dto.customfunction.request.CustomFunctionUpdateRequest; +import io.metersphere.project.enums.result.ProjectResultCode; +import io.metersphere.project.mapper.CustomFunctionBlobMapper; +import io.metersphere.project.mapper.CustomFunctionMapper; +import io.metersphere.sdk.constants.PermissionConstants; +import io.metersphere.sdk.util.BeanUtils; +import io.metersphere.sdk.util.JSON; +import io.metersphere.sdk.util.LogUtils; +import io.metersphere.system.base.BaseTest; +import io.metersphere.system.controller.handler.ResultHolder; +import io.metersphere.system.controller.handler.result.MsHttpResultCode; +import io.metersphere.system.log.constants.OperationLogType; +import io.metersphere.system.utils.Pager; +import jakarta.annotation.Resource; +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.web.servlet.MvcResult; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; + +/** + * @author: LAN + * @date: 2024/1/11 19:02 + * @version: 1.0 + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@AutoConfigureMockMvc +public class CustomFunctionControllerTests extends BaseTest { + private static final String BASE_PATH = "/project/custom/func/"; + private final static String ADD = BASE_PATH + "add"; + private final static String UPDATE = BASE_PATH + "update"; + private final static String DELETE = BASE_PATH + "delete/"; + private final static String PAGE = BASE_PATH + "page"; + private static final String DETAIL = BASE_PATH + "detail/"; + private static final String STATUS = BASE_PATH + "status"; + + private static CustomFunction customFunction; + + @Resource + private CustomFunctionMapper customFunctionMapper; + + @Resource + private CustomFunctionBlobMapper customFunctionBlobMapper; + + + @Test + @Order(1) + public void testAdd() throws Exception { + LogUtils.info("create custom function test"); + // 创建测试数据 + CustomFunctionRequest request = new CustomFunctionRequest(); + request.setProjectId(DEFAULT_PROJECT_ID); + request.setName("test1test1test1test1test1test1"); + request.setStatus("UNDERWAY"); + // 执行方法调用 + request.setName("公共脚本test"); + this.requestPostWithOkAndReturn(ADD, request); + request.setName("公共脚本test2"); + this.requestPostWithOkAndReturn(ADD, request); + request.setScript("vars.get(\"variable_name\")\n" + + "vars.put(\"variable_name\", \"variable_value\")\n" + + "prev.getResponseHeaders()\n" + + "prev.getResponseCode()\n" + + "prev.getResponseDataAsString()"); + request.setParams("[{}]"); + request.setResult("2024-01-11 19:33:39 INFO 48551350 1-1 Thread started: 48551350 1-1\n" + + "2024-01-11 19:33:39 ERROR 48551350 1-1 Problem in JSR223 script JSR223Sampler, message: {}\n" + + "Both script file and script text are empty for element:JSR223Sampler\n" + + "javax.script.ScriptException\n" + + " at org.apache.jmeter.util.JSR223TestElement.processFileOrScript(JSR223TestElement.java:240)\n" + + " at org.apache.jmeter.protocol.java.sampler.JSR223Sampler.sample(JSR223Sampler.java:72)\n" + + " at org.apache.jmeter.threads.JMeterThread.doSampling(JMeterThread.java:672)\n" + + " at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:590)\n" + + " at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:502)\n" + + " at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:265)\n" + + " at java.base/java.lang.Thread.run(Thread.java:840)"); + + request.setName("公共脚本test3"); + this.requestPostWithOkAndReturn(ADD, request); + request.setName("公共脚本test4"); + this.requestPostWithOkAndReturn(ADD, request); + request.setName("公共脚本test5"); + MvcResult mvcResult = this.requestPostWithOkAndReturn(ADD, request); + // 校验请求成功数据 + CustomFunction resultData = getResultData(mvcResult, CustomFunction.class); + customFunction = assertAddCustomFunction(request, resultData.getId()); + // 再插入一条数据,便于修改时重名校验 + request.setName("重名公共脚本test"); + request.setTags(new LinkedHashSet<>(List.of("tag1", "tag2"))); + mvcResult = this.requestPostWithOkAndReturn(ADD, request); + resultData = getResultData(mvcResult, CustomFunction.class); + assertAddCustomFunction(request, resultData.getId()); + // @@重名校验异常 + assertErrorCode(this.requestPost(ADD, request), ProjectResultCode.CUSTOM_FUNCTION_ALREADY_EXIST); + + // 校验项目是否存在 + request.setProjectId("111"); + request.setName("test123"); + assertErrorCode(this.requestPost(ADD, request), MsHttpResultCode.NOT_FOUND); + + // @@校验日志 + this.checkLog(customFunction.getId(), OperationLogType.ADD, ADD); + // @@异常参数校验 + createdGroupParamValidateTest(CustomFunctionRequest.class, ADD); + // @@校验权限 + request.setProjectId(DEFAULT_PROJECT_ID); + request.setName("permission-st-6"); + requestPostPermissionTest(PermissionConstants.PROJECT_CUSTOM_FUNCTION_ADD, ADD, request); + } + + private CustomFunction assertAddCustomFunction(CustomFunctionRequest request, String id) { + CustomFunction customFunctionInfo = customFunctionMapper.selectByPrimaryKey(id); + CustomFunctionBlob customFunctionBlob = customFunctionBlobMapper.selectByPrimaryKey(id); + CustomFunction copyCustomFunction = BeanUtils.copyBean(new CustomFunction(), customFunctionInfo); + BeanUtils.copyBean(copyCustomFunction, request); + Assertions.assertEquals(customFunctionInfo, copyCustomFunction); + if(customFunctionBlob != null){ + if(customFunctionBlob.getParams() != null) { + Assertions.assertEquals(request.getParams(), new String(customFunctionBlob.getParams(), StandardCharsets.UTF_8)); + } + if(customFunctionBlob.getScript() != null) { + Assertions.assertEquals(request.getScript(), new String(customFunctionBlob.getScript(), StandardCharsets.UTF_8)); + } + if(customFunctionBlob.getResult() != null) { + Assertions.assertEquals(request.getResult(), new String(customFunctionBlob.getResult(), StandardCharsets.UTF_8)); + } + } + return customFunctionInfo; + } + + @Test + @Order(2) + public void get() throws Exception { + // @@请求成功 + MvcResult mvcResult = this.requestGetWithOkAndReturn(DETAIL + customFunction.getId()); + // 校验请求成功数据 + CustomFunctionDTO resultData = getResultData(mvcResult, CustomFunctionDTO.class); + // 校验数据是否正确 + CustomFunctionDTO customFunctionDTO = new CustomFunctionDTO(); + CustomFunction customFunctionInfo = customFunctionMapper.selectByPrimaryKey(customFunction.getId()); + BeanUtils.copyBean(customFunctionDTO, customFunctionInfo); + CustomFunctionBlob customFunctionBlob = customFunctionBlobMapper.selectByPrimaryKey(customFunction.getId()); + if (customFunctionBlob != null) { + customFunctionDTO.setParams(new String(customFunctionBlob.getParams(), StandardCharsets.UTF_8)); + customFunctionDTO.setScript(new String(customFunctionBlob.getScript(), StandardCharsets.UTF_8)); + customFunctionDTO.setResult(new String(customFunctionBlob.getResult(), StandardCharsets.UTF_8)); + } + Assertions.assertEquals(resultData, customFunctionDTO); + + assertErrorCode(this.requestGet(DETAIL + "111"), MsHttpResultCode.NOT_FOUND); + // @@校验权限 + requestGetPermissionTest(PermissionConstants.PROJECT_CUSTOM_FUNCTION_READ, DETAIL + "111"); + } + + @Test + @Order(3) + public void testUpdate() throws Exception { + LogUtils.info("update custom function test"); + + CustomFunctionUpdateRequest request = new CustomFunctionUpdateRequest(); + BeanUtils.copyBean(request, customFunction); + request.setName("test1test1test1test1test1test1"); + request.setScript("update-vars.get(\"variable_name\")\n" + + "vars.put(\"variable_name\", \"variable_value\")\n" + + "prev.getResponseHeaders()\n" + + "prev.getResponseCode()\n" + + "prev.getResponseDataAsString()"); + request.setParams("[{\"update-\":\"update-\"}]"); + request.setResult("update-2024-01-11 19:33:39 INFO 48551350 1-1 Thread started: 48551350 1-1\n" + + "2024-01-11 19:33:39 ERROR 48551350 1-1 Problem in JSR223 script JSR223Sampler, message: {}\n" + + "Both script file and script text are empty for element:JSR223Sampler\n" + + "javax.script.ScriptException\n" + + " at org.apache.jmeter.util.JSR223TestElement.processFileOrScript(JSR223TestElement.java:240)\n" + + " at org.apache.jmeter.protocol.java.sampler.JSR223Sampler.sample(JSR223Sampler.java:72)\n" + + " at org.apache.jmeter.threads.JMeterThread.doSampling(JMeterThread.java:672)\n" + + " at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:590)\n" + + " at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:502)\n" + + " at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:265)\n" + + " at java.base/java.lang.Thread.run(Thread.java:840)"); + + + this.requestPostWithOk(UPDATE, request); + // 校验请求成功数据 + customFunction = assertUpdateCustomFunction(request, request.getId()); + + // 修改 tags + request.setTags(new LinkedHashSet<>(List.of("tag1", "tag2-update"))); + request.setName("公共脚本test公共脚本test公共脚本test公共脚本test公共脚本test公共脚本test公共脚本test公共脚本test公共脚本test"); + this.requestPostWithOk(UPDATE, request); + // 校验请求成功数据 + assertUpdateCustomFunction(request, request.getId()); + + request.setName("重名公共脚本test"); + // @@重名校验异常 + assertErrorCode(this.requestPost(UPDATE, request), ProjectResultCode.CUSTOM_FUNCTION_ALREADY_EXIST); + + // 校验项目是否存在 + request.setProjectId("111"); + request.setName("test123"); + assertErrorCode(this.requestPost(UPDATE, request), MsHttpResultCode.NOT_FOUND); + + // 校验数据是否存在 + request.setId("111"); + request.setName("test123"); + assertErrorCode(this.requestPost(UPDATE, request), MsHttpResultCode.NOT_FOUND); + + // @@校验日志 + checkLog(customFunction.getId(), OperationLogType.UPDATE, UPDATE); + // @@异常参数校验 + createdGroupParamValidateTest(CustomFunctionUpdateRequest.class, UPDATE); + // @@校验权限 + request.setId(customFunction.getId()); + request.setProjectId(DEFAULT_PROJECT_ID); + request.setName("permission-st-6"); + requestPostPermissionTest(PermissionConstants.PROJECT_CUSTOM_FUNCTION_UPDATE, UPDATE, request); + + } + + private CustomFunction assertUpdateCustomFunction(CustomFunctionUpdateRequest request, String id) { + CustomFunction customFunctionInfo = customFunctionMapper.selectByPrimaryKey(id); + CustomFunctionBlob customFunctionBlob = customFunctionBlobMapper.selectByPrimaryKey(id); + CustomFunction copyCustomFunction = new CustomFunction(); + BeanUtils.copyBean(copyCustomFunction, customFunctionInfo); + BeanUtils.copyBean(copyCustomFunction, request); + Assertions.assertEquals(customFunctionInfo, copyCustomFunction); + if(customFunctionBlob != null){ + if(customFunctionBlob.getParams() != null) { + Assertions.assertEquals(request.getParams(), new String(customFunctionBlob.getParams(), StandardCharsets.UTF_8)); + } + if(customFunctionBlob.getScript() != null) { + Assertions.assertEquals(request.getScript(), new String(customFunctionBlob.getScript(), StandardCharsets.UTF_8)); + } + if(customFunctionBlob.getResult() != null) { + Assertions.assertEquals(request.getResult(), new String(customFunctionBlob.getResult(), StandardCharsets.UTF_8)); + } + } + return customFunctionInfo; + } + + @Test + @Order(4) + public void testUpdateStatus() throws Exception { + LogUtils.info("update status custom function test"); + // @@请求成功 + CustomFunctionUpdateRequest customFunctionUpdateRequest = new CustomFunctionUpdateRequest(); + customFunctionUpdateRequest.setId(customFunction.getId()); + customFunctionUpdateRequest.setProjectId(customFunction.getProjectId()); + customFunctionUpdateRequest.setStatus("COMPLETED"); + // 执行方法调用 + this.requestPostWithOk(STATUS, customFunctionUpdateRequest); + + customFunction = customFunctionMapper.selectByPrimaryKey(customFunction.getId()); + Assertions.assertEquals(customFunction.getStatus(), customFunctionUpdateRequest.getStatus()); + // @@校验日志 + checkLog(customFunction.getId(), OperationLogType.UPDATE, STATUS); + customFunctionUpdateRequest.setId("111"); + + assertErrorCode(this.requestPost(STATUS, customFunctionUpdateRequest), MsHttpResultCode.NOT_FOUND); + + // @@校验权限 + requestPostPermissionTest(PermissionConstants.PROJECT_CUSTOM_FUNCTION_UPDATE, STATUS, customFunctionUpdateRequest); + } + + + + @Test + @Order(9) + public void getPage() throws Exception { + doCustomFunctionPage("KEYWORD"); + doCustomFunctionPage("FILTER"); + } + + private void doCustomFunctionPage(String search) throws Exception { + CustomFunctionPageRequest request = new CustomFunctionPageRequest(); + request.setProjectId(DEFAULT_PROJECT_ID); + request.setCurrent(1); + request.setPageSize(10); + request.setSort(Map.of("createTime", "asc")); + switch (search) { + case "KEYWORD" -> configureKeywordSearch(request); + case "FILTER" -> configureFilterSearch(request); + default -> {} + } + + MvcResult mvcResult = this.requestPostWithOkAndReturn(PAGE, request); + // 获取返回值 + 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(), request.getCurrent()); + // 返回的数据量不超过规定要返回的数据量相同 + Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= request.getPageSize()); + + } + +// 进行中:UNDERWAY, +// 已完成:COMPLETED, + + + private void configureKeywordSearch(CustomFunctionPageRequest request) { + request.setKeyword("100"); + request.setSort(Map.of("status", "asc")); + } + + private void configureFilterSearch(CustomFunctionPageRequest request) { + Map> filters = new HashMap<>(); + request.setSort(Map.of()); + filters.put("status", List.of("UNDERWAY")); + filters.put("tags", List.of("tag1")); + request.setFilter(filters); + } + + @Test + @Order(12) + public void testDel() throws Exception { + LogUtils.info("delete custom function test"); + // @@请求成功 + this.requestGetWithOk(DELETE + customFunction.getId()); + checkLog(customFunction.getId(), OperationLogType.DELETE); + CustomFunction customFunctionInfo = customFunctionMapper.selectByPrimaryKey(customFunction.getId()); + Assertions.assertNull(customFunctionInfo); + + // blob是否删除 + CustomFunctionBlob customFunctionBlob = customFunctionBlobMapper.selectByPrimaryKey(customFunction.getId()); + Assertions.assertNull(customFunctionBlob); + + checkLog(customFunction.getId(), OperationLogType.DELETE); + assertErrorCode(this.requestGet(DELETE + "111"), MsHttpResultCode.NOT_FOUND); + // @@校验权限 + requestGetPermissionTest(PermissionConstants.PROJECT_CUSTOM_FUNCTION_DELETE, DELETE + "222"); + } + + +} diff --git a/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java b/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java index 3411a16792..d69a49081b 100644 --- a/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java +++ b/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java @@ -788,7 +788,7 @@ public class EnvironmentControllerTests extends BaseTest { // 测试500 dataSource.setDriver("com.mysql.cj.jdbc.Driver"); dataSource.setDbUrl("jdbc:mysql://"); - this.requestPost(validate, dataSource, ERROR_REQUEST_MATCHER); + this.requestPost(validate + "500", dataSource, ERROR_REQUEST_MATCHER); } @Test diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java b/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java index 332abad1ca..085758c03b 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/log/constants/OperationLogModule.java @@ -87,6 +87,7 @@ public class OperationLogModule { public static final String PROJECT_MANAGEMENT_PERMISSION_MENU_MANAGEMENT = "PROJECT_MANAGEMENT_PERMISSION_MENU_MANAGEMENT"; public static final String PROJECT_TEMPLATE = "PROJECT_TEMPLATE";// 项目模板 public static final String PROJECT_CUSTOM_FIELD = "PROJECT_CUSTOM_FIELD";// 项目字段 + public static final String PROJECT_CUSTOM_FUNCTION = "PROJECT_CUSTOM_FUNCTION";// 项目公共脚本 //用例 public static final String FUNCTIONAL_CASE = "FUNCTIONAL_CASE";