feat(系统设置): 功能用例页面高级搜索

--task=1016128 --user=陈建星 高级搜索-视图增删改查-后端 https://www.tapd.cn/55049933/s/1573254
This commit is contained in:
AgAngle 2024-09-06 15:02:41 +08:00 committed by Craftsman
parent 170dce538d
commit 186ca8edf0
99 changed files with 606 additions and 838 deletions

View File

@ -1,6 +1,7 @@
package io.metersphere.request;
import com.google.common.base.CaseFormat;
import io.metersphere.sdk.dto.BaseCondition;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
@ -18,7 +19,7 @@ import java.util.Map;
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class AssociateBugPageRequest extends BaseProviderCondition {
public class AssociateBugPageRequest extends BaseCondition {
@Schema(description = "用例id", requiredMode = Schema.RequiredMode.REQUIRED)
private String caseId;

View File

@ -1,5 +1,6 @@
package io.metersphere.request;
import io.metersphere.sdk.dto.BaseCondition;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;
@ -13,7 +14,7 @@ import java.util.List;
* @author wx
*/
@Data
public class AssociateBugRequest extends BaseProviderCondition {
public class AssociateBugRequest extends BaseCondition {
@Schema(description = "不处理的ID")
List<String> excludeIds;

View File

@ -1,6 +1,7 @@
package io.metersphere.request;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.dto.BaseCondition;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
@ -9,7 +10,7 @@ import lombok.Data;
import java.util.List;
@Data
public class AssociateCaseModuleRequest extends BaseProviderCondition {
public class AssociateCaseModuleRequest extends BaseCondition {
@Schema(description = "模块ID(根据模块树查询时要把当前节点以及子节点都放在这里。)")
private List<@NotBlank String> moduleIds;

View File

@ -1,5 +1,6 @@
package io.metersphere.request;
import io.metersphere.sdk.dto.BaseCondition;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;
@ -54,5 +55,5 @@ public class AssociateOtherCaseRequest {
private String apiDefinitionId;
@Schema(description = "查询条件")
private BaseProviderCondition condition = new BaseProviderCondition();
private BaseCondition condition = new BaseCondition();
}

View File

@ -1,35 +0,0 @@
package io.metersphere.request;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.Map;
@Data
public class BaseProviderCondition {
@Schema(description = "关键字")
private String keyword;
@Schema(description = "匹配模式 所有/任一", allowableValues = {"AND", "OR"})
private String searchMode = "AND";
@Schema(description = "过滤字段")
private Map<String, List<String>> filter;
@Schema(description = "高级搜索")
private Map<String, Object> combine;
// 转JSON时会调用 前台数据传过来时可以顺便处理掉转义字符
public void setKeyword(String keyword) {
keyword = StringUtils.replace(keyword, "%", "\\%");
keyword = StringUtils.replace(keyword, "_", "\\_");
this.keyword = keyword;
}
// 直接初始化keyword
public void initKeyword(String keyword) {
this.keyword = keyword;
}
}

View File

@ -1,6 +1,7 @@
package io.metersphere.request;
import com.google.common.base.CaseFormat;
import io.metersphere.sdk.dto.BaseCondition;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
@ -13,7 +14,6 @@ import org.apache.commons.lang3.StringUtils;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
@ -21,7 +21,7 @@ import java.util.Map;
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class BugPageProviderRequest implements Serializable {
public class BugPageProviderRequest extends BaseCondition implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@ -38,18 +38,6 @@ public class BugPageProviderRequest implements Serializable {
@Schema(description = "排序字段model中的字段 : asc/desc")
private Map<@Valid @Pattern(regexp = "^[A-Za-z]+$") String, @Valid @NotBlank String> sort;
@Schema(description = "关键字")
private String keyword;
@Schema(description = "匹配模式 所有/任一", allowableValues = {"AND", "OR"})
private String searchMode = "AND";
@Schema(description = "过滤字段")
private Map<String, List<String>> filter;
@Schema(description = "高级搜索")
private Map<String, Object> combine;
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{functional_case.project_id.not_blank}")
private String projectId;

View File

@ -1,6 +1,7 @@
package io.metersphere.request;
import com.google.common.base.CaseFormat;
import io.metersphere.sdk.dto.BaseCondition;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.*;
@ -19,7 +20,7 @@ import java.util.Map;
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class TestCasePageProviderRequest extends BaseProviderCondition implements Serializable {
public class TestCasePageProviderRequest extends BaseCondition implements Serializable {
@Serial
private static final long serialVersionUID = 1L;

View File

@ -137,6 +137,12 @@
<version>${guava.version}</version>
</dependency>
<!-- sdk 使用 schema 注解 -->
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-core-jakarta</artifactId>
<version>${swagger-core-jakarta.revision}</version>
</dependency>
<!--java json schema json格式校验-->
<dependency>

View File

@ -1,4 +1,4 @@
package io.metersphere.system.dto.sdk;
package io.metersphere.sdk.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
@ -16,6 +16,9 @@ public class BaseCondition {
@Schema(description = "过滤字段")
private Map<String, List<String>> filter;
@Schema(description = "视图ID")
private String viewId;
@Schema(description = "高级搜索")
@Valid
private CombineSearch combineSearch;

View File

@ -1,11 +1,14 @@
package io.metersphere.system.dto.sdk;
package io.metersphere.sdk.dto;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
/**
* @Author: jianxing
* @CreateTime: 2024-08-28 17:31
@ -30,7 +33,16 @@ public class CombineCondition {
private String operator;
public boolean valid() {
return StringUtils.isNotBlank(name) && StringUtils.isNotBlank(operator) && value != null;
if (value == null) {
return false;
}
if (value instanceof List valueList && CollectionUtils.isEmpty(valueList)) {
return false;
}
if (value instanceof String valueStr && StringUtils.isBlank(valueStr)) {
return false;
}
return StringUtils.isNotBlank(name) && StringUtils.isNotBlank(operator);
}
public enum CombineConditionOperator {

View File

@ -1,6 +1,6 @@
package io.metersphere.system.dto.sdk;
package io.metersphere.sdk.dto;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import lombok.Data;

View File

@ -1,4 +1,4 @@
package io.metersphere.system.valid;
package io.metersphere.sdk.valid;
import io.metersphere.sdk.constants.ValueEnum;
import io.metersphere.sdk.util.Translator;

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto;
import io.metersphere.sdk.constants.ApiBatchRunMode;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

View File

@ -3,7 +3,7 @@ package io.metersphere.api.dto.definition;
import io.metersphere.api.constants.ApiDefinitionStatus;
import io.metersphere.api.domain.ApiDefinitionCustomField;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;

View File

@ -2,7 +2,7 @@ package io.metersphere.api.dto.definition;
import io.metersphere.api.constants.ApiDefinitionStatus;
import io.metersphere.api.domain.ApiDefinitionCustomField;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.definition;
import io.metersphere.system.dto.sdk.BaseCondition;
import io.metersphere.sdk.dto.BaseCondition;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.constants.ApiDefinitionStatus;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.definition;
import io.metersphere.api.constants.ApiDefinitionStatus;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.request.controller;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@ -4,7 +4,7 @@ import io.metersphere.api.dto.request.controller.loop.MsCountController;
import io.metersphere.api.dto.request.controller.loop.MsForEachController;
import io.metersphere.api.dto.request.controller.loop.MsWhileController;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@ -3,7 +3,7 @@ package io.metersphere.api.dto.request.controller;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.project.dto.CommonScriptInfo;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.request.controller.loop;
import io.metersphere.api.dto.request.controller.WhileConditionType;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import lombok.Data;
@Data

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.request.controller.loop;
import io.metersphere.api.dto.request.controller.ConditionUtils;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import lombok.Data;
@Data

View File

@ -4,7 +4,7 @@ import io.metersphere.api.dto.request.http.body.Body;
import io.metersphere.plugin.api.spi.AbstractMsProtocolTestElement;
import io.metersphere.project.dto.environment.auth.HTTPAuthConfig;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.request.http;
import io.metersphere.project.api.KeyValueEnableParam;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import lombok.Data;
/**

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.request.http;
import io.metersphere.project.api.KeyValueEnableParam;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import lombok.Data;
/**

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.request.http.body;
import io.metersphere.project.api.KeyValueEnableParam;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import lombok.Data;
/**

View File

@ -2,7 +2,7 @@ package io.metersphere.api.dto.scenario;
import io.metersphere.api.constants.ApiScenarioStatus;
import io.metersphere.api.dto.ResourceAddFileParam;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.scenario;
import io.metersphere.system.dto.sdk.BaseCondition;
import io.metersphere.sdk.dto.BaseCondition;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

View File

@ -2,7 +2,7 @@ package io.metersphere.api.dto.scenario;
import io.metersphere.api.constants.ApiScenarioStepRefType;
import io.metersphere.api.constants.ApiScenarioStepType;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;

View File

@ -1,7 +1,7 @@
package io.metersphere.api.dto.scenario;
import io.metersphere.api.constants.ApiScenarioStepRefType;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

View File

@ -2,7 +2,7 @@ package io.metersphere.api.dto.scenario;
import io.metersphere.api.constants.ApiScenarioStatus;
import io.metersphere.api.dto.ResourceUpdateFileParam;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -2,7 +2,7 @@ package io.metersphere.api.dto.scenario;
import io.metersphere.api.dto.ApiFile;
import io.metersphere.sdk.constants.ValueEnum;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;

View File

@ -3,7 +3,7 @@ package io.metersphere.api.dto.schema;
import io.metersphere.project.constants.PropertyConstant;
import io.metersphere.sdk.constants.ValueEnum;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@ -367,107 +367,108 @@
</sql>
<sql id="combine">
<if test='${condition}.name != null and (${name} == null or ${name} == "")'>
and api_definition.name
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.name"/>
</include>
</if>
-- todo 待修改
<!-- <if test='${condition}.name != null and (${name} == null or ${name} == "")'>-->
<!-- and api_definition.name-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="${condition}.name"/>-->
<!-- </include>-->
<!-- </if>-->
<if test='${condition}.id != null'>
and api_definition.num
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.id"/>
</include>
</if>
<!-- <if test='${condition}.id != null'>-->
<!-- and api_definition.num-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="${condition}.id"/>-->
<!-- </include>-->
<!-- </if>-->
<if test="${condition}.updateTime != null">
and api_definition.update_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.updateTime"/>
</include>
</if>
<!-- <if test="${condition}.updateTime != null">-->
<!-- and api_definition.update_time-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="${condition}.updateTime"/>-->
<!-- </include>-->
<!-- </if>-->
<if test="${condition}.createTime != null">
and api_definition.create_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<!-- <if test="${condition}.createTime != null">-->
<!-- and api_definition.create_time-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="${condition}.createTime"/>-->
<!-- </include>-->
<!-- </if>-->
<if test="${condition}.status != null">
and api_definition.status
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.status"/>
</include>
</if>
<!-- <if test="${condition}.status != null">-->
<!-- and api_definition.status-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="${condition}.status"/>-->
<!-- </include>-->
<!-- </if>-->
<if test="${condition}.path != null">
and api_definition.path
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.path"/>
</include>
</if>
<!-- <if test="${condition}.path != null">-->
<!-- and api_definition.path-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="${condition}.path"/>-->
<!-- </include>-->
<!-- </if>-->
<if test="${condition}.method != null">
and api_definition.method
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.method"/>
</include>
</if>
<!-- <if test="${condition}.method != null">-->
<!-- and api_definition.method-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="${condition}.method"/>-->
<!-- </include>-->
<!-- </if>-->
<if test='${condition}.tags != null and ${ObjectTags}.operator == "not like"'>
and (api_definition.tags is null or api_definition.tags
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.tags"/>
</include>
)
</if>
<!-- <if test='${condition}.tags != null and ${ObjectTags}.operator == "not like"'>-->
<!-- and (api_definition.tags is null or api_definition.tags-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="${condition}.tags"/>-->
<!-- </include>-->
<!-- )-->
<!-- </if>-->
<if test='${condition}.tags != null and ${ObjectTags}.operator == "like"'>
and api_definition.tags
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.tags"/>
</include>
</if>
<!-- <if test='${condition}.tags != null and ${ObjectTags}.operator == "like"'>-->
<!-- and api_definition.tags-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="${condition}.tags"/>-->
<!-- </include>-->
<!-- </if>-->
<if test="${condition}.customs != null and ${condition}.customs.size() > 0">
<foreach collection="${condition}.customs" item="custom" separator="" open="" close="">
<if test="custom.value != ''">
<if test='custom.operator == "not like" or custom.operator == "not in"'>
and api_definition.id not in (
</if>
<if test='custom.operator != "not like" and custom.operator != "not in"'>
and api_definition.id in (
</if>
select api_id from api_definition_custom_field where field_id = #{custom.id}
<choose>
<when test="custom.type == 'TEXTAREA' or custom.operator == 'current user'">
and `value`
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="custom"/>
</include>
</when>
<when test="custom.type == 'MULTIPLE_MEMBER' or custom.type == 'CHECKBOX' or custom.type == 'MULTIPLE_SELECT'">
and ${custom.value}
</when>
<when test="custom.type == 'DATE' or custom.type == 'DATETIME'">
and left(replace(unix_timestamp(trim(both '"' from `value`)), '.', ''), 13)
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="custom"/>
</include>
</when>
<otherwise>
and trim(both '"' from `value`)
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="custom"/>
</include>
</otherwise>
</choose>
)
</if>
</foreach>
</if>
<!-- <if test="${condition}.customs != null and ${condition}.customs.size() > 0">-->
<!-- <foreach collection="${condition}.customs" item="custom" separator="" open="" close="">-->
<!-- <if test="custom.value != ''">-->
<!-- <if test='custom.operator == "not like" or custom.operator == "not in"'>-->
<!-- and api_definition.id not in (-->
<!-- </if>-->
<!-- <if test='custom.operator != "not like" and custom.operator != "not in"'>-->
<!-- and api_definition.id in (-->
<!-- </if>-->
<!-- select api_id from api_definition_custom_field where field_id = #{custom.id}-->
<!-- <choose>-->
<!-- <when test="custom.type == 'TEXTAREA' or custom.operator == 'current user'">-->
<!-- and `value`-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="custom"/>-->
<!-- </include>-->
<!-- </when>-->
<!-- <when test="custom.type == 'MULTIPLE_MEMBER' or custom.type == 'CHECKBOX' or custom.type == 'MULTIPLE_SELECT'">-->
<!-- and ${custom.value}-->
<!-- </when>-->
<!-- <when test="custom.type == 'DATE' or custom.type == 'DATETIME'">-->
<!-- and left(replace(unix_timestamp(trim(both '"' from `value`)), '.', ''), 13)-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="custom"/>-->
<!-- </include>-->
<!-- </when>-->
<!-- <otherwise>-->
<!-- and trim(both '"' from `value`)-->
<!-- <include refid="io.metersphere.system.mapper.BaseMapper.condition">-->
<!-- <property name="object" value="custom"/>-->
<!-- </include>-->
<!-- </otherwise>-->
<!-- </choose>-->
<!-- )-->
<!-- </if>-->
<!-- </foreach>-->
<!-- </if>-->
</sql>
<sql id="queryVersionCondition">

View File

@ -11,7 +11,6 @@ import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.system.utils.CustomFieldUtils;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@ -74,7 +73,6 @@ public class ApiDefinitionExportService {
}
if (request.isSelectAll()) {
CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(request.getCondition(), userId);
List<String> ids = extApiDefinitionMapper.getIdsBySort(request, request.getProjectId(), protocols, request.getSortString());
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
ids.removeAll(request.getExcludeIds());

View File

@ -50,7 +50,6 @@ import io.metersphere.system.service.OperationHistoryService;
import io.metersphere.system.service.UserLoginService;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.uid.NumGenerator;
import io.metersphere.system.utils.CustomFieldUtils;
import io.metersphere.system.utils.ServiceUtils;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
@ -143,7 +142,6 @@ public class ApiDefinitionService extends MoveNodeService {
if (CollectionUtils.isEmpty(request.getProtocols())) {
return new ArrayList<>();
}
CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(request, userId);
List<ApiDefinitionDTO> list = extApiDefinitionMapper.list(request);
processApiDefinitions(list);
return list;
@ -153,7 +151,6 @@ public class ApiDefinitionService extends MoveNodeService {
if (CollectionUtils.isEmpty(request.getProtocols())) {
return new ArrayList<>();
}
CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(request, userId);
List<ApiDefinitionDTO> list = extApiDefinitionMapper.list(request);
if (!CollectionUtils.isEmpty(list)) {
processApiDefinitionsDoc(list);
@ -891,7 +888,6 @@ public class ApiDefinitionService extends MoveNodeService {
public <T> List<String> getBatchApiIds(T dto, String projectId, List<String> protocols, boolean deleted, String userId) {
TableBatchProcessDTO request = (TableBatchProcessDTO) dto;
if (request.isSelectAll() && CollectionUtils.isNotEmpty(protocols)) {
CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(request.getCondition(), userId);
List<String> ids = extApiDefinitionMapper.getIds(request, projectId, protocols, deleted);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
ids.removeAll(request.getExcludeIds());

View File

@ -45,7 +45,7 @@ import io.metersphere.system.domain.OperationHistoryExample;
import io.metersphere.system.dto.AddProjectRequest;
import io.metersphere.system.dto.request.OperationHistoryRequest;
import io.metersphere.system.dto.request.OperationHistoryVersionRequest;
import io.metersphere.system.dto.sdk.BaseCondition;
import io.metersphere.sdk.dto.BaseCondition;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.OperationHistoryMapper;

View File

@ -19,7 +19,7 @@ import io.metersphere.system.domain.TestResourcePoolBlob;
import io.metersphere.system.dto.pool.TestResourceDTO;
import io.metersphere.system.dto.pool.TestResourceNodeDTO;
import io.metersphere.system.dto.pool.TestResourcePoolDTO;
import io.metersphere.system.dto.sdk.BaseCondition;
import io.metersphere.sdk.dto.BaseCondition;
import io.metersphere.system.dto.table.TableBatchProcessDTO;
import io.metersphere.system.dto.taskcenter.request.TaskCenterBatchRequest;
import io.metersphere.system.dto.taskcenter.request.TaskCenterPageRequest;

View File

@ -1,7 +1,7 @@
package io.metersphere.api.controller.param;
import io.metersphere.api.constants.ApiDefinitionStatus;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

View File

@ -1,7 +1,7 @@
package io.metersphere.bug.dto.request;
import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.system.dto.sdk.BaseCondition;
import io.metersphere.sdk.dto.BaseCondition;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

View File

@ -1,25 +0,0 @@
package io.metersphere.functional.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* @author wx
*/
@Data
public class AssociationDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "类型",allowableValues = {"EMPTY","NOT_EMPTY"})
private String operatorType;
@Schema(description = "用例类型",allowableValues = {"API","API_SCENARIO","UI_SCENARIO","LOAD"})
private List<String> caseType;
}

View File

@ -12,6 +12,7 @@ import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.request.AssociateOtherCaseRequest;
import io.metersphere.request.TestCasePageProviderRequest;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.interceptor.BaseConditionFilter;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -33,11 +34,12 @@ public interface ExtFunctionalCaseMapper {
List<FunctionalCase> checkCaseByModuleIds(@Param("moduleIds") List<String> deleteIds);
@BaseConditionFilter
List<FunctionalCasePageDTO> list(@Param("request") FunctionalCasePageRequest request, @Param("deleted") boolean deleted, @Param("isRepeat") boolean isRepeat);
void recoverCase(@Param("ids") List<String> ids, @Param("userId") String userId, @Param("time") long time);
@BaseConditionFilter
List<String> getIds(@Param("request") BaseFunctionalCaseBatchDTO request, @Param("projectId") String projectId, @Param("deleted") boolean deleted);
void batchDelete(@Param("ids") List<String> ids, @Param("userId") String userId);
@ -46,6 +48,7 @@ public interface ExtFunctionalCaseMapper {
List<String> getRefIds(@Param("ids") List<String> ids, @Param("deleted") boolean deleted);
@BaseConditionFilter
void batchMoveModule(@Param("request") FunctionalCaseBatchMoveRequest request, @Param("ids") List<String> ids, @Param("userId") String userId);
List<FunctionalCase> getTagsByIds(@Param("ids") List<String> ids);
@ -55,8 +58,10 @@ public interface ExtFunctionalCaseMapper {
void recoverCaseByRefIds(@Param("refIds") List<String> refIds, @Param("userId") String userId, @Param("time") long time);
@BaseConditionFilter
List<ModuleCountDTO> countModuleIdByRequest(@Param("request") FunctionalCasePageRequest request, @Param("deleted") boolean deleted);
@BaseConditionFilter
long caseCount(@Param("request") FunctionalCasePageRequest request, @Param("deleted") boolean deleted);
Long getPrePos(@Param("projectId") String projectId, @Param("basePos") Long basePos);
@ -71,6 +76,7 @@ public interface ExtFunctionalCaseMapper {
* @param sort 排序
* @return 通用的列表Case集合
*/
@BaseConditionFilter
List<TestCaseProviderDTO> listUnRelatedCaseWithBug(@Param("request") TestCasePageProviderRequest request, @Param("deleted") boolean deleted, @Param("sort") String sort);
/**
@ -80,6 +86,7 @@ public interface ExtFunctionalCaseMapper {
* @param deleted 是否删除状态
* @return 关联的用例ID集合
*/
@BaseConditionFilter
List<String> getSelectIdsByAssociateParam(@Param("request") AssociateOtherCaseRequest request, @Param("deleted") boolean deleted);
/**

View File

@ -58,7 +58,7 @@
<select id="getFunctionalCaseByRefId" resultType="io.metersphere.functional.dto.FunctionalCaseVersionDTO">
SELECT
id,
NAME,
name,
version_id,
project_id
FROM
@ -184,16 +184,34 @@
<include refid="filters">
<property name="filter" value="request.filter"/>
</include>
<choose>
<when test='request.searchMode == "AND"'>
AND <include refid="queryCombine"/>
</when>
<when test='request.searchMode == "OR"'>
and (
<include refid="queryCombine"/>
)
</when>
</choose>
<include refid="queryCombine">
<property name="combineSearch" value="request.combineSearch"/>
</include>
<include refid="queryVersionCondition">
<property name="versionTable" value="functional_case"/>
</include>
</sql>
<sql id="queryWhereConditionByBaseQueryRequest">
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and functional_case.module_id in
<foreach collection="request.moduleIds" item="moduleId" separator="," open="(" close=")">
#{moduleId}
</foreach>
</if>
<if test="request.condition.keyword != null and request.condition.keyword != ''">
and (
functional_case.name like concat('%', #{request.condition.keyword},'%')
or functional_case.num like concat('%', #{request.condition.keyword},'%')
or functional_case.tags like concat('%', #{request.condition.keyword},'%')
)
</if>
<include refid="filters">
<property name="filter" value="request.condition.filter"/>
</include>
<include refid="queryCombine">
<property name="combineSearch" value="request.condition.combineSearch"/>
</include>
<include refid="queryVersionCondition">
<property name="versionTable" value="functional_case"/>
</include>
@ -264,127 +282,115 @@
</sql>
<sql id="queryCombine">
<if test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<include refid="queryAssociationCase">
<property name="searchMode" value="request.searchMode"/>
</include>
<include refid="queryAssociationBug">
<property name="searchMode" value="request.searchMode"/>
</include>
1=1
</sql>
<sql id="combine">
<!-- 名称 -->
<if test='${condition}.name != null'>
functional_case.name
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.name"/>
</include>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</if>
<!-- id -->
<if test='${condition}.id != null'>
functional_case.num
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.id"/>
</include>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</if>
<!-- 所属模块 -->
<if test='${condition}.moduleId != null'>
functional_case.moduleId
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.moduleId"/>
</include>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</if>
<!-- 创建人 -->
<if test='${condition}.createUser != null'>
functional_case.create_user
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.createUser"/>
</include>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</if>
<!-- 创建时间 -->
<if test='${condition}.createTime != null'>
functional_case.create_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.createTime"/>
</include>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</if>
<!-- 更新人 -->
<if test='${condition}.updateUser != null'>
functional_case.update_user
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.updateUser"/>
</include>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</if>
<!-- 更新时间 -->
<if test='${condition}.updateTime != null'>
functional_case.update_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.updateTime"/>
</include>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</if>
<!-- 标签 -->
<if test='${condition}.tags != null'>
<include refid="queryTag">
<property name="searchMode" value="${searchMode}"/>
<property name="combineTag" value="${condition}.tags"/>
</include>
</if>
<if test="${condition}.customs != null and ${condition}.customs.size() > 0">
<foreach collection="${condition}.customs" item="custom" separator="" open="" close="">
functional_case.id ${custom.operator} (
select case_id from functional_case_custom_field where field_id = #{custom.id}
<choose>
<when test="custom.type == 'List'">
and JSON_CONTAINS(`value`, json_array(#{custom.value}))
</when>
<when test="custom.type == 'date' or custom.type == 'datetime'">
and `value`
<trim prefix="AND" suffixOverrides="AND|OR">
<if test="${combineSearch} != null">
<foreach collection="${combineSearch}.userViewConditions" item="condition">
<if test="condition.name == 'createUser'">
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="custom"/>
<property name="condition" value="condition"/>
<property name="column" value="functional_case.create_user"/>
</include>
</when>
<otherwise>
and trim(both '"' from `value`)
</if>
<if test="condition.name == 'follower'">
functional_case.id in (
select case_id from functional_case_follower where
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="user_id"/>
</include>
)
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
</foreach>
<foreach collection="${combineSearch}.systemFieldConditions" item="condition">
<if test="condition.name == 'name'">
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="custom"/>
<property name="condition" value="condition"/>
<property name="column" value="functional_case.name"/>
</include>
</otherwise>
</choose>
)
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</foreach>
</if>
</if>
<if test="condition.name == 'num'">
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="functional_case.num"/>
</include>
</if>
<if test="condition.name == 'moduleId'">
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="functional_case.module_id"/>
</include>
</if>
<if test="condition.name == 'createUser'">
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="functional_case.create_User"/>
</include>
</if>
<if test="condition.name == 'updateUser'">
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="functional_case.update_user"/>
</include>
</if>
<if test="condition.name == 'updateTime'">
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="functional_case.update_time"/>
</include>
</if>
<if test="condition.name == 'createTime'">
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="functional_case.create_time"/>
</include>
</if>
<if test="condition.name == 'tags'">
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="functional_case.tags"/>
</include>
</if>
<if test="condition.name == 'reviewStatus'">
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="functional_case.review_status"/>
</include>
</if>
<if test="condition.name == 'demand'">
functional_case.id in (
select case_id from functional_case_demand where
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="demand_name"/>
</include>
)
</if>
<if test="condition.name == 'attachment'">
functional_case.id in (
select case_id from functional_case_attachment where
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="file_name"/>
</include>
)
</if>
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="${combineSearch}.searchMode"/>
</include>
</foreach>
<if test="${combineSearch}.customFiledConditions.size() > 0">
functional_case.id in (
select case_id from functional_case_custom_field where
<include refid="io.metersphere.system.mapper.BaseMapper.customFiledConditions">
<property name="conditions" value="${combineSearch}.customFiledConditions"/>
</include>
)
</if>
</if>
</trim>
</sql>
<sql id="queryVersionCondition">
@ -401,121 +407,6 @@
</choose>
</sql>
<sql id="queryAssociationCase">
<if test="request.associationCase != null">
<choose>
<when test="request.associationCase.operatorType == 'EMPTY'">
functional_case.id not in (
select functional_case.id from functional_case LEFT JOIN functional_case_test on functional_case.id
= functional_case_test.case_id where functional_case_test.source_type in
<foreach collection="request.associationCase.caseType" item="item" open="(" separator="," close=")">
#{item}
</foreach>
and functional_case.project_id=#{request.projectId} and functional_case.deleted = false and
<include refid="queryVersionCondition">
<property name="versionTable" value="functional_case"/>
</include>
)
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</when>
<when test="request.associationCase.operatorType == 'NOT_EMPTY'">
functional_case.id in (
select functional_case.id from functional_case LEFT JOIN functional_case_test on functional_case.id
= functional_case_test.case_id where functional_case_test.source_type in
<foreach collection="request.associationCase.caseType" item="item" open="(" separator="," close=")">
#{item}
</foreach>
and functional_case.project_id=#{request.projectId} and functional_case.deleted = false and
<include refid="queryVersionCondition">
<property name="versionTable" value="functional_case"/>
</include>
)
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</when>
</choose>
</if>
</sql>
<sql id="queryAssociationBug">
<if test="request.associationBug != null">
<choose>
<when test="request.associationBug.operatorType == 'EMPTY'">
functional_case.id not in (
select functional_case.id from functional_case LEFT JOIN bug_relation_case on functional_case.id =
bug_relation_case.case_id where bug_relation_case.case_type = 'functional'
and functional_case.project_id=#{request.projectId} and functional_case.deleted = false and
<include refid="queryVersionCondition">
<property name="versionTable" value="functional_case"/>
</include>
)
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</when>
<when test="request.associationBug.operatorType == 'NOT_EMPTY'">
functional_case.id in (
select functional_case.id from functional_case LEFT JOIN bug_relation_case on functional_case.id =
bug_relation_case.case_id where bug_relation_case.case_type = 'functional'
and functional_case.project_id=#{request.projectId} and functional_case.deleted = false and
<include refid="queryVersionCondition">
<property name="versionTable" value="functional_case"/>
</include>
)
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</when>
</choose>
</if>
</sql>
<sql id="queryType">
<choose>
<when test='${searchMode} == "AND"'>
AND
</when>
<when test='${searchMode} == "OR"'>
OR
</when>
</choose>
</sql>
<sql id="queryTag">
<!-- 不包含 -->
<if test='${combineTag}.value.size() > 0 and ${combineTag}.operator == "not like"'>
(
functional_case.tags is null or functional_case.tags = '[]' or
<foreach collection="${combineTag}.value" item="tag" separator="and" open="(" close=")">
!JSON_CONTAINS(functional_case.tags, JSON_ARRAY(#{tag}))
</foreach>
)
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</if>
<!-- 包含 -->
<if test='${combineTag}.value.size() > 0 and ${combineTag}.operator == "like"'>
<foreach collection="${combineTag}.value" item="tag" separator="or" open="(" close=")">
JSON_CONTAINS(functional_case.tags, JSON_ARRAY(#{tag}))
</foreach>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</if>
<!---->
<if test='${combineTag}.operator == "is null"'>
(functional_case.tags is null or functional_case.tags = '[]')
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
</if>
</sql>
<select id="getIds" resultType="java.lang.String">
SELECT
id
@ -527,48 +418,6 @@
<include refid="queryWhereConditionByBaseQueryRequest"/>
</select>
<sql id="queryWhereConditionByBaseQueryRequest">
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and functional_case.module_id in
<foreach collection="request.moduleIds" item="moduleId" separator="," open="(" close=")">
#{moduleId}
</foreach>
</if>
<if test="request.condition.keyword != null and request.condition.keyword != ''">
and (
functional_case.name like concat('%', #{request.condition.keyword},'%')
or functional_case.num like concat('%', #{request.condition.keyword},'%')
or functional_case.tags like concat('%', #{request.condition.keyword},'%')
)
</if>
<include refid="filters">
<property name="filter" value="request.condition.filter"/>
</include>
<choose>
<when test='request.condition.searchMode == "AND"'>
AND <include refid="baseQueryCombine"/>
</when>
<when test='request.condition.searchMode == "OR"'>
and (
<include refid="baseQueryCombine"/>
)
</when>
</choose>
<include refid="queryVersionCondition">
<property name="versionTable" value="functional_case"/>
</include>
</sql>
<sql id="baseQueryCombine">
<if test="request.condition.combine != null">
<include refid="combine">
<property name="condition" value="request.condition.combine"/>
<property name="searchMode" value="request.condition.searchMode"/>
</include>
</if>
1=1
</sql>
<select id="getRefIds" resultType="java.lang.String">
SELECT
ref_id

View File

@ -1,6 +1,6 @@
package io.metersphere.functional.request;
import io.metersphere.request.BaseProviderCondition;
import io.metersphere.sdk.dto.BaseCondition;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
@ -12,7 +12,7 @@ import java.util.List;
@Data
@EqualsAndHashCode(callSuper = false)
public class AssociatePlanPageRequest extends BaseProviderCondition {
public class AssociatePlanPageRequest extends BaseCondition {
@Schema(description = "功能用例id", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -1,6 +1,5 @@
package io.metersphere.functional.request;
import io.metersphere.functional.dto.AssociationDTO;
import io.metersphere.system.dto.sdk.BasePageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
@ -32,15 +31,6 @@ public class FunctionalCasePageRequest extends BasePageRequest implements Serial
@Schema(description = "模块id")
private List<String> moduleIds;
@Schema(description = "关联用例")
private AssociationDTO associationCase;
@Schema(description = "关联需求")
private AssociationDTO associationDemand;
@Schema(description = "关联缺陷")
private AssociationDTO associationBug;
@Schema(description = "评审id")
private String reviewId;

View File

@ -14,7 +14,7 @@ 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.dto.sdk.BaseCondition;
import io.metersphere.sdk.dto.BaseCondition;
import io.metersphere.system.dto.sdk.BaseTreeNode;
import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.utils.Pager;

View File

@ -32,6 +32,8 @@ import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.domain.CustomField;
import io.metersphere.system.dto.OperationHistoryDTO;
import io.metersphere.system.dto.request.OperationHistoryRequest;
import io.metersphere.sdk.dto.CombineCondition;
import io.metersphere.sdk.dto.CombineSearch;
import io.metersphere.system.dto.sdk.TemplateCustomFieldDTO;
import io.metersphere.system.dto.sdk.TemplateDTO;
import io.metersphere.system.dto.sdk.request.PosRequest;
@ -484,14 +486,14 @@ public class FunctionalCaseControllerTests extends BaseTest {
Assertions.assertNotNull(resultHolder);
//自定义字段 测试
Map<String, Object> map = new HashMap<>();
map.put("customs", Arrays.asList(new LinkedHashMap() {{
put("id", "TEST_FIELD_ID");
put("operator", "in");
put("value", "222");
put("type", "List");
}}));
request.setCombine(map);
CombineSearch combineSearch = new CombineSearch();
CombineCondition condition = new CombineCondition();
condition.setCustomField(true);
condition.setName("TEST_FIELD_ID");
condition.setOperator(CombineCondition.CombineConditionOperator.IN.name());
condition.setValue("222");
combineSearch.setConditions(List.of());
request.setCombineSearch(combineSearch);
MvcResult mvcResultPage = this.requestPostWithOkAndReturn(FUNCTIONAL_CASE_LIST_URL, request);
Pager<List<FunctionalCasePageDTO>> tableData = JSON.parseObject(JSON.toJSONString(
JSON.parseObject(mvcResultPage.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()),

View File

@ -5,7 +5,7 @@ import io.metersphere.project.api.assertion.body.MsDocumentAssertion;
import io.metersphere.project.api.assertion.body.MsJSONPathAssertion;
import io.metersphere.project.api.assertion.body.MsRegexAssertion;
import io.metersphere.project.api.assertion.body.MsXPathAssertion;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.Valid;
import lombok.Data;

View File

@ -1,7 +1,7 @@
package io.metersphere.project.api.assertion;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

View File

@ -1,7 +1,7 @@
package io.metersphere.project.api.assertion;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

View File

@ -1,7 +1,7 @@
package io.metersphere.project.api.assertion;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

View File

@ -1,6 +1,6 @@
package io.metersphere.project.api.assertion.body;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Size;
import lombok.Data;

View File

@ -2,7 +2,7 @@ package io.metersphere.project.api.assertion.body;
import io.metersphere.sdk.constants.MsAssertionCondition;
import io.metersphere.sdk.constants.ValueEnum;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

View File

@ -1,7 +1,7 @@
package io.metersphere.project.api.assertion.body;
import io.metersphere.sdk.constants.MsAssertionCondition;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import org.apache.commons.lang3.BooleanUtils;

View File

@ -1,7 +1,7 @@
package io.metersphere.project.api.assertion.body;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import lombok.Data;
import java.util.List;

View File

@ -3,7 +3,7 @@ package io.metersphere.project.api.processor;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.project.dto.CommonScriptInfo;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

View File

@ -2,7 +2,7 @@ package io.metersphere.project.api.processor.extract;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.constraints.Size;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

View File

@ -1,7 +1,7 @@
package io.metersphere.project.api.processor.extract;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import lombok.Data;
@Data

View File

@ -1,6 +1,6 @@
package io.metersphere.project.api.processor.extract;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.constraints.Size;
import lombok.Data;

View File

@ -1,7 +1,7 @@
package io.metersphere.project.api.processor.extract;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import lombok.Data;
/**

View File

@ -1,7 +1,7 @@
package io.metersphere.project.dto;
import io.metersphere.sdk.constants.FakeErrorType;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.metersphere.validation.groups.Created;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;

View File

@ -1,7 +1,7 @@
package io.metersphere.project.dto.customfunction.request;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.metersphere.validation.groups.Created;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;

View File

@ -1,6 +1,6 @@
package io.metersphere.project.dto.environment.auth;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import lombok.Data;
import java.util.HashMap;

View File

@ -3,7 +3,7 @@ package io.metersphere.project.dto.environment.http;
import io.metersphere.project.api.KeyValueEnableParam;
import io.metersphere.project.dto.environment.auth.HTTPAuthConfig;
import io.metersphere.sdk.constants.ValueEnum;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import lombok.Data;

View File

@ -1,6 +1,6 @@
package io.metersphere.project.dto.environment.http;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

View File

@ -1,9 +1,10 @@
package io.metersphere.system.constants;
import io.metersphere.system.dto.UserViewDTO;
import io.metersphere.system.dto.sdk.CombineCondition;
import io.metersphere.system.dto.sdk.CombineSearch;
import io.metersphere.sdk.dto.CombineCondition;
import io.metersphere.sdk.dto.CombineSearch;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
@ -21,7 +22,7 @@ public enum InternalUserView {
UserViewDTO userViewDTO = getUserViewDTO("my_follow");
CombineCondition condition = new CombineCondition();
condition.setName("follower");
condition.setValue(getCurrentUserValue());
condition.setValue(getCurrentUserArrayValue());
condition.setOperator(CombineCondition.CombineConditionOperator.IN.name());
userViewDTO.setConditions(List.of(condition));
return userViewDTO;
@ -30,7 +31,7 @@ public enum InternalUserView {
UserViewDTO userViewDTO = getUserViewDTO("my_create");
CombineCondition condition = new CombineCondition();
condition.setName("createUser");
condition.setValue(getCurrentUserValue());
condition.setValue(getCurrentUserArrayValue());
condition.setOperator(CombineCondition.CombineConditionOperator.IN.name());
userViewDTO.setConditions(List.of(condition));
return userViewDTO;
@ -39,7 +40,7 @@ public enum InternalUserView {
UserViewDTO userViewDTO = getUserViewDTO("my_review");
CombineCondition condition = new CombineCondition();
condition.setName("reviewUser");
condition.setValue(getCurrentUserValue());
condition.setValue(getCurrentUserArrayValue());
condition.setOperator(CombineCondition.CombineConditionOperator.IN.name());
userViewDTO.setConditions(List.of(condition));
return userViewDTO;
@ -60,8 +61,10 @@ public enum InternalUserView {
userView = initCombineSearchFunc.get();
}
public static String getCurrentUserValue() {
return CURRENT_USER;
public static List<String> getCurrentUserArrayValue() {
List<String> values = new ArrayList<>(0);
values.add(CURRENT_USER);
return values;
}
public UserViewDTO getUserView() {

View File

@ -1,7 +1,7 @@
package io.metersphere.system.dto;
import io.metersphere.system.domain.UserView;
import io.metersphere.system.dto.sdk.CombineCondition;
import io.metersphere.sdk.dto.CombineCondition;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@ -1,6 +1,6 @@
package io.metersphere.system.dto.request;
import io.metersphere.system.dto.sdk.BaseCondition;
import io.metersphere.sdk.dto.BaseCondition;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

View File

@ -1,6 +1,6 @@
package io.metersphere.system.dto.request;
import io.metersphere.system.dto.sdk.BaseCondition;
import io.metersphere.sdk.dto.BaseCondition;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -1,6 +1,6 @@
package io.metersphere.system.dto.request;
import io.metersphere.system.dto.sdk.CombineSearch;
import io.metersphere.sdk.dto.CombineSearch;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

View File

@ -1,6 +1,6 @@
package io.metersphere.system.dto.request;
import io.metersphere.system.dto.sdk.CombineSearch;
import io.metersphere.sdk.dto.CombineSearch;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

View File

@ -1,6 +1,7 @@
package io.metersphere.system.dto.sdk;
import com.google.common.base.CaseFormat;
import io.metersphere.sdk.dto.BaseCondition;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;

View File

@ -0,0 +1,29 @@
package io.metersphere.system.dto.sdk;
import io.metersphere.sdk.dto.CombineCondition;
import io.metersphere.sdk.dto.CombineSearch;
import lombok.Data;
import java.util.List;
/**
* @Author: jianxing
* @CreateTime: 2024-08-28 17:31
* 封装 mapper 查询需要的条件
* 搭配 BaseConditionFilter BaseConditionFilterAspect 使用
*/
@Data
public class DBCombineSearch extends CombineSearch {
/**
* 视图的查询条件
*/
private List<CombineCondition> userViewConditions;
/**
* 系统字段筛选条件
*/
private List<CombineCondition> systemFieldConditions;
/**
* 自定义字段筛选条件
*/
private List<CombineCondition> customFiledConditions;
}

View File

@ -2,7 +2,7 @@ package io.metersphere.system.dto.sdk.request;
import io.metersphere.sdk.constants.CustomFieldType;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -1,7 +1,7 @@
package io.metersphere.system.dto.sdk.request;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

View File

@ -1,7 +1,7 @@
package io.metersphere.system.dto.sdk.request;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -1,7 +1,7 @@
package io.metersphere.system.dto.sdk.request;
import io.metersphere.sdk.constants.UserRoleType;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -1,6 +1,6 @@
package io.metersphere.system.dto.table;
import io.metersphere.system.dto.sdk.BaseCondition;
import io.metersphere.sdk.dto.BaseCondition;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -2,7 +2,7 @@ package io.metersphere.system.dto.taskcenter.request;
import io.metersphere.sdk.constants.TaskCenterResourceType;
import io.metersphere.system.dto.table.TableBatchProcessDTO;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

View File

@ -2,7 +2,7 @@ package io.metersphere.system.dto.taskcenter.request;
import io.metersphere.sdk.constants.TaskCenterResourceType;
import io.metersphere.system.dto.sdk.BasePageRequest;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

View File

@ -2,7 +2,7 @@ package io.metersphere.system.dto.taskcenter.request;
import io.metersphere.system.dto.table.TableBatchProcessDTO;
import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

View File

@ -2,7 +2,7 @@ package io.metersphere.system.dto.taskcenter.request;
import io.metersphere.system.dto.sdk.BasePageRequest;
import io.metersphere.system.dto.taskcenter.enums.ScheduleTagType;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

View File

@ -0,0 +1,15 @@
package io.metersphere.system.interceptor;
import java.lang.annotation.*;
/**
* 标记需要处理 BaseCondition 查询条件
* BaseConditionFilterAspect 处理切面逻辑
* {@link BaseConditionFilterAspect}
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BaseConditionFilter {
}

View File

@ -0,0 +1,112 @@
package io.metersphere.system.interceptor;
import io.metersphere.sdk.dto.BaseCondition;
import io.metersphere.sdk.dto.CombineCondition;
import io.metersphere.sdk.dto.CombineSearch;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.constants.InternalUserView;
import io.metersphere.system.dto.UserViewDTO;
import io.metersphere.system.dto.sdk.*;
import io.metersphere.system.utils.SessionUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.List;
/**
* @Author: jianxing
* @CreateTime: 2024-08-28 17:31
* 拦截高级搜索等查询
* 处理高级搜索等通用查询条件
* 1. 处理视图查询条件
* 2. 预先过滤不合法的查询条件
* 3. 拆分系统字段和自定义字段
* 4. 处理成员选项中的 CURRENT_USER
*/
@Aspect
@Component
public class BaseConditionFilterAspect {
@Pointcut("@annotation(io.metersphere.system.interceptor.BaseConditionFilter)")
public void pointcut() {
}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
if (arg instanceof BaseCondition baseCondition) {
parseBaseCondition(baseCondition);
} else {
try {
// 批量操作
Method getCondition = arg.getClass().getMethod("getCondition");
BaseCondition baseCondition = (BaseCondition) getCondition.invoke(arg);
parseBaseCondition(baseCondition);
} catch (Exception e) {
// do nothing
}
}
}
}
private void parseBaseCondition(BaseCondition baseCondition) {
CombineSearch combineSearch = baseCondition.getCombineSearch();
if (combineSearch == null) {
return;
}
List<CombineCondition> validConditions = getValidConditions(combineSearch.getConditions());
replaceCurrentUser(validConditions);
List<CombineCondition> systemFieldConditions = validConditions.stream().filter(item -> !BooleanUtils.isTrue(item.getCustomField())).toList();
List<CombineCondition> customFieldConditions = validConditions.stream().filter(item -> BooleanUtils.isTrue(item.getCustomField())).toList();
// 拆分系统字段和自定义字段
DBCombineSearch dbCombineSearch = BeanUtils.copyBean(new DBCombineSearch(), combineSearch);
dbCombineSearch.setSystemFieldConditions(systemFieldConditions);
dbCombineSearch.setCustomFiledConditions(customFieldConditions);
baseCondition.setCombineSearch(dbCombineSearch);
// 处理视图查询条件
String viewId = baseCondition.getViewId();
dbCombineSearch.setUserViewConditions(List.of());
for (InternalUserView internalUserView : InternalUserView.values()) {
UserViewDTO userView = internalUserView.getUserView();
if (StringUtils.equals(userView.getId(), viewId)) {
replaceCurrentUser(userView.getConditions());
dbCombineSearch.setUserViewConditions(userView.getConditions());
}
}
}
/**
* 处理成员选项中的 CURRENT_USER
* 替换当前用户的用户ID
* @param validConditions
*/
private void replaceCurrentUser(List<CombineCondition> validConditions) {
for (CombineCondition validCondition : validConditions) {
Object value = validCondition.getValue();
if (value instanceof List arrayValues) {
for (int i = 0; i < arrayValues.size(); i++) {
Object arrayValue = arrayValues.get(i);
if (arrayValue != null && StringUtils.equals(arrayValue.toString(), InternalUserView.CURRENT_USER)) {
// 替换当前用户的用户ID
arrayValues.set(i, SessionUtils.getUserId());
}
}
}
}
}
public List<CombineCondition> getValidConditions(List<CombineCondition> conditions) {
if (CollectionUtils.isEmpty(conditions)) {
return List.of();
}
return conditions.stream().filter(CombineCondition::valid).toList();
}
}

View File

@ -2,7 +2,7 @@ package io.metersphere.system.log.vo;
import io.metersphere.sdk.constants.UserRoleType;
import io.metersphere.system.dto.sdk.BasePageRequest;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;

View File

@ -1,44 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.system.mapper.BaseMapper">
<sql id="customFiledConditions">
<trim suffixOverrides="AND|OR">
<foreach collection="${conditions}" item="condition">
<trim prefix="(" suffix=")">
field_id = #{condition.name}
and
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="condition" value="condition"/>
<property name="column" value="value"/>
</include>
</trim>
<include refid="io.metersphere.system.mapper.BaseMapper.queryType">
<property name="searchMode" value="request.combineSearch.searchMode"/>
</include>
</foreach>
</trim>
</sql>
<sql id="condition">
<trim prefix="(" suffix=")">
<choose>
<when test="${condition}.operator == 'CONTAINS'">
${column} like CONCAT('%', #{condition.value},'%')
</when>
<when test="${condition}.operator == 'NOT_CONTAINS'">
${column} not like CONCAT('%', #{condition.value},'%')
</when>
<when test="${condition}.operator == 'IN'">
${column} in
<foreach collection="${condition}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test="${condition}.operator == 'NOT_IN'">
${column} not in
<foreach collection="${condition}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test="${condition}.operator == 'BETWEEN'">
${column} between #{condition.value[0]} and #{condition.value[1]}
</when>
<when test="${condition}.operator == 'GT'">
${column} &gt; #{condition.value}
</when>
<when test="${condition}.operator == 'LT'">
${column} &lt; #{condition.value}
</when>
<when test="${condition}.operator == 'COUNT_GT'">
JSON_LENGTH(${column}) &gt; #{condition.value}
</when>
<when test="${condition}.operator == 'COUNT_LT'">
JSON_LENGTH(${column}) &lt; #{condition.value}
</when>
<when test="${condition}.operator == 'EMPTY'">
${column} is null or ${column} #{condition.value} = ''
</when>
<when test="${condition}.operator == 'NOT_EMPTY'">
${column} is not null and ${column} #{condition.value} = ''
</when>
<when test="${condition}.operator == 'EQUALS'">
${column} = #{condition.value}
</when>
<when test="${condition}.operator == 'NOT_EQUALS'">
${column} != #{condition.value}
</when>
</choose>
</trim>
</sql>
<sql id="queryType">
<choose>
<when test='${object}.operator == "like"'>
like CONCAT('%', #{${object}.value},'%')
<when test="${searchMode} == 'AND'">
AND
</when>
<when test='${object}.operator == "not like"'>
not like CONCAT('%', #{${object}.value},'%')
<when test="${searchMode} == 'OR'">
OR
</when>
<when test='${object}.operator == "in"'>
in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "not in"'>
not in
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
#{v}
</foreach>
</when>
<when test='${object}.operator == "between"'>
between #{${object}.value[0]} and #{${object}.value[1]}
</when>
<when test='${object}.operator == "gt"'>
&gt; #{${object}.value}
</when>
<when test='${object}.operator == "lt"'>
&lt; #{${object}.value}
</when>
<when test='${object}.operator == "ge"'>
&gt;= #{${object}.value}
</when>
<when test='${object}.operator == "le"'>
&lt;= #{${object}.value}
</when>
<otherwise>
= #{${object}.value}
</otherwise>
</choose>
</sql>

View File

@ -16,7 +16,7 @@ import io.metersphere.system.dto.UserViewDTO;
import io.metersphere.system.dto.UserViewListGroupedDTO;
import io.metersphere.system.dto.request.UserViewAddRequest;
import io.metersphere.system.dto.request.UserViewUpdateRequest;
import io.metersphere.system.dto.sdk.CombineCondition;
import io.metersphere.sdk.dto.CombineCondition;
import io.metersphere.system.mapper.ExtUserViewMapper;
import io.metersphere.system.mapper.UserViewConditionMapper;
import io.metersphere.system.mapper.UserViewMapper;
@ -65,6 +65,8 @@ public class UserViewService {
userViewDTO.setName(translateInternalView(userView.getName()));
userViewDTO.setViewType(viewType.name());
userViewDTO.setUserId(userId);
// 系统内置视图前端不展示查询条件
userViewDTO.setConditions(List.of());
return userViewDTO;
}
}

View File

@ -1,105 +0,0 @@
package io.metersphere.system.utils;
import io.metersphere.sdk.constants.CustomFieldType;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.dto.sdk.BaseCondition;
import lombok.experimental.UtilityClass;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 自定义字段处理工具类
*/
@UtilityClass
public class CustomFieldUtils {
public static final String COMBINE_CUSTOM = "customs";
public static final String COMBINE_CUSTOM_FIELD_TYPE = "type";
public static final String COMBINE_CUSTOM_FIELD_VALUE = "value";
public static final String COMBINE_CUSTOM_FIELD_OPERATOR = "operator";
public static final String IS_CURRENT_USER = "current user";
public static final String CUSTOM_MULTIPLE_PREFIX = "custom_multiple";
/**
* 设置列表查询的多选字段参数
* @param request 请求参数
*/
public static void setBaseQueryRequestCustomMultipleFields(BaseCondition request, String userId) {
handleFilterCustomMultipleFields(request);
handleCombineFields(request, userId);
}
private static void handleFilterCustomMultipleFields(BaseCondition request) {
if (MapUtils.isNotEmpty(request.getFilter())) {
request.getFilter().forEach((key, value) -> {
if (key.startsWith(CUSTOM_MULTIPLE_PREFIX) && CollectionUtils.isNotEmpty(value)) {
List<String> jsonValues = value.stream().map(item -> "[\"".concat(item).concat("\"]")).toList();
request.getFilter().put(key, jsonValues);
}
});
}
}
private static void handleCombineFields(BaseCondition request, String userId) {
Map<String, Object> combine = request.getCombine();
if (MapUtils.isNotEmpty(combine)) {
combine.forEach((k, v) -> {
if (StringUtils.equals(k, COMBINE_CUSTOM) && ObjectUtils.isNotEmpty(v)) {
handleCombineCustomFields((List<Map<String, Object>>) v, userId);
} else {
handleCombineField(v, userId);
}
});
}
}
private static void handleCombineCustomFields(List<Map<String, Object>> customs, String userId) {
customs.forEach(custom -> {
String operator = custom.get(COMBINE_CUSTOM_FIELD_OPERATOR).toString();
if (StringUtils.equalsIgnoreCase(operator, IS_CURRENT_USER)) {
custom.put(COMBINE_CUSTOM_FIELD_VALUE, userId);
return;
}
String fieldType = custom.get(COMBINE_CUSTOM_FIELD_TYPE).toString();
String fieldValue = custom.get(COMBINE_CUSTOM_FIELD_VALUE).toString();
if (StringUtils.equalsAny(fieldType, CustomFieldType.MULTIPLE_MEMBER.name(),
CustomFieldType.CHECKBOX.name(), CustomFieldType.MULTIPLE_SELECT.name()) && StringUtils.isNotEmpty(fieldValue)) {
List<String> customValues = JSON.parseArray(fieldValue, String.class);
List<String> jsonValues = customValues.stream().map(item -> "JSON_CONTAINS(`value`, '[\"".concat(item).concat("\"]')")).toList();
custom.put(COMBINE_CUSTOM_FIELD_VALUE, "(".concat(StringUtils.join(jsonValues, " OR ")).concat(")"));
}
});
}
private static void handleCombineField(Object v, String userId) {
Map<String, Object> combineField = new HashMap<>((Map<String, Object>) v);
if (StringUtils.equalsIgnoreCase(combineField.get(COMBINE_CUSTOM_FIELD_OPERATOR).toString(), IS_CURRENT_USER)) {
combineField.put(COMBINE_CUSTOM_FIELD_VALUE, userId);
}
}
/**
* 多选字段追加值
* @param originalVal 原始值
* @param appendVal 追加值
* @return 追加后的值
*/
public static String appendToMultipleCustomField(String originalVal, String appendVal) {
if (StringUtils.isEmpty(originalVal)) {
return appendVal;
}
List<String> originalList = JSON.parseArray(originalVal, String.class);
List<String> appendList = JSON.parseArray(appendVal, String.class);
originalList.addAll(appendList);
// 追加后需去重
return JSON.toJSONString(originalList.stream().distinct().toList());
}
}

View File

@ -2,7 +2,7 @@ package io.metersphere.system.base.param;
import io.metersphere.sdk.constants.ValueEnum;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

View File

@ -1,7 +1,7 @@
package io.metersphere.system.base.param;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import jakarta.validation.Valid;
import jakarta.validation.constraints.*;
import org.apache.commons.lang3.StringUtils;

View File

@ -1,132 +0,0 @@
package io.metersphere.system.controller;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.dto.sdk.BaseCondition;
import io.metersphere.system.utils.CustomFieldUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
/**
* @author: LAN
* @date: 2023/12/14 10:18
* @version: 1.0
*/
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class CustomFieldTests extends BaseTest {
@Test
@Order(1)
void testSetBaseQueryRequestCustomMultipleFields() {
BaseCondition baseCondition = new BaseCondition();
Map<String, List<String>> filters = new HashMap<>();
filters.put("status", Arrays.asList("Underway", "Completed"));
filters.put("custom_multiple_custom-field", List.of("oasis"));
Map<String, Object> map = new HashMap<>();
map.put("name", Map.of("operator", "like", "value", "test"));
map.put("method", Map.of("operator", "in", "value", Arrays.asList("GET", "POST")));
map.put("createUser", Map.of("operator", "current user", "value", StringUtils.EMPTY));
List<Map<String, Object>> customs = new ArrayList<>();
Map<String, Object> custom = new HashMap<>();
custom.put("id", "test_field");
custom.put("operator", "in");
custom.put("type", "MULTIPLE_SELECT");
custom.put("value", JSON.toJSONString(List.of("test", "default")));
customs.add(custom);
Map<String, Object> currentUserCustom = new HashMap<>();
currentUserCustom.put("id", "test_field");
currentUserCustom.put("operator", "current user");
currentUserCustom.put("type", "MULTIPLE_MEMBER");
currentUserCustom.put("value", "current user");
customs.add(currentUserCustom);
currentUserCustom.put("value", "");
customs.add(currentUserCustom);
map.put("customs", customs);
baseCondition.setFilter(filters);
baseCondition.setCombine(map);
// 调用测试方法
CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(baseCondition, "admin");
// 验证预期结果
Assertions.assertNotNull(baseCondition.getFilter());
Assertions.assertNotNull(baseCondition.getCombine());
// 验证多选字段是否被正确处理
List<String> customMultipleValues = baseCondition.getFilter().get("custom_multiple_custom-field");
Assertions.assertNotNull(customMultipleValues);
Assertions.assertEquals(1, customMultipleValues.size());
Assertions.assertTrue(customMultipleValues.contains("[\"oasis\"]"));
// 验证 CombineField 方法
Map<String, Object> combineField = (Map<String, Object>) baseCondition.getCombine().get("createUser");
Assertions.assertNotNull(combineField);
Assertions.assertEquals(StringUtils.EMPTY, combineField.get("value"));
}
@Test
void testHandleFilterCustomMultipleFieldsEmptyFilter() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 创建测试数据
BaseCondition baseCondition = new BaseCondition();
// 调用被测试方法
CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(baseCondition, "user123");
// 验证预期结果
Assertions.assertNull(baseCondition.getFilter());
}
@Test
void testHandleCombineFieldsEmptyCombine() {
// 创建测试数据
BaseCondition baseCondition = new BaseCondition();
// 调用被测试方法
CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(baseCondition, "user123");
// 验证预期结果
Assertions.assertNull(baseCondition.getCombine());
}
@Test
@Order(2)
void testAppendToMultipleCustomFieldWithEmptyOriginalValue() {
// 创建测试数据originalValue 为空
String originalValue = "";
String appendValue = "[\"value2\",\"value3\"]";
// 调用被测试方法
String resultEmptyOriginal = CustomFieldUtils.appendToMultipleCustomField(originalValue, appendValue);
// 验证预期结果
Assertions.assertNotNull(resultEmptyOriginal);
Assertions.assertEquals("[\"value2\",\"value3\"]", resultEmptyOriginal);
}
@Test
@Order(3)
void testAppendToMultipleCustomField() {
// 创建测试数据
String originalValue = "[\"value1\", \"value2\"]";
String appendValue = "[\"value2\", \"value3\"]";
// 调用被测试方法
String result = CustomFieldUtils.appendToMultipleCustomField(originalValue, appendValue);
// 验证预期结果
Assertions.assertNotNull(result);
Assertions.assertEquals("[\"value1\",\"value2\",\"value3\"]", result);
}
}

View File

@ -10,8 +10,8 @@ import io.metersphere.system.dto.UserViewDTO;
import io.metersphere.system.dto.UserViewListGroupedDTO;
import io.metersphere.system.dto.request.UserViewAddRequest;
import io.metersphere.system.dto.request.UserViewUpdateRequest;
import io.metersphere.system.dto.sdk.CombineCondition;
import io.metersphere.system.dto.sdk.CombineSearch;
import io.metersphere.sdk.dto.CombineCondition;
import io.metersphere.sdk.dto.CombineSearch;
import io.metersphere.system.mapper.UserViewMapper;
import io.metersphere.system.service.UserViewService;
import jakarta.annotation.Resource;
@ -167,6 +167,11 @@ public class UserViewControllerTests extends BaseTest {
Assertions.assertEquals(resultData.getName(), "全部数据");
Assertions.assertEquals(resultData.getId(), InternalUserView.ALL_DATA.name().toLowerCase());
Assertions.assertEquals(resultData.getConditions().size(), 0);
mvcResult = this.requestGetWithOkAndReturn(DEFAULT_GET, InternalUserView.MY_CREATE.name());
resultData = getResultData(mvcResult, UserViewDTO.class);
Assertions.assertEquals(resultData.getId(), InternalUserView.MY_CREATE.name().toLowerCase());
Assertions.assertEquals(resultData.getConditions().size(), 0);
}
@Test

View File

@ -1,7 +1,7 @@
package io.metersphere.system.controller.param;
import io.metersphere.sdk.constants.CustomFieldType;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import jakarta.validation.constraints.NotBlank;

View File

@ -1,7 +1,7 @@
package io.metersphere.system.controller.param;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

View File

@ -1,7 +1,7 @@
package io.metersphere.system.controller.param;
import io.metersphere.sdk.constants.UserRoleType;
import io.metersphere.system.valid.EnumValue;
import io.metersphere.sdk.valid.EnumValue;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import jakarta.validation.constraints.NotBlank;

View File

@ -1,7 +1,7 @@
package io.metersphere.plan.dto;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.system.dto.sdk.BaseCondition;
import io.metersphere.sdk.dto.BaseCondition;
import lombok.Data;
import lombok.NoArgsConstructor;

View File

@ -17,7 +17,7 @@ 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.dto.sdk.BaseCondition;
import io.metersphere.sdk.dto.BaseCondition;
import io.metersphere.system.dto.table.TableBatchProcessDTO;
import io.metersphere.system.dto.taskcenter.request.TaskCenterBatchRequest;
import io.metersphere.system.dto.taskcenter.request.TaskCenterPageRequest;

View File

@ -85,6 +85,7 @@
<commons-jexl3.version>3.3</commons-jexl3.version>
<revision>3.x</revision>
<monitoring-engine.revision>3.1</monitoring-engine.revision>
<swagger-core-jakarta.revision>2.2.20</swagger-core-jakarta.revision>
</properties>