feat(项目管理): 模板与字段相关接口实现

--task=1012795 --user=陈建星 项目管理-模版管理-后台 https://www.tapd.cn/55049933/s/1420871
This commit is contained in:
AgAngle 2023-09-25 18:16:28 +08:00 committed by fit2-zhao
parent 094986e8e1
commit c90772bb05
69 changed files with 3808 additions and 140 deletions

View File

@ -51,6 +51,13 @@ public class CustomField implements Serializable {
@Schema(description = "创建人")
private String createUser;
@Schema(description = "项目字段所关联的组织字段ID")
private String refId;
@Schema(description = "是否需要手动输入选项key", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{custom_field.enable_option_key.not_blank}", groups = {Created.class})
private Boolean enableOptionKey;
@Schema(description = "组织或项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{custom_field.scope_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{custom_field.scope_id.length_range}", groups = {Created.class, Updated.class})
@ -69,6 +76,8 @@ public class CustomField implements Serializable {
createTime("create_time", "createTime", "BIGINT", false),
updateTime("update_time", "updateTime", "BIGINT", false),
createUser("create_user", "createUser", "VARCHAR", false),
refId("ref_id", "refId", "VARCHAR", false),
enableOptionKey("enable_option_key", "enableOptionKey", "BIT", false),
scopeId("scope_id", "scopeId", "VARCHAR", false);
private static final String BEGINNING_DELIMITER = "`";

View File

@ -774,6 +774,136 @@ public class CustomFieldExample {
return (Criteria) this;
}
public Criteria andRefIdIsNull() {
addCriterion("ref_id is null");
return (Criteria) this;
}
public Criteria andRefIdIsNotNull() {
addCriterion("ref_id is not null");
return (Criteria) this;
}
public Criteria andRefIdEqualTo(String value) {
addCriterion("ref_id =", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotEqualTo(String value) {
addCriterion("ref_id <>", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdGreaterThan(String value) {
addCriterion("ref_id >", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdGreaterThanOrEqualTo(String value) {
addCriterion("ref_id >=", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLessThan(String value) {
addCriterion("ref_id <", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLessThanOrEqualTo(String value) {
addCriterion("ref_id <=", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLike(String value) {
addCriterion("ref_id like", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotLike(String value) {
addCriterion("ref_id not like", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdIn(List<String> values) {
addCriterion("ref_id in", values, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotIn(List<String> values) {
addCriterion("ref_id not in", values, "refId");
return (Criteria) this;
}
public Criteria andRefIdBetween(String value1, String value2) {
addCriterion("ref_id between", value1, value2, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotBetween(String value1, String value2) {
addCriterion("ref_id not between", value1, value2, "refId");
return (Criteria) this;
}
public Criteria andEnableOptionKeyIsNull() {
addCriterion("enable_option_key is null");
return (Criteria) this;
}
public Criteria andEnableOptionKeyIsNotNull() {
addCriterion("enable_option_key is not null");
return (Criteria) this;
}
public Criteria andEnableOptionKeyEqualTo(Boolean value) {
addCriterion("enable_option_key =", value, "enableOptionKey");
return (Criteria) this;
}
public Criteria andEnableOptionKeyNotEqualTo(Boolean value) {
addCriterion("enable_option_key <>", value, "enableOptionKey");
return (Criteria) this;
}
public Criteria andEnableOptionKeyGreaterThan(Boolean value) {
addCriterion("enable_option_key >", value, "enableOptionKey");
return (Criteria) this;
}
public Criteria andEnableOptionKeyGreaterThanOrEqualTo(Boolean value) {
addCriterion("enable_option_key >=", value, "enableOptionKey");
return (Criteria) this;
}
public Criteria andEnableOptionKeyLessThan(Boolean value) {
addCriterion("enable_option_key <", value, "enableOptionKey");
return (Criteria) this;
}
public Criteria andEnableOptionKeyLessThanOrEqualTo(Boolean value) {
addCriterion("enable_option_key <=", value, "enableOptionKey");
return (Criteria) this;
}
public Criteria andEnableOptionKeyIn(List<Boolean> values) {
addCriterion("enable_option_key in", values, "enableOptionKey");
return (Criteria) this;
}
public Criteria andEnableOptionKeyNotIn(List<Boolean> values) {
addCriterion("enable_option_key not in", values, "enableOptionKey");
return (Criteria) this;
}
public Criteria andEnableOptionKeyBetween(Boolean value1, Boolean value2) {
addCriterion("enable_option_key between", value1, value2, "enableOptionKey");
return (Criteria) this;
}
public Criteria andEnableOptionKeyNotBetween(Boolean value1, Boolean value2) {
addCriterion("enable_option_key not between", value1, value2, "enableOptionKey");
return (Criteria) this;
}
public Criteria andScopeIdIsNull() {
addCriterion("scope_id is null");
return (Criteria) this;

View File

@ -0,0 +1,100 @@
package io.metersphere.system.domain;
import io.metersphere.validation.groups.*;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import lombok.Data;
@Data
public class OrganizationParameter implements Serializable {
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{organization_parameter.organization_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{organization_parameter.organization_id.length_range}", groups = {Created.class, Updated.class})
private String organizationId;
@Schema(description = "配置项", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{organization_parameter.param_key.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{organization_parameter.param_key.length_range}", groups = {Created.class, Updated.class})
private String paramKey;
@Schema(description = "配置值")
private String paramValue;
private static final long serialVersionUID = 1L;
public enum Column {
organizationId("organization_id", "organizationId", "VARCHAR", false),
paramKey("param_key", "paramKey", "VARCHAR", false),
paramValue("param_value", "paramValue", "VARCHAR", false);
private static final String BEGINNING_DELIMITER = "`";
private static final String ENDING_DELIMITER = "`";
private final String column;
private final boolean isColumnNameDelimited;
private final String javaProperty;
private final String jdbcType;
public String value() {
return this.column;
}
public String getValue() {
return this.column;
}
public String getJavaProperty() {
return this.javaProperty;
}
public String getJdbcType() {
return this.jdbcType;
}
Column(String column, String javaProperty, String jdbcType, boolean isColumnNameDelimited) {
this.column = column;
this.javaProperty = javaProperty;
this.jdbcType = jdbcType;
this.isColumnNameDelimited = isColumnNameDelimited;
}
public String desc() {
return this.getEscapedColumnName() + " DESC";
}
public String asc() {
return this.getEscapedColumnName() + " ASC";
}
public static Column[] excludes(Column ... excludes) {
ArrayList<Column> columns = new ArrayList<>(Arrays.asList(Column.values()));
if (excludes != null && excludes.length > 0) {
columns.removeAll(new ArrayList<>(Arrays.asList(excludes)));
}
return columns.toArray(new Column[]{});
}
public static Column[] all() {
return Column.values();
}
public String getEscapedColumnName() {
if (this.isColumnNameDelimited) {
return new StringBuilder().append(BEGINNING_DELIMITER).append(this.column).append(ENDING_DELIMITER).toString();
} else {
return this.column;
}
}
public String getAliasedEscapedColumnName() {
return this.getEscapedColumnName();
}
}
}

View File

@ -0,0 +1,410 @@
package io.metersphere.system.domain;
import java.util.ArrayList;
import java.util.List;
public class OrganizationParameterExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public OrganizationParameterExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andOrganizationIdIsNull() {
addCriterion("organization_id is null");
return (Criteria) this;
}
public Criteria andOrganizationIdIsNotNull() {
addCriterion("organization_id is not null");
return (Criteria) this;
}
public Criteria andOrganizationIdEqualTo(String value) {
addCriterion("organization_id =", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotEqualTo(String value) {
addCriterion("organization_id <>", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdGreaterThan(String value) {
addCriterion("organization_id >", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdGreaterThanOrEqualTo(String value) {
addCriterion("organization_id >=", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdLessThan(String value) {
addCriterion("organization_id <", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdLessThanOrEqualTo(String value) {
addCriterion("organization_id <=", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdLike(String value) {
addCriterion("organization_id like", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotLike(String value) {
addCriterion("organization_id not like", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdIn(List<String> values) {
addCriterion("organization_id in", values, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotIn(List<String> values) {
addCriterion("organization_id not in", values, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdBetween(String value1, String value2) {
addCriterion("organization_id between", value1, value2, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotBetween(String value1, String value2) {
addCriterion("organization_id not between", value1, value2, "organizationId");
return (Criteria) this;
}
public Criteria andParamKeyIsNull() {
addCriterion("param_key is null");
return (Criteria) this;
}
public Criteria andParamKeyIsNotNull() {
addCriterion("param_key is not null");
return (Criteria) this;
}
public Criteria andParamKeyEqualTo(String value) {
addCriterion("param_key =", value, "paramKey");
return (Criteria) this;
}
public Criteria andParamKeyNotEqualTo(String value) {
addCriterion("param_key <>", value, "paramKey");
return (Criteria) this;
}
public Criteria andParamKeyGreaterThan(String value) {
addCriterion("param_key >", value, "paramKey");
return (Criteria) this;
}
public Criteria andParamKeyGreaterThanOrEqualTo(String value) {
addCriterion("param_key >=", value, "paramKey");
return (Criteria) this;
}
public Criteria andParamKeyLessThan(String value) {
addCriterion("param_key <", value, "paramKey");
return (Criteria) this;
}
public Criteria andParamKeyLessThanOrEqualTo(String value) {
addCriterion("param_key <=", value, "paramKey");
return (Criteria) this;
}
public Criteria andParamKeyLike(String value) {
addCriterion("param_key like", value, "paramKey");
return (Criteria) this;
}
public Criteria andParamKeyNotLike(String value) {
addCriterion("param_key not like", value, "paramKey");
return (Criteria) this;
}
public Criteria andParamKeyIn(List<String> values) {
addCriterion("param_key in", values, "paramKey");
return (Criteria) this;
}
public Criteria andParamKeyNotIn(List<String> values) {
addCriterion("param_key not in", values, "paramKey");
return (Criteria) this;
}
public Criteria andParamKeyBetween(String value1, String value2) {
addCriterion("param_key between", value1, value2, "paramKey");
return (Criteria) this;
}
public Criteria andParamKeyNotBetween(String value1, String value2) {
addCriterion("param_key not between", value1, value2, "paramKey");
return (Criteria) this;
}
public Criteria andParamValueIsNull() {
addCriterion("param_value is null");
return (Criteria) this;
}
public Criteria andParamValueIsNotNull() {
addCriterion("param_value is not null");
return (Criteria) this;
}
public Criteria andParamValueEqualTo(String value) {
addCriterion("param_value =", value, "paramValue");
return (Criteria) this;
}
public Criteria andParamValueNotEqualTo(String value) {
addCriterion("param_value <>", value, "paramValue");
return (Criteria) this;
}
public Criteria andParamValueGreaterThan(String value) {
addCriterion("param_value >", value, "paramValue");
return (Criteria) this;
}
public Criteria andParamValueGreaterThanOrEqualTo(String value) {
addCriterion("param_value >=", value, "paramValue");
return (Criteria) this;
}
public Criteria andParamValueLessThan(String value) {
addCriterion("param_value <", value, "paramValue");
return (Criteria) this;
}
public Criteria andParamValueLessThanOrEqualTo(String value) {
addCriterion("param_value <=", value, "paramValue");
return (Criteria) this;
}
public Criteria andParamValueLike(String value) {
addCriterion("param_value like", value, "paramValue");
return (Criteria) this;
}
public Criteria andParamValueNotLike(String value) {
addCriterion("param_value not like", value, "paramValue");
return (Criteria) this;
}
public Criteria andParamValueIn(List<String> values) {
addCriterion("param_value in", values, "paramValue");
return (Criteria) this;
}
public Criteria andParamValueNotIn(List<String> values) {
addCriterion("param_value not in", values, "paramValue");
return (Criteria) this;
}
public Criteria andParamValueBetween(String value1, String value2) {
addCriterion("param_value between", value1, value2, "paramValue");
return (Criteria) this;
}
public Criteria andParamValueNotBetween(String value1, String value2) {
addCriterion("param_value not between", value1, value2, "paramValue");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -50,6 +50,13 @@ public class Template implements Serializable {
@NotNull(message = "{template.enable_third_part.not_blank}", groups = {Created.class})
private Boolean enableThirdPart;
@Schema(description = "是否是默认模板", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{template.enable_default.not_blank}", groups = {Created.class})
private Boolean enableDefault;
@Schema(description = "项目模板所关联的组织模板ID")
private String refId;
@Schema(description = "使用场景", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{template.scene.not_blank}", groups = {Created.class})
@Size(min = 1, max = 30, message = "{template.scene.length_range}", groups = {Created.class, Updated.class})
@ -68,6 +75,8 @@ public class Template implements Serializable {
scopeType("scope_type", "scopeType", "VARCHAR", false),
scopeId("scope_id", "scopeId", "VARCHAR", false),
enableThirdPart("enable_third_part", "enableThirdPart", "BIT", false),
enableDefault("enable_default", "enableDefault", "BIT", false),
refId("ref_id", "refId", "VARCHAR", false),
scene("scene", "scene", "VARCHAR", false);
private static final String BEGINNING_DELIMITER = "`";

View File

@ -764,6 +764,136 @@ public class TemplateExample {
return (Criteria) this;
}
public Criteria andEnableDefaultIsNull() {
addCriterion("enable_default is null");
return (Criteria) this;
}
public Criteria andEnableDefaultIsNotNull() {
addCriterion("enable_default is not null");
return (Criteria) this;
}
public Criteria andEnableDefaultEqualTo(Boolean value) {
addCriterion("enable_default =", value, "enableDefault");
return (Criteria) this;
}
public Criteria andEnableDefaultNotEqualTo(Boolean value) {
addCriterion("enable_default <>", value, "enableDefault");
return (Criteria) this;
}
public Criteria andEnableDefaultGreaterThan(Boolean value) {
addCriterion("enable_default >", value, "enableDefault");
return (Criteria) this;
}
public Criteria andEnableDefaultGreaterThanOrEqualTo(Boolean value) {
addCriterion("enable_default >=", value, "enableDefault");
return (Criteria) this;
}
public Criteria andEnableDefaultLessThan(Boolean value) {
addCriterion("enable_default <", value, "enableDefault");
return (Criteria) this;
}
public Criteria andEnableDefaultLessThanOrEqualTo(Boolean value) {
addCriterion("enable_default <=", value, "enableDefault");
return (Criteria) this;
}
public Criteria andEnableDefaultIn(List<Boolean> values) {
addCriterion("enable_default in", values, "enableDefault");
return (Criteria) this;
}
public Criteria andEnableDefaultNotIn(List<Boolean> values) {
addCriterion("enable_default not in", values, "enableDefault");
return (Criteria) this;
}
public Criteria andEnableDefaultBetween(Boolean value1, Boolean value2) {
addCriterion("enable_default between", value1, value2, "enableDefault");
return (Criteria) this;
}
public Criteria andEnableDefaultNotBetween(Boolean value1, Boolean value2) {
addCriterion("enable_default not between", value1, value2, "enableDefault");
return (Criteria) this;
}
public Criteria andRefIdIsNull() {
addCriterion("ref_id is null");
return (Criteria) this;
}
public Criteria andRefIdIsNotNull() {
addCriterion("ref_id is not null");
return (Criteria) this;
}
public Criteria andRefIdEqualTo(String value) {
addCriterion("ref_id =", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotEqualTo(String value) {
addCriterion("ref_id <>", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdGreaterThan(String value) {
addCriterion("ref_id >", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdGreaterThanOrEqualTo(String value) {
addCriterion("ref_id >=", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLessThan(String value) {
addCriterion("ref_id <", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLessThanOrEqualTo(String value) {
addCriterion("ref_id <=", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLike(String value) {
addCriterion("ref_id like", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotLike(String value) {
addCriterion("ref_id not like", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdIn(List<String> values) {
addCriterion("ref_id in", values, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotIn(List<String> values) {
addCriterion("ref_id not in", values, "refId");
return (Criteria) this;
}
public Criteria andRefIdBetween(String value1, String value2) {
addCriterion("ref_id between", value1, value2, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotBetween(String value1, String value2) {
addCriterion("ref_id not between", value1, value2, "refId");
return (Criteria) this;
}
public Criteria andSceneIsNull() {
addCriterion("scene is null");
return (Criteria) this;

View File

@ -12,6 +12,8 @@
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
<result column="ref_id" jdbcType="VARCHAR" property="refId" />
<result column="enable_option_key" jdbcType="BIT" property="enableOptionKey" />
<result column="scope_id" jdbcType="VARCHAR" property="scopeId" />
</resultMap>
<sql id="Example_Where_Clause">
@ -74,7 +76,7 @@
</sql>
<sql id="Base_Column_List">
id, `name`, scene, `type`, remark, internal, scope_type, create_time, update_time,
create_user, scope_id
create_user, ref_id, enable_option_key, scope_id
</sql>
<select id="selectByExample" parameterType="io.metersphere.system.domain.CustomFieldExample" resultMap="BaseResultMap">
select
@ -110,11 +112,13 @@
insert into custom_field (id, `name`, scene,
`type`, remark, internal,
scope_type, create_time, update_time,
create_user, scope_id)
create_user, ref_id, enable_option_key,
scope_id)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{scene,jdbcType=VARCHAR},
#{type,jdbcType=VARCHAR}, #{remark,jdbcType=VARCHAR}, #{internal,jdbcType=BIT},
#{scopeType,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{createUser,jdbcType=VARCHAR}, #{scopeId,jdbcType=VARCHAR})
#{createUser,jdbcType=VARCHAR}, #{refId,jdbcType=VARCHAR}, #{enableOptionKey,jdbcType=BIT},
#{scopeId,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.system.domain.CustomField">
insert into custom_field
@ -149,6 +153,12 @@
<if test="createUser != null">
create_user,
</if>
<if test="refId != null">
ref_id,
</if>
<if test="enableOptionKey != null">
enable_option_key,
</if>
<if test="scopeId != null">
scope_id,
</if>
@ -184,6 +194,12 @@
<if test="createUser != null">
#{createUser,jdbcType=VARCHAR},
</if>
<if test="refId != null">
#{refId,jdbcType=VARCHAR},
</if>
<if test="enableOptionKey != null">
#{enableOptionKey,jdbcType=BIT},
</if>
<if test="scopeId != null">
#{scopeId,jdbcType=VARCHAR},
</if>
@ -228,6 +244,12 @@
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
<if test="record.refId != null">
ref_id = #{record.refId,jdbcType=VARCHAR},
</if>
<if test="record.enableOptionKey != null">
enable_option_key = #{record.enableOptionKey,jdbcType=BIT},
</if>
<if test="record.scopeId != null">
scope_id = #{record.scopeId,jdbcType=VARCHAR},
</if>
@ -248,6 +270,8 @@
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
create_user = #{record.createUser,jdbcType=VARCHAR},
ref_id = #{record.refId,jdbcType=VARCHAR},
enable_option_key = #{record.enableOptionKey,jdbcType=BIT},
scope_id = #{record.scopeId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -283,6 +307,12 @@
<if test="createUser != null">
create_user = #{createUser,jdbcType=VARCHAR},
</if>
<if test="refId != null">
ref_id = #{refId,jdbcType=VARCHAR},
</if>
<if test="enableOptionKey != null">
enable_option_key = #{enableOptionKey,jdbcType=BIT},
</if>
<if test="scopeId != null">
scope_id = #{scopeId,jdbcType=VARCHAR},
</if>
@ -300,19 +330,22 @@
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
create_user = #{createUser,jdbcType=VARCHAR},
ref_id = #{refId,jdbcType=VARCHAR},
enable_option_key = #{enableOptionKey,jdbcType=BIT},
scope_id = #{scopeId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into custom_field
(id, `name`, scene, `type`, remark, internal, scope_type, create_time, update_time,
create_user, scope_id)
create_user, ref_id, enable_option_key, scope_id)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR}, #{item.scene,jdbcType=VARCHAR},
#{item.type,jdbcType=VARCHAR}, #{item.remark,jdbcType=VARCHAR}, #{item.internal,jdbcType=BIT},
#{item.scopeType,jdbcType=VARCHAR}, #{item.createTime,jdbcType=BIGINT}, #{item.updateTime,jdbcType=BIGINT},
#{item.createUser,jdbcType=VARCHAR}, #{item.scopeId,jdbcType=VARCHAR})
#{item.createUser,jdbcType=VARCHAR}, #{item.refId,jdbcType=VARCHAR}, #{item.enableOptionKey,jdbcType=BIT},
#{item.scopeId,jdbcType=VARCHAR})
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
@ -355,6 +388,12 @@
<if test="'create_user'.toString() == column.value">
#{item.createUser,jdbcType=VARCHAR}
</if>
<if test="'ref_id'.toString() == column.value">
#{item.refId,jdbcType=VARCHAR}
</if>
<if test="'enable_option_key'.toString() == column.value">
#{item.enableOptionKey,jdbcType=BIT}
</if>
<if test="'scope_id'.toString() == column.value">
#{item.scopeId,jdbcType=VARCHAR}
</if>

View File

@ -0,0 +1,34 @@
package io.metersphere.system.mapper;
import io.metersphere.system.domain.OrganizationParameter;
import io.metersphere.system.domain.OrganizationParameterExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface OrganizationParameterMapper {
long countByExample(OrganizationParameterExample example);
int deleteByExample(OrganizationParameterExample example);
int deleteByPrimaryKey(@Param("organizationId") String organizationId, @Param("paramKey") String paramKey);
int insert(OrganizationParameter record);
int insertSelective(OrganizationParameter record);
List<OrganizationParameter> selectByExample(OrganizationParameterExample example);
OrganizationParameter selectByPrimaryKey(@Param("organizationId") String organizationId, @Param("paramKey") String paramKey);
int updateByExampleSelective(@Param("record") OrganizationParameter record, @Param("example") OrganizationParameterExample example);
int updateByExample(@Param("record") OrganizationParameter record, @Param("example") OrganizationParameterExample example);
int updateByPrimaryKeySelective(OrganizationParameter record);
int updateByPrimaryKey(OrganizationParameter record);
int batchInsert(@Param("list") List<OrganizationParameter> list);
int batchInsertSelective(@Param("list") List<OrganizationParameter> list, @Param("selective") OrganizationParameter.Column ... selective);
}

View File

@ -0,0 +1,213 @@
<?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.OrganizationParameterMapper">
<resultMap id="BaseResultMap" type="io.metersphere.system.domain.OrganizationParameter">
<id column="organization_id" jdbcType="VARCHAR" property="organizationId" />
<id column="param_key" jdbcType="VARCHAR" property="paramKey" />
<result column="param_value" jdbcType="VARCHAR" property="paramValue" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
organization_id, param_key, param_value
</sql>
<select id="selectByExample" parameterType="io.metersphere.system.domain.OrganizationParameterExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from organization_parameter
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="map" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from organization_parameter
where organization_id = #{organizationId,jdbcType=VARCHAR}
and param_key = #{paramKey,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="map">
delete from organization_parameter
where organization_id = #{organizationId,jdbcType=VARCHAR}
and param_key = #{paramKey,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.system.domain.OrganizationParameterExample">
delete from organization_parameter
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.system.domain.OrganizationParameter">
insert into organization_parameter (organization_id, param_key, param_value
)
values (#{organizationId,jdbcType=VARCHAR}, #{paramKey,jdbcType=VARCHAR}, #{paramValue,jdbcType=VARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.system.domain.OrganizationParameter">
insert into organization_parameter
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="organizationId != null">
organization_id,
</if>
<if test="paramKey != null">
param_key,
</if>
<if test="paramValue != null">
param_value,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="organizationId != null">
#{organizationId,jdbcType=VARCHAR},
</if>
<if test="paramKey != null">
#{paramKey,jdbcType=VARCHAR},
</if>
<if test="paramValue != null">
#{paramValue,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.system.domain.OrganizationParameterExample" resultType="java.lang.Long">
select count(*) from organization_parameter
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update organization_parameter
<set>
<if test="record.organizationId != null">
organization_id = #{record.organizationId,jdbcType=VARCHAR},
</if>
<if test="record.paramKey != null">
param_key = #{record.paramKey,jdbcType=VARCHAR},
</if>
<if test="record.paramValue != null">
param_value = #{record.paramValue,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update organization_parameter
set organization_id = #{record.organizationId,jdbcType=VARCHAR},
param_key = #{record.paramKey,jdbcType=VARCHAR},
param_value = #{record.paramValue,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.system.domain.OrganizationParameter">
update organization_parameter
<set>
<if test="paramValue != null">
param_value = #{paramValue,jdbcType=VARCHAR},
</if>
</set>
where organization_id = #{organizationId,jdbcType=VARCHAR}
and param_key = #{paramKey,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.system.domain.OrganizationParameter">
update organization_parameter
set param_value = #{paramValue,jdbcType=VARCHAR}
where organization_id = #{organizationId,jdbcType=VARCHAR}
and param_key = #{paramKey,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into organization_parameter
(organization_id, param_key, param_value)
values
<foreach collection="list" item="item" separator=",">
(#{item.organizationId,jdbcType=VARCHAR}, #{item.paramKey,jdbcType=VARCHAR}, #{item.paramValue,jdbcType=VARCHAR}
)
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
insert into organization_parameter (
<foreach collection="selective" item="column" separator=",">
${column.escapedColumnName}
</foreach>
)
values
<foreach collection="list" item="item" separator=",">
(
<foreach collection="selective" item="column" separator=",">
<if test="'organization_id'.toString() == column.value">
#{item.organizationId,jdbcType=VARCHAR}
</if>
<if test="'param_key'.toString() == column.value">
#{item.paramKey,jdbcType=VARCHAR}
</if>
<if test="'param_value'.toString() == column.value">
#{item.paramValue,jdbcType=VARCHAR}
</if>
</foreach>
)
</foreach>
</insert>
</mapper>

View File

@ -12,6 +12,8 @@
<result column="scope_type" jdbcType="VARCHAR" property="scopeType" />
<result column="scope_id" jdbcType="VARCHAR" property="scopeId" />
<result column="enable_third_part" jdbcType="BIT" property="enableThirdPart" />
<result column="enable_default" jdbcType="BIT" property="enableDefault" />
<result column="ref_id" jdbcType="VARCHAR" property="refId" />
<result column="scene" jdbcType="VARCHAR" property="scene" />
</resultMap>
<sql id="Example_Where_Clause">
@ -74,7 +76,7 @@
</sql>
<sql id="Base_Column_List">
id, `name`, remark, internal, update_time, create_time, create_user, scope_type,
scope_id, enable_third_part, scene
scope_id, enable_third_part, enable_default, ref_id, scene
</sql>
<select id="selectByExample" parameterType="io.metersphere.system.domain.TemplateExample" resultMap="BaseResultMap">
select
@ -110,11 +112,13 @@
insert into template (id, `name`, remark,
internal, update_time, create_time,
create_user, scope_type, scope_id,
enable_third_part, scene)
enable_third_part, enable_default, ref_id,
scene)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{remark,jdbcType=VARCHAR},
#{internal,jdbcType=BIT}, #{updateTime,jdbcType=BIGINT}, #{createTime,jdbcType=BIGINT},
#{createUser,jdbcType=VARCHAR}, #{scopeType,jdbcType=VARCHAR}, #{scopeId,jdbcType=VARCHAR},
#{enableThirdPart,jdbcType=BIT}, #{scene,jdbcType=VARCHAR})
#{enableThirdPart,jdbcType=BIT}, #{enableDefault,jdbcType=BIT}, #{refId,jdbcType=VARCHAR},
#{scene,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.system.domain.Template">
insert into template
@ -149,6 +153,12 @@
<if test="enableThirdPart != null">
enable_third_part,
</if>
<if test="enableDefault != null">
enable_default,
</if>
<if test="refId != null">
ref_id,
</if>
<if test="scene != null">
scene,
</if>
@ -184,6 +194,12 @@
<if test="enableThirdPart != null">
#{enableThirdPart,jdbcType=BIT},
</if>
<if test="enableDefault != null">
#{enableDefault,jdbcType=BIT},
</if>
<if test="refId != null">
#{refId,jdbcType=VARCHAR},
</if>
<if test="scene != null">
#{scene,jdbcType=VARCHAR},
</if>
@ -228,6 +244,12 @@
<if test="record.enableThirdPart != null">
enable_third_part = #{record.enableThirdPart,jdbcType=BIT},
</if>
<if test="record.enableDefault != null">
enable_default = #{record.enableDefault,jdbcType=BIT},
</if>
<if test="record.refId != null">
ref_id = #{record.refId,jdbcType=VARCHAR},
</if>
<if test="record.scene != null">
scene = #{record.scene,jdbcType=VARCHAR},
</if>
@ -248,6 +270,8 @@
scope_type = #{record.scopeType,jdbcType=VARCHAR},
scope_id = #{record.scopeId,jdbcType=VARCHAR},
enable_third_part = #{record.enableThirdPart,jdbcType=BIT},
enable_default = #{record.enableDefault,jdbcType=BIT},
ref_id = #{record.refId,jdbcType=VARCHAR},
scene = #{record.scene,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -283,6 +307,12 @@
<if test="enableThirdPart != null">
enable_third_part = #{enableThirdPart,jdbcType=BIT},
</if>
<if test="enableDefault != null">
enable_default = #{enableDefault,jdbcType=BIT},
</if>
<if test="refId != null">
ref_id = #{refId,jdbcType=VARCHAR},
</if>
<if test="scene != null">
scene = #{scene,jdbcType=VARCHAR},
</if>
@ -300,19 +330,22 @@
scope_type = #{scopeType,jdbcType=VARCHAR},
scope_id = #{scopeId,jdbcType=VARCHAR},
enable_third_part = #{enableThirdPart,jdbcType=BIT},
enable_default = #{enableDefault,jdbcType=BIT},
ref_id = #{refId,jdbcType=VARCHAR},
scene = #{scene,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into template
(id, `name`, remark, internal, update_time, create_time, create_user, scope_type,
scope_id, enable_third_part, scene)
scope_id, enable_third_part, enable_default, ref_id, scene)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR}, #{item.remark,jdbcType=VARCHAR},
#{item.internal,jdbcType=BIT}, #{item.updateTime,jdbcType=BIGINT}, #{item.createTime,jdbcType=BIGINT},
#{item.createUser,jdbcType=VARCHAR}, #{item.scopeType,jdbcType=VARCHAR}, #{item.scopeId,jdbcType=VARCHAR},
#{item.enableThirdPart,jdbcType=BIT}, #{item.scene,jdbcType=VARCHAR})
#{item.enableThirdPart,jdbcType=BIT}, #{item.enableDefault,jdbcType=BIT}, #{item.refId,jdbcType=VARCHAR},
#{item.scene,jdbcType=VARCHAR})
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
@ -355,6 +388,12 @@
<if test="'enable_third_part'.toString() == column.value">
#{item.enableThirdPart,jdbcType=BIT}
</if>
<if test="'enable_default'.toString() == column.value">
#{item.enableDefault,jdbcType=BIT}
</if>
<if test="'ref_id'.toString() == column.value">
#{item.refId,jdbcType=VARCHAR}
</if>
<if test="'scene'.toString() == column.value">
#{item.scene,jdbcType=VARCHAR}
</if>

View File

@ -352,6 +352,8 @@ CREATE TABLE IF NOT EXISTS custom_field(
`create_time` BIGINT NOT NULL COMMENT '创建时间' ,
`update_time` BIGINT NOT NULL COMMENT '更新时间' ,
`create_user` VARCHAR(50) NOT NULL COMMENT '创建人' ,
`ref_id` VARCHAR(50) COMMENT '项目字段所关联的组织字段ID' ,
`enable_option_key` BIT DEFAULT 0 COMMENT '是否需要手动输入选项key' ,
`scope_id` VARCHAR(50) NOT NULL COMMENT '组织或项目ID' ,
PRIMARY KEY (id)
) ENGINE = InnoDB
@ -381,9 +383,11 @@ CREATE TABLE IF NOT EXISTS template(
`scope_type` VARCHAR(50) NOT NULL COMMENT '组织或项目级别字段PROJECT, ORGANIZATION' ,
`scope_id` VARCHAR(50) NOT NULL COMMENT '组织或项目ID' ,
`enable_third_part` BIT NOT NULL DEFAULT 0 COMMENT '是否开启api字段名配置' ,
`enable_default` BIT NOT NULL DEFAULT 0 COMMENT '是否是默认模板' ,
`ref_id` VARCHAR(50) COMMENT '项目模板所关联的组织模板ID' ,
`scene` VARCHAR(30) NOT NULL COMMENT '使用场景' ,
PRIMARY KEY (id)
) ENGINE = InnoDB
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci
COMMENT = '模版';
@ -444,8 +448,15 @@ CREATE TABLE IF NOT EXISTS status_flow(
COLLATE = utf8mb4_general_ci
COMMENT = '状态流转';
-- set innodb lock wait timeout to default
SET SESSION innodb_lock_wait_timeout = DEFAULT;
-- 组织级别参数
CREATE TABLE IF NOT EXISTS organization_parameter(
`organization_id` VARCHAR(50) NOT NULL COMMENT '项目ID' ,
`param_key` VARCHAR(50) NOT NULL COMMENT '配置项' ,
`param_value` VARCHAR(255) COMMENT '配置值' ,
PRIMARY KEY (organization_id,param_key)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '组织参数';
-- 用户邀请记录
CREATE TABLE IF NOT EXISTS user_invite
@ -457,5 +468,10 @@ CREATE TABLE IF NOT EXISTS user_invite
`invite_time` BIGINT NOT NULL COMMENT '邀请时间',
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '用户邀请记录';
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '用户邀请记录';
-- set innodb lock wait timeout to default
SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -136,9 +136,9 @@ INSERT into system_parameter values('base.prometheus.host', 'http://ms-prometheu
INSERT INTO test_resource_pool (id, name, type, description, enable, create_time, update_time, create_user, api_test, load_test, ui_test, all_org, deleted) VALUES (uuid_short(), 'LOCAL', 'Node', '系统初始化资源池', true, 1690440108595, 1690440110182, 'admin', true, true, true, true, false);
INSERT INTO test_resource_pool_blob (id, configuration) VALUES ((select id from test_resource_pool where name = 'LOCAL'), 0x504B03041400080808004F76FC56000000000000000000000000030000007A6970ED58C18EA33810FD1584E618266969B4D272A3136F9A9E8444408F76351921079CC413B09131D989A2FCFB96A1932604D3873DADB63941D5F3F3ABA2EC329CCC94E32424857433BC25A66D9A83ABE989E0BCB6309E9062460B69DADF4F265556898BBD254AC6880040CE05F8CCDF46A3113C659C51C905187E7FA80C316771290461D22BB3358CB0C17EFE31A8A85899A60353F23D619707863312E43826C5C572CF50DB739E843B41707245FEE4EB09D950504039109A38A7DF8828E0C136D658C6BBE1E161C5F69425B6F1CCD72B961189132CB1BD628691E235498BEAD6302424C1A280FB740A511046EEE4AC1C4A9DB23D2F1E23CF992330163989AB413916384D494A8BCC361E9445922C4FB124AF9C37B3A9EB66C69E590DE33A89BAF0A68AF1D81808B97098A4CEBD077C826C08E42F999482B26D10EF4852A670E76E19BF9AD12F12972A6F37630DC3AAB85F794322B296FF1A47405212C3ABEFF043E82AFBE8174829D4EB283A416AB23D39DA973474630C83E744603593E1321DE680D392E8A6A9A76AE7B879499EF3946F8F5F959C7D0955C708A8FA4CF970C70BA9CAA03DE86F42B73B096F7E34BAB8A07225A6B04C9A422C306719861A6C27BAD8B52D56DCB60C61DD592A3F9F6FD1841DEEF8EA620D42C70FA3D09DA3B6E22A47B6B1323F9DDE40E795D9CD33F51DEF65E6F86EF8570F5103A5657A9EA310F9918F960B3F0CA270B174C71A4A58691DE073376F850C964FC847D18B3FD352B6701A361F058B177F8CA040B44C0D8C86E5D1197F45DE249AB941883CE4F7A4AE0DD5E6EF71B10883D077965180FC6F108A56DF1D5217AB13BA8B1E69955FABA77E37D11FAEE7E8925E9134605AAED725A98DA87BC95E473FF9C89944DECBBC47C71B48ABE209394BAD04E5D4D64C15626FC5BC22FA1940E1EC9D25DB42F6BC9D4B8D7A13F4672F6113A8E59B2DA6EF2CD92B4213E3741C39B3A9AEDE600FA9FD37A3A93AA334F60377EE4CD13D6209E780254F690CDBB6BBF1B85C42C781934313588BF809DD98889B3E09079976C7B0DEF6F025B86D431D73466DE5B9E092C73C85021CDFD4CD81A76546E6BC641DCC99322FB1DCD9C650EDE86DD65A67D50B37342545DFF83A1A0B5A56370B38DA24FFB20F6D09535D985882A8C47DB4A33BDE8F76D4D6F7D18E3A747CB4231DE1FFA91DD5BBE87FA377400C120B7909CC2387B7465AABBEFDDE81AF60799C50F85E3B9DEF23EF12F9DE98862473A03EF31BBF31EA5F0109C9537EF4007DB194742A6862DAE64ECADC1E0E0BF85E65B4CCAC5DB9B6BFC0054C5B2A92F1DDEF862F03938BADABFE337CFF71FE07504B07081EC0585CBB03000038110000504B010214001400080808004F76FC561EC0585CBB030000381100000300000000000000000000000000000000007A6970504B0506000000000100010031000000EC0300000000);
-- 初始化内置自定义字段和模板
-- 初始化组织功能用例字段
INSERT INTO custom_field(id, name, scene, `type`, remark, internal, scope_type, create_time, update_time, create_user, scope_id)
VALUES(uuid(), 'functional_priority', 'FUNCTIONAL', 'SELECT', '', 1, 'ORGANIZATION', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', '100001');
VALUES(UUID_SHORT(), 'functional_priority', 'FUNCTIONAL', 'SELECT', '', 1, 'ORGANIZATION', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', '100001');
INSERT INTO custom_field_option (field_id,value,`text`,internal)
VALUES ((select id from custom_field where name = 'functional_priority'), 'P0', 'P0', 1);
INSERT INTO custom_field_option (field_id,value,`text`,internal)
@ -148,14 +148,76 @@ VALUES ((select id from custom_field where name = 'functional_priority'), 'P2',
INSERT INTO custom_field_option (field_id,value,`text`,internal)
VALUES ((select id from custom_field where name = 'functional_priority'), 'P3', 'P3', 1);
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,scene)
VALUES (uuid(), 'functional_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 'FUNCTIONAL');
-- 初始化组织功能用例模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,enable_default, scene)
VALUES (UUID_SHORT(), 'functional_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 1, 'FUNCTIONAL');
INSERT INTO template_custom_field(id, field_id, template_id, required, pos, api_field_id, default_value)
VALUES(uuid(), (select id from custom_field where name = 'functional_priority'), (select id from template where name = 'functional_default'), 1, 0, NULL, NULL);
VALUES(UUID_SHORT(), (select id from custom_field where name = 'functional_priority'), (select id from template where name = 'functional_default'), 1, 0, NULL, NULL);
-- 初始化默认项目版本
INSERT INTO project_version (id, project_id, name, description, status, latest, publish_time, start_time, end_time, create_time, create_user) VALUES (UUID_SHORT(), '100001100001', 'v1.0', NULL, 'open', 0, NULL, NULL, NULL, UNIX_TIMESTAMP() * 1000, 'admin');
-- 初始化项目功能用例字段
INSERT INTO custom_field(id, name, scene, `type`, remark, internal, scope_type, create_time, update_time, create_user, scope_id, ref_id)
VALUES(UUID_SHORT(), 'functional_priority', 'FUNCTIONAL', 'SELECT', '', 1, 'PROJECT', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', '100001100001',
(SELECT id FROM (SELECT * FROM custom_field) t where name = 'functional_priority'));
INSERT INTO custom_field_option (field_id,value,`text`,internal)
VALUES ((select id from custom_field where name = 'functional_priority' and scope_id = '100001100001'), 'P0', 'P0', 1);
INSERT INTO custom_field_option (field_id,value,`text`,internal)
VALUES ((select id from custom_field where name = 'functional_priority' and scope_id = '100001100001'), 'P1', 'P1', 1);
INSERT INTO custom_field_option (field_id,value,`text`,internal)
VALUES ((select id from custom_field where name = 'functional_priority' and scope_id = '100001100001'), 'P2', 'P2', 1);
INSERT INTO custom_field_option (field_id,value,`text`,internal)
VALUES ((select id from custom_field where name = 'functional_priority' and scope_id = '100001100001'), 'P3', 'P3', 1);
-- 初始化项目功能用例模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, enable_default, scene, ref_id)
VALUES (UUID_SHORT(), 'functional_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 1, 'FUNCTIONAL',
(SELECT id FROM (SELECT * FROM template) t where name = 'functional_default'));
INSERT INTO template_custom_field(id, field_id, template_id, required, pos, api_field_id, default_value)
VALUES(
UUID_SHORT(),
(select id from custom_field where name = 'functional_priority' and scope_id = '100001100001'),
(select id from template where name = 'functional_default' and scope_id = '100001100001'),
1, 0, NULL, null
);
-- 初始化组织缺陷模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,enable_default,scene)
VALUES (UUID_SHORT(), 'issue_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 1, 'ISSUE');
-- 初始化项目缺陷模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, enable_default, scene, ref_id)
VALUES (UUID_SHORT(), 'issue_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 1, 'ISSUE',
(SELECT id FROM (SELECT * FROM template) t where name = 'issue_default'));
-- 初始化组织接口模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,enable_default,scene)
VALUES (UUID_SHORT(), 'api_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 1, 'API');
-- 初始化项目接口模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, enable_default, scene, ref_id)
VALUES (UUID_SHORT(), 'api_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 1, 'API',
(SELECT id FROM (SELECT * FROM template) t where name = 'api_default'));
-- 初始化组织UI模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,enable_default,scene)
VALUES (UUID_SHORT(), 'ui_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 1, 'UI');
-- 初始化项目UI模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, enable_default, scene, ref_id)
VALUES (UUID_SHORT(), 'ui_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 1, 'UI',
(SELECT id FROM (SELECT * FROM template) t where name = 'ui_default'));
-- 初始化组织测试计划模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,enable_default,scene)
VALUES (UUID_SHORT(), 'test_plan_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 1, 'TEST_PLAN');
-- 初始化项目测试计划模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, enable_default, scene, ref_id)
VALUES (UUID_SHORT(), 'test_plan_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 1, 'TEST_PLAN',
(SELECT id FROM (SELECT * FROM template) t where name = 'test_plan_default'));
-- 初始化内置消息机器人
SET @robot_in_site_id = UUID_SHORT();
Insert into project_robot(id, project_id, name, platform, webhook, type, app_key, app_secret, enable, create_user, create_time, update_user, update_time, description)

View File

@ -0,0 +1,52 @@
package io.metersphere.sdk.constants;
import io.metersphere.system.domain.CustomFieldOption;
import java.util.Arrays;
import java.util.List;
/**
* 默认的功能性自定义字段
* 方便初始化项目模板
*/
public enum DefaultFunctionalCustomField {
PRIORITY("functional_priority", CustomFieldType.SELECT,
Arrays.asList(
getNewOption("P1", "P1"),
getNewOption("P2", "P2"),
getNewOption("P3", "P3"),
getNewOption("P4", "P4")
)
);
private String name;
private CustomFieldType type;
private List<CustomFieldOption> options;
DefaultFunctionalCustomField(String name, CustomFieldType type, List<CustomFieldOption> options) {
this.name = name;
this.type = type;
this.options = options;
}
public CustomFieldType getType() {
return type;
}
public String getName() {
return name;
}
public List<CustomFieldOption> getOptions() {
return options;
}
private static CustomFieldOption getNewOption(String value, String text) {
CustomFieldOption customFieldOption = new CustomFieldOption();
customFieldOption.setValue(value);
customFieldOption.setText(text);
customFieldOption.setInternal(true);
return customFieldOption;
}
}

View File

@ -0,0 +1,8 @@
package io.metersphere.sdk.constants;
public class OrganizationParameterConstants {
public static final String ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY = "organization.functional.template.enable";
public static final String ORGANIZATION_ISSUE_TEMPLATE_ENABLE_KEY = "organization.issue.template.enable";
public static final String ORGANIZATION_API_TEMPLATE_ENABLE_KEY = "organization.api.template.enable";
public static final String ORGANIZATION_UI_TEMPLATE_ENABLE_KEY = "organization.ui.template.enable";
}

View File

@ -99,6 +99,7 @@ public class PermissionConstants {
public static final String ORGANIZATION_TEMPLATE_ADD = "ORGANIZATION_TEMPLATE:READ+ADD";
public static final String ORGANIZATION_TEMPLATE_UPDATE = "ORGANIZATION_TEMPLATE:READ+UPDATE";
public static final String ORGANIZATION_TEMPLATE_DELETE = "ORGANIZATION_TEMPLATE:READ+DELETE";
public static final String ORGANIZATION_TEMPLATE_ENABLE = "ORGANIZATION_TEMPLATE:READ+ENABLE";
/*------ end: ORGANIZATION_TEMPLATE ------*/
/**
@ -186,8 +187,6 @@ public class PermissionConstants {
public static final String PROJECT_VERSION_READ_DELETE = "PROJECT_VERSION:READ+DELETE";
/*------ end: PROJECT_VERSION ------*/
/**
* 文件模块树
* 查看文件 项目管理-文件管理-查询权限
@ -201,4 +200,18 @@ public class PermissionConstants {
public static final String PROJECT_FILE_MANAGEMENT_READ_UPDATE = "PROJECT_FILE_MANAGEMENT:READ+UPDATE";
public static final String PROJECT_FILE_MANAGEMENT_READ_DOWNLOAD = "PROJECT_FILE_MANAGEMENT:READ+DOWNLOAD";
public static final String PROJECT_FILE_MANAGEMENT_READ_DELETE = "PROJECT_FILE_MANAGEMENT:READ+DELETE";
/*------ start: PROJECT_CUSTOM_FIELD ------*/
public static final String PROJECT_CUSTOM_FIELD_READ = "PROJECT_CUSTOM_FIELD:READ";
public static final String PROJECT_CUSTOM_FIELD_ADD = "PROJECT_CUSTOM_FIELD:READ+ADD";
public static final String PROJECT_CUSTOM_FIELD_UPDATE = "PROJECT_CUSTOM_FIELD:READ+UPDATE";
public static final String PROJECT_CUSTOM_FIELD_DELETE = "PROJECT_CUSTOM_FIELD:READ+DELETE";
/*------ end: PROJECT_CUSTOM_FIELD ------*/
/*------ start: PROJECT_TEMPLATE ------*/
public static final String PROJECT_TEMPLATE_READ = "PROJECT_TEMPLATE:READ";
public static final String PROJECT_TEMPLATE_ADD = "PROJECT_TEMPLATE:READ+ADD";
public static final String PROJECT_TEMPLATE_UPDATE = "PROJECT_TEMPLATE:READ+UPDATE";
public static final String PROJECT_TEMPLATE_DELETE = "PROJECT_TEMPLATE:READ+DELETE";
/*------ end: PROJECT_TEMPLATE ------*/
}

View File

@ -4,5 +4,6 @@ public enum TemplateScene {
FUNCTIONAL,
ISSUE,
API,
UI
UI,
TEST_PLAN
}

View File

@ -1,6 +1,7 @@
package io.metersphere.sdk.dto.request;
import io.metersphere.sdk.constants.CustomFieldType;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.sdk.valid.EnumValue;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
@ -26,7 +27,8 @@ public class CustomFieldUpdateRequest {
@Schema(title = "使用场景", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{custom_field.scene.not_blank}", groups = {Created.class})
@Size(min = 1, max = 30, message = "{custom_field.scene.length_range}", groups = {Created.class, Updated.class})
@EnumValue(enumClass = TemplateScene.class, groups = {Created.class})
@Size(min = 1, max = 30, message = "{custom_field.scene.length_range}", groups = {Created.class})
private String scene;
@Schema(title = "自定义字段类型", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -1,5 +1,7 @@
package io.metersphere.sdk.dto.request;
import io.metersphere.sdk.constants.TemplateScene;
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;
@ -35,7 +37,8 @@ public class TemplateUpdateRequest {
@Schema(title = "使用场景", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{template.scene.not_blank}", groups = {Created.class})
@Size(min = 1, max = 30, message = "{template.scene.length_range}", groups = {Created.class, Updated.class})
@EnumValue(enumClass = TemplateScene.class, groups = {Created.class})
@Size(min = 1, max = 30, message = "{template.scene.length_range}", groups = {Created.class})
private String scene;
@Valid

View File

@ -0,0 +1,26 @@
package io.metersphere.sdk.util;
import java.util.List;
import java.util.function.Consumer;
public class SubListUtil {
/**
* 将较长的数组截断成较短的数组进行批处理
*/
public static void dealForSubList(List totalList, Integer batchSize, Consumer<List> subFunc) {
int count = totalList.size();
int iteratorCount = count / batchSize;
for (int i = 0; i <= iteratorCount; i++) {
int endIndex, startIndex;
startIndex = i * batchSize;
endIndex = ((endIndex = (i + 1) * batchSize) > count) ? count : endIndex;
if (endIndex == startIndex) {
break;
}
List subList = totalList.subList(startIndex, endIndex);
subFunc.accept(subList);
}
}
}

View File

@ -405,6 +405,7 @@ user_role_relation_remove_admin_user_permission_error=无法将 admin 用户将
# customField
internal_custom_field_permission_error=系统字段或模板无法删除!
internal_template_permission_error=系统模板无法删除!
default_template_permission_error=默认模板无法删除!
#result message
http_result_success=操作成功
@ -445,7 +446,11 @@ template_scene_illegal_error=使用场景不合法
# 内置的模板或字段
custom_field.functional_priority=优先级
template.functional_default=默认模板
parent.node.not_blank=父节点不能为空
node.not_blank=节点不能为空
node.name.repeat=节点名称重复
project.cannot.match.parent=和父节点的项目无法匹配
project.cannot.match.parent=和父节点的项目无法匹配
set_default_template=设置默认模板

View File

@ -408,6 +408,7 @@ user_role_relation_remove_admin_user_permission_error=Unable to delete the admin
# customField
internal_custom_field_permission_error=System fields cannot be deleted
internal_template_permission_error=System template cannot be deleted
default_template_permission_error=Default templates cannot be deleted
#result message
http_result_success=operate success
@ -449,6 +450,8 @@ template_scene_illegal_error=Scene is illegal
custom_field.functional_priority=Priority
template.functional_default=Default
set_default_template=Set the default template
global_parameters_already_exist=Global parameters already exist
global_parameters_is_not_exist=Global parameters is not exist
api_test_environment_not_exist=Environment is not exist

View File

@ -405,6 +405,7 @@ user_role_relation_remove_admin_user_permission_error=无法将 admin 用户将
# customField
internal_custom_field_permission_error=系统字段或模板无法删除!
internal_template_permission_error=系统模板无法删除!
default_template_permission_error=默认模板无法删除!
#result message
http_result_success=操作成功
@ -447,6 +448,8 @@ template_scene_illegal_error=使用场景不合法
custom_field.functional_priority=优先级
template.functional_default=默认模板
set_default_template=设置默认模板
global_parameters_already_exist=全局参数已存在
global_parameters_is_not_exist=全局参数不存在
parent.node.not_blank=父节点不能为空

View File

@ -404,6 +404,7 @@ user_role_relation_remove_admin_user_permission_error=無法將 admin 用戶將
# customField
internal_custom_field_permission_error=系統字段或模板無法刪除!
internal_template_permission_error=系統模板無法刪除!
default_template_permission_error=默认模板无法删除!
#result message
http_result_success=操作成功
@ -446,6 +447,8 @@ template_scene_illegal_error=使用場景不合法
custom_field.functional_priority=優先級
template.functional_default=默認模板
set_default_template=設置默認模板
global_parameters_already_exist=全局參數已存在
global_parameters_is_not_exist=全局參數不存在

View File

@ -114,6 +114,7 @@ permission.project_application_ui.read=UI测试-查询
permission.project_application_ui.update=UI测试-编辑
permission.project_base_info.name=基本信息
permission.project_log.name=日志
# message
message.test_plan_task=测试计划
message.schedule_task=定时任务
@ -256,6 +257,7 @@ message.title.load_test_task_execute_completed=性能用例执行完成通知
message.title.load_report_task_delete=性能报告删除通知
message.title.jenkins_task_execute_successful=Jenkins任务执行成功通知
message.title.jenkins_task_execute_failed=Jenkins任务执行失败通知
#file management
file_module.not.exist=文件模块不存在
upload.file.error=上传文件失败
@ -270,4 +272,8 @@ file.log.previous=之前
file.log.upload=上传
file.log.re-upload=重新上传
file.name.cannot.be.empty=文件名称不能为空
#file management over
#file management over
# template
project_template_permission_error=未开启项目模板

View File

@ -307,4 +307,7 @@ file.log.previous=behind
file.log.upload=upload
file.log.re-upload=re-upload
file.name.cannot.be.empty=File name cannot be empty
#file management over
#file management over
# template
project_template_permission_error=The project template is not turned on

View File

@ -306,4 +306,6 @@ file.log.previous=之前
file.log.upload=上传
file.log.re-upload=重新上传
file.name.cannot.be.empty=文件名称不能为空
#file management over
#file management over
# template
project_template_permission_error=未开启项目模板

View File

@ -148,6 +148,7 @@ environment_datasource.driverId.not_blank=驅動ID不能為空
environment_datasource.dbUrl.not_blank=數據庫地址不能為空
environment_name_is_null=環境名稱不能為空
environment_config_is_null=環境配置不能為空
# message
message.test_plan_task=測試計劃
message.schedule_task=定時任務
@ -306,4 +307,8 @@ file.log.previous=之前
file.log.upload=上傳
file.log.re-upload=重新上傳
file.name.cannot.be.empty=文件名稱不能為空
#file management over
#file management over
# template
project_template_permission_error=未開啟項目模板

View File

@ -167,6 +167,7 @@ user_role_not_exist=用户组不存在
user_role_not_edit=用户组无法编辑
at_least_one_user_role_require=至少需要一个用户组
default_organization_not_allow_delete=默认组织无法删除
organization_template_permission_error=未开启组织模板
# plugin
plugin.id.not_blank=ID不能为空
plugin.id.length_range=ID长度必须在{min}和{max}之间
@ -222,6 +223,7 @@ permission.system_operation_log.name=日志
permission.organization_operation_log.name=日志
permission.organization_custom_field.name=自定义字段
permission.organization_template.name=模板
permission.system_organization_template.enable=启用项目模板
# message
user.remove=已被移除
alert_others=通知人

View File

@ -169,6 +169,7 @@ user_role_not_exist=User role not exist
user_role_not_edit=User role can not edit
at_least_one_user_role_require=At least one user role require
default_organization_not_allow_delete=Default organization not allow delete
organization_template_permission_error=The organization template is not turned on
# plugin
plugin.id.not_blank=id cannot be empty
plugin.id.length_range=id length must be between {min} and {max}
@ -224,6 +225,7 @@ permission.system_operation_log.name=Operation log
permission.organization_operation_log.name=Operation log
permission.organization_custom_field.name=Custom Field
permission.organization_template.name=Template
permission.system_organization_template.enable=Enable project templates
# message
user.remove=has been removed
alert_others=Alert others

View File

@ -168,6 +168,7 @@ user_role_not_exist=用户组不存在
user_role_not_edit=用户组无法编辑
at_least_one_user_role_require=至少需要一个用户组
default_organization_not_allow_delete=默认组织无法删除
organization_template_permission_error=未开启组织模板
# plugin
plugin.id.not_blank=ID不能为空
plugin.id.length_range=ID长度必须在{min}和{max}之间
@ -223,6 +224,7 @@ permission.system_operation_log.name=日志
permission.organization_operation_log.name=日志
permission.organization_custom_field.name=自定义字段
permission.organization_template.name=模板
permission.system_organization_template.enable=启用项目模板
# message
user.remove=已被移除
alert_others=通知人

View File

@ -168,6 +168,7 @@ user_role_not_exist=用戶組不存在
user_role_not_edit=用戶組無法編輯
at_least_one_user_role_require=至少需要一個用戶組
default_organization_not_allow_delete=默認組織無法刪除
organization_template_permission_error=未開啟組織模板
# plugin
plugin.id.not_blank=ID不能為空
plugin.id.length_range=ID長度必須在{min}和{max}之间
@ -223,6 +224,7 @@ permission.system_operation_log.name=日志
permission.organization_operation_log.name=日志
permission.organization_custom_field.name=自定義字段
permission.organization_template.name=模板
permission.system_organization_template.enable=啟用項目模板
# message
user.remove=已被移除
alert_others=通知人

View File

@ -0,0 +1,82 @@
package io.metersphere.project.controller;
import io.metersphere.project.service.ProjectCustomFieldLogService;
import io.metersphere.project.service.ProjectCustomFieldService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.CustomFieldDTO;
import io.metersphere.sdk.dto.request.CustomFieldUpdateRequest;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.domain.CustomField;
import io.metersphere.system.log.annotation.Log;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.utils.SessionUtils;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author jianxing
*/
@Tag(name = "系统设置-项目-自定义字段")
@RestController
@RequestMapping("/project/custom/field")
public class ProjectCustomFieldController {
@Resource
private ProjectCustomFieldService projectCustomFieldService;
@GetMapping("/list/{projectId}/{scene}")
@Operation(summary = "获取自定义字段列表")
@RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FIELD_READ)
public List<CustomField> list(@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@PathVariable String projectId,
@Schema(description = "模板的使用场景FUNCTIONAL,ISSUE,API,UI", requiredMode = Schema.RequiredMode.REQUIRED)
@PathVariable String scene) {
return projectCustomFieldService.list(projectId, scene);
}
@GetMapping("/get/{id}")
@Operation(summary = "获取自定义字段详情")
@RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FIELD_READ)
public CustomFieldDTO get(@PathVariable String id) {
return projectCustomFieldService.getCustomFieldDTOWithCheck(id);
}
@PostMapping("/add")
@Operation(summary = "创建自定义字段")
@RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FIELD_ADD)
@Log(type = OperationLogType.ADD, expression = "#msClass.addLog(#request)", msClass = ProjectCustomFieldLogService.class)
public CustomField add(@Validated({Created.class}) @RequestBody CustomFieldUpdateRequest request) {
CustomField customField = new CustomField();
BeanUtils.copyBean(customField, request);
customField.setCreateUser(SessionUtils.getUserId());
return projectCustomFieldService.add(customField, request.getOptions());
}
@PostMapping("/update")
@Operation(summary = "更新自定义字段")
@RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FIELD_UPDATE)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateLog(#request)", msClass = ProjectCustomFieldLogService.class)
public CustomField update(@Validated({Updated.class}) @RequestBody CustomFieldUpdateRequest request) {
CustomField customField = new CustomField();
BeanUtils.copyBean(customField, request);
return projectCustomFieldService.update(customField, request.getOptions());
}
@GetMapping("/delete/{id}")
@Operation(summary = "删除自定义字段")
@RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FIELD_DELETE)
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = ProjectCustomFieldLogService.class)
public void delete(@PathVariable String id) {
projectCustomFieldService.delete(id);
}
}

View File

@ -0,0 +1,90 @@
package io.metersphere.project.controller;
import io.metersphere.project.service.ProjectTemplateLogService;
import io.metersphere.project.service.ProjectTemplateService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.TemplateDTO;
import io.metersphere.sdk.dto.request.TemplateUpdateRequest;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.domain.Template;
import io.metersphere.system.log.annotation.Log;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.utils.SessionUtils;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author : jianxing
* @date : 2023-8-30
*/
@RestController
@RequestMapping("/project/template")
@Tag(name = "系统设置-组织-模版")
public class ProjectTemplateController {
@Resource
private ProjectTemplateService projectTemplateservice;
@GetMapping("/list/{projectId}/{scene}")
@Operation(summary = "获取模版列表")
@RequiresPermissions(PermissionConstants.PROJECT_TEMPLATE_READ)
public List<Template> list(@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@PathVariable String projectId,
@Schema(description = "模板的使用场景FUNCTIONAL,ISSUE,API,UI", requiredMode = Schema.RequiredMode.REQUIRED)
@PathVariable String scene) {
return projectTemplateservice.list(projectId, scene);
}
@GetMapping("/get/{id}")
@Operation(summary = "获取模版详情")
@RequiresPermissions(PermissionConstants.PROJECT_TEMPLATE_READ)
public TemplateDTO get(@PathVariable String id) {
return projectTemplateservice.geDTOWithCheck(id);
}
@PostMapping("/add")
@Operation(summary = "创建模版")
@RequiresPermissions(PermissionConstants.PROJECT_TEMPLATE_ADD)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.addLog(#request)", msClass = ProjectTemplateLogService.class)
public Template add(@Validated({Created.class}) @RequestBody TemplateUpdateRequest request) {
Template template = new Template();
BeanUtils.copyBean(template, request);
template.setCreateUser(SessionUtils.getUserId());
return projectTemplateservice.add(template, request.getCustomFields());
}
@PostMapping("/update")
@Operation(summary = "更新模版")
@RequiresPermissions(PermissionConstants.PROJECT_TEMPLATE_UPDATE)
@Log(type = OperationLogType.ADD, expression = "#msClass.updateLog(#request)", msClass = ProjectTemplateLogService.class)
public Template update(@Validated({Updated.class}) @RequestBody TemplateUpdateRequest request) {
Template template = new Template();
BeanUtils.copyBean(template, request);
return projectTemplateservice.update(template, request.getCustomFields());
}
@GetMapping("/delete/{id}")
@Operation(summary = "删除模版")
@RequiresPermissions(PermissionConstants.PROJECT_TEMPLATE_DELETE)
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = ProjectTemplateLogService.class)
public void delete(@PathVariable String id) {
projectTemplateservice.delete(id);
}
@GetMapping("/set-default/{id}")
@Operation(summary = "设置模板模板")
@RequiresPermissions(PermissionConstants.ORGANIZATION_TEMPLATE_UPDATE)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.setDefaultTemplateLog(#id)", msClass = ProjectTemplateLogService.class)
public void setDefaultTemplate(@PathVariable String id) {
projectTemplateservice.setDefaultTemplate(id);
}
}

View File

@ -10,7 +10,11 @@ public enum ProjectResultCode implements IResultCode {
/**
* 项目管理-消息设置-保存消息设置-所选用户不在当前系统中会返回
*/
SAVE_MESSAGE_TASK_USER_NO_EXIST(102001, "save_message_task_user_no_exist");
SAVE_MESSAGE_TASK_USER_NO_EXIST(102001, "save_message_task_user_no_exist"),
/**
* 开启组织模板操作项目模板时会返回
*/
PROJECT_TEMPLATE_PERMISSION(102002, "project_template_permission_error");
private final int code;
private final String message;

View File

@ -0,0 +1,64 @@
package io.metersphere.project.service;
import io.metersphere.sdk.dto.LogDTO;
import io.metersphere.sdk.dto.request.CustomFieldUpdateRequest;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.domain.CustomField;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author jianxing
* @date : 2023-8-29
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class ProjectCustomFieldLogService {
@Resource
private ProjectCustomFieldService projectCustomFieldService;
public LogDTO addLog(CustomFieldUpdateRequest request) {
LogDTO dto = new LogDTO(
null,
null,
null,
null,
OperationLogType.ADD.name(),
OperationLogModule.PROJECT_CUSTOM_FIELD,
request.getName());
dto.setOriginalValue(JSON.toJSONBytes(request));
return dto;
}
public LogDTO updateLog(CustomFieldUpdateRequest request) {
CustomField customField = projectCustomFieldService.getWithCheck(request.getId());
LogDTO dto = new LogDTO(
null,
null,
customField.getId(),
null,
OperationLogType.UPDATE.name(),
OperationLogModule.PROJECT_CUSTOM_FIELD,
customField.getName());
dto.setOriginalValue(JSON.toJSONBytes(customField));
return dto;
}
public LogDTO deleteLog(String id) {
CustomField customField = projectCustomFieldService.getWithCheck(id);
LogDTO dto = new LogDTO(
null,
null,
customField.getId(),
null,
OperationLogType.DELETE.name(),
OperationLogModule.PROJECT_CUSTOM_FIELD,
customField.getName());
dto.setOriginalValue(JSON.toJSONBytes(customField));
return dto;
}
}

View File

@ -0,0 +1,73 @@
package io.metersphere.project.service;
import io.metersphere.project.domain.Project;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.sdk.dto.CustomFieldDTO;
import io.metersphere.sdk.dto.request.CustomFieldOptionRequest;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.system.domain.CustomField;
import io.metersphere.system.service.BaseCustomFieldService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import static io.metersphere.project.enums.result.ProjectResultCode.PROJECT_TEMPLATE_PERMISSION;
/**
* @author jianxing
* @date : 2023-8-29
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class ProjectCustomFieldService extends BaseCustomFieldService {
@Resource
private ProjectService projectService;
@Override
public List<CustomField> list(String projectId, String scene) {
projectService.checkResourceExist(projectId);
return super.list(projectId, scene);
}
@Override
public CustomFieldDTO getCustomFieldDTOWithCheck(String id) {
CustomFieldDTO customField = super.getCustomFieldDTOWithCheck(id);
projectService.checkResourceExist(customField.getScopeId());
return customField;
}
@Override
public CustomField add(CustomField customField, List<CustomFieldOptionRequest> options) {
Project project = projectService.checkResourceExist(customField.getScopeId());
checkProjectTemplateEnable(project.getOrganizationId(), customField.getScene());
customField.setScopeType(TemplateScopeType.PROJECT.name());
return super.add(customField, options);
}
@Override
public CustomField update(CustomField customField, List<CustomFieldOptionRequest> options) {
CustomField originCustomField = getWithCheck(customField.getId());
customField.setScopeId(originCustomField.getScopeId());
Project project = projectService.checkResourceExist(originCustomField.getScopeId());
checkProjectTemplateEnable(project.getOrganizationId(), originCustomField.getScene());
return super.update(customField, options);
}
@Override
public void delete(String id) {
CustomField customField = getWithCheck(id);
checkInternal(customField);
Project project = projectService.checkResourceExist(customField.getScopeId());
checkProjectTemplateEnable(project.getOrganizationId(), customField.getScene());
super.delete(id);
}
private void checkProjectTemplateEnable(String orgId, String scene) {
if (isOrganizationTemplateEnable(orgId, scene)) {
throw new MSException(PROJECT_TEMPLATE_PERMISSION);
}
}
}

View File

@ -15,6 +15,7 @@ import io.metersphere.sdk.dto.SessionUser;
import io.metersphere.sdk.dto.UserDTO;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.*;
@ -26,6 +27,7 @@ import io.metersphere.system.mapper.TestResourcePoolOrganizationMapper;
import io.metersphere.system.mapper.UserRoleRelationMapper;
import io.metersphere.system.service.BaseUserService;
import io.metersphere.system.service.CommonProjectService;
import io.metersphere.system.utils.ServiceUtils;
import io.metersphere.system.utils.SessionUtils;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
@ -188,4 +190,8 @@ public class ProjectService {
new OptionDTO(testResourcePool.getId(), testResourcePool.getName())
).toList();
}
public static Project checkResourceExist(String id) {
return ServiceUtils.checkResourceExist(CommonBeanFactory.getBean(ProjectMapper.class).selectByPrimaryKey(id), "permission.project.name");
}
}

View File

@ -0,0 +1,85 @@
package io.metersphere.project.service;
import io.metersphere.sdk.dto.LogDTO;
import io.metersphere.sdk.dto.request.TemplateUpdateRequest;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.Template;
import io.metersphere.system.log.constants.OperationLogType;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import io.metersphere.system.log.constants.OperationLogModule;
/**
* @author jianxing
* @date : 2023-8-30
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class ProjectTemplateLogService {
@Resource
private ProjectTemplateService projectTemplateService;
public LogDTO addLog(TemplateUpdateRequest request) {
LogDTO dto = new LogDTO(
null,
null,
null,
null,
OperationLogType.ADD.name(),
OperationLogModule.PROJECT_TEMPLATE,
request.getName());
dto.setOriginalValue(JSON.toJSONBytes(request));
return dto;
}
public LogDTO updateLog(TemplateUpdateRequest request) {
Template template = projectTemplateService.getWithCheck(request.getId());
LogDTO dto = null;
if (template != null) {
dto = new LogDTO(
null,
null,
template.getId(),
null,
OperationLogType.UPDATE.name(),
OperationLogModule.PROJECT_TEMPLATE,
template.getName());
dto.setOriginalValue(JSON.toJSONBytes(template));
}
return dto;
}
public LogDTO setDefaultTemplateLog(TemplateUpdateRequest request) {
Template template = projectTemplateService.getWithCheck(request.getId());
LogDTO dto = null;
if (template != null) {
dto = new LogDTO(
null,
null,
template.getId(),
null,
String.join(Translator.get("set_default_template"), ":", OperationLogType.UPDATE.name()),
OperationLogModule.PROJECT_TEMPLATE,
template.getName());
dto.setOriginalValue(JSON.toJSONBytes(template));
}
return dto;
}
public LogDTO deleteLog(String id) {
Template template = projectTemplateService.getWithCheck(id);
LogDTO dto = new LogDTO(
null,
null,
template.getId(),
null,
OperationLogType.DELETE.name(),
OperationLogModule.PROJECT_TEMPLATE,
template.getName());
dto.setOriginalValue(JSON.toJSONBytes(template));
return dto;
}
}

View File

@ -0,0 +1,90 @@
package io.metersphere.project.service;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.sdk.dto.TemplateDTO;
import io.metersphere.sdk.dto.request.TemplateCustomFieldRequest;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.system.domain.Template;
import io.metersphere.system.dto.ProjectDTO;
import io.metersphere.system.service.BaseTemplateService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import static io.metersphere.project.enums.result.ProjectResultCode.PROJECT_TEMPLATE_PERMISSION;
/**
* @author jianxing
* @date : 2023-8-30
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class ProjectTemplateService extends BaseTemplateService {
@Resource
private ProjectService projectService;
@Override
public List<Template> list(String projectId, String scene) {
projectService.checkResourceExist(projectId);
return super.list(projectId, scene);
}
public TemplateDTO geDTOWithCheck(String id) {
Template template = super.getWithCheck(id);
checkProjectResourceExist(template);
return super.geDTOWithCheck(template);
}
@Override
public Template add(Template template, List<TemplateCustomFieldRequest> customFields) {
checkProjectResourceExist(template);
checkProjectTemplateEnable(template.getScopeId(), template.getScene());
template.setScopeType(TemplateScopeType.PROJECT.name());
template.setRefId(null);
return super.add(template, customFields);
}
public void checkProjectResourceExist(Template template) {
projectService.checkResourceExist(template.getScopeId());
}
@Override
public Template update(Template template, List<TemplateCustomFieldRequest> customFields) {
Template originTemplate = super.getWithCheck(template.getId());
checkProjectTemplateEnable(originTemplate.getScopeId(), originTemplate.getScene());
template.setScopeId(originTemplate.getScopeId());
checkProjectResourceExist(originTemplate);
return super.update(template, customFields);
}
@Override
public void delete(String id) {
Template template = getWithCheck(id);
checkProjectTemplateEnable(template.getScopeId(), template.getScene());
super.delete(id);
}
/**
* 将模板设置成默认模板
* 同时将其他没模板设置成非默认模板
*
* @param id
*/
@Override
public void setDefaultTemplate(String id) {
Template template = getWithCheck(id);
checkProjectTemplateEnable(template.getScopeId(), template.getScene());
super.setDefaultTemplate(id);
}
private void checkProjectTemplateEnable(String projectId, String scene) {
ProjectDTO project = projectService.getProjectById(projectId);
if (isOrganizationTemplateEnable(project.getOrganizationId(), scene)) {
throw new MSException(PROJECT_TEMPLATE_PERMISSION);
}
}
}

View File

@ -0,0 +1,292 @@
package io.metersphere.project.controller;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.dto.CustomFieldDTO;
import io.metersphere.sdk.dto.request.CustomFieldOptionRequest;
import io.metersphere.sdk.dto.request.CustomFieldUpdateRequest;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.param.CustomFieldUpdateRequestDefinition;
import io.metersphere.system.domain.CustomField;
import io.metersphere.system.domain.CustomFieldExample;
import io.metersphere.system.domain.CustomFieldOption;
import io.metersphere.system.domain.OrganizationParameter;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.CustomFieldMapper;
import io.metersphere.system.mapper.OrganizationParameterMapper;
import io.metersphere.system.service.BaseCustomFieldOptionService;
import io.metersphere.system.service.BaseCustomFieldService;
import io.metersphere.system.service.BaseUserService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MvcResult;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static io.metersphere.project.enums.result.ProjectResultCode.PROJECT_TEMPLATE_PERMISSION;
import static io.metersphere.sdk.constants.InternalUserRole.ADMIN;
import static io.metersphere.system.controller.handler.result.CommonResultCode.*;
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
/**
* @author jianxing
* @date : 2023-8-29
*/
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ProjectCustomFieldControllerTests extends BaseTest {
private static final String BASE_PATH = "/project/custom/field/";
private static final String LIST = "list/{0}/{1}";
@Resource
private CustomFieldMapper customFieldMapper;
@Resource
private BaseCustomFieldOptionService baseCustomFieldOptionService;
@Resource
private BaseCustomFieldService baseCustomFieldService;
@Resource
private BaseUserService baseUserService;
@Resource
private OrganizationParameterMapper organizationParameterMapper;
private static CustomField addCustomField;
private static CustomField anotherAddCustomField;
@Override
protected String getBasePath() {
return BASE_PATH;
}
@Test
@Order(0)
public void listEmpty() throws Exception {
// @@校验没有数据的情况
this.requestGetWithOk(LIST, DEFAULT_PROJECT_ID, TemplateScene.UI.name());
}
@Test
@Order(1)
public void add() throws Exception {
// 开启项目模板
changeOrgTemplateEnable(false);
// @@请求成功
CustomFieldUpdateRequest request = new CustomFieldUpdateRequest();
request.setScene(TemplateScene.FUNCTIONAL.name());
request.setName("test");
request.setType(CustomFieldType.SELECT.name());
request.setRemark("AAA");
request.setScopeId(DEFAULT_PROJECT_ID);
CustomFieldOptionRequest customFieldOptionRequest = new CustomFieldOptionRequest();
customFieldOptionRequest.setValue("1111");
customFieldOptionRequest.setText("test");
List<CustomFieldOptionRequest> optionRequests = Arrays.asList(customFieldOptionRequest);
request.setOptions(optionRequests);
MvcResult mvcResult = this.requestPostWithOkAndReturn(DEFAULT_ADD, request);
CustomField resultData = getResultData(mvcResult, CustomField.class);
CustomField customField = customFieldMapper.selectByPrimaryKey(resultData.getId());
this.addCustomField = customField;
// 校验请求成功数据
request.setOptions(null);
request.setId(customField.getId());
Assertions.assertEquals(request, BeanUtils.copyBean(new CustomFieldUpdateRequest(), customField));
Assertions.assertEquals(customField.getCreateUser(), ADMIN.getValue());
Assertions.assertEquals(customField.getInternal(), false);
Assertions.assertEquals(customField.getScopeType(), TemplateScopeType.PROJECT.name());
List<CustomFieldOption> options = baseCustomFieldOptionService.getByFieldId(customField.getId());
for (int i = 0; i < options.size(); i++) {
CustomFieldOptionRequest optionRequestItem = optionRequests.get(i);
CustomFieldOption optionItem = options.get(i);
Assertions.assertEquals(optionRequestItem.getText(), optionItem.getText());
Assertions.assertEquals(optionRequestItem.getValue(), optionItem.getValue());
Assertions.assertEquals(false, optionItem.getInternal());
Assertions.assertEquals(customField.getId(), optionItem.getFieldId());
}
// @校验是否开启项目模板
changeOrgTemplateEnable(true);
assertErrorCode(this.requestPost(DEFAULT_ADD, request), PROJECT_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(false);
// @@重名校验异常
assertErrorCode(this.requestPost(DEFAULT_ADD, request), CUSTOM_FIELD_EXIST);
// @@校验组织是否存在
request.setScopeId("1111");
request.setName("test1");
assertErrorCode(this.requestPost(DEFAULT_ADD, request), NOT_FOUND);
// 插入另一条数据用户更新时重名校验
request.setScopeId(DEFAULT_PROJECT_ID);
MvcResult anotherMvcResult = this.requestPostWithOkAndReturn(DEFAULT_ADD, request);
this.anotherAddCustomField = customFieldMapper.selectByPrimaryKey(getResultData(anotherMvcResult, CustomField.class).getId());
// @@校验日志
checkLog(this.addCustomField.getId(), OperationLogType.ADD);
// @@异常参数校验
createdGroupParamValidateTest(CustomFieldUpdateRequestDefinition.class, DEFAULT_ADD);
// @@校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_CUSTOM_FIELD_ADD, DEFAULT_ADD, request);
}
@Test
@Order(2)
public void update() throws Exception {
// @@请求成功
CustomFieldUpdateRequest request = new CustomFieldUpdateRequest();
request.setId(addCustomField.getId());
request.setScene(TemplateScene.FUNCTIONAL.name());
request.setName("test2");
request.setType(CustomFieldType.SELECT.name());
request.setRemark("AAA1");
request.setScopeId("1111");
CustomFieldOptionRequest customFieldOptionRequest = new CustomFieldOptionRequest();
customFieldOptionRequest.setValue("11112");
customFieldOptionRequest.setText("test1");
List<CustomFieldOptionRequest> optionRequests = Arrays.asList(customFieldOptionRequest);
request.setOptions(optionRequests);
this.requestPostWithOk(DEFAULT_UPDATE, request);
CustomField customField = customFieldMapper.selectByPrimaryKey(request.getId());
// 校验请求成功数据
request.setOptions(null);
request.setId(customField.getId());
request.setScopeId(DEFAULT_PROJECT_ID);
Assertions.assertEquals(request, BeanUtils.copyBean(new CustomFieldUpdateRequest(), customField));
Assertions.assertEquals(customField.getCreateUser(), ADMIN.getValue());
Assertions.assertEquals(customField.getInternal(), false);
Assertions.assertEquals(customField.getScopeType(), TemplateScopeType.PROJECT.name());
List<CustomFieldOption> options = baseCustomFieldOptionService.getByFieldId(customField.getId());
for (int i = 0; i < options.size(); i++) {
CustomFieldOptionRequest optionRequestItem = optionRequests.get(i);
CustomFieldOption optionItem = options.get(i);
Assertions.assertEquals(optionRequestItem.getText(), optionItem.getText());
Assertions.assertEquals(optionRequestItem.getValue(), optionItem.getValue());
Assertions.assertEquals(false, optionItem.getInternal());
Assertions.assertEquals(customField.getId(), optionItem.getFieldId());
}
// @校验是否开启项目模板
changeOrgTemplateEnable(true);
assertErrorCode(this.requestPost(DEFAULT_ADD, request), PROJECT_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(false);
// @@重名校验异常
request.setName(anotherAddCustomField.getName());
assertErrorCode(this.requestPost(DEFAULT_UPDATE, request), CUSTOM_FIELD_EXIST);
// @校验 NOT_FOUND 异常
request.setId("1111");
request.setName("1111");
assertErrorCode(this.requestPost(DEFAULT_UPDATE, request), NOT_FOUND);
// @@校验日志
checkLog(addCustomField.getId(), OperationLogType.UPDATE);
// @@异常参数校验
updatedGroupParamValidateTest(CustomFieldUpdateRequestDefinition.class, DEFAULT_UPDATE);
// @@校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_CUSTOM_FIELD_UPDATE, DEFAULT_UPDATE, request);
}
@Test
@Order(3)
public void list() throws Exception {
String scene = TemplateScene.FUNCTIONAL.name();
// @@请求成功
MvcResult mvcResult = this.requestGetWithOk(LIST, DEFAULT_PROJECT_ID, scene)
.andReturn();
// 校验数据是否正确
List<CustomField> resultList = getResultDataArray(mvcResult, CustomField.class);
List<CustomField> customFields = baseCustomFieldService.getByScopeIdAndScene(DEFAULT_PROJECT_ID, scene);
List<String> userIds = customFields.stream().map(CustomField::getCreateUser).toList();
Map<String, String> userNameMap = baseUserService.getUserNameMap(userIds);
for (int i = 0; i < resultList.size(); i++) {
CustomField resultItem = resultList.get(i);
CustomField customField = customFields.get(i);
customField.setCreateUser(userNameMap.get(customField.getCreateUser()));
if (customField.getInternal()) {
// 校验内置用户名称是否翻译
customField.setName(baseCustomFieldService.translateInternalField(customField.getName()));
}
Assertions.assertEquals(customField, resultItem);
Assertions.assertEquals(resultItem.getScene(), scene);
}
// @@校验组织是否存在
assertErrorCode(this.requestGet(LIST, "1111", scene), NOT_FOUND);
// @@校验使用场景不合法
assertErrorCode(this.requestGet(LIST, DEFAULT_PROJECT_ID, "111"), TEMPLATE_SCENE_ILLEGAL);
// @@校验权限
requestGetPermissionTest(PermissionConstants.PROJECT_CUSTOM_FIELD_READ, LIST, DEFAULT_PROJECT_ID, scene);
}
@Test
@Order(4)
public void get() throws Exception {
// @@请求成功
MvcResult mvcResult = this.requestGetWithOk(DEFAULT_GET, addCustomField.getId())
.andReturn();
// 校验数据是否正确
CustomFieldDTO customFieldDTO = getResultData(mvcResult, CustomFieldDTO.class);
List<CustomFieldOption> options = customFieldDTO.getOptions();
CustomField customField = customFieldMapper.selectByPrimaryKey(customFieldDTO.getId());
Assertions.assertEquals(customField, BeanUtils.copyBean(new CustomField(), customFieldDTO));
Assertions.assertEquals(options, baseCustomFieldOptionService.getByFieldId(customField.getId()));
// @@校验权限
requestGetPermissionTest(PermissionConstants.PROJECT_CUSTOM_FIELD_READ, DEFAULT_GET, customFieldDTO.getId());
}
@Test
@Order(5)
public void delete() throws Exception {
// @校验是否开启项目模板
changeOrgTemplateEnable(true);
assertErrorCode(this.requestGet(DEFAULT_DELETE, addCustomField.getId()), PROJECT_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(false);
// @@请求成功
this.requestGetWithOk(DEFAULT_DELETE, addCustomField.getId());
Assertions.assertNull(customFieldMapper.selectByPrimaryKey(addCustomField.getId()));
Assertions.assertTrue(CollectionUtils.isEmpty(baseCustomFieldOptionService.getByFieldId(addCustomField.getId())));
// @@校验内置字段删除异常
CustomFieldExample example = new CustomFieldExample();
example.createCriteria()
.andInternalEqualTo(true);
CustomField internalCustomField = customFieldMapper.selectByExample(example).get(0);
assertErrorCode(this.requestGet(DEFAULT_DELETE, internalCustomField.getId()), INTERNAL_CUSTOM_FIELD_PERMISSION);
// @@校验 NOT_FOUND 异常
assertErrorCode(this.requestGet(DEFAULT_DELETE, "1111"), NOT_FOUND);
// @@校验日志
checkLog(addCustomField.getId(), OperationLogType.DELETE);
// @@校验权限
requestGetPermissionTest(PermissionConstants.PROJECT_CUSTOM_FIELD_DELETE, DEFAULT_DELETE, addCustomField.getId());
}
private void changeOrgTemplateEnable(boolean enable) {
if (enable) {
organizationParameterMapper.deleteByPrimaryKey(DEFAULT_ORGANIZATION_ID, OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY);
} else {
OrganizationParameter organizationParameter = new OrganizationParameter();
organizationParameter.setOrganizationId(DEFAULT_ORGANIZATION_ID);
organizationParameter.setParamKey(OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY);
organizationParameter.setParamValue(BooleanUtils.toStringTrueFalse(false));
if (organizationParameterMapper.selectByPrimaryKey(DEFAULT_ORGANIZATION_ID,
OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY) == null) {
organizationParameterMapper.insert(organizationParameter);
}
}
}
}

View File

@ -0,0 +1,372 @@
package io.metersphere.project.controller;
import io.metersphere.sdk.constants.OrganizationParameterConstants;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.sdk.dto.TemplateCustomFieldDTO;
import io.metersphere.sdk.dto.TemplateDTO;
import io.metersphere.sdk.dto.request.TemplateCustomFieldRequest;
import io.metersphere.sdk.dto.request.TemplateUpdateRequest;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.param.TemplateUpdateRequestDefinition;
import io.metersphere.system.domain.*;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.OrganizationParameterMapper;
import io.metersphere.system.mapper.TemplateMapper;
import io.metersphere.system.service.BaseCustomFieldService;
import io.metersphere.system.service.BaseTemplateCustomFieldService;
import io.metersphere.system.service.BaseTemplateService;
import io.metersphere.system.service.BaseUserService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MvcResult;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static io.metersphere.project.enums.result.ProjectResultCode.PROJECT_TEMPLATE_PERMISSION;
import static io.metersphere.sdk.constants.InternalUserRole.ADMIN;
import static io.metersphere.system.controller.handler.result.CommonResultCode.*;
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
/**
* @author jianxing
* @date : 2023-8-30
*/
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ProjectTemplateControllerTests extends BaseTest {
private static final String BASE_PATH = "/project/template/";
private static final String LIST = "list/{0}/{1}";
private static final String SET_DEFAULT = "set-default/{0}";
@Resource
private TemplateMapper templateMapper;
@Resource
private BaseTemplateService baseTemplateService;
@Resource
private BaseUserService baseUserService;
@Resource
private BaseCustomFieldService baseCustomFieldService;
@Resource
private BaseTemplateCustomFieldService baseTemplateCustomFieldService;
@Resource
private OrganizationParameterMapper organizationParameterMapper;
private static Template addTemplate;
private static Template anotherTemplateField;
private static Template defaultTemplate;
@Override
protected String getBasePath() {
return BASE_PATH;
}
@Test
@Order(0)
public void listEmpty() throws Exception {
// @@校验没有数据的情况
MvcResult mvcResult = this.requestGetWithOkAndReturn(LIST, DEFAULT_PROJECT_ID, TemplateScene.FUNCTIONAL.name());
List<Template> templates = getResultDataArray(mvcResult, Template.class);
this.defaultTemplate = templates.get(0);
}
@Test
@Order(1)
public void add() throws Exception {
// 开启项目模板
changeOrgTemplateEnable(false);
String scene = TemplateScene.FUNCTIONAL.name();
// @@请求成功
TemplateUpdateRequest request = new TemplateUpdateRequest();
TemplateCustomFieldRequest templateCustomFieldRequest = getTemplateCustomFieldRequest(scene);
request.setScene(scene);
request.setName("test");
request.setRemark("AAA");
request.setEnableThirdPart(true);
request.setScopeId(DEFAULT_PROJECT_ID);
request.setCustomFields(List.of(templateCustomFieldRequest));
MvcResult mvcResult = this.requestPostWithOkAndReturn(DEFAULT_ADD, request);
Template resultData = getResultData(mvcResult, Template.class);
Template template = templateMapper.selectByPrimaryKey(resultData.getId());
this.addTemplate = template;
// 校验请求成功数据
request.setId(template.getId());
TemplateUpdateRequest copyRequest = BeanUtils.copyBean(new TemplateUpdateRequest(), request);
copyRequest.setCustomFields(null);
Assertions.assertEquals(copyRequest, BeanUtils.copyBean(new TemplateUpdateRequest(), template));
Assertions.assertEquals(template.getCreateUser(), ADMIN.getValue());
Assertions.assertEquals(template.getInternal(), false);
Assertions.assertEquals(template.getScopeType(), TemplateScopeType.PROJECT.name());
asserTemplateCustomFields(request, template);
// @@重名校验异常
assertErrorCode(this.requestPost(DEFAULT_ADD, request), TEMPLATE_EXIST);
// @校验是否开启项目模板
changeOrgTemplateEnable(true);
assertErrorCode(this.requestPost(DEFAULT_ADD, request), PROJECT_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(false);
// @@校验组织是否存在
request.setScopeId("1111");
request.setName("test1");
assertErrorCode(this.requestPost(DEFAULT_ADD, request), NOT_FOUND);
// 插入另一条数据用户更新时重名校验
request.setScopeId(DEFAULT_PROJECT_ID);
MvcResult anotherMvcResult = this.requestPostWithOkAndReturn(DEFAULT_ADD, request);
this.anotherTemplateField = templateMapper.selectByPrimaryKey(getResultData(anotherMvcResult, Template.class).getId());
// @@校验日志
checkLog(this.addTemplate.getId(), OperationLogType.ADD);
// @@异常参数校验
createdGroupParamValidateTest(TemplateUpdateRequestDefinition.class, DEFAULT_ADD);
// @@校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_TEMPLATE_ADD, DEFAULT_ADD, request);
}
private void asserTemplateCustomFields(TemplateUpdateRequest request, Template template) {
List<TemplateCustomField> templateCustomFields = baseTemplateCustomFieldService.getByTemplateId(template.getId());
Assertions.assertEquals(templateCustomFields.size(), request.getCustomFields().size());
for (int i = 0; i < templateCustomFields.size(); i++) {
TemplateCustomField templateCustomField = templateCustomFields.get(i);
TemplateCustomFieldRequest customFieldRequest = request.getCustomFields().get(i);
Assertions.assertEquals(templateCustomField.getFieldId(), customFieldRequest.getFieldId());
Assertions.assertEquals(templateCustomField.getTemplateId(), template.getId());
Assertions.assertEquals(templateCustomField.getRequired(), customFieldRequest.getRequired());
Assertions.assertEquals(templateCustomField.getApiFieldId(), customFieldRequest.getApiFieldId());
Assertions.assertEquals(templateCustomField.getDefaultValue(), customFieldRequest.getDefaultValue());
}
}
private TemplateCustomFieldRequest getTemplateCustomFieldRequest(String scene) {
List<CustomField> customFields = baseCustomFieldService.getByScopeIdAndScene(DEFAULT_PROJECT_ID, scene);
CustomField customField = customFields.stream()
.filter(item -> item.getName().equals("functional_priority"))
.findFirst()
.get();
TemplateCustomFieldRequest templateCustomFieldRequest = new TemplateCustomFieldRequest();
BeanUtils.copyBean(templateCustomFieldRequest, customField);
templateCustomFieldRequest.setFieldId(customField.getId());
templateCustomFieldRequest.setRequired(true);
templateCustomFieldRequest.setApiFieldId("aaa");
templateCustomFieldRequest.setDefaultValue("P0");
return templateCustomFieldRequest;
}
@Test
@Order(2)
public void update() throws Exception {
// @@请求成功
String scene = TemplateScene.FUNCTIONAL.name();
TemplateUpdateRequest request = new TemplateUpdateRequest();
request.setId(addTemplate.getId());
request.setScene(scene);
request.setName("test2");
request.setRemark("AAA1");
request.setScopeId(DEFAULT_PROJECT_ID);
request.setScene(TemplateScene.UI.name());
request.setEnableThirdPart(true);
request.setCustomFields(new ArrayList<>(0));
this.requestPostWithOk(DEFAULT_UPDATE, request);
Template template = templateMapper.selectByPrimaryKey(request.getId());
// 校验请求成功数据
Assertions.assertEquals(template.getName(), request.getName());
Assertions.assertEquals(template.getRemark(), request.getRemark());
Assertions.assertEquals(template.getScopeId(), DEFAULT_PROJECT_ID);
Assertions.assertEquals(template.getCreateUser(), ADMIN.getValue());
Assertions.assertEquals(template.getInternal(), false);
Assertions.assertEquals(template.getScopeType(), TemplateScopeType.PROJECT.name());
Assertions.assertEquals(template.getScene(), scene);
Assertions.assertEquals(template.getEnableThirdPart(), request.getEnableThirdPart());
asserTemplateCustomFields(request, template);
// 带字段的更新
TemplateCustomFieldRequest templateCustomFieldRequest = getTemplateCustomFieldRequest(scene);
request.setCustomFields(List.of(templateCustomFieldRequest));
this.requestPostWithOk(DEFAULT_UPDATE, request);
asserTemplateCustomFields(request, template);
// 不更新字段
request.setCustomFields(null);
this.requestPostWithOk(DEFAULT_UPDATE, request);
Assertions.assertEquals(baseTemplateCustomFieldService.getByTemplateId(template.getId()).size(), 1);
// @校验是否开启项目模板
changeOrgTemplateEnable(true);
assertErrorCode(this.requestPost(DEFAULT_ADD, request), PROJECT_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(false);
// @@重名校验异常
request.setName(anotherTemplateField.getName());
assertErrorCode(this.requestPost(DEFAULT_UPDATE, request), TEMPLATE_EXIST);
// @校验 NOT_FOUND 异常
request.setId("1111");
request.setName("1111");
assertErrorCode(this.requestPost(DEFAULT_UPDATE, request), NOT_FOUND);
// @@校验日志
checkLog(addTemplate.getId(), OperationLogType.UPDATE);
// @@异常参数校验
updatedGroupParamValidateTest(TemplateUpdateRequestDefinition.class, DEFAULT_UPDATE);
// @@校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_TEMPLATE_UPDATE, DEFAULT_UPDATE, request);
}
@Test
@Order(3)
public void list() throws Exception {
String scene = TemplateScene.FUNCTIONAL.name();
// @@请求成功
MvcResult mvcResult = this.requestGetWithOk(LIST, DEFAULT_PROJECT_ID, scene)
.andReturn();
// 校验数据是否正确
List<Template> resultList = getResultDataArray(mvcResult, Template.class);
List<Template> templates = baseTemplateService.getTemplates(DEFAULT_PROJECT_ID, scene);
List<String> userIds = templates.stream().map(Template::getCreateUser).toList();
Map<String, String> userNameMap = baseUserService.getUserNameMap(userIds);
for (int i = 0; i < resultList.size(); i++) {
Template resultItem = resultList.get(i);
Template template = templates.get(i);
template.setCreateUser(userNameMap.get(template.getCreateUser()));
if (template.getInternal()) {
// 校验内置用户名称是否翻译
template.setName(baseTemplateService.translateInternalTemplate(template.getName()));
}
Assertions.assertEquals(template, resultItem);
Assertions.assertEquals(resultItem.getScene(), scene);
}
// @@校验组织是否存在
assertErrorCode(this.requestGet(LIST, "1111", scene), NOT_FOUND);
// @@校验使用场景不合法
assertErrorCode(this.requestGet(LIST, DEFAULT_PROJECT_ID, "111"), TEMPLATE_SCENE_ILLEGAL);
// @@校验权限
requestGetPermissionTest(PermissionConstants.PROJECT_TEMPLATE_READ, LIST, DEFAULT_PROJECT_ID, scene);
}
@Test
@Order(4)
public void get() throws Exception {
// @@请求成功
MvcResult mvcResult = this.requestGetWithOk(DEFAULT_GET, addTemplate.getId())
.andReturn();
// 校验数据是否正确
TemplateDTO templateDTO = getResultData(mvcResult, TemplateDTO.class);
Template template = templateMapper.selectByPrimaryKey(templateDTO.getId());
Assertions.assertEquals(template, BeanUtils.copyBean(new Template(), templateDTO));
List<TemplateCustomFieldDTO> customFields = templateDTO.getCustomFields();
List<TemplateCustomField> templateCustomFields = baseTemplateCustomFieldService.getByTemplateId(template.getId());
for (int i = 0; i < customFields.size(); i++) {
TemplateCustomFieldDTO customFieldDTO = customFields.get(i);
TemplateCustomField templateCustomField = templateCustomFields.get(i);
Assertions.assertEquals(customFieldDTO.getFieldId(), templateCustomField.getFieldId());
Assertions.assertEquals(customFieldDTO.getApiFieldId(), templateCustomField.getApiFieldId());
Assertions.assertEquals(customFieldDTO.getRequired(), templateCustomField.getRequired());
Assertions.assertEquals(templateCustomField.getTemplateId(), template.getId());
Assertions.assertEquals(customFieldDTO.getFieldName(), "优先级");
}
// @@校验权限
requestGetPermissionTest(PermissionConstants.PROJECT_TEMPLATE_READ, DEFAULT_GET, templateDTO.getId());
}
@Test
@Order(5)
public void setDefaultTemplate() throws Exception {
changeOrgTemplateEnable(false);
// @@请求成功
this.requestGetWithOk(SET_DEFAULT, addTemplate.getId());
Template template = templateMapper.selectByPrimaryKey(addTemplate.getId());
assertSetDefaultTemplate(template);
// @校验是否开启项目模板
changeOrgTemplateEnable(true);
assertErrorCode(this.requestGet(SET_DEFAULT, addTemplate.getId()), PROJECT_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(false);
// @@校验日志
checkLog(addTemplate.getId(), OperationLogType.UPDATE);
// @@校验权限
requestGetPermissionTest(PermissionConstants.ORGANIZATION_TEMPLATE_UPDATE, SET_DEFAULT, addTemplate.getScopeId(), addTemplate.getScene());
}
@Test
@Order(6)
public void delete() throws Exception {
// @校验是否开启项目模板
changeOrgTemplateEnable(true);
assertErrorCode(this.requestGet(DEFAULT_DELETE, addTemplate.getId()), PROJECT_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(false);
// @@校验删除默认模板
assertErrorCode(this.requestGet(DEFAULT_DELETE, addTemplate.getId()), DEFAULT_TEMPLATE_PERMISSION);
// 设置回来保证正常删除
this.requestGetWithOk(SET_DEFAULT, defaultTemplate.getId());
// @@请求成功
this.requestGetWithOk(DEFAULT_DELETE, addTemplate.getId());
Assertions.assertNull(templateMapper.selectByPrimaryKey(addTemplate.getId()));
Assertions.assertTrue(CollectionUtils.isEmpty(baseTemplateCustomFieldService.getByTemplateId(addTemplate.getId())));
// @@校验内置模板删除异常
TemplateExample example = new TemplateExample();
example.createCriteria()
.andScopeTypeEqualTo(TemplateScopeType.PROJECT.name())
.andInternalEqualTo(true);
Template internalTemplate = templateMapper.selectByExample(example).get(0);
assertErrorCode(this.requestGet(DEFAULT_DELETE, internalTemplate.getId()), INTERNAL_TEMPLATE_PERMISSION);
// @@校验 NOT_FOUND 异常
assertErrorCode(this.requestGet(DEFAULT_DELETE, "1111"), NOT_FOUND);
// @@校验日志
checkLog(addTemplate.getId(), OperationLogType.DELETE);
// @@校验权限
requestGetPermissionTest(PermissionConstants.PROJECT_TEMPLATE_DELETE, DEFAULT_DELETE, addTemplate.getId());
}
private void assertSetDefaultTemplate(Template template) {
Assertions.assertTrue(template.getEnableDefault());
int defaultCount = getTemplateByScopeId(addTemplate.getScopeId())
.stream()
.filter(Template::getEnableDefault)
.toList().size();
Assertions.assertEquals(defaultCount, 1);
}
private List<Template> getTemplateByScopeId(String scopeId) {
TemplateExample example = new TemplateExample();
example.createCriteria().andScopeIdEqualTo(scopeId);
return templateMapper.selectByExample(example);
}
private void changeOrgTemplateEnable(boolean enable) {
if (enable) {
organizationParameterMapper.deleteByPrimaryKey(DEFAULT_ORGANIZATION_ID, OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY);
} else {
OrganizationParameter organizationParameter = new OrganizationParameter();
organizationParameter.setOrganizationId(DEFAULT_ORGANIZATION_ID);
organizationParameter.setParamKey(OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY);
organizationParameter.setParamValue(BooleanUtils.toStringTrueFalse(false));
if (organizationParameterMapper.selectByPrimaryKey(DEFAULT_ORGANIZATION_ID,
OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY) == null) {
organizationParameterMapper.insert(organizationParameter);
}
}
}
}

View File

@ -3,11 +3,11 @@ package io.metersphere.system.controller;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.TemplateDTO;
import io.metersphere.sdk.dto.request.TemplateUpdateRequest;
import io.metersphere.system.log.annotation.Log;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.utils.SessionUtils;
import io.metersphere.system.domain.Template;
import io.metersphere.system.log.annotation.Log;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.service.OrganizationTemplateLogService;
import io.metersphere.system.service.OrganizationTemplateService;
import io.metersphere.validation.groups.Created;
@ -79,4 +79,21 @@ public class OrganizationTemplateController {
public void delete(@PathVariable String id) {
organizationTemplateservice.delete(id);
}
@GetMapping("/disable/{organizationId}/{scene}")
@Operation(summary = "关闭组织模板,开启项目模板")
@RequiresPermissions(PermissionConstants.ORGANIZATION_TEMPLATE_ENABLE)
// todo 操作日志待页面设计
// @Log(type = OperationLogType.UPDATE, expression = "#msClass.update(#id)", msClass = OrganizationTemplateLogService.class)
public void disableOrganizationTemplate(@PathVariable String organizationId, @PathVariable String scene) {
organizationTemplateservice.disableOrganizationTemplate(organizationId, scene);
}
@GetMapping("/set-default/{id}")
@Operation(summary = "设置模板模板")
@RequiresPermissions(PermissionConstants.ORGANIZATION_TEMPLATE_UPDATE)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.setDefaultTemplateLog(#id)", msClass = OrganizationTemplateLogService.class)
public void setDefaultTemplate(@PathVariable String id) {
organizationTemplateservice.setDefaultTemplate(id);
}
}

View File

@ -14,16 +14,17 @@ public enum CommonResultCode implements IResultCode {
/**
* 调用获取全局用户组接口如果操作的是内置的用户组会返回该响应码
*/
INTERNAL_USER_ROLE_PERMISSION(101003, "internal_user_role_permission_error"),
INTERNAL_USER_ROLE_PERMISSION(100003, "internal_user_role_permission_error"),
USER_ROLE_RELATION_REMOVE_ADMIN_USER_PERMISSION(100004, "user_role_relation_remove_admin_user_permission_error"),
FILE_NAME_ILLEGAL(100005, "file_name_illegal_error"),
PLUGIN_ENABLE(100006, "plugin_enable_error"),
PLUGIN_PERMISSION(100007, "plugin_permission_error"),
INTERNAL_CUSTOM_FIELD_PERMISSION(101008, "internal_custom_field_permission_error"),
INTERNAL_TEMPLATE_PERMISSION(101009, "internal_template_permission_error"),
TEMPLATE_SCENE_ILLEGAL(101010, "template_scene_illegal_error"),
CUSTOM_FIELD_EXIST(101012, "custom_field.exist"),
TEMPLATE_EXIST(101013, "template.exist");
INTERNAL_CUSTOM_FIELD_PERMISSION(100008, "internal_custom_field_permission_error"),
INTERNAL_TEMPLATE_PERMISSION(100009, "internal_template_permission_error"),
TEMPLATE_SCENE_ILLEGAL(100010, "template_scene_illegal_error"),
CUSTOM_FIELD_EXIST(100012, "custom_field.exist"),
TEMPLATE_EXIST(100013, "template.exist"),
DEFAULT_TEMPLATE_PERMISSION(100014, "default_template_permission_error");
private int code;

View File

@ -20,6 +20,10 @@ public enum SystemResultCode implements IResultCode {
*/
NO_ORG_USER_ROLE_PERMISSION(101007, "organization_user_role_permission_error"),
PLUGIN_EXIST(101008, "plugin.exist"),
/**
* 开启项目模板操作组织模板时会返回
*/
ORGANIZATION_TEMPLATE_PERMISSION(101009, "organization_template_permission_error"),
PLUGIN_SCRIPT_EXIST(101010, "plugin.script.exist"),
PLUGIN_SCRIPT_FORMAT(101011, "plugin.script.format"),
NO_PROJECT_USER_ROLE_PERMISSION(101012, "project_user_role_permission_error");

View File

@ -90,7 +90,6 @@ public class OperationLogModule {
public static final String PROJECT_MANAGEMENT_PERMISSION_VERSION = "PROJECT_MANAGEMENT_PERMISSION_VERSION";
//项目管理-消息设置
public static final String PROJECT_MANAGEMENT_MESSAGE = "PROJECT_MANAGEMENT_MESSAGE";
public static final String PROJECT_TEMPLATE = "PROJECT_TEMPLATE";// 项目模板
public static final String PROJECT_CUSTOM_FIELD = "PROJECT_CUSTOM_FIELD";// 项目字段
}

View File

@ -1,6 +1,7 @@
package io.metersphere.system.mapper;
import io.metersphere.project.domain.Project;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -8,4 +9,6 @@ public interface BaseProjectMapper {
Project selectOne();
List<Project> selectProjectByIdList(List<String> projectIds);
List<String> getProjectIdByOrgId(@Param("orgId") String orgId);
}

View File

@ -16,4 +16,9 @@
#{id}
</foreach>
</select>
<select id="getProjectIdByOrgId" resultType="java.lang.String">
SELECT id
FROM project
WHERE organization_id = #{orgId}
</select>
</mapper>

View File

@ -0,0 +1,12 @@
package io.metersphere.system.mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author jianxing
*/
public interface ExtOrganizationCustomFieldMapper {
List<String> getCustomFieldByRefId(@Param("refId") String refId);
}

View File

@ -0,0 +1,7 @@
<?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.ExtOrganizationCustomFieldMapper">
<select id="getCustomFieldByRefId" resultType="java.lang.String">
SELECT id FROM custom_field WHERE ref_id = #{refId}
</select>
</mapper>

View File

@ -0,0 +1,12 @@
package io.metersphere.system.mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author jianxing
*/
public interface ExtOrganizationTemplateMapper {
List<String> getTemplateIdByRefId(@Param("refId") String refId);
}

View File

@ -0,0 +1,7 @@
<?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.ExtOrganizationTemplateMapper">
<select id="getTemplateIdByRefId" resultType="java.lang.String">
SELECT id FROM template WHERE ref_id = #{refId}
</select>
</mapper>

View File

@ -7,9 +7,11 @@ import io.metersphere.system.domain.CustomFieldOptionExample;
import io.metersphere.system.mapper.CustomFieldOptionMapper;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@ -30,23 +32,29 @@ public class BaseCustomFieldOptionService {
customFieldOptionMapper.deleteByExample(example);
}
public void deleteByFieldIds(List<String> fieldIds) {
if (CollectionUtils.isEmpty(fieldIds)) {
return;
}
CustomFieldOptionExample example = new CustomFieldOptionExample();
example.createCriteria().andFieldIdIn(fieldIds);
customFieldOptionMapper.deleteByExample(example);
}
public List<CustomFieldOption> getByFieldId(String fieldId) {
CustomFieldOptionExample example = new CustomFieldOptionExample();
example.createCriteria().andFieldIdEqualTo(fieldId);
return customFieldOptionMapper.selectByExample(example);
}
public void addByFieldId(String fieldId, List<CustomFieldOptionRequest> customFieldOptionRequests) {
if (CollectionUtils.isEmpty(customFieldOptionRequests)) {
public void addByFieldId(String fieldId, List<CustomFieldOption> customFieldOptions) {
if (CollectionUtils.isEmpty(customFieldOptions)) {
return;
}
List<CustomFieldOption> customFieldOptions = customFieldOptionRequests.stream().map(item -> {
CustomFieldOption customFieldOption = new CustomFieldOption();
BeanUtils.copyBean(customFieldOption, item);
customFieldOption.setFieldId(fieldId);
customFieldOption.setInternal(false);
return customFieldOption;
}).toList();
customFieldOptions.stream().forEach(item -> {
item.setFieldId(fieldId);
item.setInternal(BooleanUtils.isTrue(item.getInternal()) ? true : false);
});
customFieldOptionMapper.batchInsert(customFieldOptions);
}
@ -73,4 +81,13 @@ public class BaseCustomFieldOptionService {
}).toList();
customFieldOptionMapper.batchInsert(customFieldOptions);
}
public List<CustomFieldOption> getByFieldIds(List<String> fieldIds) {
if (CollectionUtils.isEmpty(fieldIds)) {
return new ArrayList<>(0);
}
CustomFieldOptionExample example = new CustomFieldOptionExample();
example.createCriteria().andFieldIdIn(fieldIds);
return customFieldOptionMapper.selectByExample(example);
}
}

View File

@ -1,23 +1,31 @@
package io.metersphere.system.service;
import io.metersphere.sdk.constants.DefaultFunctionalCustomField;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.sdk.dto.CustomFieldDTO;
import io.metersphere.sdk.dto.request.CustomFieldOptionRequest;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.utils.ServiceUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.CustomField;
import io.metersphere.system.domain.CustomFieldExample;
import io.metersphere.system.domain.CustomFieldOption;
import io.metersphere.system.mapper.CustomFieldMapper;
import io.metersphere.system.uid.UUID;
import io.metersphere.system.utils.ServiceUtils;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import io.metersphere.system.uid.UUID;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static io.metersphere.system.controller.handler.result.CommonResultCode.*;
/**
@ -28,11 +36,13 @@ import static io.metersphere.system.controller.handler.result.CommonResultCode.*
@Transactional(rollbackFor = Exception.class)
public class BaseCustomFieldService {
@Resource
private CustomFieldMapper customFieldMapper;
protected CustomFieldMapper customFieldMapper;
@Resource
private BaseUserService baseUserService;
protected BaseUserService baseUserService;
@Resource
private BaseCustomFieldOptionService baseCustomFieldOptionService;
protected BaseCustomFieldOptionService baseCustomFieldOptionService;
@Resource
protected BaseOrganizationParameterService baseOrganizationParameterService;
public List<CustomField> list(String scopeId, String scene) {
checkScene(scene);
@ -83,11 +93,30 @@ public class BaseCustomFieldService {
}
public CustomField add(CustomField customField, List<CustomFieldOptionRequest> options) {
customField.setInternal(false);
List<CustomFieldOption> customFieldOptions = parseCustomFieldOptionRequest2Option(options);
return this.baseAdd(customField, customFieldOptions);
}
public List<CustomFieldOption> parseCustomFieldOptionRequest2Option(List<CustomFieldOptionRequest> options) {
return options == null ? null : options.stream().map(item -> {
CustomFieldOption customFieldOption = new CustomFieldOption();
BeanUtils.copyBean(customFieldOption, item);
return customFieldOption;
}).toList();
}
/**
* 添加自定义字段不设置是否是内置字段
* @param customField
* @param options
* @return
*/
public CustomField baseAdd(CustomField customField, List<CustomFieldOption> options) {
checkAddExist(customField);
customField.setId(UUID.randomUUID().toString());
customField.setCreateTime(System.currentTimeMillis());
customField.setUpdateTime(System.currentTimeMillis());
customField.setInternal(false);
customFieldMapper.insert(customField);
baseCustomFieldOptionService.addByFieldId(customField.getId(), options);
return customField;
@ -165,4 +194,77 @@ public class BaseCustomFieldService {
.andIdIn(fieldIds);
return customFieldMapper.selectByExample(example);
}
public List<CustomField> getByRefIdsAndScopeId(List<String> fieldIds, String scopeId) {
if (CollectionUtils.isEmpty(fieldIds)) {
return new ArrayList<>(0);
}
CustomFieldExample example = new CustomFieldExample();
example.createCriteria()
.andRefIdIn(fieldIds)
.andScopeIdEqualTo(scopeId);
return customFieldMapper.selectByExample(example);
}
public boolean isOrganizationTemplateEnable(String orgId, String scene) {
String key = baseOrganizationParameterService.getOrgTemplateEnableKeyByScene(scene);
String value = baseOrganizationParameterService.getValue(orgId, key);
// 没有配置默认为 true
return !StringUtils.equals(BooleanUtils.toStringTrueFalse(false), value);
}
public void deleteByScopeId(String copeId) {
// 删除字段
CustomFieldExample example = new CustomFieldExample();
example.createCriteria()
.andScopeIdEqualTo(copeId);
customFieldMapper.deleteByExample(example);
// 删除字段选项
List<String> ids = customFieldMapper.selectByExample(example)
.stream()
.map(CustomField::getId)
.toList();
baseCustomFieldOptionService.deleteByFieldIds(ids);
}
public List<CustomField> getByScopeId(String scopeId) {
CustomFieldExample example = new CustomFieldExample();
example.createCriteria()
.andScopeIdEqualTo(scopeId);
return customFieldMapper.selectByExample(example);
}
public CustomField initDefaultCustomField(CustomField customField) {
customField.setId(UUID.randomUUID().toString());
customField.setInternal(true);
customField.setCreateTime(System.currentTimeMillis());
customField.setUpdateTime(System.currentTimeMillis());
customField.setCreateUser("admin");
customFieldMapper.insert(customField);
return customField;
}
/**
* 初始化功能用例模板
* @param scopeType
* @param scopeId
* @return
*/
public List<CustomField> initFunctionalDefaultCustomField(TemplateScopeType scopeType, String scopeId) {
List<CustomField> customFields = new ArrayList<>();
for (DefaultFunctionalCustomField defaultFunctionalCustomField : DefaultFunctionalCustomField.values()) {
CustomField customField = new CustomField();
customField.setName(defaultFunctionalCustomField.getName());
customField.setScene(TemplateScene.FUNCTIONAL.name());
customField.setType(defaultFunctionalCustomField.getType().name());
customField.setScopeType(scopeType.name());
customField.setScopeId(scopeId);
customField.setEnableOptionKey(false);
customFields.add(this.initDefaultCustomField(customField));
// 初始化选项
baseCustomFieldOptionService.addByFieldId(customField.getId(), defaultFunctionalCustomField.getOptions());
}
return customFields;
}
}

View File

@ -0,0 +1,43 @@
package io.metersphere.system.service;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.system.domain.OrganizationParameter;
import io.metersphere.system.mapper.OrganizationParameterMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.Map;
import static io.metersphere.sdk.constants.OrganizationParameterConstants.*;
/**
* @author jianxing
* @date : 2023-9-20
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class BaseOrganizationParameterService {
@Resource
private OrganizationParameterMapper organizationParameterMapper;
public String getValue(String orgId, String key) {
OrganizationParameter organizationParameter = organizationParameterMapper.selectByPrimaryKey(orgId, key);
return organizationParameter == null ? null : organizationParameter.getParamValue();
}
public String getOrgTemplateEnableKeyByScene(String scene) {
Map<String, String> sceneMap = new HashMap<>();
sceneMap.put(TemplateScene.FUNCTIONAL.name(), ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY);
sceneMap.put(TemplateScene.ISSUE.name(), ORGANIZATION_ISSUE_TEMPLATE_ENABLE_KEY);
sceneMap.put(TemplateScene.API.name(), ORGANIZATION_API_TEMPLATE_ENABLE_KEY);
sceneMap.put(TemplateScene.UI.name(), ORGANIZATION_UI_TEMPLATE_ENABLE_KEY);
return sceneMap.get(scene);
}
public void add(OrganizationParameter organizationParameter) {
organizationParameterMapper.insert(organizationParameter);
}
}

View File

@ -11,6 +11,7 @@ import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import io.metersphere.system.uid.UUID;
@ -35,6 +36,15 @@ public class BaseTemplateCustomFieldService {
templateCustomFieldMapper.deleteByExample(example);
}
public void deleteByTemplateIds(List<String> projectTemplateIds) {
if (CollectionUtils.isEmpty(projectTemplateIds)) {
return;
}
TemplateCustomFieldExample example = new TemplateCustomFieldExample();
example.createCriteria().andTemplateIdIn(projectTemplateIds);
templateCustomFieldMapper.deleteByExample(example);
}
public void addByTemplateId(String id, List<TemplateCustomFieldRequest> customFieldRequests) {
if (CollectionUtils.isEmpty(customFieldRequests)) {
return;
@ -64,4 +74,13 @@ public class BaseTemplateCustomFieldService {
example.createCriteria().andTemplateIdEqualTo(id);
return templateCustomFieldMapper.selectByExample(example);
}
public List<TemplateCustomField> getByTemplateIds(List<String> projectTemplateIds) {
if (CollectionUtils.isEmpty(projectTemplateIds)) {
return new ArrayList(0);
}
TemplateCustomFieldExample example = new TemplateCustomFieldExample();
example.createCriteria().andTemplateIdIn(projectTemplateIds);
return templateCustomFieldMapper.selectByExample(example);
}
}

View File

@ -1,6 +1,7 @@
package io.metersphere.system.service;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.sdk.dto.TemplateCustomFieldDTO;
import io.metersphere.sdk.dto.TemplateDTO;
import io.metersphere.sdk.dto.request.TemplateCustomFieldRequest;
@ -36,13 +37,13 @@ import static io.metersphere.system.controller.handler.result.CommonResultCode.*
public class BaseTemplateService {
@Resource
private TemplateMapper templateMapper;
protected TemplateMapper templateMapper;
@Resource
private BaseTemplateCustomFieldService baseTemplateCustomFieldService;
protected BaseTemplateCustomFieldService baseTemplateCustomFieldService;
@Resource
private BaseUserService baseUserService;
protected BaseUserService baseUserService;
@Resource
private BaseCustomFieldService baseCustomFieldService;
protected BaseCustomFieldService baseCustomFieldService;
public List<Template> list(String scopeId, String scene) {
checkScene(scene);
@ -63,8 +64,14 @@ public class BaseTemplateService {
example.createCriteria()
.andScopeIdEqualTo(scopeId)
.andSceneEqualTo(scene);
List<Template> templates = templateMapper.selectByExample(example);
return templates;
return templateMapper.selectByExample(example);
}
public List<Template> getByScopeId(String scopeId) {
TemplateExample example = new TemplateExample();
example.createCriteria()
.andScopeIdEqualTo(scopeId);
return templateMapper.selectByExample(example);
}
public String translateInternalTemplate(String filedName) {
@ -104,11 +111,16 @@ public class BaseTemplateService {
}
public Template add(Template template, List<TemplateCustomFieldRequest> customFields) {
template.setInternal(false);
template.setEnableDefault(false);
return this.baseAdd(template, customFields);
}
public Template baseAdd(Template template, List<TemplateCustomFieldRequest> customFields) {
checkAddExist(template);
template.setId(UUID.randomUUID().toString());
template.setCreateTime(System.currentTimeMillis());
template.setUpdateTime(System.currentTimeMillis());
template.setInternal(false);
templateMapper.insert(template);
baseTemplateCustomFieldService.deleteByTemplateId(template.getId());
baseTemplateCustomFieldService.addByTemplateId(template.getId(), customFields);
@ -132,6 +144,7 @@ public class BaseTemplateService {
template.setScopeId(null);
template.setCreateUser(null);
template.setCreateTime(null);
template.setEnableDefault(null);
// customFields null 则不修改
if (customFields != null) {
baseTemplateCustomFieldService.deleteByTemplateId(template.getId());
@ -142,17 +155,51 @@ public class BaseTemplateService {
}
public void delete(String id) {
checkResourceExist(id);
Template template = checkResourceExist(id);
checkInternal(template);
checkDefault(template);
templateMapper.deleteByPrimaryKey(id);
baseTemplateCustomFieldService.deleteByTemplateId(id);
}
public void setDefaultTemplate(String id) {
Template originTemplate = templateMapper.selectByPrimaryKey(id);
// 将当前模板设置成默认模板
Template template = new Template();
template.setId(id);
template.setEnableDefault(true);
templateMapper.updateByPrimaryKeySelective(template);
// 将其他模板设置成非默认模板
template = new Template();
template.setEnableDefault(false);
TemplateExample example = new TemplateExample();
example.createCriteria()
.andIdNotEqualTo(id)
.andScopeIdEqualTo(originTemplate.getScopeId());
templateMapper.updateByExampleSelective(template, example);
}
/**
* 校验时候是内置模板
* @param template
*/
protected void checkInternal(Template template) {
if (template.getInternal()) {
throw new MSException(INTERNAL_TEMPLATE_PERMISSION);
}
}
/**
* 设置成默认模板后不能删除
* @param template
*/
protected void checkDefault(Template template) {
if (template.getEnableDefault()) {
throw new MSException(DEFAULT_TEMPLATE_PERMISSION);
}
}
protected void checkAddExist(Template template) {
TemplateExample example = new TemplateExample();
example.createCriteria()
@ -180,4 +227,111 @@ public class BaseTemplateService {
private Template checkResourceExist(String id) {
return ServiceUtils.checkResourceExist(templateMapper.selectByPrimaryKey(id), "permission.system_template.name");
}
public boolean isOrganizationTemplateEnable(String orgId, String scene) {
return baseCustomFieldService.isOrganizationTemplateEnable(orgId, scene);
}
public void deleteByScopeId(String scopeId) {
// 删除模板
TemplateExample example = new TemplateExample();
example.createCriteria()
.andScopeIdEqualTo(scopeId);
templateMapper.deleteByExample(example);
// 删除模板和字段的关联关系
List<String> ids = templateMapper.selectByExample(example)
.stream()
.map(Template::getId)
.toList();
baseTemplateCustomFieldService.deleteByTemplateIds(ids);
}
/**
* 将创建组织模板与字段的关联关系请求
* 转换为项目模板与字段的关联关系请求
*
* @param customFields
* @return
*/
public List<TemplateCustomFieldRequest> getRefTemplateCustomFieldRequest(String projectId, List<TemplateCustomFieldRequest> customFields) {
if (customFields == null) {
return null;
}
List<String> fieldIds = customFields.stream()
.map(TemplateCustomFieldRequest::getFieldId).toList();
// 查询当前组织字段所对应的项目字段构建map键为组织字段ID值为项目字段ID
Map<String, String> refFieldMap = baseCustomFieldService.getByRefIdsAndScopeId(fieldIds, projectId)
.stream()
.collect(Collectors.toMap(CustomField::getRefId, CustomField::getId));
// 根据组织字段ID替换为项目字段ID
return customFields.stream()
.map(item -> {
TemplateCustomFieldRequest request = BeanUtils.copyBean(new TemplateCustomFieldRequest(), item);
request.setFieldId(refFieldMap.get(item.getFieldId()));
return request;
})
.toList();
}
/**
* 初始化功能用例模板
* 创建组织的时候调用初始化组织模板
* 创建项目的时候调用初始化项目模板
* @param scopeId
* @param scopeType
*/
public void initFunctionalDefaultTemplate(String scopeId, TemplateScopeType scopeType) {
// 初始化字段
List<CustomField> customFields = baseCustomFieldService.initFunctionalDefaultCustomField(scopeType, scopeId);
// 初始化模板
Template template = this.initDefaultTemplate(scopeId, "functional_default", scopeType, TemplateScene.FUNCTIONAL);
// 初始化模板和字段的关联关系
List<TemplateCustomFieldRequest> templateCustomFieldRequests = customFields.stream().map(customField -> {
TemplateCustomFieldRequest templateCustomFieldRequest = new TemplateCustomFieldRequest();
templateCustomFieldRequest.setRequired(true);
templateCustomFieldRequest.setFieldId(customField.getId());
return templateCustomFieldRequest;
}).toList();
baseTemplateCustomFieldService.addByTemplateId(template.getId(), templateCustomFieldRequests);
}
/**
* 初始化缺陷模板
* 创建组织的时候调用初始化组织模板
* 创建项目的时候调用初始化项目模板
* @param scopeId
* @param scopeType
*/
public void initIssueDefaultTemplate(String scopeId, TemplateScopeType scopeType) {
this.initDefaultTemplate(scopeId, "issue_default", scopeType, TemplateScene.ISSUE);
}
public void initApiDefaultTemplate(String scopeId, TemplateScopeType scopeType) {
this.initDefaultTemplate(scopeId, "api_default", scopeType, TemplateScene.API);
}
public void initUiDefaultTemplate(String scopeId, TemplateScopeType scopeType) {
this.initDefaultTemplate(scopeId, "ui_default", scopeType, TemplateScene.UI);
}
public void initTestPlanDefaultTemplate(String scopeId, TemplateScopeType scopeType) {
this.initDefaultTemplate(scopeId, "test_plan_default", scopeType, TemplateScene.TEST_PLAN);
}
public Template initDefaultTemplate(String scopeId, String name, TemplateScopeType scopeType, TemplateScene scene) {
Template template = new Template();
template.setId(UUID.randomUUID().toString());
template.setName(name);
template.setInternal(true);
template.setUpdateTime(System.currentTimeMillis());
template.setCreateTime(System.currentTimeMillis());
template.setCreateUser("admin");
template.setScopeType(scopeType.name());
template.setScopeId(scopeId);
template.setEnableThirdPart(false);
template.setEnableDefault(true);
template.setScene(scene.name());
templateMapper.insert(template);
return template;
}
}

View File

@ -0,0 +1,20 @@
package io.metersphere.system.service;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class CleanupTemplateResourceService implements CleanupProjectResourceService {
@Resource
private BaseTemplateService baseTemplateService;
@Resource
private BaseCustomFieldService baseCustomFieldService;
@Override
public void deleteResources(String projectId) {
baseTemplateService.deleteByScopeId(projectId);
baseCustomFieldService.deleteByScopeId(projectId);
}
@Override
public void cleanReportResources(String projectId) {}
}

View File

@ -0,0 +1,155 @@
package io.metersphere.system.service;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.sdk.dto.request.TemplateCustomFieldRequest;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.domain.CustomField;
import io.metersphere.system.domain.CustomFieldOption;
import io.metersphere.system.domain.Template;
import io.metersphere.system.domain.TemplateCustomField;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class CreateTemplateResourceService implements CreateProjectResourceService {
@Resource
ProjectMapper projectMapper;
@Resource
BaseTemplateCustomFieldService baseTemplateCustomFieldService;
@Resource
BaseTemplateService baseTemplateService;
@Resource
BaseCustomFieldService baseCustomFieldService;
@Resource
BaseCustomFieldOptionService baseCustomFieldOptionService;
@Override
public void createResources(String projectId) {
Project project = projectMapper.selectByPrimaryKey(projectId);
if (project == null) {
return;
}
String organizationId = project.getOrganizationId();
for (TemplateScene scene : TemplateScene.values()) {
if (baseTemplateService.isOrganizationTemplateEnable(organizationId, scene.name())) {
// 如果没有开启项目模板则根据组织模板创建项目模板
// 先创建字段再创建模板
createProjectCustomField(projectId, organizationId, scene);
createProjectTemplate(projectId, organizationId, scene);
} else {
// 开启了项目模板则初始化项目模板和字段
initProjectTemplate(projectId, scene);
}
}
}
/**
* 当开启项目模板后创建项目时初始化项目模板
*
* @param projectId
* @param scene
*/
private void initProjectTemplate(String projectId, TemplateScene scene) {
switch (scene) {
case FUNCTIONAL:
baseTemplateService.initFunctionalDefaultTemplate(projectId, TemplateScopeType.PROJECT);
break;
case ISSUE:
baseTemplateService.initIssueDefaultTemplate(projectId, TemplateScopeType.PROJECT);
break;
case API:
baseTemplateService.initApiDefaultTemplate(projectId, TemplateScopeType.PROJECT);
break;
case UI:
baseTemplateService.initUiDefaultTemplate(projectId, TemplateScopeType.PROJECT);
break;
case TEST_PLAN:
baseTemplateService.initTestPlanDefaultTemplate(projectId, TemplateScopeType.PROJECT);
break;
default:
break;
}
}
/**
* 当没有开启项目模板创建项目时要根据当前组织模板创建项目模板
*
* @param projectId
* @param organizationId
* @param scene
*/
private void createProjectTemplate(String projectId, String organizationId, TemplateScene scene) {
// 同步创建项目级别模板
List<Template> orgTemplates = baseTemplateService.getTemplates(organizationId, scene.name());
List<String> orgTemplateIds = orgTemplates.stream().map(Template::getId).toList();
Map<String, List<TemplateCustomField>> customFieldMap = baseTemplateCustomFieldService.getByTemplateIds(orgTemplateIds)
.stream()
.collect(Collectors.groupingBy(item -> item.getTemplateId()));
orgTemplates.forEach((template) -> {
List<TemplateCustomField> templateCustomFields = customFieldMap.get(template.getId());
templateCustomFields = templateCustomFields == null ? List.of() : templateCustomFields;
List<TemplateCustomFieldRequest> templateCustomFieldRequests = templateCustomFields.stream()
.map(templateCustomField -> BeanUtils.copyBean(new TemplateCustomFieldRequest(), templateCustomField))
.toList();
addRefProjectTemplate(projectId, template, templateCustomFieldRequests);
});
}
/**
* 当没有开启项目模板创建项目时要根据当前组织字段创建项目字段
*
* @param projectId
* @param organizationId
* @param scene
*/
private void createProjectCustomField(String projectId, String organizationId, TemplateScene scene) {
// 查询组织字段和选项
List<CustomField> orgFields = baseCustomFieldService.getByScopeIdAndScene(organizationId, scene.name());
List<String> orgFieldIds = orgFields.stream().map(CustomField::getId).toList();
Map<String, List<CustomFieldOption>> customFieldOptionMap = baseCustomFieldOptionService.getByFieldIds(orgFieldIds)
.stream()
.collect(Collectors.groupingBy(item -> item.getFieldId()));
orgFields.forEach((field) -> {
List<CustomFieldOption> options = customFieldOptionMap.get(field.getId());
addRefProjectCustomField(projectId, field, options);
});
}
/**
* 当没有开启项目模板创建项目时要根据当前组织字段创建项目字段
*
* @param orgCustomField
* @param options
*/
public void addRefProjectCustomField(String projectId, CustomField orgCustomField, List<CustomFieldOption> options) {
CustomField customField = BeanUtils.copyBean(new CustomField(), orgCustomField);
customField.setScopeType(TemplateScopeType.PROJECT.name());
customField.setScopeId(projectId);
customField.setRefId(orgCustomField.getId());
baseCustomFieldService.baseAdd(customField, options);
}
/**
* 当没有开启项目模板创建项目时要根据当前组织模板创建项目模板
*
* @param orgTemplate
* @param customFields
*/
public void addRefProjectTemplate(String projectId, Template orgTemplate, List<TemplateCustomFieldRequest> customFields) {
Template template = BeanUtils.copyBean(new Template(), orgTemplate);
template.setScopeId(projectId);
template.setRefId(orgTemplate.getId());
template.setScopeType(TemplateScopeType.PROJECT.name());
List<TemplateCustomFieldRequest> refCustomFields = baseTemplateService.getRefTemplateCustomFieldRequest(projectId, customFields);
baseTemplateService.baseAdd(template, refCustomFields);
}
}

View File

@ -3,13 +3,22 @@ package io.metersphere.system.service;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.sdk.dto.CustomFieldDTO;
import io.metersphere.sdk.dto.request.CustomFieldOptionRequest;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.SubListUtil;
import io.metersphere.system.domain.CustomField;
import io.metersphere.system.domain.CustomFieldExample;
import io.metersphere.system.domain.CustomFieldOption;
import io.metersphere.system.mapper.BaseProjectMapper;
import io.metersphere.system.mapper.ExtOrganizationCustomFieldMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import static io.metersphere.system.controller.result.SystemResultCode.ORGANIZATION_TEMPLATE_PERMISSION;
/**
* @author jianxing
* @date : 2023-8-29
@ -19,45 +28,127 @@ import java.util.List;
public class OrganizationCustomFieldService extends BaseCustomFieldService {
@Resource
private OrganizationService organizationService;
private BaseProjectMapper baseProjectMapper;
@Resource
private ExtOrganizationCustomFieldMapper extOrganizationCustomFieldMapper;
@Override
public List<CustomField> list(String orgId, String scene) {
organizationService.checkResourceExist(orgId);
OrganizationService.checkResourceExist(orgId);
return super.list(orgId, scene);
}
@Override
public CustomFieldDTO getCustomFieldDTOWithCheck(String id) {
CustomFieldDTO customField = super.getCustomFieldDTOWithCheck(id);
organizationService.checkResourceExist(customField.getScopeId());
OrganizationService.checkResourceExist(customField.getScopeId());
return customField;
}
@Override
public CustomField add(CustomField customField, List<CustomFieldOptionRequest> options) {
// todo 校验是否开启组织模板
// todo 同步创建项目级别模板
organizationService.checkResourceExist(customField.getScopeId());
checkOrganizationTemplateEnable(customField.getScopeId(), customField.getScene());
OrganizationService.checkResourceExist(customField.getScopeId());
customField.setScopeType(TemplateScopeType.ORGANIZATION.name());
return super.add(customField, options);
customField = super.add(customField, options);
// 同步创建项目级别字段
addRefProjectCustomField(customField, options);
return customField;
}
/**
* 同步创建项目级别字段
* 当开启组织模板时操作组织字段同时维护与之关联的项目字段
* 避免当开启项目模板时需要将各个资源关联的模板和字段从组织切换为项目
* 无论是否开启组织模板各资源都只关联各自项目下的模板和字段
*
* @param orgCustomField
* @param options
*/
public void addRefProjectCustomField(CustomField orgCustomField, List<CustomFieldOptionRequest> options) {
String orgId = orgCustomField.getScopeId();
List<String> projectIds = baseProjectMapper.getProjectIdByOrgId(orgId);
CustomField customField = BeanUtils.copyBean(new CustomField(), orgCustomField);
List<CustomFieldOption> customFieldOptions = parseCustomFieldOptionRequest2Option(options);
projectIds.forEach(projectId -> {
customField.setScopeType(TemplateScopeType.PROJECT.name());
customField.setScopeId(projectId);
customField.setRefId(orgCustomField.getId());
super.baseAdd(customField, customFieldOptions);
});
}
@Override
public CustomField update(CustomField customField, List<CustomFieldOptionRequest> options) {
// todo 校验是否开启组织模板
// todo 同步修改项目级别模板
CustomField originCustomField = getWithCheck(customField.getId());
checkOrganizationTemplateEnable(customField.getScopeId(), originCustomField.getScene());
customField.setScopeId(originCustomField.getScopeId());
organizationService.checkResourceExist(originCustomField.getScopeId());
OrganizationService.checkResourceExist(originCustomField.getScopeId());
// 同步创建项目级别字段
updateRefProjectCustomField(customField, options);
return super.update(customField, options);
}
/**
* 同步更新项目级别字段
* 当开启组织模板时操作组织字段同时维护与之关联的项目字段
* 避免当开启项目模板时需要将各个资源关联的模板和字段从组织切换为项目
* 无论是否开启组织模板各资源都只关联各自项目下的模板和字段
*
* @param orgCustomField
* @param options
*/
public void updateRefProjectCustomField(CustomField orgCustomField, List<CustomFieldOptionRequest> options) {
List<CustomField> projectFields = getByRefId(orgCustomField.getId());
CustomField customField = BeanUtils.copyBean(new CustomField(), orgCustomField);
projectFields.forEach(projectField -> {
customField.setId(projectField.getId());
customField.setScopeId(projectField.getScopeId());
customField.setRefId(orgCustomField.getId());
super.update(customField, options);
});
}
public List<CustomField> getByRefId(String refId) {
CustomFieldExample example = new CustomFieldExample();
example.createCriteria().andRefIdEqualTo(refId);
return customFieldMapper.selectByExample(example);
}
@Override
public void delete(String id) {
CustomField customField = getWithCheck(id);
checkOrganizationTemplateEnable(customField.getScopeId(), customField.getScene());
checkInternal(customField);
organizationService.checkResourceExist(customField.getScopeId());
OrganizationService.checkResourceExist(customField.getScopeId());
// 同步删除项目级别字段
deleteRefProjectTemplate(id);
super.delete(id);
}
/**
* 同步删除项目级别字段
* 当开启组织模板时操作组织字段同时维护与之关联的项目字段
* 避免当开启项目模板时需要将各个资源关联的模板和字段从组织切换为项目
* 无论是否开启组织模板各资源都只关联各自项目下的模板和字段
*
* @param orgCustomFieldId
*/
public void deleteRefProjectTemplate(String orgCustomFieldId) {
// 删除关联的项目字段
CustomFieldExample example = new CustomFieldExample();
example.createCriteria().andRefIdEqualTo(orgCustomFieldId);
customFieldMapper.deleteByExample(example);
// 删除字段选项
List<String> projectCustomFieldIds = extOrganizationCustomFieldMapper.getCustomFieldByRefId(orgCustomFieldId);
// 分批删除
SubListUtil.dealForSubList(projectCustomFieldIds, 100, baseCustomFieldOptionService::deleteByFieldIds);
}
private void checkOrganizationTemplateEnable(String orgId, String scene) {
if (!isOrganizationTemplateEnable(orgId, scene)) {
throw new MSException(ORGANIZATION_TEMPLATE_PERMISSION);
}
}
}

View File

@ -9,6 +9,7 @@ import io.metersphere.sdk.dto.OptionDTO;
import io.metersphere.sdk.dto.UserExtend;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.*;
@ -68,6 +69,10 @@ public class OrganizationService {
private PluginOrganizationService pluginOrganizationService;
@Resource
private BaseUserService baseUserService;
@Resource
private BaseTemplateService baseTemplateService;
@Resource
private BaseCustomFieldService baseCustomFieldService;
private static final String ADD_MEMBER_PATH = "/system/organization/add-member";
private static final String REMOVE_MEMBER_PATH = "/system/organization/remove-member";
@ -136,6 +141,10 @@ public class OrganizationService {
// TODO: 删除环境组, 删除定时任务
// 删除组织模板和字段
baseTemplateService.deleteByScopeId(organizationId);
baseCustomFieldService.deleteByScopeId(organizationId);
// 删除组织
organizationMapper.deleteByPrimaryKey(organizationId);
// 操作记录
@ -901,7 +910,13 @@ public class OrganizationService {
return total;
}
public Organization checkResourceExist(String id) {
return ServiceUtils.checkResourceExist(organizationMapper.selectByPrimaryKey(id), "permission.system_organization_project.name");
/**
* 校验组织是否存在
* 这里使用静态方法避免需要注入导致循环依赖
* @param id
* @return
*/
public static Organization checkResourceExist(String id) {
return ServiceUtils.checkResourceExist( CommonBeanFactory.getBean(OrganizationMapper.class).selectByPrimaryKey(id), "permission.system_organization_project.name");
}
}

View File

@ -3,6 +3,7 @@ package io.metersphere.system.service;
import io.metersphere.sdk.constants.OperationLogConstants;
import io.metersphere.sdk.dto.LogDTO;
import io.metersphere.sdk.dto.request.TemplateUpdateRequest;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.sdk.util.JSON;
@ -34,6 +35,23 @@ public class OrganizationTemplateLogService {
return dto;
}
public LogDTO setDefaultTemplateLog(TemplateUpdateRequest request) {
Template template = organizationTemplateService.getWithCheck(request.getId());
LogDTO dto = null;
if (template != null) {
dto = new LogDTO(
OperationLogConstants.ORGANIZATION,
null,
template.getId(),
null,
String.join(Translator.get("set_default_template"), ":", OperationLogType.UPDATE.name()),
OperationLogModule.SETTING_SYSTEM_ORGANIZATION_TEMPLATE,
template.getName());
dto.setOriginalValue(JSON.toJSONBytes(template));
}
return dto;
}
public LogDTO updateLog(TemplateUpdateRequest request) {
Template template = organizationTemplateService.getWithCheck(request.getId());
LogDTO dto = null;

View File

@ -3,13 +3,24 @@ package io.metersphere.system.service;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.sdk.dto.TemplateDTO;
import io.metersphere.sdk.dto.request.TemplateCustomFieldRequest;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.SubListUtil;
import io.metersphere.system.domain.OrganizationParameter;
import io.metersphere.system.domain.Template;
import io.metersphere.system.domain.TemplateExample;
import io.metersphere.system.mapper.BaseProjectMapper;
import io.metersphere.system.mapper.ExtOrganizationTemplateMapper;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import static io.metersphere.system.controller.result.SystemResultCode.ORGANIZATION_TEMPLATE_PERMISSION;
/**
* @author jianxing
* @date : 2023-8-30
@ -19,11 +30,17 @@ import java.util.List;
public class OrganizationTemplateService extends BaseTemplateService {
@Resource
private OrganizationService organizationService;
private BaseProjectMapper baseProjectMapper;
@Resource
private BaseCustomFieldService baseCustomFieldService;
@Resource
protected ExtOrganizationTemplateMapper extOrganizationTemplateMapper;
@Resource
protected BaseOrganizationParameterService baseOrganizationParameterService;
@Override
public List<Template> list(String organizationId, String scene) {
organizationService.checkResourceExist(organizationId);
OrganizationService.checkResourceExist(organizationId);
return super.list(organizationId, scene);
}
@ -36,29 +53,156 @@ public class OrganizationTemplateService extends BaseTemplateService {
@Override
public Template add(Template template, List<TemplateCustomFieldRequest> customFields) {
checkOrgResourceExist(template);
// todo 校验是否开启组织模板
// todo 同步创建项目级别模板
checkOrganizationTemplateEnable(template.getScopeId(), template.getScene());
template.setScopeType(TemplateScopeType.ORGANIZATION.name());
return super.add(template, customFields);
template.setRefId(null);
template = super.add(template, customFields);
// 同步创建项目级别模板
addRefProjectTemplate(template, customFields);
return template;
}
/**
* 同步创建项目级别模板
* 当开启组织模板时操作组织模板同时维护与之关联的项目模板
* 避免当开启项目模板时需要将各个资源关联的模板和字段从组织切换为项目
* 无论是否开启组织模板各资源都只关联各自项目下的模板和字段
*
* @param orgTemplate
* @param customFields
*/
public void addRefProjectTemplate(Template orgTemplate, List<TemplateCustomFieldRequest> customFields) {
String orgId = orgTemplate.getScopeId();
List<String> projectIds = baseProjectMapper.getProjectIdByOrgId(orgId);
Template template = BeanUtils.copyBean(new Template(), orgTemplate);
projectIds.forEach(projectId -> {
template.setScopeId(projectId);
template.setRefId(orgTemplate.getId());
template.setScopeType(TemplateScopeType.PROJECT.name());
List<TemplateCustomFieldRequest> refCustomFields = getRefTemplateCustomFieldRequest(projectId, customFields);
super.baseAdd(template, refCustomFields);
});
}
public void checkOrgResourceExist(Template template) {
organizationService.checkResourceExist(template.getScopeId());
OrganizationService.checkResourceExist(template.getScopeId());
}
@Override
public Template update(Template template, List<TemplateCustomFieldRequest> customFields) {
Template originTemplate = super.getWithCheck(template.getId());
checkOrganizationTemplateEnable(originTemplate.getScopeId(), originTemplate.getScene());
template.setScopeId(originTemplate.getScopeId());
checkOrgResourceExist(originTemplate);
updateRefProjectTemplate(template, customFields);
template.setRefId(null);
return super.update(template, customFields);
}
/**
* 同步更新项目级别模板
* 当开启组织模板时操作组织模板同时维护与之关联的项目模板
* 避免当开启项目模板时需要将各个资源关联的模板和字段从组织切换为项目
* 无论是否开启组织模板各资源都只关联各自项目下的模板和字段
*
* @param orgTemplate
* @param customFields
*/
public void updateRefProjectTemplate(Template orgTemplate, List<TemplateCustomFieldRequest> customFields) {
List<Template> projectTemplates = getByRefId(orgTemplate.getId());
Template template = BeanUtils.copyBean(new Template(), orgTemplate);
projectTemplates.forEach(projectTemplate -> {
template.setId(projectTemplate.getId());
template.setScopeId(projectTemplate.getScopeId());
template.setRefId(orgTemplate.getId());
List<TemplateCustomFieldRequest> refCustomFields = getRefTemplateCustomFieldRequest(projectTemplate.getScopeId(), customFields);
super.update(template, refCustomFields);
});
}
public List<Template> getByRefId(String refId) {
TemplateExample example = new TemplateExample();
example.createCriteria().andRefIdEqualTo(refId);
return templateMapper.selectByExample(example);
}
@Override
public void delete(String id) {
this.getWithCheck(id);
Template template = getWithCheck(id);
checkInternal(template);
checkOrganizationTemplateEnable(template.getScopeId(), template.getScene());
deleteRefProjectTemplate(id);
super.delete(id);
}
/**
* 将模板设置成默认模板
* 同时将其他没模板设置成非默认模板
*
* @param id
*/
@Override
public void setDefaultTemplate(String id) {
Template template = getWithCheck(id);
checkOrganizationTemplateEnable(template.getScopeId(), template.getScene());
setRefDefaultTemplate(id);
super.setDefaultTemplate(id);
}
/**
* 同步设置项目级别模板
* 当开启组织模板时操作组织模板同时维护与之关联的项目模板
* 避免当开启项目模板时需要将各个资源关联的模板和字段从组织切换为项目
* 无论是否开启组织模板各资源都只关联各自项目下的模板和字段
*
* @param id
*/
private void setRefDefaultTemplate(String id) {
getByRefId(id).stream()
.map(Template::getId)
.forEach(super::setDefaultTemplate);
}
/**
* 同步删除项目级别模板
* 当开启组织模板时操作组织模板同时维护与之关联的项目模板
* 避免当开启项目模板时需要将各个资源关联的模板和字段从组织切换为项目
* 无论是否开启组织模板各资源都只关联各自项目下的模板和字段
*
* @param orgTemplateId
*/
public void deleteRefProjectTemplate(String orgTemplateId) {
// 删除关联的项目模板
TemplateExample example = new TemplateExample();
example.createCriteria().andRefIdEqualTo(orgTemplateId);
templateMapper.deleteByExample(example);
// 删除项目模板和字段的关联关系
List<String> projectTemplateIds = extOrganizationTemplateMapper.getTemplateIdByRefId(orgTemplateId);
// 分批删除
SubListUtil.dealForSubList(projectTemplateIds, 100, baseTemplateCustomFieldService::deleteByTemplateIds);
}
private void checkOrganizationTemplateEnable(String orgId, String scene) {
if (!isOrganizationTemplateEnable(orgId, scene)) {
throw new MSException(ORGANIZATION_TEMPLATE_PERMISSION);
}
}
/**
* 禁用组织模板即启用项目模板
* 启用后添加组织级别的系统参数
* 启用后不可逆只添加一次
*
* @param orgId
* @param scene
*/
public void disableOrganizationTemplate(String orgId, String scene) {
if (StringUtils.isBlank(baseOrganizationParameterService.getValue(orgId, scene))) {
OrganizationParameter organizationParameter = new OrganizationParameter();
organizationParameter.setOrganizationId(orgId);
organizationParameter.setParamKey(baseOrganizationParameterService.getOrgTemplateEnableKeyByScene(scene));
organizationParameter.setParamValue(BooleanUtils.toStringTrueFalse(false));
baseOrganizationParameterService.add(organizationParameter);
}
}
}

View File

@ -291,6 +291,10 @@
},
{
"id": "ORGANIZATION_TEMPLATE:READ+DELETE"
},
{
"id": "ORGANIZATION_TEMPLATE:READ+ENABLE",
"name": "permission.system_organization_template.enable"
}
]
},

View File

@ -100,6 +100,7 @@
<table tableName="template_custom_field"/>
<table tableName="status_item"/>
<table tableName="status_definition"/>
<table tableName="organization_parameter"/>
<!-- 要忽略的字段-->
<!-- <table tableName="test_case">

View File

@ -1,25 +1,26 @@
package io.metersphere.system.controller;
import io.metersphere.project.domain.Project;
import io.metersphere.project.domain.ProjectExample;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.*;
import io.metersphere.system.base.BaseTest;
import io.metersphere.sdk.constants.CustomFieldType;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.sdk.dto.CustomFieldDTO;
import io.metersphere.sdk.dto.request.CustomFieldOptionRequest;
import io.metersphere.sdk.dto.request.CustomFieldUpdateRequest;
import io.metersphere.system.domain.*;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.OrganizationParameterMapper;
import io.metersphere.system.service.BaseCustomFieldOptionService;
import io.metersphere.system.service.BaseCustomFieldService;
import io.metersphere.system.service.BaseUserService;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.controller.param.CustomFieldUpdateRequestDefinition;
import io.metersphere.system.domain.CustomField;
import io.metersphere.system.domain.CustomFieldExample;
import io.metersphere.system.domain.CustomFieldOption;
import io.metersphere.system.mapper.CustomFieldMapper;
import io.metersphere.system.service.OrganizationCustomFieldService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
@ -32,6 +33,7 @@ import java.util.Map;
import static io.metersphere.sdk.constants.InternalUserRole.ADMIN;
import static io.metersphere.system.controller.handler.result.CommonResultCode.*;
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
import static io.metersphere.system.controller.result.SystemResultCode.ORGANIZATION_TEMPLATE_PERMISSION;
/**
* @author jianxing
@ -53,6 +55,12 @@ public class OrganizationCustomFieldControllerTests extends BaseTest {
private BaseCustomFieldService baseCustomFieldService;
@Resource
private BaseUserService baseUserService;
@Resource
private OrganizationParameterMapper organizationParameterMapper;
@Resource
private ProjectMapper projectMapper;
@Resource
private OrganizationCustomFieldService organizationCustomFieldService;
private static CustomField addCustomField;
private static CustomField anotherAddCustomField;
@ -105,6 +113,12 @@ public class OrganizationCustomFieldControllerTests extends BaseTest {
Assertions.assertEquals(false, optionItem.getInternal());
Assertions.assertEquals(customField.getId(), optionItem.getFieldId());
}
asserRefCustomField(customField);
// @校验是否开启组织模板
changeOrgTemplateEnable(false);
assertErrorCode(this.requestPost(DEFAULT_ADD, request), ORGANIZATION_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(true);
// @@重名校验异常
assertErrorCode(this.requestPost(DEFAULT_ADD, request), CUSTOM_FIELD_EXIST);
@ -162,6 +176,12 @@ public class OrganizationCustomFieldControllerTests extends BaseTest {
Assertions.assertEquals(false, optionItem.getInternal());
Assertions.assertEquals(customField.getId(), optionItem.getFieldId());
}
asserRefCustomField(customField);
// @校验是否开启组织模板
changeOrgTemplateEnable(false);
assertErrorCode(this.requestPost(DEFAULT_UPDATE, request), ORGANIZATION_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(true);
// @@重名校验异常
request.setName(anotherAddCustomField.getName());
@ -234,6 +254,11 @@ public class OrganizationCustomFieldControllerTests extends BaseTest {
@Test
@Order(5)
public void delete() throws Exception {
// @校验是否开启组织模板
changeOrgTemplateEnable(false);
assertErrorCode(this.requestGet(DEFAULT_DELETE, addCustomField.getId()), ORGANIZATION_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(true);
// @@请求成功
this.requestGetWithOk(DEFAULT_DELETE, addCustomField.getId());
Assertions.assertNull(customFieldMapper.selectByPrimaryKey(addCustomField.getId()));
@ -254,4 +279,51 @@ public class OrganizationCustomFieldControllerTests extends BaseTest {
// @@校验权限
requestGetPermissionTest(PermissionConstants.ORGANIZATION_CUSTOM_FIELD_DELETE, DEFAULT_DELETE, addCustomField.getId());
}
/**
* 校验变更组织字段时有没有同步变更项目字段
*/
private void asserRefCustomField(CustomField customField) {
List<CustomField> refFields = organizationCustomFieldService.getByRefId(customField.getId());
List<Project> orgProjects = getProjectByOrgId(customField.getScopeId());
// 校验所有项目下是否都有同步变更
Assertions.assertEquals(getCustomFieldByScopeId(customField.getScopeId()).size(),
getCustomFieldByScopeId(orgProjects.get(0).getId()).size() * orgProjects.size());
refFields.forEach(refField -> {
Assertions.assertEquals(refField.getScene(), customField.getScene());
Assertions.assertEquals(refField.getRemark(), customField.getRemark());
Assertions.assertEquals(refField.getName(), customField.getName());
Assertions.assertEquals(refField.getInternal(), customField.getInternal());
Assertions.assertEquals(refField.getCreateUser(), customField.getCreateUser());
Assertions.assertEquals(refField.getType(), customField.getType());
Assertions.assertEquals(refField.getScopeType(), TemplateScopeType.PROJECT.name());
});
}
private List<Project> getProjectByOrgId(String orgId) {
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andOrganizationIdEqualTo(orgId);
return projectMapper.selectByExample(projectExample);
}
private List<CustomField> getCustomFieldByScopeId(String scopeId) {
CustomFieldExample example = new CustomFieldExample();
example.createCriteria().andScopeIdEqualTo(scopeId);
return customFieldMapper.selectByExample(example);
}
private void changeOrgTemplateEnable(boolean enable) {
if (enable) {
organizationParameterMapper.deleteByPrimaryKey(DEFAULT_ORGANIZATION_ID, OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY);
} else {
OrganizationParameter organizationParameter = new OrganizationParameter();
organizationParameter.setOrganizationId(DEFAULT_ORGANIZATION_ID);
organizationParameter.setParamKey(OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY);
organizationParameter.setParamValue(BooleanUtils.toStringTrueFalse(false));
if (organizationParameterMapper.selectByPrimaryKey(DEFAULT_ORGANIZATION_ID,
OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY) == null) {
organizationParameterMapper.insert(organizationParameter);
}
}
}
}

View File

@ -1,6 +1,7 @@
package io.metersphere.system.controller;
import io.metersphere.system.base.BaseTest;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.OrganizationParameterConstants;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.sdk.constants.TemplateScopeType;
@ -8,20 +9,17 @@ import io.metersphere.sdk.dto.TemplateCustomFieldDTO;
import io.metersphere.sdk.dto.TemplateDTO;
import io.metersphere.sdk.dto.request.TemplateCustomFieldRequest;
import io.metersphere.sdk.dto.request.TemplateUpdateRequest;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.service.BaseCustomFieldService;
import io.metersphere.system.service.BaseTemplateCustomFieldService;
import io.metersphere.system.service.BaseTemplateService;
import io.metersphere.system.service.BaseUserService;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.param.TemplateUpdateRequestDefinition;
import io.metersphere.system.domain.CustomField;
import io.metersphere.system.domain.Template;
import io.metersphere.system.domain.TemplateCustomField;
import io.metersphere.system.domain.TemplateExample;
import io.metersphere.system.domain.*;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.OrganizationParameterMapper;
import io.metersphere.system.mapper.TemplateMapper;
import io.metersphere.system.service.*;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
@ -34,6 +32,7 @@ import java.util.Map;
import static io.metersphere.sdk.constants.InternalUserRole.ADMIN;
import static io.metersphere.system.controller.handler.result.CommonResultCode.*;
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
import static io.metersphere.system.controller.result.SystemResultCode.ORGANIZATION_TEMPLATE_PERMISSION;
/**
* @author jianxing
@ -45,6 +44,8 @@ import static io.metersphere.system.controller.handler.result.MsHttpResultCode.N
public class OrganizationTemplateControllerTests extends BaseTest {
private static final String BASE_PATH = "/organization/template/";
private static final String LIST = "list/{0}/{1}";
private static final String DISABLE_ORG_TEMPLATE = "disable/{0}/{1}";
private static final String SET_DEFAULT = "set-default/{0}";
@Resource
private TemplateMapper templateMapper;
@ -56,9 +57,18 @@ public class OrganizationTemplateControllerTests extends BaseTest {
private BaseCustomFieldService baseCustomFieldService;
@Resource
private BaseTemplateCustomFieldService baseTemplateCustomFieldService;
@Resource
private OrganizationParameterMapper organizationParameterMapper;
@Resource
private BaseOrganizationParameterService organizationParameterService;
@Resource
private OrganizationTemplateService organizationTemplateService;
@Resource
private ProjectMapper projectMapper;
private static Template addTemplate;
private static Template anotherTemplateField;
private static Template defaultTemplate;
@Override
protected String getBasePath() {
@ -69,7 +79,9 @@ public class OrganizationTemplateControllerTests extends BaseTest {
@Order(0)
public void listEmpty() throws Exception {
// @@校验没有数据的情况
this.requestGetWithOk(LIST, DEFAULT_ORGANIZATION_ID, TemplateScene.UI.name());
MvcResult mvcResult = this.requestGetWithOkAndReturn(LIST, DEFAULT_ORGANIZATION_ID, TemplateScene.FUNCTIONAL.name());
List<Template> templates = getResultDataArray(mvcResult, Template.class);
this.defaultTemplate = templates.get(0);
}
@Test
@ -100,10 +112,17 @@ public class OrganizationTemplateControllerTests extends BaseTest {
Assertions.assertEquals(template.getInternal(), false);
Assertions.assertEquals(template.getScopeType(), TemplateScopeType.ORGANIZATION.name());
asserTemplateCustomFields(request, template);
asserRefTemplate(template);
// @@重名校验异常
assertErrorCode(this.requestPost(DEFAULT_ADD, request), TEMPLATE_EXIST);
// @校验是否开启组织模板
request.setName("test1");
changeOrgTemplateEnable(false);
assertErrorCode(this.requestPost(DEFAULT_ADD, request), ORGANIZATION_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(true);
// @@校验组织是否存在
request.setScopeId("1111");
request.setName("test1");
@ -122,6 +141,45 @@ public class OrganizationTemplateControllerTests extends BaseTest {
requestPostPermissionTest(PermissionConstants.ORGANIZATION_TEMPLATE_ADD, DEFAULT_ADD, request);
}
/**
* 校验变更组织模板时有没有同步变更项目模板
*
* @param template
*/
private void asserRefTemplate(Template template) {
List<Template> refTemplates = organizationTemplateService.getByRefId(template.getId());
refTemplates.forEach(refTemplate -> {
Assertions.assertEquals(refTemplate.getEnableThirdPart(), template.getEnableThirdPart());
Assertions.assertEquals(refTemplate.getScene(), template.getScene());
Assertions.assertEquals(refTemplate.getRemark(), template.getRemark());
Assertions.assertEquals(refTemplate.getName(), template.getName());
Assertions.assertEquals(refTemplate.getInternal(), template.getInternal());
Assertions.assertEquals(refTemplate.getCreateUser(), template.getCreateUser());
Assertions.assertEquals(refTemplate.getScopeType(), TemplateScopeType.PROJECT.name());
});
}
private List<Template> getTemplateByScopeId(String scopeId) {
TemplateExample example = new TemplateExample();
example.createCriteria().andScopeIdEqualTo(scopeId);
return templateMapper.selectByExample(example);
}
private void changeOrgTemplateEnable(boolean enable) {
if (enable) {
organizationParameterMapper.deleteByPrimaryKey(DEFAULT_ORGANIZATION_ID, OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY);
} else {
OrganizationParameter organizationParameter = new OrganizationParameter();
organizationParameter.setOrganizationId(DEFAULT_ORGANIZATION_ID);
organizationParameter.setParamKey(OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY);
organizationParameter.setParamValue(BooleanUtils.toStringTrueFalse(false));
if (organizationParameterMapper.selectByPrimaryKey(DEFAULT_ORGANIZATION_ID,
OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY) == null) {
organizationParameterMapper.insert(organizationParameter);
}
}
}
private void asserTemplateCustomFields(TemplateUpdateRequest request, Template template) {
List<TemplateCustomField> templateCustomFields = baseTemplateCustomFieldService.getByTemplateId(template.getId());
Assertions.assertEquals(templateCustomFields.size(), request.getCustomFields().size());
@ -177,6 +235,7 @@ public class OrganizationTemplateControllerTests extends BaseTest {
Assertions.assertEquals(template.getScene(), scene);
Assertions.assertEquals(template.getEnableThirdPart(), request.getEnableThirdPart());
asserTemplateCustomFields(request, template);
asserRefTemplate(template);
// 带字段的更新
TemplateCustomFieldRequest templateCustomFieldRequest = getTemplateCustomFieldRequest(scene);
@ -189,6 +248,11 @@ public class OrganizationTemplateControllerTests extends BaseTest {
this.requestPostWithOk(DEFAULT_UPDATE, request);
Assertions.assertEquals(baseTemplateCustomFieldService.getByTemplateId(template.getId()).size(), 1);
// @校验是否开启组织模板
changeOrgTemplateEnable(false);
assertErrorCode(this.requestPost(DEFAULT_UPDATE, request), ORGANIZATION_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(true);
// @@重名校验异常
request.setName(anotherTemplateField.getName());
assertErrorCode(this.requestPost(DEFAULT_UPDATE, request), TEMPLATE_EXIST);
@ -268,15 +332,90 @@ public class OrganizationTemplateControllerTests extends BaseTest {
@Test
@Order(5)
public void disableOrganizationTemplate() throws Exception {
// @@请求成功
this.requestGetWithOk(DISABLE_ORG_TEMPLATE, addTemplate.getScopeId(), addTemplate.getScene());
String value = organizationParameterService.getValue(addTemplate.getScopeId(),
organizationParameterService.getOrgTemplateEnableKeyByScene(addTemplate.getScene()));
Assertions.assertEquals(value, BooleanUtils.toStringTrueFalse(false));
// 将数据改回来
changeOrgTemplateEnable(true);
// 提高覆盖率
this.requestGetWithOk(DISABLE_ORG_TEMPLATE, addTemplate.getScopeId(), addTemplate.getScene());
// todo @@校验日志
// checkLog(addTemplate.getId(), OperationLogType.DELETE);
// @@校验权限
requestGetPermissionTest(PermissionConstants.ORGANIZATION_TEMPLATE_ENABLE, DISABLE_ORG_TEMPLATE, addTemplate.getScopeId(), addTemplate.getScene());
}
@Test
@Order(6)
public void setDefaultTemplate() throws Exception {
changeOrgTemplateEnable(true);
// @@请求成功
this.requestGetWithOk(SET_DEFAULT, addTemplate.getId());
Template template = templateMapper.selectByPrimaryKey(addTemplate.getId());
assertSetDefaultTemplate(template);
asserRefSetDefaultTemplate(template);
// @校验是否开启组织模板
changeOrgTemplateEnable(false);
assertErrorCode(this.requestGet(SET_DEFAULT, addTemplate.getId()), ORGANIZATION_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(true);
// @@校验日志
checkLog(addTemplate.getId(), OperationLogType.UPDATE);
// @@校验权限
requestGetPermissionTest(PermissionConstants.ORGANIZATION_TEMPLATE_UPDATE, SET_DEFAULT, addTemplate.getScopeId(), addTemplate.getScene());
}
private void assertSetDefaultTemplate(Template template) {
Assertions.assertTrue(template.getEnableDefault());
int defaultCount = getTemplateByScopeId(addTemplate.getScopeId())
.stream()
.filter(Template::getEnableDefault)
.toList().size();
Assertions.assertEquals(defaultCount, 1);
}
/**
* 校验变更组织模板时有没有同步变更项目模板
*
* @param template
*/
private void asserRefSetDefaultTemplate(Template template) {
List<Template> refTemplates = organizationTemplateService.getByRefId(template.getId());
refTemplates.forEach(this::assertSetDefaultTemplate);
}
@Test
@Order(7)
public void delete() throws Exception {
// @校验是否开启组织模板
changeOrgTemplateEnable(false);
assertErrorCode(this.requestGet(DEFAULT_DELETE, addTemplate.getId()), ORGANIZATION_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(true);
// @@校验删除默认模板
assertErrorCode(this.requestGet(DEFAULT_DELETE, addTemplate.getId()), DEFAULT_TEMPLATE_PERMISSION);
// 设置回来保证正常删除
this.requestGetWithOk(SET_DEFAULT, defaultTemplate.getId());
// @@请求成功
this.requestGetWithOk(DEFAULT_DELETE, addTemplate.getId());
Assertions.assertNull(templateMapper.selectByPrimaryKey(addTemplate.getId()));
Assertions.assertTrue(CollectionUtils.isEmpty(baseTemplateCustomFieldService.getByTemplateId(addTemplate.getId())));
// 校验是否同步删除了项目模板
Assertions.assertTrue(CollectionUtils.isEmpty(organizationTemplateService.getByRefId(addTemplate.getId())));
// @@校验内置模板删除异常
TemplateExample example = new TemplateExample();
example.createCriteria()
.andScopeTypeEqualTo(TemplateScopeType.ORGANIZATION.name())
.andInternalEqualTo(true);
Template internalTemplate = templateMapper.selectByExample(example).get(0);
assertErrorCode(this.requestGet(DEFAULT_DELETE, internalTemplate.getId()), INTERNAL_TEMPLATE_PERMISSION);

View File

@ -6,27 +6,30 @@ import io.metersphere.project.domain.ProjectTestResourcePool;
import io.metersphere.project.domain.ProjectTestResourcePoolExample;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.project.mapper.ProjectTestResourcePoolMapper;
import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.dto.UserExtend;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Pager;
import io.metersphere.system.base.BaseTest;
import io.metersphere.sdk.constants.InternalUserRole;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.sdk.dto.*;
import io.metersphere.system.domain.*;
import io.metersphere.system.dto.AddProjectRequest;
import io.metersphere.system.dto.ProjectDTO;
import io.metersphere.system.dto.UpdateProjectRequest;
import io.metersphere.system.job.CleanProjectJob;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Pager;
import io.metersphere.system.domain.User;
import io.metersphere.system.domain.UserRoleRelation;
import io.metersphere.system.domain.UserRoleRelationExample;
import io.metersphere.system.mapper.OrganizationParameterMapper;
import io.metersphere.system.mapper.UserMapper;
import io.metersphere.system.mapper.UserRoleRelationMapper;
import io.metersphere.system.request.ProjectAddMemberRequest;
import io.metersphere.system.request.ProjectMemberRequest;
import io.metersphere.system.request.ProjectRequest;
import io.metersphere.system.service.BaseCustomFieldService;
import io.metersphere.system.service.BaseTemplateService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@ -82,6 +85,14 @@ public class SystemProjectControllerTests extends BaseTest {
private UserMapper userMapper;
@Resource
private ProjectTestResourcePoolMapper projectTestResourcePoolMapper;
@Resource
private BaseTemplateService baseTemplateService;
@Resource
private BaseCustomFieldService baseCustomFieldService;
@Resource
private OrganizationParameterMapper organizationParameterMapper;
@Resource
private CleanProjectJob cleanProjectJob;
private void requestPost(String url, Object param, ResultMatcher resultMatcher) throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post(url)
@ -180,7 +191,7 @@ public class SystemProjectControllerTests extends BaseTest {
config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED),
executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
public void testAddProjectSuccess() throws Exception {
AddProjectRequest project = this.generatorAdd("organizationId","name", "description", true, List.of("admin"));
AddProjectRequest project = this.generatorAdd(DEFAULT_ORGANIZATION_ID,"name", "description", true, List.of("admin"));
MvcResult mvcResult = this.responsePost(addProject, project);
ProjectDTO result = parseObjectFromMvcResult(mvcResult, ProjectDTO.class);
ProjectExample projectExample = new ProjectExample();
@ -196,15 +207,20 @@ public class SystemProjectControllerTests extends BaseTest {
userRoleRelationExample.createCriteria().andSourceIdEqualTo(projectId).andRoleIdEqualTo(InternalUserRole.PROJECT_ADMIN.getValue());
List<UserRoleRelation> userRoleRelations = userRoleRelationMapper.selectByExample(userRoleRelationExample);
Assertions.assertTrue(userRoleRelations.stream().map(UserRoleRelation::getUserId).toList().contains("admin"));
userRoleRelationExample.createCriteria().andSourceIdEqualTo("organizationId").andRoleIdEqualTo(InternalUserRole.ORG_MEMBER.getValue());
userRoleRelationExample.createCriteria().andSourceIdEqualTo(DEFAULT_ORGANIZATION_ID).andRoleIdEqualTo(InternalUserRole.ORG_MEMBER.getValue());
userRoleRelations = userRoleRelationMapper.selectByExample(userRoleRelationExample);
Assertions.assertTrue(userRoleRelations.stream().map(UserRoleRelation::getUserId).toList().contains("admin"));
Project currentProject = projectMapper.selectByPrimaryKey(projectId);
Assertions.assertNull(currentProject.getModuleSetting());
// 项目模板未启用时校验是否创建了项目模板
assertionsRefTemplateCreate(projectId);
//userId为空的时候
project = this.generatorAdd("organizationId","userIdIsNull", "description", true, new ArrayList<>());
project = this.generatorAdd(DEFAULT_ORGANIZATION_ID,"userIdIsNull", "description", true, new ArrayList<>());
// 开启项目模板
changeOrgTemplateEnable(false);
mvcResult = this.responsePost(addProject, project);
changeOrgTemplateEnable(true);
result = parseObjectFromMvcResult(mvcResult, ProjectDTO.class);
projectExample = new ProjectExample();
projectExample.createCriteria().andOrganizationIdEqualTo(project.getOrganizationId()).andNameEqualTo(project.getName());
@ -219,11 +235,13 @@ public class SystemProjectControllerTests extends BaseTest {
userRoleRelationExample.createCriteria().andSourceIdEqualTo(projectId).andRoleIdEqualTo(InternalUserRole.PROJECT_ADMIN.getValue());
userRoleRelations = userRoleRelationMapper.selectByExample(userRoleRelationExample);
Assertions.assertTrue(userRoleRelations.stream().map(UserRoleRelation::getUserId).toList().contains("admin"));
userRoleRelationExample.createCriteria().andSourceIdEqualTo("organizationId").andRoleIdEqualTo(InternalUserRole.ORG_MEMBER.getValue());
userRoleRelationExample.createCriteria().andSourceIdEqualTo(DEFAULT_ORGANIZATION_ID).andRoleIdEqualTo(InternalUserRole.ORG_MEMBER.getValue());
userRoleRelations = userRoleRelationMapper.selectByExample(userRoleRelationExample);
Assertions.assertTrue(userRoleRelations.stream().map(UserRoleRelation::getUserId).toList().contains("admin"));
currentProject = projectMapper.selectByPrimaryKey(projectId);
Assertions.assertNull(currentProject.getModuleSetting());
// 项目模板开启时校验是否初始化了项目模板
assertionsInitTemplate(projectId);
//设置了模块模版
List<String> moduleIds = new ArrayList<>();
@ -246,7 +264,7 @@ public class SystemProjectControllerTests extends BaseTest {
userRoleRelationExample.createCriteria().andSourceIdEqualTo(projectId).andRoleIdEqualTo(InternalUserRole.PROJECT_ADMIN.getValue());
userRoleRelations = userRoleRelationMapper.selectByExample(userRoleRelationExample);
Assertions.assertTrue(userRoleRelations.stream().map(UserRoleRelation::getUserId).toList().contains("admin"));
userRoleRelationExample.createCriteria().andSourceIdEqualTo("organizationId").andRoleIdEqualTo(InternalUserRole.ORG_MEMBER.getValue());
userRoleRelationExample.createCriteria().andSourceIdEqualTo(DEFAULT_ORGANIZATION_ID).andRoleIdEqualTo(InternalUserRole.ORG_MEMBER.getValue());
userRoleRelations = userRoleRelationMapper.selectByExample(userRoleRelationExample);
Assertions.assertTrue(userRoleRelations.stream().map(UserRoleRelation::getUserId).toList().contains("admin"));
currentProject = projectMapper.selectByPrimaryKey(projectId);
@ -272,34 +290,114 @@ public class SystemProjectControllerTests extends BaseTest {
List<ProjectTestResourcePool> projectTestResourcePools = projectTestResourcePoolMapper.selectByExample(projectTestResourcePoolExample);
Assertions.assertTrue(projectTestResourcePools.stream().map(ProjectTestResourcePool::getTestResourcePoolId).toList().contains("resourcePoolId"));
project.setName("testAddProjectSuccess1");
// @@校验权限
requestPostPermissionTest(PermissionConstants.SYSTEM_ORGANIZATION_PROJECT_READ_ADD, addProject, project);
}
public void assertionsRefTemplateCreate(String projectId) {
Project project = projectMapper.selectByPrimaryKey(projectId);
// 校验是否初始化了项目字段
List<CustomField> orgFields = baseCustomFieldService.getByScopeId(project.getOrganizationId());
List<CustomField> projectFields = baseCustomFieldService.getByScopeId(projectId);
Assertions.assertEquals(orgFields.size(), projectFields.size());
orgFields.forEach(orgField -> {
CustomField projectField = projectFields.stream()
.filter(field -> StringUtils.equals(field.getRefId(), orgField.getId()))
.findFirst()
.get();
CustomField copyField = BeanUtils.copyBean(new CustomField(), orgField);
copyField.setId(projectField.getId());
copyField.setScopeId(projectId);
copyField.setScopeType(TemplateScopeType.PROJECT.name());
copyField.setCreateTime(projectField.getCreateTime());
copyField.setUpdateTime(projectField.getUpdateTime());
copyField.setRefId(orgField.getId());
Assertions.assertEquals(copyField, projectField);
});
// 校验是否初始化了项目模板
List<Template> orgTemplates = baseTemplateService.getByScopeId(project.getOrganizationId());
List<Template> projectTemplates = baseTemplateService.getByScopeId(projectId);
Assertions.assertEquals(orgTemplates.size(), projectTemplates.size());
orgTemplates.forEach(orgTemplate -> {
Template projectTemplate = projectTemplates.stream()
.filter(template -> StringUtils.equals(template.getRefId(), orgTemplate.getId()))
.findFirst()
.get();
Template copyTemplate = BeanUtils.copyBean(new Template(), orgTemplate);
copyTemplate.setId(projectTemplate.getId());
copyTemplate.setScopeId(projectId);
copyTemplate.setScopeType(TemplateScopeType.PROJECT.name());
copyTemplate.setUpdateTime(projectTemplate.getUpdateTime());
copyTemplate.setCreateTime(projectTemplate.getCreateTime());
copyTemplate.setRefId(orgTemplate.getId());
Assertions.assertEquals(copyTemplate, projectTemplate);
});
}
public void assertionsInitTemplate(String projectId) {
Project project = projectMapper.selectByPrimaryKey(projectId);
// 校验是否初始化了项目字段
List<CustomField> fields = baseCustomFieldService.getByScopeId(project.getId());
Assertions.assertEquals(fields.size(), DefaultFunctionalCustomField.values().length);
for (DefaultFunctionalCustomField value : DefaultFunctionalCustomField.values()) {
CustomField customField = fields.stream()
.filter(field -> StringUtils.equals(field.getName(), value.getName()))
.findFirst().get();
Assertions.assertEquals(customField.getType(), value.getType().name());
}
// 校验是否初始化了项目模板
List<Template> templates = baseTemplateService.getByScopeId(project.getId());
Assertions.assertEquals(templates.size(), TemplateScene.values().length);
for (TemplateScene scene : TemplateScene.values()) {
Template template = templates.stream()
.filter(field -> StringUtils.equals(field.getScene(), scene.name()))
.findFirst().get();
Assertions.assertNotNull(template);
}
}
private void changeOrgTemplateEnable(boolean enable) {
if (enable) {
organizationParameterMapper.deleteByPrimaryKey(DEFAULT_ORGANIZATION_ID, OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY);
} else {
OrganizationParameter organizationParameter = new OrganizationParameter();
organizationParameter.setOrganizationId(DEFAULT_ORGANIZATION_ID);
organizationParameter.setParamKey(OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY);
organizationParameter.setParamValue(BooleanUtils.toStringTrueFalse(false));
if (organizationParameterMapper.selectByPrimaryKey(DEFAULT_ORGANIZATION_ID,
OrganizationParameterConstants.ORGANIZATION_FUNCTIONAL_TEMPLATE_ENABLE_KEY) == null) {
organizationParameterMapper.insert(organizationParameter);
}
}
}
@Test
@Order(2)
/**
* 测试添加项目失败的用例
*/
public void testAddProjectError() throws Exception {
AddProjectRequest project = this.generatorAdd("organizationId","nameError", "description", true, List.of("admin"));
AddProjectRequest project = this.generatorAdd(DEFAULT_ORGANIZATION_ID,"nameError", "description", true, List.of("admin"));
this.responsePost(addProject, project);
//项目名称存在 500
project = this.generatorAdd("organizationId","nameError", "description", true, List.of("admin"));
project = this.generatorAdd(DEFAULT_ORGANIZATION_ID,"nameError", "description", true, List.of("admin"));
this.requestPost(addProject, project, ERROR_REQUEST_MATCHER);
//参数组织Id为空
project = this.generatorAdd(null, null, null, true, List.of("admin"));
this.requestPost(addProject, project, BAD_REQUEST_MATCHER);
//项目名称为空
project = this.generatorAdd("organizationId", null, null, true, List.of("admin"));
project = this.generatorAdd(DEFAULT_ORGANIZATION_ID, null, null, true, List.of("admin"));
this.requestPost(addProject, project, BAD_REQUEST_MATCHER);
//项目成员在系统中不存在
project = this.generatorAdd("organizationId", "name", null, true, List.of("admin", "admin1", "admin3"));
project = this.generatorAdd(DEFAULT_ORGANIZATION_ID, "name", null, true, List.of("admin", "admin1", "admin3"));
this.requestPost(addProject, project, ERROR_REQUEST_MATCHER);
//资源池不存在
project = this.generatorAdd("organizationId", "pool", null, true, List.of("admin"));
project = this.generatorAdd(DEFAULT_ORGANIZATION_ID, "pool", null, true, List.of("admin"));
project.setResourcePoolIds(List.of("resourcePoolId3"));
this.requestPost(addProject, project, ERROR_REQUEST_MATCHER);
@ -307,7 +405,7 @@ public class SystemProjectControllerTests extends BaseTest {
@Test
@Order(3)
public void testGetProject() throws Exception {
AddProjectRequest project = this.generatorAdd("organizationId","getName", "description", true, List.of("admin"));
AddProjectRequest project = this.generatorAdd(DEFAULT_ORGANIZATION_ID,"getName", "description", true, List.of("admin"));
List<String> moduleIds = new ArrayList<>();
moduleIds.add("apiTest");
moduleIds.add("uiTest");
@ -436,7 +534,7 @@ public class SystemProjectControllerTests extends BaseTest {
@Test
@Order(7)
public void testUpdateProject() throws Exception {
UpdateProjectRequest project = this.generatorUpdate("organizationId", "projectId1","TestName", "Edit name", true, List.of("admin", "admin1"));
UpdateProjectRequest project = this.generatorUpdate(DEFAULT_ORGANIZATION_ID, "projectId1","TestName", "Edit name", true, List.of("admin", "admin1"));
MvcResult mvcResult = this.responsePost(updateProject, project);
ProjectDTO result = parseObjectFromMvcResult(mvcResult, ProjectDTO.class);
Project currentProject = projectMapper.selectByPrimaryKey(project.getId());
@ -445,12 +543,12 @@ public class SystemProjectControllerTests extends BaseTest {
userRoleRelationExample.createCriteria().andSourceIdEqualTo("projectId1").andRoleIdEqualTo(InternalUserRole.PROJECT_ADMIN.getValue());
List<UserRoleRelation> userRoleRelations = userRoleRelationMapper.selectByExample(userRoleRelationExample);
Assertions.assertTrue(userRoleRelations.stream().map(UserRoleRelation::getUserId).toList().containsAll(List.of("admin", "admin1")));
userRoleRelationExample.createCriteria().andSourceIdEqualTo("organizationId").andRoleIdEqualTo(InternalUserRole.ORG_MEMBER.getValue());
userRoleRelationExample.createCriteria().andSourceIdEqualTo(DEFAULT_ORGANIZATION_ID).andRoleIdEqualTo(InternalUserRole.ORG_MEMBER.getValue());
userRoleRelations = userRoleRelationMapper.selectByExample(userRoleRelationExample);
Assertions.assertTrue(userRoleRelations.stream().map(UserRoleRelation::getUserId).toList().containsAll(List.of("admin", "admin1")));
//用户id为空
project = this.generatorUpdate("organizationId", "projectId1", "TestNameUserIdIsNull", "Edit name", true, new ArrayList<>());
project = this.generatorUpdate(DEFAULT_ORGANIZATION_ID, "projectId1", "TestNameUserIdIsNull", "Edit name", true, new ArrayList<>());
Project projectExtend = projectMapper.selectByPrimaryKey("projectId1");
projectExtend.setModuleSetting(null);
mvcResult = this.responsePost(updateProject, project);
@ -464,7 +562,7 @@ public class SystemProjectControllerTests extends BaseTest {
Assertions.assertTrue(userRoleRelations.isEmpty());
// 修改模块设置
project = this.generatorUpdate("organizationId", "projectId1", "Module", "Edit name", true, new ArrayList<>());
project = this.generatorUpdate(DEFAULT_ORGANIZATION_ID, "projectId1", "Module", "Edit name", true, new ArrayList<>());
List<String> moduleIds = new ArrayList<>();
moduleIds.add("apiTest");
moduleIds.add("uiTest");
@ -484,7 +582,7 @@ public class SystemProjectControllerTests extends BaseTest {
Assertions.assertEquals(projectExtend.getModuleSetting(), JSON.toJSONString(moduleIds));
//设置资源池
project = this.generatorUpdate("organizationId", "projectId5", "updatePools", "updatePools", true, new ArrayList<>());
project = this.generatorUpdate(DEFAULT_ORGANIZATION_ID, "projectId5", "updatePools", "updatePools", true, new ArrayList<>());
project.setResourcePoolIds(List.of("resourcePoolId","resourcePoolId1"));
mvcResult = this.responsePost(updateProject, project);
result = parseObjectFromMvcResult(mvcResult, ProjectDTO.class);
@ -506,22 +604,22 @@ public class SystemProjectControllerTests extends BaseTest {
@Order(8)
public void testUpdateProjectError() throws Exception {
//项目名称存在 500
UpdateProjectRequest project = this.generatorUpdate("organizationId", "projectId2","TestName2", "description", true, List.of("admin"));
UpdateProjectRequest project = this.generatorUpdate(DEFAULT_ORGANIZATION_ID, "projectId2","TestName2", "description", true, List.of("admin"));
this.requestPost(updateProject, project, ERROR_REQUEST_MATCHER);
//参数组织Id为空
project = this.generatorUpdate(null, "projectId",null, null, true , List.of("admin"));
this.requestPost(updateProject, project, BAD_REQUEST_MATCHER);
//项目Id为空
project = this.generatorUpdate("organizationId", null,null, null, true, List.of("admin"));
project = this.generatorUpdate(DEFAULT_ORGANIZATION_ID, null,null, null, true, List.of("admin"));
this.requestPost(updateProject, project, BAD_REQUEST_MATCHER);
//项目名称为空
project = this.generatorUpdate("organizationId", "projectId",null, null, true, List.of("admin"));
project = this.generatorUpdate(DEFAULT_ORGANIZATION_ID, "projectId",null, null, true, List.of("admin"));
this.requestPost(updateProject, project, BAD_REQUEST_MATCHER);
//项目不存在
project = this.generatorUpdate("organizationId", "1111","123", null, true, List.of("admin"));
project = this.generatorUpdate(DEFAULT_ORGANIZATION_ID, "1111","123", null, true, List.of("admin"));
this.requestPost(updateProject, project, ERROR_REQUEST_MATCHER);
//资源池不存在
project = this.generatorUpdate("organizationId", "projectId2","pool-edit", "description", true, List.of("admin"));
project = this.generatorUpdate(DEFAULT_ORGANIZATION_ID, "projectId2","pool-edit", "description", true, List.of("admin"));
project.setResourcePoolIds(List.of("resourcePoolId3"));
this.requestPost(updateProject, project, ERROR_REQUEST_MATCHER);
@ -768,8 +866,25 @@ public class SystemProjectControllerTests extends BaseTest {
@Order(22)
public void testGetOptions() throws Exception {
this.requestGetWithOkAndReturn(getPoolOptions);
this.requestGetWithOkAndReturn(getPoolOptions + "?organizationId=organizationId");
this.requestGetWithOkAndReturn(getPoolOptions + "?organizationId=" + DEFAULT_ORGANIZATION_ID);
// @@校验权限
requestGetPermissionTest(PermissionConstants.SYSTEM_ORGANIZATION_PROJECT_READ, getPoolOptions + "?organizationId=organizationId");
requestGetPermissionTest(PermissionConstants.SYSTEM_ORGANIZATION_PROJECT_READ, getPoolOptions + "?organizationId=" + DEFAULT_ORGANIZATION_ID);
}
@Test
@Order(23)
public void testDeleteForce() {
String id = "projectId";
// 设置成过期强制删除
Project project = new Project();
project.setId(id);
project.setDeleteTime(1L);
project.setDeleted(true);
projectMapper.updateByPrimaryKeySelective(project);
// 直接调用删除项目资源的定时任务校验资源是否删除
cleanProjectJob.cleanupProject();
Assertions.assertTrue(CollectionUtils.isEmpty(baseCustomFieldService.getByScopeId(id)));
Assertions.assertTrue(CollectionUtils.isEmpty(baseTemplateService.getByScopeId(id)));
}
}

View File

@ -19,7 +19,7 @@ public class CustomFieldUpdateRequestDefinition {
private String name;
@NotBlank(groups = {Created.class})
@Size(min = 1, max = 30, groups = {Created.class, Updated.class})
@Size(min = 1, max = 30, groups = {Created.class})
private String scene;
@NotBlank(groups = {Created.class})

View File

@ -47,6 +47,6 @@ public class TemplateUpdateRequestDefinition {
@Schema(title = "使用场景", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{template.scene.not_blank}", groups = {Created.class})
@Size(min = 1, max = 30, message = "{template.scene.length_range}", groups = {Created.class, Updated.class})
@Size(min = 1, max = 30, message = "{template.scene.length_range}", groups = {Created.class})
private String scene;
}