refactor(项目设置): 补充模板相关接口

This commit is contained in:
AgAngle 2023-10-22 21:13:35 +08:00 committed by jianxing
parent 0c97f714a8
commit d4d7307819
32 changed files with 722 additions and 369 deletions

View File

@ -37,9 +37,7 @@ public class StatusItem implements Serializable {
@Size(min = 1, max = 50, message = "{status_item.scope_type.length_range}", groups = {Created.class, Updated.class}) @Size(min = 1, max = 50, message = "{status_item.scope_type.length_range}", groups = {Created.class, Updated.class})
private String scopeType; private String scopeType;
@Schema(description = "项目状态所关联的组织状态ID", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "项目状态所关联的组织状态ID")
@NotBlank(message = "{status_item.ref_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{status_item.ref_id.length_range}", groups = {Created.class, Updated.class})
private String refId; private String refId;
@Schema(description = "组织或项目ID", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "组织或项目ID", requiredMode = Schema.RequiredMode.REQUIRED)

View File

@ -50,10 +50,6 @@ public class Template implements Serializable {
@NotNull(message = "{template.enable_third_part.not_blank}", groups = {Created.class}) @NotNull(message = "{template.enable_third_part.not_blank}", groups = {Created.class})
private Boolean enableThirdPart; 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") @Schema(description = "项目模板所关联的组织模板ID")
private String refId; private String refId;
@ -75,7 +71,6 @@ public class Template implements Serializable {
scopeType("scope_type", "scopeType", "VARCHAR", false), scopeType("scope_type", "scopeType", "VARCHAR", false),
scopeId("scope_id", "scopeId", "VARCHAR", false), scopeId("scope_id", "scopeId", "VARCHAR", false),
enableThirdPart("enable_third_part", "enableThirdPart", "BIT", false), enableThirdPart("enable_third_part", "enableThirdPart", "BIT", false),
enableDefault("enable_default", "enableDefault", "BIT", false),
refId("ref_id", "refId", "VARCHAR", false), refId("ref_id", "refId", "VARCHAR", false),
scene("scene", "scene", "VARCHAR", false); scene("scene", "scene", "VARCHAR", false);

View File

@ -764,66 +764,6 @@ public class TemplateExample {
return (Criteria) this; 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() { public Criteria andRefIdIsNull() {
addCriterion("ref_id is null"); addCriterion("ref_id is null");
return (Criteria) this; return (Criteria) this;

View File

@ -12,7 +12,6 @@
<result column="scope_type" jdbcType="VARCHAR" property="scopeType" /> <result column="scope_type" jdbcType="VARCHAR" property="scopeType" />
<result column="scope_id" jdbcType="VARCHAR" property="scopeId" /> <result column="scope_id" jdbcType="VARCHAR" property="scopeId" />
<result column="enable_third_part" jdbcType="BIT" property="enableThirdPart" /> <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="ref_id" jdbcType="VARCHAR" property="refId" />
<result column="scene" jdbcType="VARCHAR" property="scene" /> <result column="scene" jdbcType="VARCHAR" property="scene" />
</resultMap> </resultMap>
@ -76,7 +75,7 @@
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, `name`, remark, internal, update_time, create_time, create_user, scope_type, id, `name`, remark, internal, update_time, create_time, create_user, scope_type,
scope_id, enable_third_part, enable_default, ref_id, scene scope_id, enable_third_part, ref_id, scene
</sql> </sql>
<select id="selectByExample" parameterType="io.metersphere.system.domain.TemplateExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="io.metersphere.system.domain.TemplateExample" resultMap="BaseResultMap">
select select
@ -112,13 +111,13 @@
insert into template (id, `name`, remark, insert into template (id, `name`, remark,
internal, update_time, create_time, internal, update_time, create_time,
create_user, scope_type, scope_id, create_user, scope_type, scope_id,
enable_third_part, enable_default, ref_id, enable_third_part, ref_id, scene
scene) )
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{remark,jdbcType=VARCHAR}, values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{remark,jdbcType=VARCHAR},
#{internal,jdbcType=BIT}, #{updateTime,jdbcType=BIGINT}, #{createTime,jdbcType=BIGINT}, #{internal,jdbcType=BIT}, #{updateTime,jdbcType=BIGINT}, #{createTime,jdbcType=BIGINT},
#{createUser,jdbcType=VARCHAR}, #{scopeType,jdbcType=VARCHAR}, #{scopeId,jdbcType=VARCHAR}, #{createUser,jdbcType=VARCHAR}, #{scopeType,jdbcType=VARCHAR}, #{scopeId,jdbcType=VARCHAR},
#{enableThirdPart,jdbcType=BIT}, #{enableDefault,jdbcType=BIT}, #{refId,jdbcType=VARCHAR}, #{enableThirdPart,jdbcType=BIT}, #{refId,jdbcType=VARCHAR}, #{scene,jdbcType=VARCHAR}
#{scene,jdbcType=VARCHAR}) )
</insert> </insert>
<insert id="insertSelective" parameterType="io.metersphere.system.domain.Template"> <insert id="insertSelective" parameterType="io.metersphere.system.domain.Template">
insert into template insert into template
@ -153,9 +152,6 @@
<if test="enableThirdPart != null"> <if test="enableThirdPart != null">
enable_third_part, enable_third_part,
</if> </if>
<if test="enableDefault != null">
enable_default,
</if>
<if test="refId != null"> <if test="refId != null">
ref_id, ref_id,
</if> </if>
@ -194,9 +190,6 @@
<if test="enableThirdPart != null"> <if test="enableThirdPart != null">
#{enableThirdPart,jdbcType=BIT}, #{enableThirdPart,jdbcType=BIT},
</if> </if>
<if test="enableDefault != null">
#{enableDefault,jdbcType=BIT},
</if>
<if test="refId != null"> <if test="refId != null">
#{refId,jdbcType=VARCHAR}, #{refId,jdbcType=VARCHAR},
</if> </if>
@ -244,9 +237,6 @@
<if test="record.enableThirdPart != null"> <if test="record.enableThirdPart != null">
enable_third_part = #{record.enableThirdPart,jdbcType=BIT}, enable_third_part = #{record.enableThirdPart,jdbcType=BIT},
</if> </if>
<if test="record.enableDefault != null">
enable_default = #{record.enableDefault,jdbcType=BIT},
</if>
<if test="record.refId != null"> <if test="record.refId != null">
ref_id = #{record.refId,jdbcType=VARCHAR}, ref_id = #{record.refId,jdbcType=VARCHAR},
</if> </if>
@ -270,7 +260,6 @@
scope_type = #{record.scopeType,jdbcType=VARCHAR}, scope_type = #{record.scopeType,jdbcType=VARCHAR},
scope_id = #{record.scopeId,jdbcType=VARCHAR}, scope_id = #{record.scopeId,jdbcType=VARCHAR},
enable_third_part = #{record.enableThirdPart,jdbcType=BIT}, enable_third_part = #{record.enableThirdPart,jdbcType=BIT},
enable_default = #{record.enableDefault,jdbcType=BIT},
ref_id = #{record.refId,jdbcType=VARCHAR}, ref_id = #{record.refId,jdbcType=VARCHAR},
scene = #{record.scene,jdbcType=VARCHAR} scene = #{record.scene,jdbcType=VARCHAR}
<if test="_parameter != null"> <if test="_parameter != null">
@ -307,9 +296,6 @@
<if test="enableThirdPart != null"> <if test="enableThirdPart != null">
enable_third_part = #{enableThirdPart,jdbcType=BIT}, enable_third_part = #{enableThirdPart,jdbcType=BIT},
</if> </if>
<if test="enableDefault != null">
enable_default = #{enableDefault,jdbcType=BIT},
</if>
<if test="refId != null"> <if test="refId != null">
ref_id = #{refId,jdbcType=VARCHAR}, ref_id = #{refId,jdbcType=VARCHAR},
</if> </if>
@ -330,7 +316,6 @@
scope_type = #{scopeType,jdbcType=VARCHAR}, scope_type = #{scopeType,jdbcType=VARCHAR},
scope_id = #{scopeId,jdbcType=VARCHAR}, scope_id = #{scopeId,jdbcType=VARCHAR},
enable_third_part = #{enableThirdPart,jdbcType=BIT}, enable_third_part = #{enableThirdPart,jdbcType=BIT},
enable_default = #{enableDefault,jdbcType=BIT},
ref_id = #{refId,jdbcType=VARCHAR}, ref_id = #{refId,jdbcType=VARCHAR},
scene = #{scene,jdbcType=VARCHAR} scene = #{scene,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
@ -338,14 +323,14 @@
<insert id="batchInsert" parameterType="map"> <insert id="batchInsert" parameterType="map">
insert into template insert into template
(id, `name`, remark, internal, update_time, create_time, create_user, scope_type, (id, `name`, remark, internal, update_time, create_time, create_user, scope_type,
scope_id, enable_third_part, enable_default, ref_id, scene) scope_id, enable_third_part, ref_id, scene)
values values
<foreach collection="list" item="item" separator=","> <foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR}, #{item.remark,jdbcType=VARCHAR}, (#{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.internal,jdbcType=BIT}, #{item.updateTime,jdbcType=BIGINT}, #{item.createTime,jdbcType=BIGINT},
#{item.createUser,jdbcType=VARCHAR}, #{item.scopeType,jdbcType=VARCHAR}, #{item.scopeId,jdbcType=VARCHAR}, #{item.createUser,jdbcType=VARCHAR}, #{item.scopeType,jdbcType=VARCHAR}, #{item.scopeId,jdbcType=VARCHAR},
#{item.enableThirdPart,jdbcType=BIT}, #{item.enableDefault,jdbcType=BIT}, #{item.refId,jdbcType=VARCHAR}, #{item.enableThirdPart,jdbcType=BIT}, #{item.refId,jdbcType=VARCHAR}, #{item.scene,jdbcType=VARCHAR}
#{item.scene,jdbcType=VARCHAR}) )
</foreach> </foreach>
</insert> </insert>
<insert id="batchInsertSelective" parameterType="map"> <insert id="batchInsertSelective" parameterType="map">
@ -388,9 +373,6 @@
<if test="'enable_third_part'.toString() == column.value"> <if test="'enable_third_part'.toString() == column.value">
#{item.enableThirdPart,jdbcType=BIT} #{item.enableThirdPart,jdbcType=BIT}
</if> </if>
<if test="'enable_default'.toString() == column.value">
#{item.enableDefault,jdbcType=BIT}
</if>
<if test="'ref_id'.toString() == column.value"> <if test="'ref_id'.toString() == column.value">
#{item.refId,jdbcType=VARCHAR} #{item.refId,jdbcType=VARCHAR}
</if> </if>

View File

@ -383,16 +383,14 @@ CREATE TABLE IF NOT EXISTS template(
`scope_type` VARCHAR(50) NOT NULL COMMENT '组织或项目级别字段PROJECT, ORGANIZATION' , `scope_type` VARCHAR(50) NOT NULL COMMENT '组织或项目级别字段PROJECT, ORGANIZATION' ,
`scope_id` VARCHAR(50) NOT NULL COMMENT '组织或项目ID' , `scope_id` VARCHAR(50) NOT NULL COMMENT '组织或项目ID' ,
`enable_third_part` BIT NOT NULL DEFAULT 0 COMMENT '是否开启api字段名配置' , `enable_third_part` BIT NOT NULL DEFAULT 0 COMMENT '是否开启api字段名配置' ,
`enable_default` BIT NOT NULL DEFAULT 0 COMMENT '是否是默认模板' ,
`ref_id` VARCHAR(50) COMMENT '项目模板所关联的组织模板ID' , `ref_id` VARCHAR(50) COMMENT '项目模板所关联的组织模板ID' ,
`scene` VARCHAR(30) NOT NULL COMMENT '使用场景' , `scene` VARCHAR(30) NOT NULL COMMENT '使用场景' ,
PRIMARY KEY (id) PRIMARY KEY (id)
) ENGINE = InnoDB ) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4 DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COLLATE = utf8mb4_general_ci COMMENT = '模版';
COMMENT = '模版';
CREATE INDEX idx_scope_id ON template(scope_id); CREATE INDEX idx_scope_id_scene ON template(`scope_id`,`scene`);
CREATE TABLE IF NOT EXISTS template_custom_field( CREATE TABLE IF NOT EXISTS template_custom_field(
`id` VARCHAR(50) NOT NULL COMMENT 'ID' , `id` VARCHAR(50) NOT NULL COMMENT 'ID' ,

View File

@ -145,8 +145,8 @@ INSERT INTO custom_field_option (field_id,value,`text`,internal)
VALUES ((select id from custom_field where name = 'functional_priority'), 'P3', 'P3', 1); 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,enable_default, scene) INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, scene)
VALUES (UUID_SHORT(), 'functional_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 1, 'FUNCTIONAL'); VALUES (UUID_SHORT(), 'functional_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 'FUNCTIONAL');
INSERT INTO template_custom_field(id, field_id, template_id, required, pos, api_field_id, default_value) 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'), (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);
@ -167,8 +167,8 @@ 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); 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) INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, scene, ref_id)
VALUES (UUID_SHORT(), 'functional_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 1, 'FUNCTIONAL', VALUES (UUID_SHORT(), 'functional_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 'FUNCTIONAL',
(SELECT id FROM (SELECT * FROM template) t where name = 'functional_default')); (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) INSERT INTO template_custom_field(id, field_id, template_id, required, pos, api_field_id, default_value)
VALUES( VALUES(
@ -179,39 +179,39 @@ VALUES(
); );
-- 初始化组织缺陷模板 -- 初始化组织缺陷模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,enable_default,scene) INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,scene)
VALUES (UUID_SHORT(), 'bug_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 1, 'BUG'); VALUES (UUID_SHORT(), 'bug_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 'BUG');
-- 初始化项目缺陷模板 -- 初始化项目缺陷模板
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) INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, scene, ref_id)
VALUES (UUID_SHORT(), 'bug_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 1, 'BUG', VALUES (UUID_SHORT(), 'bug_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 'BUG',
(SELECT id FROM (SELECT * FROM template) t where name = 'bug_default')); (SELECT id FROM (SELECT * FROM template) t where name = 'bug_default'));
-- 初始化组织接口模板 -- 初始化组织接口模板
INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,enable_default,scene) INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,scene)
VALUES (UUID_SHORT(), 'api_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 1, 'API'); VALUES (UUID_SHORT(), 'api_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, '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) INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, scene, ref_id)
VALUES (UUID_SHORT(), 'api_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 1, 'API', VALUES (UUID_SHORT(), 'api_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 'API',
(SELECT id FROM (SELECT * FROM template) t where name = 'api_default')); (SELECT id FROM (SELECT * FROM template) t where name = 'api_default'));
-- 初始化组织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) INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,scene)
VALUES (UUID_SHORT(), 'ui_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 1, 'UI'); VALUES (UUID_SHORT(), 'ui_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 'UI');
-- 初始化项目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) INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, scene, ref_id)
VALUES (UUID_SHORT(), 'ui_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 1, 'UI', VALUES (UUID_SHORT(), 'ui_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 'UI',
(SELECT id FROM (SELECT * FROM template) t where name = 'ui_default')); (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) INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part,scene)
VALUES (UUID_SHORT(), 'test_plan_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, 1, 'TEST_PLAN'); VALUES (UUID_SHORT(), 'test_plan_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'ORGANIZATION', '100001', 0, '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) INSERT INTO template (id,name,remark,internal,update_time,create_time,create_user,scope_type,scope_id,enable_third_part, scene, ref_id)
VALUES (UUID_SHORT(), 'test_plan_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 1, 'TEST_PLAN', VALUES (UUID_SHORT(), 'test_plan_default', '', 1, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'PROJECT', '100001100001', 0, 'TEST_PLAN',
(SELECT id FROM (SELECT * FROM template) t where name = 'test_plan_default')); (SELECT id FROM (SELECT * FROM template) t where name = 'test_plan_default'));
-- 初始化组织缺陷状态项 -- 初始化组织缺陷状态项

View File

@ -1,7 +1,10 @@
package io.metersphere.plugin.platform.spi; package io.metersphere.plugin.platform.spi;
import io.metersphere.plugin.platform.dto.PlatformCustomFieldItemDTO;
import org.pf4j.ExtensionPoint; import org.pf4j.ExtensionPoint;
import java.util.List;
/** /**
* 平台对接相关业务接口 * 平台对接相关业务接口
* @author jianxing.chen * @author jianxing.chen
@ -19,4 +22,17 @@ public interface Platform extends ExtensionPoint {
* 项目设置成点击校验项目 key 时调用 * 项目设置成点击校验项目 key 时调用
*/ */
void validateProjectConfig(String projectConfig); void validateProjectConfig(String projectConfig);
/**
* 插件是否支持第三方模板
* @return
*/
boolean isThirdPartTemplateSupport();
/**
* 获取第三方平台缺陷的自定义字段
* 需要 PluginMetaInfo isThirdPartTemplateSupport 返回 true
* @return
*/
List<PlatformCustomFieldItemDTO> getThirdPartCustomField(String projectConfig);
} }

View File

@ -0,0 +1,20 @@
package io.metersphere.sdk.constants;
/**
* 系统内置用户ID
* @author jianxing
*/
public enum InternalUser {
ADMIN("admin");
private String value;
InternalUser(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}

View File

@ -1,5 +1,7 @@
package io.metersphere.sdk.constants; package io.metersphere.sdk.constants;
import java.util.Arrays;
/** /**
* 应用设置 -相关配置 * 应用设置 -相关配置
*/ */
@ -81,4 +83,22 @@ public class ProjectApplicationType {
VERSION_ENABLE VERSION_ENABLE
} }
/**
* 记录项目中配置的默认模板
*/
public enum DEFAULT_TEMPLATE{
FUNCTIONAL_DEFAULT_TEMPLATE,
BUG_DEFAULT_TEMPLATE,
API_DEFAULT_TEMPLATE,
UI_DEFAULT_TEMPLATE,
TEST_PLAN_DEFAULT_TEMPLATE;
public static DEFAULT_TEMPLATE getByTemplateScene(String scene) {
return Arrays.stream(DEFAULT_TEMPLATE.values())
.filter(e -> e.name().startsWith(scene))
.findFirst()
.orElse(null);
}
}
} }

View File

@ -1,11 +1,13 @@
package io.metersphere.sdk.dto; package io.metersphere.sdk.dto;
import io.metersphere.system.domain.Template; import io.metersphere.system.domain.Template;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
@Data @Data
public class TemplateDTO extends Template { public class TemplateDTO extends Template {
@Schema(description = "相关的自定义字段")
List<TemplateCustomFieldDTO> customFields; List<TemplateCustomFieldDTO> customFields;
} }

View File

@ -445,7 +445,7 @@ template_scene_illegal_error=使用场景不合法
# 内置的模板或字段 # 内置的模板或字段
custom_field.functional_priority=优先级 custom_field.functional_priority=优先级
template.functional_default=默认模板 template.default=默认模板
parent.node.not_blank=父节点不能为空 parent.node.not_blank=父节点不能为空
node.not_blank=节点不能为空 node.not_blank=节点不能为空

View File

@ -448,7 +448,7 @@ scheduled_tasks=Scheduled Tasks
template_scene_illegal_error=Scene is illegal template_scene_illegal_error=Scene is illegal
# 内置的模板或字段 # 内置的模板或字段
custom_field.functional_priority=Priority custom_field.functional_priority=Priority
template.functional_default=Default template.default=Default
set_default_template=Set the default template set_default_template=Set the default template
project_template_enable=Enable the project template project_template_enable=Enable the project template

View File

@ -446,7 +446,7 @@ scheduled_tasks=定时任务
template_scene_illegal_error=使用场景不合法 template_scene_illegal_error=使用场景不合法
# 内置的模板或字段 # 内置的模板或字段
custom_field.functional_priority=优先级 custom_field.functional_priority=优先级
template.functional_default=默认模板 template.default=默认模板
set_default_template=设置默认模板 set_default_template=设置默认模板
project_template_enable=开启项目模板 project_template_enable=开启项目模板

View File

@ -445,7 +445,7 @@ template_scene_illegal_error=使用場景不合法
# 内置的模板或字段 # 内置的模板或字段
custom_field.functional_priority=優先級 custom_field.functional_priority=優先級
template.functional_default=默認模板 template.default=默認模板
set_default_template=設置默認模板 set_default_template=設置默認模板
project_template_enable=開啟項目模板 project_template_enable=開啟項目模板

View File

@ -310,4 +310,6 @@ file.name.cannot.be.empty=文件名称不能为空
# template # template
project_template_permission_error=未开启项目模板 project_template_permission_error=未开启项目模板
plugin_bug_template_remark=模板为系统自动获取,不支持编辑和查看

View File

@ -344,3 +344,4 @@ file.name.cannot.be.empty=File name cannot be empty
# template # template
project_template_permission_error=The project template is not turned on project_template_permission_error=The project template is not turned on
third_part_config_is_null=Third party configuration cannot be empty third_part_config_is_null=Third party configuration cannot be empty
plugin_bug_template_remark=Templates are automatically obtained by the system and do not support editing and viewing

View File

@ -344,3 +344,4 @@ file.name.cannot.be.empty=文件名称不能为空
project_template_permission_error=未开启项目模板 project_template_permission_error=未开启项目模板
third_part_config_is_null=第三方平台配置信息不能为空 third_part_config_is_null=第三方平台配置信息不能为空
plugin_bug_template_remark=模板为系统自动获取,不支持编辑和查看

View File

@ -343,3 +343,4 @@ file.name.cannot.be.empty=文件名稱不能為空
# template # template
project_template_permission_error=未開啟項目模板 project_template_permission_error=未開啟項目模板
third_part_config_is_null=第三方平臺配置信息不能爲空 third_part_config_is_null=第三方平臺配置信息不能爲空
plugin_bug_template_remark=模板為系統自動獲取,不支持編輯和查看

View File

@ -1,5 +1,6 @@
package io.metersphere.project.controller; package io.metersphere.project.controller;
import io.metersphere.project.dto.ProjectTemplateDTO;
import io.metersphere.project.service.ProjectTemplateLogService; import io.metersphere.project.service.ProjectTemplateLogService;
import io.metersphere.project.service.ProjectTemplateService; import io.metersphere.project.service.ProjectTemplateService;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
@ -37,7 +38,7 @@ public class ProjectTemplateController {
@GetMapping("/list/{projectId}/{scene}") @GetMapping("/list/{projectId}/{scene}")
@Operation(summary = "获取模版列表") @Operation(summary = "获取模版列表")
@RequiresPermissions(PermissionConstants.PROJECT_TEMPLATE_READ) @RequiresPermissions(PermissionConstants.PROJECT_TEMPLATE_READ)
public List<Template> list(@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED) public List<ProjectTemplateDTO> list(@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@PathVariable String projectId, @PathVariable String projectId,
@Schema(description = "模板的使用场景FUNCTIONAL,BUG,API,UI,TEST_PLAN", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "模板的使用场景FUNCTIONAL,BUG,API,UI,TEST_PLAN", requiredMode = Schema.RequiredMode.REQUIRED)
@PathVariable String scene) { @PathVariable String scene) {
@ -48,7 +49,7 @@ public class ProjectTemplateController {
@Operation(summary = "获取模版详情") @Operation(summary = "获取模版详情")
@RequiresPermissions(PermissionConstants.PROJECT_TEMPLATE_READ) @RequiresPermissions(PermissionConstants.PROJECT_TEMPLATE_READ)
public TemplateDTO get(@PathVariable String id) { public TemplateDTO get(@PathVariable String id) {
return projectTemplateservice.geDTOWithCheck(id); return projectTemplateservice.geTemplateDTOWithCheck(id);
} }
@PostMapping("/add") @PostMapping("/add")
@ -80,11 +81,11 @@ public class ProjectTemplateController {
projectTemplateservice.delete(id); projectTemplateservice.delete(id);
} }
@GetMapping("/set-default/{id}") @GetMapping("/set-default/{projectId}/{id}")
@Operation(summary = "设置模板模板") @Operation(summary = "设置模板模板")
@RequiresPermissions(PermissionConstants.ORGANIZATION_TEMPLATE_UPDATE) @RequiresPermissions(PermissionConstants.ORGANIZATION_TEMPLATE_UPDATE)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.setDefaultTemplateLog(#id)", msClass = ProjectTemplateLogService.class) @Log(type = OperationLogType.UPDATE, expression = "#msClass.setDefaultTemplateLog(#id)", msClass = ProjectTemplateLogService.class)
public void setDefaultTemplate(@PathVariable String id) { public void setDefaultTemplate(@PathVariable String projectId, @PathVariable String id) {
projectTemplateservice.setDefaultTemplate(id); projectTemplateservice.setDefaultTemplate(projectId, id);
} }
} }

View File

@ -0,0 +1,22 @@
package io.metersphere.project.dto;
import io.metersphere.system.domain.Template;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
* @Author: jianxing
* @CreateTime: 2023-10-19 16:46
*/
@Getter
@Setter
public class ProjectTemplateDTO extends Template implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "是否是默认模板")
private Boolean enableDefault = false;
}

View File

@ -0,0 +1,22 @@
package io.metersphere.project.dto;
import io.metersphere.sdk.dto.OptionDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
* @Author: jianxing
* @CreateTime: 2023-10-19 16:46
*/
@Getter
@Setter
public class ProjectTemplateOptionDTO extends OptionDTO implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "是否是默认模板")
private Boolean enableDefault;
}

View File

@ -87,7 +87,7 @@ public class ProjectApplicationService {
this.createOrUpdateConfig(application); this.createOrUpdateConfig(application);
} }
private void createOrUpdateConfig(ProjectApplication application) { public void createOrUpdateConfig(ProjectApplication application) {
String type = application.getType(); String type = application.getType();
String projectId = application.getProjectId(); String projectId = application.getProjectId();
ProjectApplicationExample example = new ProjectApplicationExample(); ProjectApplicationExample example = new ProjectApplicationExample();
@ -546,4 +546,10 @@ public class ProjectApplicationService {
return null; return null;
} }
public ProjectApplication getByType(String projectId, String type) {
ProjectApplicationExample example = new ProjectApplicationExample();
example.createCriteria().andProjectIdEqualTo(projectId).andTypeEqualTo(type);
List<ProjectApplication> projectApplications = projectApplicationMapper.selectByExample(example);
return CollectionUtils.isEmpty(projectApplications) ? null : projectApplications.get(0);
}
} }

View File

@ -1,19 +1,41 @@
package io.metersphere.project.service; package io.metersphere.project.service;
import io.metersphere.plugin.platform.spi.Platform;
import io.metersphere.plugin.sdk.spi.MsPlugin;
import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.project.dto.ProjectTemplateDTO;
import io.metersphere.project.dto.ProjectTemplateOptionDTO;
import io.metersphere.sdk.constants.InternalUser;
import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.sdk.constants.TemplateScene;
import io.metersphere.sdk.constants.TemplateScopeType; import io.metersphere.sdk.constants.TemplateScopeType;
import io.metersphere.sdk.dto.TemplateDTO; import io.metersphere.sdk.dto.TemplateDTO;
import io.metersphere.sdk.dto.request.TemplateCustomFieldRequest; import io.metersphere.sdk.dto.request.TemplateCustomFieldRequest;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.Plugin;
import io.metersphere.system.domain.ServiceIntegration;
import io.metersphere.system.domain.Template; import io.metersphere.system.domain.Template;
import io.metersphere.system.domain.TemplateExample;
import io.metersphere.system.dto.ProjectDTO; import io.metersphere.system.dto.ProjectDTO;
import io.metersphere.system.service.BaseTemplateService; import io.metersphere.system.service.BaseTemplateService;
import io.metersphere.system.service.PlatformPluginService;
import io.metersphere.system.service.PluginLoadService;
import io.metersphere.system.service.ServiceIntegrationService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.pf4j.PluginWrapper;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static io.metersphere.project.enums.result.ProjectResultCode.PROJECT_TEMPLATE_PERMISSION; import static io.metersphere.project.enums.result.ProjectResultCode.PROJECT_TEMPLATE_PERMISSION;
import static io.metersphere.system.controller.handler.result.CommonResultCode.DEFAULT_TEMPLATE_PERMISSION;
/** /**
* @author jianxing * @author jianxing
@ -25,17 +47,231 @@ public class ProjectTemplateService extends BaseTemplateService {
@Resource @Resource
private ProjectService projectService; private ProjectService projectService;
@Resource
private ServiceIntegrationService serviceIntegrationService;
@Resource
private PluginLoadService pluginLoadService;
@Resource
private PlatformPluginService platformPluginService;
@Resource
private ProjectApplicationService projectApplicationService;
@Override @Override
public List<Template> list(String projectId, String scene) { public List list(String projectId, String scene) {
projectService.checkResourceExist(projectId); projectService.checkResourceExist(projectId);
return super.list(projectId, scene); List<Template> templates = super.list(projectId, scene);
// 缺陷模板需要获取第三方平台模板
templates = addPluginBugTemplate(projectId, scene, templates);
// 标记默认模板
return tagDefaultTemplate(projectId, scene, templates);
} }
public TemplateDTO geDTOWithCheck(String id) { /**
* 如果是缺陷模板并且配置了服务集成和项目信息则添加第三方平台模板
* @param projectId
* @param scene
* @param templates
* @return
*/
private List<Template> addPluginBugTemplate(String projectId, String scene, List<Template> templates) {
if (StringUtils.equals(scene, TemplateScene.BUG.name())) {
Template pluginBugTemplate = getPluginBugTemplate(projectId);
if (pluginBugTemplate != null) {
templates.add(pluginBugTemplate);
}
}
return templates;
}
/**
* 获取当前项目中可用的模板选项
* 默认模板排前面
* !提供给其他模块调用
* @param projectId
* @param scene
* @return
*/
public List<ProjectTemplateOptionDTO> getOption(String projectId, String scene) {
projectService.checkResourceExist(projectId);
List<Template> templates = getTemplates(projectId, scene);
translateInternalTemplate(templates);
// 缺陷模板需要获取第三方平台模板
templates = addPluginBugTemplate(projectId, scene, templates);
List<ProjectTemplateDTO> projectTemplateDTOS = tagDefaultTemplate(projectId, scene, templates);
return sortByDefaultTemplate(projectTemplateDTOS).stream()
.map(item -> BeanUtils.copyBean(new ProjectTemplateOptionDTO(), item))
.collect(Collectors.toList());
}
/**
* 将默认模板排最前面
* @param projectTemplateDTOS
* @return
*/
private static List<ProjectTemplateDTO> sortByDefaultTemplate(List<ProjectTemplateDTO> projectTemplateDTOS) {
return projectTemplateDTOS.stream()
.sorted(Comparator.comparing(ProjectTemplateDTO::getEnableDefault)) // 默认模板排在前面
.toList();
}
/**
* 获取默认的模板以及字段
* !提供给其他模块调用
* @param projectId
* @param scene
* @return
*/
public TemplateDTO getDefaultTemplateDTO(String projectId, String scene) {
String defaultTemplateId = getDefaultTemplateId(projectId, scene);
Template template;
if (StringUtils.isBlank(defaultTemplateId)) {
// 如果没有默认模板则获取内置模板
template = getInternalTemplate(projectId, scene);
} else {
template = templateMapper.selectByPrimaryKey(defaultTemplateId);
if (template == null) {
// 如果默认模板查不到则获取内置模板
template = getInternalTemplate(projectId, scene);
}
}
return geTemplateDTO(template);
}
/**
* 获取内置模板
* @param projectId
* @param scene
* @return
*/
public Template getInternalTemplate(String projectId, String scene) {
// 获取内置模板
TemplateExample example = new TemplateExample();
example.createCriteria()
.andScopeIdEqualTo(projectId)
.andSceneEqualTo(scene)
.andInternalEqualTo(true);
return templateMapper.selectByExample(example).get(0);
}
/**
* 获取设置的默认模板ID
*
* @param projectId
* @param scene
* @return
*/
public String getDefaultTemplateId(String projectId, String scene) {
ProjectApplicationType.DEFAULT_TEMPLATE defaultTemplateParam = ProjectApplicationType.DEFAULT_TEMPLATE.getByTemplateScene(scene);
ProjectApplication projectApplication = projectApplicationService.getByType(projectId, defaultTemplateParam.name());
return projectApplication == null ? null : projectApplication.getTypeValue();
}
/**
* 标记默认模板
*
* @param projectId
* @param scene
* @param templates
* @return
*/
private List<ProjectTemplateDTO> tagDefaultTemplate(String projectId, String scene, List<Template> templates) {
// 查询项目下设置中配置的默认模板
String defaultProjectId = getDefaultTemplateId(projectId, scene);
List<ProjectTemplateDTO> templateDTOS = templates.stream().map(item -> BeanUtils.copyBean(new ProjectTemplateDTO(), item)).toList();
ProjectTemplateDTO defaultTemplate = templateDTOS.stream()
.filter(t -> StringUtils.equals(defaultProjectId, t.getId()))
.findFirst()
.orElse(null);
// 如果查询不到默认模板设置内置模板为默认模板
if (defaultTemplate == null) {
defaultTemplate = templateDTOS.stream()
.filter(ProjectTemplateDTO::getInternal)
.findFirst()
.get();
}
defaultTemplate.setEnableDefault(true);
return templateDTOS;
}
/**
* 获取第三方平台模板
*
* @param projectId
* @return
*/
private Template getPluginBugTemplate(String projectId) {
ServiceIntegration serviceIntegration = getServiceIntegration(projectId);
if (serviceIntegration == null) {
return null;
}
Platform platform = platformPluginService.getPlatform(serviceIntegration.getPluginId(),
serviceIntegration.getOrganizationId(), new String(serviceIntegration.getConfiguration()));
if (platform != null && platform.isThirdPartTemplateSupport()) {
return getPluginBugTemplate(projectId, serviceIntegration.getPluginId()); // 该插件支持第三方平台模板
}
return null;
}
private Template getPluginBugTemplate(String projectId, String pluginId) {
PluginWrapper pluginWrapper = pluginLoadService.getPluginWrapper(pluginId);
Template template = new Template();
template.setId(pluginWrapper.getPluginId());
template.setCreateUser(InternalUser.ADMIN.getValue());
template.setScene(TemplateScene.BUG.name());
template.setEnableThirdPart(true);
template.setScopeId(projectId);
template.setScopeType(TemplateScopeType.PROJECT.name());
template.setInternal(false);
template.setRemark(((MsPlugin) pluginWrapper.getPlugin()).getName() + Translator.get("plugin_bug_template_remark"));
return template;
}
/**
* 如果项目下配置了第三方平台信息
* 获取对应的服务集成信息
*
* @param projectId
* @return
*/
private ServiceIntegration getServiceIntegration(String projectId) {
// 判断项目是否开启集成缺陷
ProjectApplication syncEnableConfig = projectApplicationService.getByType(projectId, ProjectApplicationType.BUG_SYNC_CONFIG.SYNC_ENABLE.name());
boolean isSyncEnable = syncEnableConfig != null && Boolean.parseBoolean(syncEnableConfig.getTypeValue());
if (!isSyncEnable) {
return null;
}
ProjectDTO project = projectService.getProjectById(projectId);
// 查询组织下有权限的插件
Set<String> orgPluginIds = platformPluginService.getOrgEnabledPlatformPlugins(project.getOrganizationId())
.stream()
.map(Plugin::getId)
.collect(Collectors.toSet());
// 查询服务集成中启用并且支持第三方模板的插件
return serviceIntegrationService.getServiceIntegrationByOrgId(project.getOrganizationId())
.stream()
.filter(serviceIntegration -> {
return serviceIntegration.getEnable() // 服务集成开启
&& orgPluginIds.contains(serviceIntegration.getPluginId()); // 该服务集成对应的插件有权限
})
.findFirst()
.orElse(null);
}
/**
* 获取模板以及字段
* !提供给其他模块调用
* @param id
* @return
*/
public TemplateDTO geTemplateDTOWithCheck(String id) {
Template template = super.getWithCheck(id); Template template = super.getWithCheck(id);
checkProjectResourceExist(template); checkProjectResourceExist(template);
return super.geDTOWithCheck(template); return super.geTemplateDTO(template);
} }
@Override @Override
@ -64,20 +300,45 @@ public class ProjectTemplateService extends BaseTemplateService {
public void delete(String id) { public void delete(String id) {
Template template = getWithCheck(id); Template template = getWithCheck(id);
checkProjectTemplateEnable(template.getScopeId(), template.getScene()); checkProjectTemplateEnable(template.getScopeId(), template.getScene());
checkDefault(template);
super.delete(id); super.delete(id);
} }
/**
* 设置成默认模板后不能删除
*
* @param template
*/
protected void checkDefault(Template template) {
String defaultTemplateId = getDefaultTemplateId(template.getScopeId(), template.getScene());
if (StringUtils.equals(template.getId(), defaultTemplateId)) {
throw new MSException(DEFAULT_TEMPLATE_PERMISSION);
}
}
/** /**
* 将模板设置成默认模板 * 将模板设置成默认模板
* 同时将其他没模板设置成非默认模板
* *
* @param id * @param id
*/ */
@Override public void setDefaultTemplate(String projectId, String id) {
public void setDefaultTemplate(String id) { Template template = get(id);
Template template = getWithCheck(id); if (template == null) {
checkProjectTemplateEnable(template.getScopeId(), template.getScene()); Template pluginBugTemplate = getPluginBugTemplate(projectId);
super.setDefaultTemplate(id); if (pluginBugTemplate != null && StringUtils.equals(pluginBugTemplate.getId(), id)) {
template = pluginBugTemplate;
}
}
if (template == null) {
// 为空check抛出异常
template = getWithCheck(id);
}
String paramType = ProjectApplicationType.DEFAULT_TEMPLATE.getByTemplateScene(template.getScene()).name();
ProjectApplication projectApplication = new ProjectApplication();
projectApplication.setProjectId(projectId);
projectApplication.setTypeValue(id);
projectApplication.setType(paramType);
projectApplicationService.createOrUpdateConfig(projectApplication);
} }

View File

@ -1,5 +1,8 @@
package io.metersphere.project.controller; package io.metersphere.project.controller;
import io.metersphere.project.dto.ProjectTemplateDTO;
import io.metersphere.project.dto.ProjectTemplateOptionDTO;
import io.metersphere.project.service.ProjectTemplateService;
import io.metersphere.sdk.constants.OrganizationParameterConstants; import io.metersphere.sdk.constants.OrganizationParameterConstants;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.TemplateScene; import io.metersphere.sdk.constants.TemplateScene;
@ -9,6 +12,7 @@ import io.metersphere.sdk.dto.TemplateDTO;
import io.metersphere.sdk.dto.request.TemplateCustomFieldRequest; import io.metersphere.sdk.dto.request.TemplateCustomFieldRequest;
import io.metersphere.sdk.dto.request.TemplateUpdateRequest; import io.metersphere.sdk.dto.request.TemplateUpdateRequest;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.system.base.BasePluginTestService;
import io.metersphere.system.base.BaseTest; import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.param.TemplateUpdateRequestDefinition; import io.metersphere.system.controller.param.TemplateUpdateRequestDefinition;
import io.metersphere.system.domain.*; import io.metersphere.system.domain.*;
@ -22,6 +26,7 @@ import io.metersphere.system.service.UserLoginService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
@ -30,6 +35,8 @@ import org.springframework.test.web.servlet.MvcResult;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static io.metersphere.project.enums.result.ProjectResultCode.PROJECT_TEMPLATE_PERMISSION; import static io.metersphere.project.enums.result.ProjectResultCode.PROJECT_TEMPLATE_PERMISSION;
import static io.metersphere.sdk.constants.InternalUserRole.ADMIN; import static io.metersphere.sdk.constants.InternalUserRole.ADMIN;
@ -46,7 +53,7 @@ import static io.metersphere.system.controller.handler.result.MsHttpResultCode.N
public class ProjectTemplateControllerTests extends BaseTest { public class ProjectTemplateControllerTests extends BaseTest {
private static final String BASE_PATH = "/project/template/"; private static final String BASE_PATH = "/project/template/";
private static final String LIST = "list/{0}/{1}"; private static final String LIST = "list/{0}/{1}";
private static final String SET_DEFAULT = "set-default/{0}"; private static final String SET_DEFAULT = "set-default/{0}/{1}";
@Resource @Resource
private TemplateMapper templateMapper; private TemplateMapper templateMapper;
@ -60,6 +67,10 @@ public class ProjectTemplateControllerTests extends BaseTest {
private BaseTemplateCustomFieldService baseTemplateCustomFieldService; private BaseTemplateCustomFieldService baseTemplateCustomFieldService;
@Resource @Resource
private OrganizationParameterMapper organizationParameterMapper; private OrganizationParameterMapper organizationParameterMapper;
@Resource
private ProjectTemplateService projectTemplateService;
@Resource
private BasePluginTestService basePluginTestService;
private static Template addTemplate; private static Template addTemplate;
private static Template anotherTemplateField; private static Template anotherTemplateField;
@ -77,6 +88,7 @@ public class ProjectTemplateControllerTests extends BaseTest {
MvcResult mvcResult = this.requestGetWithOkAndReturn(LIST, DEFAULT_PROJECT_ID, TemplateScene.FUNCTIONAL.name()); MvcResult mvcResult = this.requestGetWithOkAndReturn(LIST, DEFAULT_PROJECT_ID, TemplateScene.FUNCTIONAL.name());
List<Template> templates = getResultDataArray(mvcResult, Template.class); List<Template> templates = getResultDataArray(mvcResult, Template.class);
this.defaultTemplate = templates.get(0); this.defaultTemplate = templates.get(0);
this.requestGetWithOkAndReturn(LIST, DEFAULT_PROJECT_ID, TemplateScene.BUG.name());
} }
@Test @Test
@ -228,26 +240,58 @@ public class ProjectTemplateControllerTests extends BaseTest {
@Test @Test
@Order(3) @Order(3)
public void list() throws Exception { public void list() throws Exception {
String scene = TemplateScene.FUNCTIONAL.name(); String scene = TemplateScene.FUNCTIONAL.name();
// @@请求成功 // @@请求成功
MvcResult mvcResult = this.requestGetWithOk(LIST, DEFAULT_PROJECT_ID, scene) MvcResult mvcResult = this.requestGetWithOk(LIST, DEFAULT_PROJECT_ID, scene)
.andReturn(); .andReturn();
// 校验数据是否正确 // 校验数据是否正确
List<Template> resultList = getResultDataArray(mvcResult, Template.class); List<ProjectTemplateDTO> resultList = getResultDataArray(mvcResult, ProjectTemplateDTO.class);
List<Template> templates = baseTemplateService.getTemplates(DEFAULT_PROJECT_ID, scene); List<Template> dbTemplates = baseTemplateService.getTemplates(DEFAULT_PROJECT_ID, scene);
List<String> userIds = templates.stream().map(Template::getCreateUser).toList(); assertListTemplate(scene, resultList, dbTemplates);
Map<String, String> userNameMap = userLoginService.getUserNameMap(userIds);
for (int i = 0; i < resultList.size(); i++) { // 校验获取模板选项方法
Template resultItem = resultList.get(i); List<ProjectTemplateOptionDTO> projectTemplateOptions = projectTemplateService.getOption(DEFAULT_PROJECT_ID, scene);
Template template = templates.get(i); assertTemplateOption(resultList, projectTemplateOptions);
template.setCreateUser(userNameMap.get(template.getCreateUser()));
if (template.getInternal()) { scene = TemplateScene.BUG.name();
// 校验内置用户名称是否翻译 // @@缺陷模板请求成功
template.setName(baseTemplateService.translateInternalTemplate(template.getName())); mvcResult = this.requestGetWithOk(LIST, DEFAULT_PROJECT_ID, scene)
} .andReturn();
Assertions.assertEquals(template, resultItem); // 校验数据是否正确
Assertions.assertEquals(resultItem.getScene(), scene); resultList = getResultDataArray(mvcResult, ProjectTemplateDTO.class);
} dbTemplates = baseTemplateService.getTemplates(DEFAULT_PROJECT_ID, scene);
assertListTemplate(scene, resultList, dbTemplates);
// 校验获取模板选项方法
projectTemplateOptions = projectTemplateService.getOption(DEFAULT_PROJECT_ID, scene);
assertTemplateOption(resultList, projectTemplateOptions);
// 上传jira插件添加jira集成
basePluginTestService.addJiraPlugin();
basePluginTestService.addServiceIntegration(DEFAULT_ORGANIZATION_ID);
// @@校验配置服务集成后是否有jira模板
mvcResult = this.requestGetWithOk(LIST, DEFAULT_PROJECT_ID, scene)
.andReturn();
resultList = getResultDataArray(mvcResult, ProjectTemplateDTO.class);
// 没有配置项目信息校验是否有jira模板
Assertions.assertTrue(resultList.size() == dbTemplates.size());
Assertions.assertTrue(resultList.stream().filter(item -> StringUtils.equals(item.getId(), "jira")).count() == 0);
// 校验获取模板选项方法
projectTemplateOptions = projectTemplateService.getOption(DEFAULT_PROJECT_ID, scene);
assertTemplateOption(resultList, projectTemplateOptions);
// 配置项目信息
basePluginTestService.enableProjectBugConfig(DEFAULT_PROJECT_ID);
// @@校验配置项目信息后是否有jira模板
mvcResult = this.requestGetWithOk(LIST, DEFAULT_PROJECT_ID, scene)
.andReturn();
Template jiraTemplate = getResultDataArray(mvcResult, Template.class).stream()
.filter(item -> StringUtils.equals(item.getId(), "jira"))
.findFirst()
.get();
Assertions.assertNotNull(jiraTemplate);
// @@校验组织是否存在 // @@校验组织是否存在
assertErrorCode(this.requestGet(LIST, "1111", scene), NOT_FOUND); assertErrorCode(this.requestGet(LIST, "1111", scene), NOT_FOUND);
@ -259,6 +303,34 @@ public class ProjectTemplateControllerTests extends BaseTest {
requestGetPermissionTest(PermissionConstants.PROJECT_TEMPLATE_READ, LIST, DEFAULT_PROJECT_ID, scene); requestGetPermissionTest(PermissionConstants.PROJECT_TEMPLATE_READ, LIST, DEFAULT_PROJECT_ID, scene);
} }
private static void assertTemplateOption(List<ProjectTemplateDTO> resultList, List<ProjectTemplateOptionDTO> projectTemplateOptions) {
Map<String, ProjectTemplateDTO> templateMap = resultList.stream().collect(Collectors.toMap(Template::getId, Function.identity()));
Assertions.assertEquals(projectTemplateOptions.size(), resultList.size());
projectTemplateOptions.forEach(option -> {
ProjectTemplateDTO template = templateMap.get(option.getId());
Assertions.assertEquals(option.getId(), template.getId());
Assertions.assertEquals(option.getName(), template.getName());
Assertions.assertEquals(option.getEnableDefault(), template.getEnableDefault());
});
}
private void assertListTemplate(String scene, List<ProjectTemplateDTO> resultList, List<Template> dbTemplates) {
List<String> userIds = dbTemplates.stream().map(Template::getCreateUser).toList();
Map<String, String> userNameMap = userLoginService.getUserNameMap(userIds);
Assertions.assertTrue(resultList.size() == dbTemplates.size());
for (int i = 0; i < resultList.size(); i++) {
Template resultItem = resultList.get(i);
Template template = dbTemplates.get(i);
template.setCreateUser(userNameMap.get(template.getCreateUser()));
if (template.getInternal()) {
// 校验内置用户名称是否翻译
template.setName(baseTemplateService.translateInternalTemplate());
}
Assertions.assertEquals(template, resultItem);
Assertions.assertEquals(resultItem.getScene(), scene);
}
}
@Test @Test
@Order(4) @Order(4)
public void get() throws Exception { public void get() throws Exception {
@ -289,20 +361,26 @@ public class ProjectTemplateControllerTests extends BaseTest {
@Order(5) @Order(5)
public void setDefaultTemplate() throws Exception { public void setDefaultTemplate() throws Exception {
changeOrgTemplateEnable(false); changeOrgTemplateEnable(false);
String projectId = DEFAULT_PROJECT_ID;
String scene = TemplateScene.FUNCTIONAL.name();
String defaultTemplateId = projectTemplateService.getDefaultTemplateId(projectId, scene);
// 校验默认没有设置默认模板使用内置模板
Assertions.assertNull(defaultTemplateId);
TemplateDTO defaultTemplateDTO = projectTemplateService.getDefaultTemplateDTO(projectId, scene);
Assertions.assertEquals(defaultTemplateDTO.getInternal(), true);
// @@请求成功 // @@请求成功
this.requestGetWithOk(SET_DEFAULT, addTemplate.getId()); this.requestGetWithOk(SET_DEFAULT, DEFAULT_PROJECT_ID, addTemplate.getId());
Template template = templateMapper.selectByPrimaryKey(addTemplate.getId()); Template template = templateMapper.selectByPrimaryKey(addTemplate.getId());
assertSetDefaultTemplate(template); assertSetDefaultTemplate(template);
defaultTemplateDTO = projectTemplateService.getDefaultTemplateDTO(projectId, scene);
// @校验是否开启项目模板 Assertions.assertEquals(defaultTemplateDTO.getId(), template.getId());
changeOrgTemplateEnable(true);
assertErrorCode(this.requestGet(SET_DEFAULT, addTemplate.getId()), PROJECT_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(false);
// @@校验日志 // @@校验日志
checkLog(addTemplate.getId(), OperationLogType.UPDATE); checkLog(addTemplate.getId(), OperationLogType.UPDATE);
// @@校验权限 // @@校验权限
requestGetPermissionTest(PermissionConstants.ORGANIZATION_TEMPLATE_UPDATE, SET_DEFAULT, addTemplate.getScopeId(), addTemplate.getScene()); requestGetPermissionTest(PermissionConstants.ORGANIZATION_TEMPLATE_UPDATE, SET_DEFAULT, DEFAULT_PROJECT_ID, addTemplate.getId());
} }
@Test @Test
@ -313,23 +391,21 @@ public class ProjectTemplateControllerTests extends BaseTest {
assertErrorCode(this.requestGet(DEFAULT_DELETE, addTemplate.getId()), PROJECT_TEMPLATE_PERMISSION); assertErrorCode(this.requestGet(DEFAULT_DELETE, addTemplate.getId()), PROJECT_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(false); changeOrgTemplateEnable(false);
// @@校验内置模板删除异常
Template internalTemplate = projectTemplateService.getInternalTemplate(DEFAULT_PROJECT_ID, TemplateScene.FUNCTIONAL.name());
assertErrorCode(this.requestGet(DEFAULT_DELETE, internalTemplate.getId()), INTERNAL_TEMPLATE_PERMISSION);
// @@校验删除默认模板 // @@校验删除默认模板
assertErrorCode(this.requestGet(DEFAULT_DELETE, addTemplate.getId()), DEFAULT_TEMPLATE_PERMISSION); assertErrorCode(this.requestGet(DEFAULT_DELETE, addTemplate.getId()), DEFAULT_TEMPLATE_PERMISSION);
// 设置回来保证正常删除 // 设置回来保证正常删除
this.requestGetWithOk(SET_DEFAULT, defaultTemplate.getId()); this.requestGetWithOk(SET_DEFAULT, DEFAULT_PROJECT_ID, defaultTemplate.getId());
// @@请求成功 // @@请求成功
this.requestGetWithOk(DEFAULT_DELETE, addTemplate.getId()); this.requestGetWithOk(DEFAULT_DELETE, addTemplate.getId());
Assertions.assertNull(templateMapper.selectByPrimaryKey(addTemplate.getId())); Assertions.assertNull(templateMapper.selectByPrimaryKey(addTemplate.getId()));
Assertions.assertTrue(CollectionUtils.isEmpty(baseTemplateCustomFieldService.getByTemplateId(addTemplate.getId()))); Assertions.assertTrue(CollectionUtils.isEmpty(baseTemplateCustomFieldService.getByTemplateId(addTemplate.getId())));
// @@校验内置模板删除异常 basePluginTestService.deleteJiraPlugin();
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 异常 // @@校验 NOT_FOUND 异常
assertErrorCode(this.requestGet(DEFAULT_DELETE, "1111"), NOT_FOUND); assertErrorCode(this.requestGet(DEFAULT_DELETE, "1111"), NOT_FOUND);
@ -341,18 +417,8 @@ public class ProjectTemplateControllerTests extends BaseTest {
} }
private void assertSetDefaultTemplate(Template template) { private void assertSetDefaultTemplate(Template template) {
Assertions.assertTrue(template.getEnableDefault()); String defaultTemplateId = projectTemplateService.getDefaultTemplateId(template.getScopeId(), template.getScene());
int defaultCount = getTemplateByScopeId(addTemplate.getScopeId()) Assertions.assertEquals(defaultTemplateId, template.getId());
.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) { private void changeOrgTemplateEnable(boolean enable) {

View File

@ -88,14 +88,6 @@ public class OrganizationTemplateController {
organizationTemplateService.disableOrganizationTemplate(organizationId, 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);
}
@GetMapping("/is-enable/{organizationId}/{scene}") @GetMapping("/is-enable/{organizationId}/{scene}")
@Operation(summary = "是否启用组织模版") @Operation(summary = "是否启用组织模版")
@RequiresPermissions(PermissionConstants.ORGANIZATION_TEMPLATE_READ) @RequiresPermissions(PermissionConstants.ORGANIZATION_TEMPLATE_READ)

View File

@ -50,10 +50,15 @@ public class BaseTemplateService {
List<Template> templates = getTemplates(scopeId, scene); List<Template> templates = getTemplates(scopeId, scene);
List<String> userIds = templates.stream().map(Template::getCreateUser).toList(); List<String> userIds = templates.stream().map(Template::getCreateUser).toList();
Map<String, String> userNameMap = userLoginService.getUserNameMap(userIds); Map<String, String> userNameMap = userLoginService.getUserNameMap(userIds);
templates.forEach(item -> item.setCreateUser(userNameMap.get(item.getCreateUser())));
translateInternalTemplate(templates);
return templates;
}
public List<Template> translateInternalTemplate(List<Template> templates) {
templates.forEach(item -> { templates.forEach(item -> {
item.setCreateUser(userNameMap.get(item.getCreateUser()));
if (item.getInternal()) { if (item.getInternal()) {
item.setName(translateInternalTemplate(item.getName())); item.setName(translateInternalTemplate());
} }
}); });
return templates; return templates;
@ -74,16 +79,19 @@ public class BaseTemplateService {
return templateMapper.selectByExample(example); return templateMapper.selectByExample(example);
} }
public String translateInternalTemplate(String filedName) { public String translateInternalTemplate() {
return Translator.get("template." + filedName); return Translator.get("template.default");
} }
public Template getWithCheck(String id) { public Template getWithCheck(String id) {
return checkResourceExist(id); return checkResourceExist(id);
} }
public Template get(String id) {
return templateMapper.selectByPrimaryKey(id);
}
public TemplateDTO geDTOWithCheck(Template template) { protected TemplateDTO geTemplateDTO(Template template) {
List<TemplateCustomField> templateCustomFields = baseTemplateCustomFieldService.getByTemplateId(template.getId()); List<TemplateCustomField> templateCustomFields = baseTemplateCustomFieldService.getByTemplateId(template.getId());
// 查找字段名称 // 查找字段名称
@ -112,7 +120,6 @@ public class BaseTemplateService {
public Template add(Template template, List<TemplateCustomFieldRequest> customFields) { public Template add(Template template, List<TemplateCustomFieldRequest> customFields) {
template.setInternal(false); template.setInternal(false);
template.setEnableDefault(false);
return this.baseAdd(template, customFields); return this.baseAdd(template, customFields);
} }
@ -144,7 +151,6 @@ public class BaseTemplateService {
template.setScopeId(null); template.setScopeId(null);
template.setCreateUser(null); template.setCreateUser(null);
template.setCreateTime(null); template.setCreateTime(null);
template.setEnableDefault(null);
// customFields null 则不修改 // customFields null 则不修改
if (customFields != null) { if (customFields != null) {
baseTemplateCustomFieldService.deleteByTemplateId(template.getId()); baseTemplateCustomFieldService.deleteByTemplateId(template.getId());
@ -157,29 +163,10 @@ public class BaseTemplateService {
public void delete(String id) { public void delete(String id) {
Template template = checkResourceExist(id); Template template = checkResourceExist(id);
checkInternal(template); checkInternal(template);
checkDefault(template);
templateMapper.deleteByPrimaryKey(id); templateMapper.deleteByPrimaryKey(id);
baseTemplateCustomFieldService.deleteByTemplateId(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 * @param template
@ -190,16 +177,6 @@ public class BaseTemplateService {
} }
} }
/**
* 设置成默认模板后不能删除
* @param template
*/
protected void checkDefault(Template template) {
if (template.getEnableDefault()) {
throw new MSException(DEFAULT_TEMPLATE_PERMISSION);
}
}
protected void checkAddExist(Template template) { protected void checkAddExist(Template template) {
TemplateExample example = new TemplateExample(); TemplateExample example = new TemplateExample();
example.createCriteria() example.createCriteria()
@ -329,7 +306,6 @@ public class BaseTemplateService {
template.setScopeType(scopeType.name()); template.setScopeType(scopeType.name());
template.setScopeId(scopeId); template.setScopeId(scopeId);
template.setEnableThirdPart(false); template.setEnableThirdPart(false);
template.setEnableDefault(true);
template.setScene(scene.name()); template.setScene(scene.name());
templateMapper.insert(template); templateMapper.insert(template);
return template; return template;

View File

@ -45,7 +45,7 @@ public class OrganizationTemplateService extends BaseTemplateService {
public TemplateDTO geDTOWithCheck(String id) { public TemplateDTO geDTOWithCheck(String id) {
Template template = super.getWithCheck(id); Template template = super.getWithCheck(id);
checkOrgResourceExist(template); checkOrgResourceExist(template);
return super.geDTOWithCheck(template); return super.geTemplateDTO(template);
} }
@Override @Override
@ -132,34 +132,6 @@ public class OrganizationTemplateService extends BaseTemplateService {
super.delete(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);
}
/** /**
* 同步删除项目级别模板 * 同步删除项目级别模板
* 当开启组织模板时操作组织模板同时维护与之关联的项目模板 * 当开启组织模板时操作组织模板同时维护与之关联的项目模板

View File

@ -73,7 +73,7 @@ public class ServiceIntegrationService {
}).toList(); }).toList();
} }
private List<ServiceIntegration> getServiceIntegrationByOrgId(String organizationId) { public List<ServiceIntegration> getServiceIntegrationByOrgId(String organizationId) {
ServiceIntegrationExample example = new ServiceIntegrationExample(); ServiceIntegrationExample example = new ServiceIntegrationExample();
example.createCriteria() example.createCriteria()
.andOrganizationIdEqualTo(organizationId); .andOrganizationIdEqualTo(organizationId);

View File

@ -0,0 +1,151 @@
package io.metersphere.system.base;
import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.project.domain.ProjectApplicationExample;
import io.metersphere.project.mapper.ProjectApplicationMapper;
import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.domain.Plugin;
import io.metersphere.system.domain.ServiceIntegration;
import io.metersphere.system.mapper.PluginMapper;
import io.metersphere.system.request.PluginUpdateRequest;
import io.metersphere.system.request.ServiceIntegrationUpdateRequest;
import io.metersphere.system.service.PluginService;
import io.metersphere.system.service.ServiceIntegrationService;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.FileInputStream;
import java.util.Map;
import static io.metersphere.sdk.constants.InternalUserRole.ADMIN;
/**
* @Author: jianxing
* @CreateTime: 2023-10-20 11:32
*/
@Service
public class BasePluginTestService {
@Resource
private PluginService pluginService;
@Value("${embedded.mockserver.host}")
private String mockServerHost;
@Value("${embedded.mockserver.port}")
private int mockServerHostPort;
@Resource
private ServiceIntegrationService serviceIntegrationService;
@Resource
private ProjectApplicationMapper projectApplicationMapper;
@Resource
private PluginMapper pluginMapper;
private static Plugin jiraPlugin;
private static ServiceIntegration serviceIntegration;
/**
* 添加插件供测试使用
*
* @return
* @throws Exception
*/
public Plugin addJiraPlugin() throws Exception {
if (hasJiraPlugin()) {
return jiraPlugin;
}
PluginUpdateRequest request = new PluginUpdateRequest();
File jarFile = new File(
this.getClass().getClassLoader().getResource("file/metersphere-jira-plugin-3.x.jar")
.getPath()
);
FileInputStream inputStream = new FileInputStream(jarFile);
MockMultipartFile mockMultipartFile = new MockMultipartFile(jarFile.getName(), jarFile.getName(), "jar", inputStream);
request.setName("测试插件");
request.setGlobal(true);
request.setEnable(true);
request.setCreateUser(ADMIN.name());
jiraPlugin = pluginService.add(request, mockMultipartFile);
return jiraPlugin;
}
/**
* 添加服务集成信息
* @return
* @throws Exception
*/
public ServiceIntegration addServiceIntegration(String orgId) {
JiraIntegrationConfig integrationConfig = new JiraIntegrationConfig();
integrationConfig.setAddress(String.format("http://%s:%s", mockServerHost, mockServerHostPort));
Map<String, Object> integrationConfigMap = JSON.parseMap(JSON.toJSONString(integrationConfig));
ServiceIntegrationUpdateRequest request = new ServiceIntegrationUpdateRequest();
request.setEnable(true);
request.setPluginId(jiraPlugin.getId());
request.setConfiguration(integrationConfigMap);
request.setOrganizationId(orgId);
serviceIntegration = serviceIntegrationService.add(request);
return serviceIntegration;
}
public Plugin getJiraPlugin() throws Exception {
if (!hasJiraPlugin()) {
return this.addJiraPlugin();
}
return jiraPlugin;
}
public boolean hasJiraPlugin() {
if (jiraPlugin != null) {
return true;
}
jiraPlugin = pluginMapper.selectByPrimaryKey("jira");
return jiraPlugin != null;
}
public void deleteJiraPlugin() {
if (jiraPlugin != null) {
pluginService.delete(jiraPlugin.getId());
jiraPlugin = null;
}
}
public void enableProjectBugConfig(String defaultProjectId) {
ProjectApplication projectApplication = new ProjectApplication();
projectApplication.setProjectId(defaultProjectId);
projectApplication.setType(ProjectApplicationType.BUG_SYNC_CONFIG.SYNC_ENABLE.name());
projectApplication.setTypeValue(BooleanUtils.toStringTrueFalse(true));
createOrUpdateConfig(projectApplication);
}
public void createOrUpdateConfig(ProjectApplication application) {
String type = application.getType();
String projectId = application.getProjectId();
ProjectApplicationExample example = new ProjectApplicationExample();
example.createCriteria().andProjectIdEqualTo(projectId).andTypeEqualTo(type);
if (projectApplicationMapper.countByExample(example) > 0) {
example.clear();
example.createCriteria().andProjectIdEqualTo(projectId).andTypeEqualTo(type);
projectApplicationMapper.updateByExample(application, example);
} else {
projectApplicationMapper.insertSelective(application);
}
}
@Getter
@Setter
public static class JiraIntegrationConfig {
private String account;
private String password;
private String token;
private String authType;
private String address;
private String version;
}
}

View File

@ -44,7 +44,6 @@ public class OrganizationTemplateControllerTests extends BaseTest {
private static final String BASE_PATH = "/organization/template/"; private static final String BASE_PATH = "/organization/template/";
private static final String LIST = "list/{0}/{1}"; private static final String LIST = "list/{0}/{1}";
private static final String DISABLE_ORG_TEMPLATE = "disable/{0}/{1}"; private static final String DISABLE_ORG_TEMPLATE = "disable/{0}/{1}";
private static final String SET_DEFAULT = "set-default/{0}";
protected static final String IS_ORGANIZATION_TEMPLATE_ENABLE = "is-enable/{0}/{1}"; protected static final String IS_ORGANIZATION_TEMPLATE_ENABLE = "is-enable/{0}/{1}";
@Resource @Resource
@ -286,7 +285,7 @@ public class OrganizationTemplateControllerTests extends BaseTest {
template.setCreateUser(userNameMap.get(template.getCreateUser())); template.setCreateUser(userNameMap.get(template.getCreateUser()));
if (template.getInternal()) { if (template.getInternal()) {
// 校验内置用户名称是否翻译 // 校验内置用户名称是否翻译
template.setName(baseTemplateService.translateInternalTemplate(template.getName())); template.setName(baseTemplateService.translateInternalTemplate());
} }
Assertions.assertEquals(template, resultItem); Assertions.assertEquals(template, resultItem);
Assertions.assertEquals(resultItem.getScene(), scene); Assertions.assertEquals(resultItem.getScene(), scene);
@ -349,46 +348,6 @@ public class OrganizationTemplateControllerTests extends BaseTest {
requestGetPermissionTest(PermissionConstants.ORGANIZATION_TEMPLATE_ENABLE, DISABLE_ORG_TEMPLATE, addTemplate.getScopeId(), addTemplate.getScene()); 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);
assertRefSetDefaultTemplate(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 assertRefSetDefaultTemplate(Template template) {
List<Template> refTemplates = organizationTemplateService.getByRefId(template.getId());
refTemplates.forEach(this::assertSetDefaultTemplate);
}
@Test @Test
@Order(7) @Order(7)
public void delete() throws Exception { public void delete() throws Exception {
@ -398,11 +357,6 @@ public class OrganizationTemplateControllerTests extends BaseTest {
assertErrorCode(this.requestGet(DEFAULT_DELETE, addTemplate.getId()), ORGANIZATION_TEMPLATE_PERMISSION); assertErrorCode(this.requestGet(DEFAULT_DELETE, addTemplate.getId()), ORGANIZATION_TEMPLATE_PERMISSION);
changeOrgTemplateEnable(true); changeOrgTemplateEnable(true);
// @@校验删除默认模板
assertErrorCode(this.requestGet(DEFAULT_DELETE, addTemplate.getId()), DEFAULT_TEMPLATE_PERMISSION);
// 设置回来保证正常删除
this.requestGetWithOk(SET_DEFAULT, defaultTemplate.getId());
// @@请求成功 // @@请求成功
this.requestGetWithOk(DEFAULT_DELETE, addTemplate.getId()); this.requestGetWithOk(DEFAULT_DELETE, addTemplate.getId());
Assertions.assertNull(templateMapper.selectByPrimaryKey(addTemplate.getId())); Assertions.assertNull(templateMapper.selectByPrimaryKey(addTemplate.getId()));

View File

@ -1,25 +1,22 @@
package io.metersphere.system.controller; package io.metersphere.system.controller;
import io.metersphere.plugin.platform.spi.AbstractPlatformPlugin; import io.metersphere.plugin.platform.spi.AbstractPlatformPlugin;
import io.metersphere.system.base.BaseTest;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.service.PluginLoadService;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BasePluginTestService;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.param.ServiceIntegrationUpdateRequestDefinition; import io.metersphere.system.controller.param.ServiceIntegrationUpdateRequestDefinition;
import io.metersphere.system.domain.Organization; import io.metersphere.system.domain.Organization;
import io.metersphere.system.domain.Plugin; import io.metersphere.system.domain.Plugin;
import io.metersphere.system.domain.ServiceIntegration; import io.metersphere.system.domain.ServiceIntegration;
import io.metersphere.system.dto.ServiceIntegrationDTO; import io.metersphere.system.dto.ServiceIntegrationDTO;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.PluginMapper; import io.metersphere.system.mapper.PluginMapper;
import io.metersphere.system.mapper.ServiceIntegrationMapper; import io.metersphere.system.mapper.ServiceIntegrationMapper;
import io.metersphere.system.request.PluginUpdateRequest;
import io.metersphere.system.request.ServiceIntegrationUpdateRequest; import io.metersphere.system.request.ServiceIntegrationUpdateRequest;
import io.metersphere.system.service.OrganizationService; import io.metersphere.system.service.OrganizationService;
import io.metersphere.system.service.PluginService; import io.metersphere.system.service.PluginLoadService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
import org.mockserver.client.MockServerClient; import org.mockserver.client.MockServerClient;
@ -27,15 +24,11 @@ import org.mockserver.model.Header;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import java.io.File;
import java.io.FileInputStream;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static io.metersphere.sdk.constants.InternalUserRole.ADMIN;
import static io.metersphere.system.controller.handler.result.CommonResultCode.PLUGIN_ENABLE; import static io.metersphere.system.controller.handler.result.CommonResultCode.PLUGIN_ENABLE;
import static io.metersphere.system.controller.handler.result.CommonResultCode.PLUGIN_PERMISSION; import static io.metersphere.system.controller.handler.result.CommonResultCode.PLUGIN_PERMISSION;
import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND; import static io.metersphere.system.controller.handler.result.MsHttpResultCode.NOT_FOUND;
@ -58,7 +51,6 @@ public class ServiceIntegrationControllerTests extends BaseTest {
private static final String VALIDATE_POST = "/validate/{0}"; private static final String VALIDATE_POST = "/validate/{0}";
private static final String SCRIPT_GET = "/script/{0}"; private static final String SCRIPT_GET = "/script/{0}";
private static ServiceIntegration addServiceIntegration; private static ServiceIntegration addServiceIntegration;
private static Plugin plugin;
private static Organization defaultOrg; private static Organization defaultOrg;
@Resource @Resource
@ -68,7 +60,7 @@ public class ServiceIntegrationControllerTests extends BaseTest {
@Resource @Resource
private PluginLoadService pluginLoadService; private PluginLoadService pluginLoadService;
@Resource @Resource
private PluginService pluginService; private BasePluginTestService basePluginTestService;
@Resource @Resource
private PluginMapper pluginMapper; private PluginMapper pluginMapper;
@Resource @Resource
@ -95,9 +87,9 @@ public class ServiceIntegrationControllerTests extends BaseTest {
@Test @Test
@Order(1) @Order(1)
public void add() throws Exception { public void add() throws Exception {
plugin = addPlugin(); Plugin plugin = basePluginTestService.addJiraPlugin();
JiraIntegrationConfig integrationConfig = new JiraIntegrationConfig(); BasePluginTestService.JiraIntegrationConfig integrationConfig = new BasePluginTestService.JiraIntegrationConfig();
Map<String, Object> integrationConfigMap = JSON.parseMap(JSON.toJSONString(integrationConfig)); Map<String, Object> integrationConfigMap = JSON.parseMap(JSON.toJSONString(integrationConfig));
// @@请求成功 // @@请求成功
@ -140,7 +132,7 @@ public class ServiceIntegrationControllerTests extends BaseTest {
@Test @Test
@Order(2) @Order(2)
public void update() throws Exception { public void update() throws Exception {
JiraIntegrationConfig integrationConfig = new JiraIntegrationConfig(); BasePluginTestService.JiraIntegrationConfig integrationConfig = new BasePluginTestService.JiraIntegrationConfig();
integrationConfig.setAddress(String.format("http://%s:%s", mockServerHost, mockServerHostPort)); integrationConfig.setAddress(String.format("http://%s:%s", mockServerHost, mockServerHostPort));
Map<String, Object> integrationConfigMap = JSON.parseMap(JSON.toJSONString(integrationConfig)); Map<String, Object> integrationConfigMap = JSON.parseMap(JSON.toJSONString(integrationConfig));
@ -148,7 +140,7 @@ public class ServiceIntegrationControllerTests extends BaseTest {
ServiceIntegrationUpdateRequest request = new ServiceIntegrationUpdateRequest(); ServiceIntegrationUpdateRequest request = new ServiceIntegrationUpdateRequest();
request.setId(addServiceIntegration.getId()); request.setId(addServiceIntegration.getId());
request.setEnable(false); request.setEnable(false);
request.setPluginId(plugin.getId()); request.setPluginId(basePluginTestService.getJiraPlugin().getId());
request.setConfiguration(integrationConfigMap); request.setConfiguration(integrationConfigMap);
request.setOrganizationId(defaultOrg.getId()); request.setOrganizationId(defaultOrg.getId());
this.requestPostWithOk(DEFAULT_UPDATE, request); this.requestPostWithOk(DEFAULT_UPDATE, request);
@ -190,6 +182,7 @@ public class ServiceIntegrationControllerTests extends BaseTest {
@Test @Test
@Order(3) @Order(3)
public void list() throws Exception { public void list() throws Exception {
Plugin plugin = basePluginTestService.getJiraPlugin();
// @@请求成功 // @@请求成功
MvcResult mvcResult = this.requestGetWithOkAndReturn(LIST, defaultOrg.getId()); MvcResult mvcResult = this.requestGetWithOkAndReturn(LIST, defaultOrg.getId());
// 校验请求成功数据 // 校验请求成功数据
@ -252,7 +245,8 @@ public class ServiceIntegrationControllerTests extends BaseTest {
@Test @Test
@Order(5) @Order(5)
public void validatePost() throws Exception { public void validatePost() throws Exception {
JiraIntegrationConfig integrationConfig = new JiraIntegrationConfig(); Plugin plugin = basePluginTestService.getJiraPlugin();
BasePluginTestService.JiraIntegrationConfig integrationConfig = new BasePluginTestService.JiraIntegrationConfig();
integrationConfig.setAddress(String.format("http://%s:%s", mockServerHost, mockServerHostPort)); integrationConfig.setAddress(String.format("http://%s:%s", mockServerHost, mockServerHostPort));
Map<String, Object> integrationConfigMap = JSON.parseMap(JSON.toJSONString(integrationConfig)); Map<String, Object> integrationConfigMap = JSON.parseMap(JSON.toJSONString(integrationConfig));
// @@请求成功 // @@请求成功
@ -277,6 +271,7 @@ public class ServiceIntegrationControllerTests extends BaseTest {
@Test @Test
@Order(6) @Order(6)
public void getPluginScript() throws Exception { public void getPluginScript() throws Exception {
Plugin plugin = basePluginTestService.getJiraPlugin();
// @@请求成功 // @@请求成功
MvcResult mvcResult = this.requestGetWithOkAndReturn(SCRIPT_GET, plugin.getId()); MvcResult mvcResult = this.requestGetWithOkAndReturn(SCRIPT_GET, plugin.getId());
// 校验请求成功数据 // 校验请求成功数据
@ -307,7 +302,7 @@ public class ServiceIntegrationControllerTests extends BaseTest {
Assertions.assertNull(serviceIntegration); Assertions.assertNull(serviceIntegration);
// 清理插件 // 清理插件
deletePlugin(); basePluginTestService.deleteJiraPlugin();
// @@校验日志 // @@校验日志
checkLog(addServiceIntegration.getId(), OperationLogType.DELETE); checkLog(addServiceIntegration.getId(), OperationLogType.DELETE);
@ -319,28 +314,6 @@ public class ServiceIntegrationControllerTests extends BaseTest {
requestGetPermissionTest(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_DELETE, DEFAULT_DELETE, addServiceIntegration.getId()); requestGetPermissionTest(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_DELETE, DEFAULT_DELETE, addServiceIntegration.getId());
} }
/**
* 添加插件供测试使用
*
* @return
* @throws Exception
*/
public Plugin addPlugin() throws Exception {
PluginUpdateRequest request = new PluginUpdateRequest();
File jarFile = new File(
this.getClass().getClassLoader().getResource("file/metersphere-jira-plugin-3.x.jar")
.getPath()
);
FileInputStream inputStream = new FileInputStream(jarFile);
MockMultipartFile mockMultipartFile = new MockMultipartFile(jarFile.getName(), jarFile.getName(), "jar", inputStream);
request.setName("测试插件");
request.setGlobal(true);
request.setEnable(true);
request.setCreateUser(ADMIN.name());
return pluginService.add(request, mockMultipartFile);
}
public void setPluginEnable(String pluginId, boolean enabled) { public void setPluginEnable(String pluginId, boolean enabled) {
Plugin plugin = new Plugin(); Plugin plugin = new Plugin();
plugin.setId(pluginId); plugin.setId(pluginId);
@ -354,23 +327,4 @@ public class ServiceIntegrationControllerTests extends BaseTest {
plugin.setGlobal(global); plugin.setGlobal(global);
pluginMapper.updateByPrimaryKeySelective(plugin); pluginMapper.updateByPrimaryKeySelective(plugin);
} }
/**
* 删除插件
* @throws Exception
*/
public void deletePlugin() {
pluginService.delete(plugin.getId());
}
@Getter
@Setter
public class JiraIntegrationConfig {
private String account;
private String password;
private String token;
private String authType;
private String address;
private String version;
}
} }