diff --git a/backend/framework/domain/src/main/java/io/metersphere/api/domain/ApiDocShare.java b/backend/framework/domain/src/main/java/io/metersphere/api/domain/ApiDocShare.java index c45837329d..821eba17e7 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/api/domain/ApiDocShare.java +++ b/backend/framework/domain/src/main/java/io/metersphere/api/domain/ApiDocShare.java @@ -24,15 +24,14 @@ public class ApiDocShare implements Serializable { @Size(min = 1, max = 255, message = "{api_doc_share.name.length_range}", groups = {Created.class, Updated.class}) private String name; - @Schema(title = "是否公开;0: 私有、1: 公开", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "{api_doc_share.is_public.not_blank}", groups = {Created.class}) - private Boolean isPublic; + @Schema(title = "是否私有;0: 公开、1: 私有", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "{api_doc_share.is_private.not_blank}", groups = {Created.class}) + private Boolean isPrivate; @Schema(title = "访问密码;私有时需要访问密码") private String password; - @Schema(title = "允许导出;0: 不允许、1: 允许", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "{api_doc_share.allow_export.not_blank}", groups = {Created.class}) + @Schema(title = "允许导出;0: 不允许、1: 允许") private Boolean allowExport; @Schema(title = "接口范围;全部接口(ALL)、模块(MODULE)、路径(PATH)、标签(TAG)", requiredMode = Schema.RequiredMode.REQUIRED) @@ -68,7 +67,7 @@ public class ApiDocShare implements Serializable { public enum Column { id("id", "id", "VARCHAR", false), name("name", "name", "VARCHAR", true), - isPublic("is_public", "isPublic", "BIT", false), + isPrivate("is_private", "isPrivate", "BIT", false), password("password", "password", "VARCHAR", true), allowExport("allow_export", "allowExport", "BIT", false), apiRange("api_range", "apiRange", "VARCHAR", false), diff --git a/backend/framework/domain/src/main/java/io/metersphere/api/domain/ApiDocShareExample.java b/backend/framework/domain/src/main/java/io/metersphere/api/domain/ApiDocShareExample.java index ccc21d4806..02f144d9ad 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/api/domain/ApiDocShareExample.java +++ b/backend/framework/domain/src/main/java/io/metersphere/api/domain/ApiDocShareExample.java @@ -244,63 +244,63 @@ public class ApiDocShareExample { return (Criteria) this; } - public Criteria andIsPublicIsNull() { - addCriterion("is_public is null"); + public Criteria andIsPrivateIsNull() { + addCriterion("is_private is null"); return (Criteria) this; } - public Criteria andIsPublicIsNotNull() { - addCriterion("is_public is not null"); + public Criteria andIsPrivateIsNotNull() { + addCriterion("is_private is not null"); return (Criteria) this; } - public Criteria andIsPublicEqualTo(Boolean value) { - addCriterion("is_public =", value, "isPublic"); + public Criteria andIsPrivateEqualTo(Boolean value) { + addCriterion("is_private =", value, "isPrivate"); return (Criteria) this; } - public Criteria andIsPublicNotEqualTo(Boolean value) { - addCriterion("is_public <>", value, "isPublic"); + public Criteria andIsPrivateNotEqualTo(Boolean value) { + addCriterion("is_private <>", value, "isPrivate"); return (Criteria) this; } - public Criteria andIsPublicGreaterThan(Boolean value) { - addCriterion("is_public >", value, "isPublic"); + public Criteria andIsPrivateGreaterThan(Boolean value) { + addCriterion("is_private >", value, "isPrivate"); return (Criteria) this; } - public Criteria andIsPublicGreaterThanOrEqualTo(Boolean value) { - addCriterion("is_public >=", value, "isPublic"); + public Criteria andIsPrivateGreaterThanOrEqualTo(Boolean value) { + addCriterion("is_private >=", value, "isPrivate"); return (Criteria) this; } - public Criteria andIsPublicLessThan(Boolean value) { - addCriterion("is_public <", value, "isPublic"); + public Criteria andIsPrivateLessThan(Boolean value) { + addCriterion("is_private <", value, "isPrivate"); return (Criteria) this; } - public Criteria andIsPublicLessThanOrEqualTo(Boolean value) { - addCriterion("is_public <=", value, "isPublic"); + public Criteria andIsPrivateLessThanOrEqualTo(Boolean value) { + addCriterion("is_private <=", value, "isPrivate"); return (Criteria) this; } - public Criteria andIsPublicIn(List values) { - addCriterion("is_public in", values, "isPublic"); + public Criteria andIsPrivateIn(List values) { + addCriterion("is_private in", values, "isPrivate"); return (Criteria) this; } - public Criteria andIsPublicNotIn(List values) { - addCriterion("is_public not in", values, "isPublic"); + public Criteria andIsPrivateNotIn(List values) { + addCriterion("is_private not in", values, "isPrivate"); return (Criteria) this; } - public Criteria andIsPublicBetween(Boolean value1, Boolean value2) { - addCriterion("is_public between", value1, value2, "isPublic"); + public Criteria andIsPrivateBetween(Boolean value1, Boolean value2) { + addCriterion("is_private between", value1, value2, "isPrivate"); return (Criteria) this; } - public Criteria andIsPublicNotBetween(Boolean value1, Boolean value2) { - addCriterion("is_public not between", value1, value2, "isPublic"); + public Criteria andIsPrivateNotBetween(Boolean value1, Boolean value2) { + addCriterion("is_private not between", value1, value2, "isPrivate"); return (Criteria) this; } diff --git a/backend/framework/domain/src/main/java/io/metersphere/api/mapper/ApiDocShareMapper.xml b/backend/framework/domain/src/main/java/io/metersphere/api/mapper/ApiDocShareMapper.xml index 6944e43054..558e40c2c5 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/api/mapper/ApiDocShareMapper.xml +++ b/backend/framework/domain/src/main/java/io/metersphere/api/mapper/ApiDocShareMapper.xml @@ -4,7 +4,7 @@ - + @@ -75,8 +75,8 @@ - id, `name`, is_public, `password`, allow_export, api_range, range_match_symbol, range_match_val, - invalid_time, invalid_unit, project_id, create_time, create_user + id, `name`, is_private, `password`, allow_export, api_range, range_match_symbol, + range_match_val, invalid_time, invalid_unit, project_id, create_time, create_user - select id, name, is_public isPublic, create_user createUser, create_time createTime, + select id, name, is_private isPrivate, create_user createUser, create_time createTime, api_range apiRange, range_match_symbol rangeMatchSymbol, range_match_val rangeMatchVal, invalid_time invalidTime, invalid_unit invalidUnit, project_id projectId from api_doc_share diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDocShareService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDocShareService.java index 20eb9f1052..b483f03b3e 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDocShareService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDocShareService.java @@ -5,21 +5,27 @@ import io.metersphere.api.dto.definition.ApiDocShareDTO; import io.metersphere.api.dto.definition.ApiDocShareDetail; import io.metersphere.api.dto.definition.request.ApiDocShareCheckRequest; import io.metersphere.api.dto.definition.request.ApiDocShareEditRequest; +import io.metersphere.api.dto.definition.request.ApiDocShareModuleRequest; import io.metersphere.api.dto.definition.request.ApiDocSharePageRequest; import io.metersphere.api.mapper.ApiDocShareMapper; import io.metersphere.api.mapper.ExtApiDefinitionMapper; import io.metersphere.api.mapper.ExtApiDocShareMapper; import io.metersphere.sdk.constants.MsAssertionCondition; +import io.metersphere.sdk.dto.CombineCondition; +import io.metersphere.sdk.dto.CombineSearch; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.Translator; +import io.metersphere.system.dto.sdk.BaseTreeNode; import io.metersphere.system.uid.IDGenerator; import jakarta.annotation.Resource; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Arrays; import java.util.List; +import java.util.Map; /** * @author song-cc-rock @@ -35,6 +41,8 @@ public class ApiDocShareService { private ApiDocShareMapper apiDocShareMapper; @Resource private ExtApiDocShareMapper extApiDocShareMapper; + @Resource + private ApiDefinitionModuleService apiDefinitionModuleService; public static final String RANGE_ALL = "ALL"; @@ -106,7 +114,7 @@ public class ApiDocShareService { */ public ApiDocShareDetail detail(String id) { ApiDocShare docShare = checkExit(id); - ApiDocShareDetail detail = ApiDocShareDetail.builder().allowExport(docShare.getAllowExport()).isPublic(docShare.getIsPublic()).build(); + ApiDocShareDetail detail = ApiDocShareDetail.builder().allowExport(docShare.getAllowExport()).isPrivate(docShare.getIsPrivate()).build(); if (docShare.getInvalidTime() == null || StringUtils.isBlank(docShare.getInvalidUnit())) { detail.setInvalid(false); } else { @@ -116,6 +124,26 @@ public class ApiDocShareService { return detail; } + /** + * 查询分享左侧模块树 + * @param request 请求参数 + * @return 模块树 + */ + public List getShareTree(ApiDocShareModuleRequest request) { + ApiDocShare docShare = checkExit(request.getShareId()); + return apiDefinitionModuleService.getTree(buildModuleParam(request, docShare), false, true); + } + + /** + * 查询分享左侧模块树节点数量 + * @param request 请求参数 + * @return 模块树节点数量 + */ + public Map getShareTreeCount(ApiDocShareModuleRequest request) { + ApiDocShare docShare = checkExit(request.getShareId()); + return apiDefinitionModuleService.moduleCount(buildModuleParam(request, docShare), false); + } + /** * 构建分享额外信息 * @param docShares 分享列表 @@ -162,6 +190,41 @@ public class ApiDocShareService { return extApiDefinitionMapper.countByShareParam(docShare.getProjectId(), condition.toString()).intValue(); } + /** + * 构建模块树查询参数 + * @param request 查询参数 + * @param docShare 分享对象 + * @return 模块树查询参数 + */ + public ApiDocShareModuleRequest buildModuleParam(ApiDocShareModuleRequest request, ApiDocShare docShare) { + // 设置接口范围查询条件 + if (!StringUtils.equals(docShare.getApiRange(), RANGE_ALL) && !StringUtils.isBlank(docShare.getRangeMatchVal())) { + CombineSearch combineSearch = new CombineSearch(); + switch (docShare.getApiRange()) { + case "MODULE" -> request.setModuleIds(List.of(docShare.getRangeMatchVal())); + case "PATH" -> { + if (StringUtils.equals(docShare.getRangeMatchSymbol(), MsAssertionCondition.EQUALS.name())) { + CombineCondition condition = buildModuleCondition("path", docShare.getRangeMatchVal(), MsAssertionCondition.EQUALS.name()); + combineSearch.setConditions(List.of(condition)); + } else { + CombineCondition condition = buildModuleCondition("path", docShare.getRangeMatchVal(), MsAssertionCondition.CONTAINS.name()); + combineSearch.setConditions(List.of(condition)); + } + } + case "TAG" -> { + // 暂时只有包含操作 + String[] tags = StringUtils.split(docShare.getRangeMatchVal(), ","); + CombineCondition condition = buildModuleCondition("tags", Arrays.asList(tags), MsAssertionCondition.CONTAINS.name()); + combineSearch.setConditions(List.of(condition)); + } + default -> { + } + } + request.setCombineSearch(combineSearch); + } + return request; + } + /** * 计算截止时间 * @param val 时间值 @@ -193,4 +256,21 @@ public class ApiDocShareService { } return docShare; } + + /** + * 组合左侧模块树的查询条件 + * @param name 条件字段名 + * @param val 条件字段值 + * @param operator 操作符 + * @return 组合查询条件 + */ + private CombineCondition buildModuleCondition(String name, Object val, String operator) { + CombineCondition condition = new CombineCondition(); + condition.setCustomField(false); + condition.setCustomFieldType(StringUtils.EMPTY); + condition.setName(name); + condition.setValue(val); + condition.setOperator(operator); + return condition; + } } diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDocShareControllerTests.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDocShareControllerTests.java index f5e008ae18..4e38efce64 100644 --- a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDocShareControllerTests.java +++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDocShareControllerTests.java @@ -3,6 +3,7 @@ package io.metersphere.api.controller; import io.metersphere.api.domain.ApiDocShare; import io.metersphere.api.dto.definition.request.ApiDocShareCheckRequest; import io.metersphere.api.dto.definition.request.ApiDocShareEditRequest; +import io.metersphere.api.dto.definition.request.ApiDocShareModuleRequest; import io.metersphere.api.dto.definition.request.ApiDocSharePageRequest; import io.metersphere.sdk.util.JSON; import io.metersphere.system.base.BaseTest; @@ -17,6 +18,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.web.servlet.MvcResult; import java.nio.charset.StandardCharsets; +import java.util.List; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -32,6 +34,8 @@ public class ApiDocShareControllerTests extends BaseTest { private final static String PAGE = BASE_PATH + "page"; private final static String CHECK = BASE_PATH + "check"; private final static String DETAIL = BASE_PATH + "detail/"; + private final static String MODULE_TREE = BASE_PATH + "module/tree"; + private final static String MODULE_COUNT = BASE_PATH + "module/count"; @Order(1) @Test @@ -40,7 +44,7 @@ public class ApiDocShareControllerTests extends BaseTest { request.setName("share-1"); request.setProjectId(DEFAULT_PROJECT_ID); request.setApiRange("ALL"); - request.setIsPublic(false); + request.setIsPrivate(false); request.setPassword("123456"); request.setAllowExport(false); MvcResult mvcResult = this.requestPostWithOk(ADD, request).andReturn(); @@ -53,6 +57,11 @@ public class ApiDocShareControllerTests extends BaseTest { checkRequest.setPassword("123456"); this.requestPostWithOk(CHECK, checkRequest); this.requestGetWithOk(DETAIL + docShare.getId()); + ApiDocShareModuleRequest moduleRequest = new ApiDocShareModuleRequest(); + moduleRequest.setShareId(docShare.getId()); + moduleRequest.setProjectId(DEFAULT_PROJECT_ID); + moduleRequest.setProtocols(List.of("HTTP", "SPX", "Redis", "MongoDB")); + this.requestPostWithOk(MODULE_TREE, moduleRequest); request.setId(docShare.getId()); request.setName("share-2"); request.setPassword(StringUtils.EMPTY); @@ -63,6 +72,7 @@ public class ApiDocShareControllerTests extends BaseTest { this.requestPostWithOk(UPDATE, request); this.requestPostWithOk(CHECK, checkRequest); this.requestGetWithOk(DETAIL + docShare.getId()); + this.requestPostWithOk(MODULE_TREE, moduleRequest); this.requestGetWithOk(DELETE + docShare.getId()); // 不存在的ID this.requestGet(DELETE + "not-exist-id").andExpect(status().is5xxServerError()); @@ -75,7 +85,7 @@ public class ApiDocShareControllerTests extends BaseTest { request.setName("share-1"); request.setProjectId(DEFAULT_PROJECT_ID); request.setApiRange("ALL"); - request.setIsPublic(false); + request.setIsPrivate(false); request.setAllowExport(false); this.requestPostWithOk(ADD, request); request.setInvalidTime(1); @@ -86,12 +96,30 @@ public class ApiDocShareControllerTests extends BaseTest { request.setApiRange("PATH"); request.setRangeMatchSymbol("EQUALS"); request.setRangeMatchVal("path-1"); - this.requestPostWithOk(ADD, request); + MvcResult mvcResult = this.requestPostWithOk(ADD, request).andReturn(); + String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); + ApiDocShare docShare = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), ApiDocShare.class); + ApiDocShareModuleRequest moduleRequest = new ApiDocShareModuleRequest(); + moduleRequest.setShareId(docShare.getId()); + moduleRequest.setProjectId(DEFAULT_PROJECT_ID); + moduleRequest.setProtocols(List.of("HTTP", "SPX", "Redis", "MongoDB")); + this.requestPostWithOk(MODULE_COUNT, moduleRequest); request.setRangeMatchSymbol("CONTAINS"); - this.requestPostWithOk(ADD, request); + MvcResult mvcResult1 = this.requestPostWithOk(ADD, request).andReturn(); + String returnData1 = mvcResult1.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder1 = JSON.parseObject(returnData1, ResultHolder.class); + ApiDocShare docShare1 = JSON.parseObject(JSON.toJSONString(resultHolder1.getData()), ApiDocShare.class); + moduleRequest.setShareId(docShare1.getId()); + this.requestPostWithOk(MODULE_COUNT, moduleRequest); request.setApiRange("TAG"); request.setRangeMatchVal("tag-1,tag-2"); - this.requestPostWithOk(ADD, request); + MvcResult mvcResult2 = this.requestPostWithOk(ADD, request).andReturn(); + String returnData2 = mvcResult2.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder2 = JSON.parseObject(returnData2, ResultHolder.class); + ApiDocShare docShare2 = JSON.parseObject(JSON.toJSONString(resultHolder2.getData()), ApiDocShare.class); + moduleRequest.setShareId(docShare2.getId()); + this.requestPostWithOk(MODULE_COUNT, moduleRequest); ApiDocSharePageRequest pageRequest = new ApiDocSharePageRequest(); pageRequest.setProjectId(DEFAULT_PROJECT_ID); pageRequest.setCurrent(1);