feat(系统设置): 服务集成接口设计

--task=1012656 --user=陈建星 系统设置-组织-服务集成-后台 https://www.tapd.cn/55049933/s/1401952
This commit is contained in:
jianxing 2023-08-09 17:53:27 +08:00 committed by jianxing
parent 1e92bc77b5
commit 2618c93cc0
22 changed files with 734 additions and 77 deletions

View File

@ -10,20 +10,25 @@ import lombok.Data;
@Data
public class ServiceIntegration implements Serializable {
@Schema(title = "", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(title = "ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{service_integration.id.not_blank}", groups = {Updated.class})
@Size(min = 1, max = 50, message = "{service_integration.id.length_range}", groups = {Created.class, Updated.class})
private String id;
@Schema(title = "平台", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{service_integration.platform.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{service_integration.platform.length_range}", groups = {Created.class, Updated.class})
private String platform;
@Schema(title = "插件的ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{service_integration.plugin_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{service_integration.plugin_id.length_range}", groups = {Created.class, Updated.class})
private String pluginId;
@Schema(title = "组织ID")
@Schema(title = "是否启用")
private Boolean enable;
@Schema(title = "组织ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{service_integration.organization_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{service_integration.organization_id.length_range}", groups = {Created.class, Updated.class})
private String organizationId;
@Schema(title = "", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(title = "配置内容", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{service_integration.configuration.not_blank}", groups = {Created.class})
private byte[] configuration;
@ -31,7 +36,8 @@ public class ServiceIntegration implements Serializable {
public enum Column {
id("id", "id", "VARCHAR", false),
platform("platform", "platform", "VARCHAR", false),
pluginId("plugin_id", "pluginId", "VARCHAR", false),
enable("enable", "enable", "BIT", true),
organizationId("organization_id", "organizationId", "VARCHAR", false),
configuration("configuration", "configuration", "LONGVARBINARY", false);

View File

@ -174,73 +174,133 @@ public class ServiceIntegrationExample {
return (Criteria) this;
}
public Criteria andPlatformIsNull() {
addCriterion("platform is null");
public Criteria andPluginIdIsNull() {
addCriterion("plugin_id is null");
return (Criteria) this;
}
public Criteria andPlatformIsNotNull() {
addCriterion("platform is not null");
public Criteria andPluginIdIsNotNull() {
addCriterion("plugin_id is not null");
return (Criteria) this;
}
public Criteria andPlatformEqualTo(String value) {
addCriterion("platform =", value, "platform");
public Criteria andPluginIdEqualTo(String value) {
addCriterion("plugin_id =", value, "pluginId");
return (Criteria) this;
}
public Criteria andPlatformNotEqualTo(String value) {
addCriterion("platform <>", value, "platform");
public Criteria andPluginIdNotEqualTo(String value) {
addCriterion("plugin_id <>", value, "pluginId");
return (Criteria) this;
}
public Criteria andPlatformGreaterThan(String value) {
addCriterion("platform >", value, "platform");
public Criteria andPluginIdGreaterThan(String value) {
addCriterion("plugin_id >", value, "pluginId");
return (Criteria) this;
}
public Criteria andPlatformGreaterThanOrEqualTo(String value) {
addCriterion("platform >=", value, "platform");
public Criteria andPluginIdGreaterThanOrEqualTo(String value) {
addCriterion("plugin_id >=", value, "pluginId");
return (Criteria) this;
}
public Criteria andPlatformLessThan(String value) {
addCriterion("platform <", value, "platform");
public Criteria andPluginIdLessThan(String value) {
addCriterion("plugin_id <", value, "pluginId");
return (Criteria) this;
}
public Criteria andPlatformLessThanOrEqualTo(String value) {
addCriterion("platform <=", value, "platform");
public Criteria andPluginIdLessThanOrEqualTo(String value) {
addCriterion("plugin_id <=", value, "pluginId");
return (Criteria) this;
}
public Criteria andPlatformLike(String value) {
addCriterion("platform like", value, "platform");
public Criteria andPluginIdLike(String value) {
addCriterion("plugin_id like", value, "pluginId");
return (Criteria) this;
}
public Criteria andPlatformNotLike(String value) {
addCriterion("platform not like", value, "platform");
public Criteria andPluginIdNotLike(String value) {
addCriterion("plugin_id not like", value, "pluginId");
return (Criteria) this;
}
public Criteria andPlatformIn(List<String> values) {
addCriterion("platform in", values, "platform");
public Criteria andPluginIdIn(List<String> values) {
addCriterion("plugin_id in", values, "pluginId");
return (Criteria) this;
}
public Criteria andPlatformNotIn(List<String> values) {
addCriterion("platform not in", values, "platform");
public Criteria andPluginIdNotIn(List<String> values) {
addCriterion("plugin_id not in", values, "pluginId");
return (Criteria) this;
}
public Criteria andPlatformBetween(String value1, String value2) {
addCriterion("platform between", value1, value2, "platform");
public Criteria andPluginIdBetween(String value1, String value2) {
addCriterion("plugin_id between", value1, value2, "pluginId");
return (Criteria) this;
}
public Criteria andPlatformNotBetween(String value1, String value2) {
addCriterion("platform not between", value1, value2, "platform");
public Criteria andPluginIdNotBetween(String value1, String value2) {
addCriterion("plugin_id not between", value1, value2, "pluginId");
return (Criteria) this;
}
public Criteria andEnableIsNull() {
addCriterion("`enable` is null");
return (Criteria) this;
}
public Criteria andEnableIsNotNull() {
addCriterion("`enable` is not null");
return (Criteria) this;
}
public Criteria andEnableEqualTo(Boolean value) {
addCriterion("`enable` =", value, "enable");
return (Criteria) this;
}
public Criteria andEnableNotEqualTo(Boolean value) {
addCriterion("`enable` <>", value, "enable");
return (Criteria) this;
}
public Criteria andEnableGreaterThan(Boolean value) {
addCriterion("`enable` >", value, "enable");
return (Criteria) this;
}
public Criteria andEnableGreaterThanOrEqualTo(Boolean value) {
addCriterion("`enable` >=", value, "enable");
return (Criteria) this;
}
public Criteria andEnableLessThan(Boolean value) {
addCriterion("`enable` <", value, "enable");
return (Criteria) this;
}
public Criteria andEnableLessThanOrEqualTo(Boolean value) {
addCriterion("`enable` <=", value, "enable");
return (Criteria) this;
}
public Criteria andEnableIn(List<Boolean> values) {
addCriterion("`enable` in", values, "enable");
return (Criteria) this;
}
public Criteria andEnableNotIn(List<Boolean> values) {
addCriterion("`enable` not in", values, "enable");
return (Criteria) this;
}
public Criteria andEnableBetween(Boolean value1, Boolean value2) {
addCriterion("`enable` between", value1, value2, "enable");
return (Criteria) this;
}
public Criteria andEnableNotBetween(Boolean value1, Boolean value2) {
addCriterion("`enable` not between", value1, value2, "enable");
return (Criteria) this;
}

View File

@ -3,7 +3,8 @@
<mapper namespace="io.metersphere.system.mapper.ServiceIntegrationMapper">
<resultMap id="BaseResultMap" type="io.metersphere.system.domain.ServiceIntegration">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="platform" jdbcType="VARCHAR" property="platform" />
<result column="plugin_id" jdbcType="VARCHAR" property="pluginId" />
<result column="enable" jdbcType="BIT" property="enable" />
<result column="organization_id" jdbcType="VARCHAR" property="organizationId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.system.domain.ServiceIntegration">
@ -68,7 +69,7 @@
</where>
</sql>
<sql id="Base_Column_List">
id, platform, organization_id
id, plugin_id, `enable`, organization_id
</sql>
<sql id="Blob_Column_List">
configuration
@ -122,10 +123,10 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.system.domain.ServiceIntegration">
insert into service_integration (id, platform, organization_id,
configuration)
values (#{id,jdbcType=VARCHAR}, #{platform,jdbcType=VARCHAR}, #{organizationId,jdbcType=VARCHAR},
#{configuration,jdbcType=LONGVARBINARY})
insert into service_integration (id, plugin_id, `enable`,
organization_id, configuration)
values (#{id,jdbcType=VARCHAR}, #{pluginId,jdbcType=VARCHAR}, #{enable,jdbcType=BIT},
#{organizationId,jdbcType=VARCHAR}, #{configuration,jdbcType=LONGVARBINARY})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.system.domain.ServiceIntegration">
insert into service_integration
@ -133,8 +134,11 @@
<if test="id != null">
id,
</if>
<if test="platform != null">
platform,
<if test="pluginId != null">
plugin_id,
</if>
<if test="enable != null">
`enable`,
</if>
<if test="organizationId != null">
organization_id,
@ -147,8 +151,11 @@
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="platform != null">
#{platform,jdbcType=VARCHAR},
<if test="pluginId != null">
#{pluginId,jdbcType=VARCHAR},
</if>
<if test="enable != null">
#{enable,jdbcType=BIT},
</if>
<if test="organizationId != null">
#{organizationId,jdbcType=VARCHAR},
@ -170,8 +177,11 @@
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.platform != null">
platform = #{record.platform,jdbcType=VARCHAR},
<if test="record.pluginId != null">
plugin_id = #{record.pluginId,jdbcType=VARCHAR},
</if>
<if test="record.enable != null">
`enable` = #{record.enable,jdbcType=BIT},
</if>
<if test="record.organizationId != null">
organization_id = #{record.organizationId,jdbcType=VARCHAR},
@ -187,7 +197,8 @@
<update id="updateByExampleWithBLOBs" parameterType="map">
update service_integration
set id = #{record.id,jdbcType=VARCHAR},
platform = #{record.platform,jdbcType=VARCHAR},
plugin_id = #{record.pluginId,jdbcType=VARCHAR},
`enable` = #{record.enable,jdbcType=BIT},
organization_id = #{record.organizationId,jdbcType=VARCHAR},
configuration = #{record.configuration,jdbcType=LONGVARBINARY}
<if test="_parameter != null">
@ -197,7 +208,8 @@
<update id="updateByExample" parameterType="map">
update service_integration
set id = #{record.id,jdbcType=VARCHAR},
platform = #{record.platform,jdbcType=VARCHAR},
plugin_id = #{record.pluginId,jdbcType=VARCHAR},
`enable` = #{record.enable,jdbcType=BIT},
organization_id = #{record.organizationId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -206,8 +218,11 @@
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.system.domain.ServiceIntegration">
update service_integration
<set>
<if test="platform != null">
platform = #{platform,jdbcType=VARCHAR},
<if test="pluginId != null">
plugin_id = #{pluginId,jdbcType=VARCHAR},
</if>
<if test="enable != null">
`enable` = #{enable,jdbcType=BIT},
</if>
<if test="organizationId != null">
organization_id = #{organizationId,jdbcType=VARCHAR},
@ -220,24 +235,27 @@
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.system.domain.ServiceIntegration">
update service_integration
set platform = #{platform,jdbcType=VARCHAR},
set plugin_id = #{pluginId,jdbcType=VARCHAR},
`enable` = #{enable,jdbcType=BIT},
organization_id = #{organizationId,jdbcType=VARCHAR},
configuration = #{configuration,jdbcType=LONGVARBINARY}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.system.domain.ServiceIntegration">
update service_integration
set platform = #{platform,jdbcType=VARCHAR},
set plugin_id = #{pluginId,jdbcType=VARCHAR},
`enable` = #{enable,jdbcType=BIT},
organization_id = #{organizationId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into service_integration
(id, platform, organization_id, configuration)
(id, plugin_id, `enable`, organization_id, configuration)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.platform,jdbcType=VARCHAR}, #{item.organizationId,jdbcType=VARCHAR},
#{item.configuration,jdbcType=LONGVARBINARY})
(#{item.id,jdbcType=VARCHAR}, #{item.pluginId,jdbcType=VARCHAR}, #{item.enable,jdbcType=BIT},
#{item.organizationId,jdbcType=VARCHAR}, #{item.configuration,jdbcType=LONGVARBINARY}
)
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
@ -253,8 +271,11 @@
<if test="'id'.toString() == column.value">
#{item.id,jdbcType=VARCHAR}
</if>
<if test="'platform'.toString() == column.value">
#{item.platform,jdbcType=VARCHAR}
<if test="'plugin_id'.toString() == column.value">
#{item.pluginId,jdbcType=VARCHAR}
</if>
<if test="'enable'.toString() == column.value">
#{item.enable,jdbcType=BIT}
</if>
<if test="'organization_id'.toString() == column.value">
#{item.organizationId,jdbcType=VARCHAR}

View File

@ -215,17 +215,18 @@ CREATE INDEX idx_type ON schedule (`type`);
CREATE TABLE IF NOT EXISTS service_integration
(
`id` VARCHAR(50) NOT NULL COMMENT '',
`platform` VARCHAR(50) NOT NULL COMMENT '平台',
`configuration` BLOB NOT NULL COMMENT '',
`organization_id` VARCHAR(50) COMMENT '组织ID',
`id` VARCHAR(50) NOT NULL COMMENT 'ID' ,
`plugin_id` VARCHAR(50) NOT NULL COMMENT '插件的ID' ,
`enable` BIT NOT NULL DEFAULT 1 COMMENT '是否启用' ,
`configuration` BLOB NOT NULL COMMENT '配置内容' ,
`organization_id` VARCHAR(50) NOT NULL COMMENT '组织ID' ,
PRIMARY KEY (id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci COMMENT = '服务集成';
CREATE INDEX idx_workspace_id ON service_integration (`organization_id`);
CREATE INDEX idx_organization_id ON service_integration (`organization_id`);
CREATE TABLE IF NOT EXISTS system_parameter
(

View File

@ -49,6 +49,14 @@ public class PermissionConstants {
public static final String SYSTEM_PLUGIN_DELETE = "SYSTEM_PLUGIN_READ:READ+DELETE";
/*------ end: SYSTEM_PLUGIN ------*/
/*------ start: SYSTEM_SERVICE_INTEGRATION ------*/
public static final String SYSTEM_SERVICE_INTEGRATION_READ = "SYSTEM_SERVICE_INTEGRATION_READ:READ";
public static final String SYSTEM_SERVICE_INTEGRATION_ADD = "SYSTEM_SERVICE_INTEGRATION_READ:READ+ADD";
public static final String SYSTEM_SERVICE_INTEGRATION_UPDATE = "SYSTEM_SERVICE_INTEGRATION_READ:READ+UPDATE";
public static final String SYSTEM_SERVICE_INTEGRATION_DELETE = "SYSTEM_SERVICE_INTEGRATION_READ:READ+DELETE";
/*------ end: SYSTEM_SERVICE_INTEGRATION ------*/
public static final String SYSTEM_USER_READ = "SYSTEM_USER:READ";
public static final String SYSTEM_USER_READ_ADD = "SYSTEM_USER:READ+ADD";
public static final String SYSTEM_USER_READ_IMPORT = "SYSTEM_USER:READ+IMPORT";

View File

@ -54,6 +54,9 @@ public class FilterChainUtils {
// websocket
filterChainDefinitionMap.put("/websocket/**", "csrf");
// 获取插件中的图片
filterChainDefinitionMap.put("/platform/plugin/image/**", "anon");
return filterChainDefinitionMap;
}

View File

@ -65,9 +65,6 @@ schedule.job.not_blank=Schedule job must not be blank
schedule.job.length_range=Schedule job must be between {min} and {max} characters long
schedule.create_user.not_blank=Schedule create user must not be blank
schedule.create_user.length_range=Schedule create user must be between {min} and {max} characters long
service_integration.id.not_blank=Service integration id must not be blank
service_integration.platform.not_blank=Service integration platform must not be blank
service_integration.platform.length_range=Service integration platform must be between {min} and {max} characters long
system_parameter.param_key.not_blank=System parameter param key must not be blank
system_parameter.type.not_blank=System parameter type must not be blank
system_parameter.type.length_range=System parameter type must be between {min} and {max} characters long
@ -168,6 +165,14 @@ plugin.exist=plugin name or filename already exists
plugin.type.exist=plugin type already exists
plugin.script.exist=duplicate script id
plugin.script.format=malformed script
# serviceIntegration
service_integration.id.not_blank=id cannot be empty
service_integration.id.length_range=id length must be between {min} and {max}
service_integration.plugin_id.not_blank=pluginId cannot be empty
service_integration.plugin_id.length_range=pluginId length must be between {min} and {max}
service_integration.organization_id.not_blank=organizationId cannot be empty
service_integration.organization_id.length_range=organizationId length must be between {min} and {max}
service_integration_exist_error=Service integration configuration already exists
# permission
permission.system_plugin.name=Plugin
permission.system_organization_project.name=Organization Project
@ -184,6 +189,7 @@ permission.system_parameter_setting_auth.update=Auth parameter setting update
permission.system_parameter_setting_auth.delete=Auth parameter setting delete
permission.organization_user_role.name=User group
permission.organization_member.name=User
permission.service_integration.name=Service Integration

View File

@ -65,9 +65,6 @@ schedule.job.not_blank=定时任务不能为空
schedule.job.length_range=定时任务长度必须在{min}和{max}之间
schedule.create_user.not_blank=定时任务创建人不能为空
schedule.create_user.length_range=定时任务创建人长度必须在{min}和{max}之间
service_integration.id.not_blank=服务集成ID不能为空
service_integration.platform.not_blank=服务集成平台不能为空
service_integration.platform.length_range=服务集成平台长度必须在{min}和{max}之间
system_parameter.param_key.not_blank=系统参数Key不能为空
system_parameter.type.not_blank=系统参数类型不能为空
system_parameter.type.length_range=系统参数类型长度必须在{min}和{max}之间
@ -167,6 +164,14 @@ plugin.exist=插件名称或文件名已存在
plugin.type.exist=插件类型已存在
plugin.script.exist=脚本id重复
plugin.script.format=脚本格式错误
# serviceIntegration
service_integration.id.not_blank=ID不能為空
service_integration.id.length_range=ID長度必須在{min}和{max}之间
service_integration.plugin_id.not_blank=插件的ID不能為空
service_integration.plugin_id.length_range=插件的ID長度必須在{min}和{max}之间
service_integration.organization_id.not_blank=组织ID不能為空
service_integration.organization_id.length_range=组织ID長度必須在{min}和{max}之间
service_integration_exist_error=服务集成配置已存在
# permission
permission.system_plugin.name=插件
permission.system_organization_project.name=组织与项目
@ -183,6 +188,7 @@ permission.system_parameter_setting_auth.update=认证设置-编辑
permission.system_parameter_setting_auth.delete=认证设置-删除
permission.organization_user_role.name=用户组
permission.organization_member.name=用户
permission.service_integration.name=服务集成

View File

@ -65,9 +65,6 @@ schedule.job.not_blank=定時任務不能為空
schedule.job.length_range=定時任務長度必須在{min}和{max}之間
schedule.create_user.not_blank=定時任務創建人不能為空
schedule.create_user.length_range=定時任務創建人長度必須在{min}和{max}之間
service_integration.id.not_blank=服務集成ID不能為空
service_integration.platform.not_blank=服務集成平台不能為空
service_integration.platform.length_range=服務集成平台長度必須在{min}和{max}之間
system_parameter.param_key.not_blank=系統參數Key不能為空
system_parameter.type.not_blank=系統參數類型不能為空
system_parameter.type.length_range=系統參數類型長度必須在{min}和{max}之間
@ -167,6 +164,14 @@ plugin.exist=插件名稱或文件名已存在
plugin.type.exist=插件類型已存在
plugin.script.exist=腳本id重複
plugin.script.format=腳本格式錯誤
# serviceIntegration
service_integration.id.not_blank=ID不能为空
service_integration.id.length_range=ID长度必须在{min}和{max}之间
service_integration.plugin_id.not_blank=插件的ID不能为空
service_integration.plugin_id.length_range=插件的ID长度必须在{min}和{max}之间
service_integration.organization_id.not_blank=组织ID不能为空
service_integration.organization_id.length_range=组织ID长度必须在{min}和{max}之间
service_integration_exist_error=服務集成配置已存在
# permission
permission.system_plugin.name=插件
permission.system_organization_project.name=組織與項目
@ -183,4 +188,5 @@ permission.system_parameter_setting_auth.update=認證設置-編輯
permission.system_parameter_setting_auth.delete=認證設置-刪除
permission.organization_user_role.name=用戶組
permission.organization_member.name=用戶
permission.service_integration.name=服務集成

View File

@ -104,7 +104,7 @@ public abstract class BaseTest {
return new AuthInfo(sessionId, csrfToken);
}
private MockHttpServletRequestBuilder getPostRequestBuilder(String url, Object param, Object... uriVariables) {
protected MockHttpServletRequestBuilder getPostRequestBuilder(String url, Object param, Object... uriVariables) {
return MockMvcRequestBuilders.post(getBasePath() + url, uriVariables)
.header(SessionConstants.HEADER_TOKEN, adminAuthInfo.getSessionId())
.header(SessionConstants.CSRF_TOKEN, adminAuthInfo.getCsrfToken())
@ -112,7 +112,7 @@ public abstract class BaseTest {
.contentType(MediaType.APPLICATION_JSON);
}
private MockHttpServletRequestBuilder getRequestBuilder(String url, Object... uriVariables) {
protected MockHttpServletRequestBuilder getRequestBuilder(String url, Object... uriVariables) {
return MockMvcRequestBuilders.get(getBasePath() + url, uriVariables)
.header(SessionConstants.HEADER_TOKEN, adminAuthInfo.getSessionId())
.header(SessionConstants.CSRF_TOKEN, adminAuthInfo.getCsrfToken());

View File

@ -13,8 +13,10 @@ import io.metersphere.system.service.PluginService;
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 jakarta.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -75,4 +77,16 @@ public class PluginController {
public String getScript(@PathVariable String pluginId, @PathVariable String scriptId) {
return pluginService.getScript(pluginId, scriptId);
}
@GetMapping("/image/{pluginId}")
public void getPluginImg(
@Schema(title = "插件ID", requiredMode = Schema.RequiredMode.REQUIRED)
@PathVariable("pluginId")
String pluginId,
@Schema(title = "图片路径", requiredMode = Schema.RequiredMode.REQUIRED)
@RequestParam("imagePath")
String imagePath,
HttpServletResponse response) {
// todo
}
}

View File

@ -0,0 +1,88 @@
package io.metersphere.system.controller;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.log.annotation.Log;
import io.metersphere.sdk.log.constants.OperationLogType;
import io.metersphere.system.domain.ServiceIntegration;
import io.metersphere.system.dto.ServiceIntegrationDTO;
import io.metersphere.system.request.ServiceIntegrationUpdateRequest;
import io.metersphere.system.service.ServiceIntegrationLogService;
import io.metersphere.system.service.ServiceIntegrationService;
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;
import java.util.Map;
/**
* @author : jianxing
* @date : 2023-8-9
*/
@RestController
@RequestMapping("/service/integration")
@Tag(name = "服务集成")
public class ServiceIntegrationController {
@Resource
private ServiceIntegrationService serviceIntegrationService;
@GetMapping("/list/{organizationId}")
@Operation(summary = "获取服务集成列表")
@RequiresPermissions(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_READ)
public List<ServiceIntegrationDTO> list(@PathVariable String organizationId) {
return serviceIntegrationService.list(organizationId);
}
@PostMapping("/add")
@Operation(summary = "创建服务集成")
@RequiresPermissions(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_ADD)
@Log(type = OperationLogType.UPDATE, expression = "#msClass.addLog(#request)", msClass = ServiceIntegrationLogService.class)
public ServiceIntegration add(@Validated({Created.class}) @RequestBody ServiceIntegrationUpdateRequest request) {
return serviceIntegrationService.add(request);
}
@PostMapping("/update")
@Operation(summary = "更新服务集成")
@RequiresPermissions(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_UPDATE)
@Log(type = OperationLogType.ADD, expression = "#msClass.updateLog(#request)", msClass = ServiceIntegrationLogService.class)
public ServiceIntegration update(@Validated({Updated.class}) @RequestBody ServiceIntegrationUpdateRequest request) {
return serviceIntegrationService.update(request);
}
@GetMapping("/delete/{id}")
@Operation(summary = "删除服务集成")
@RequiresPermissions(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_DELETE)
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = ServiceIntegrationLogService.class)
public String delete(@PathVariable String id) {
return serviceIntegrationService.delete(id);
}
@PostMapping("/validate")
@Operation(summary = "校验服务集成信息")
@RequiresPermissions(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_UPDATE)
public boolean validate(@Validated({Updated.class}) @RequestBody
@Schema(title = "配置的表单键值对", requiredMode = Schema.RequiredMode.REQUIRED)
Map<String, String> serviceIntegrationInfo) {
return serviceIntegrationService.validate(serviceIntegrationInfo);
}
@GetMapping("/validate/{id}")
@Operation(summary = "校验服务集成信息")
@RequiresPermissions(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_UPDATE)
public boolean validate(@PathVariable String id) {
return serviceIntegrationService.validate(id);
}
@GetMapping("/script/{pluginId}")
@Operation(summary = "获取前端配置脚本")
@RequiresPermissions(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_READ)
public Object getPluginScript(@PathVariable String pluginId) {
return serviceIntegrationService.getPluginScript(pluginId);
}
}

View File

@ -14,6 +14,7 @@ public enum SystemResultCode implements IResultCode {
GLOBAL_USER_ROLE_EXIST(101002, "global_user_role_exist_error"),
GLOBAL_USER_ROLE_RELATION_SYSTEM_PERMISSION(101003, "global_user_role_relation_system_permission_error"),
GLOBAL_USER_ROLE_LIMIT(101004, "global_user_role_limit_error"),
SERVICE_INTEGRATION_EXIST(101005, "service_integration_exist_error"),
/**
* 获取/编辑组织自定义用户组如果非组织自定义用户组会返回该响应码
*/

View File

@ -0,0 +1,39 @@
package io.metersphere.system.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.util.Map;
@Data
public class ServiceIntegrationDTO implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(title = "ID")
private String id;
@Schema(title = "插件的ID")
private String pluginId;
@Schema(title = "插件的名称")
private String title;
@Schema(title = "插件描述")
private String describe;
@Schema(title = "是否启用")
private Boolean enable;
@Schema(title = "是否配置")
private Boolean config;
@Schema(title = "logo图片地址")
private String logo;
@Schema(title = "组织ID")
private String organizationId;
@Schema(title = "配置的表单值,已配置才有值")
private Map<String, String> configuration;
}

View File

@ -0,0 +1,39 @@
package io.metersphere.system.request;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serializable;
import java.util.Map;
@Data
public class ServiceIntegrationUpdateRequest implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(title = "ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{service_integration.id.not_blank}", groups = {Updated.class})
@Size(min = 1, max = 50, message = "{service_integration.id.length_range}", groups = {Created.class, Updated.class})
private String id;
@Schema(title = "插件的ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{service_integration.plugin_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{service_integration.plugin_id.length_range}", groups = {Created.class, Updated.class})
private String pluginId;
@Schema(title = "是否启用")
private Boolean enable;
@Schema(title = "组织ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{service_integration.organization_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{service_integration.organization_id.length_range}", groups = {Created.class, Updated.class})
private String organizationId;
@Schema(title = "配置的表单键值对", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{service_integration.configuration.not_blank}", groups = {Created.class})
private Map<String, String> configuration;
}

View File

@ -4,6 +4,7 @@ import io.metersphere.sdk.dto.PermissionDefinitionItem;
import io.metersphere.sdk.dto.request.PermissionSettingUpdateRequest;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.service.BaseUserRoleService;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.UserRole;
import io.metersphere.system.domain.UserRoleExample;
import io.metersphere.system.dto.UserRoleOption;
@ -104,7 +105,7 @@ public class GlobalUserRoleService extends BaseUserRoleService {
public void checkRoleIsGlobalAndHaveMember(@Valid @NotEmpty List<String> roleIdList, boolean isSystem) {
List<String> globalRoleList = extUserRoleMapper.selectGlobalRoleList(roleIdList, isSystem);
if (globalRoleList.size() != roleIdList.size()) {
throw new MSException("role.not.global");
throw new MSException(Translator.get("role.not.global"));
}
}

View File

@ -0,0 +1,70 @@
package io.metersphere.system.service;
import io.metersphere.system.domain.ServiceIntegration;
import io.metersphere.system.request.ServiceIntegrationUpdateRequest;
import io.metersphere.sdk.constants.OperationLogConstants;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import io.metersphere.sdk.dto.LogDTO;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.log.constants.OperationLogType;
import io.metersphere.sdk.log.constants.OperationLogModule;
import org.springframework.transaction.annotation.Transactional;
/**
* @author jianxing
* @date : 2023-8-9
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class ServiceIntegrationLogService {
@Resource
private ServiceIntegrationService serviceIntegrationService;
public LogDTO addLog(ServiceIntegrationUpdateRequest request) {
LogDTO dto = new LogDTO(
OperationLogConstants.SYSTEM,
OperationLogConstants.SYSTEM,
null,
null,
OperationLogType.ADD.name(),
OperationLogModule.ORGANIZATION_SERVICE_INTEGRATION,
"创建服务集成");
dto.setOriginalValue(JSON.toJSONBytes(request));
return dto;
}
public LogDTO updateLog(ServiceIntegrationUpdateRequest request) {
ServiceIntegration serviceIntegration = serviceIntegrationService.get(request.getId());
LogDTO dto = null;
if (serviceIntegration != null) {
dto = new LogDTO(
OperationLogConstants.SYSTEM,
OperationLogConstants.SYSTEM,
serviceIntegration.getId(),
null,
OperationLogType.UPDATE.name(),
OperationLogModule.ORGANIZATION_SERVICE_INTEGRATION,
"更新服务集成");
dto.setOriginalValue(JSON.toJSONBytes(serviceIntegration));
}
return dto;
}
public LogDTO deleteLog(String id) {
ServiceIntegration serviceIntegration = serviceIntegrationService.get(id);
if (serviceIntegration == null) {
return null;
}
LogDTO dto = new LogDTO(
OperationLogConstants.SYSTEM,
OperationLogConstants.SYSTEM,
serviceIntegration.getId(),
null,
OperationLogType.DELETE.name(),
OperationLogModule.ORGANIZATION_SERVICE_INTEGRATION,
"删除服务集成");
dto.setOriginalValue(JSON.toJSONBytes(serviceIntegration));
return dto;
}
}

View File

@ -0,0 +1,89 @@
package io.metersphere.system.service;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.domain.ServiceIntegration;
import io.metersphere.system.domain.ServiceIntegrationExample;
import io.metersphere.system.dto.ServiceIntegrationDTO;
import io.metersphere.system.mapper.ServiceIntegrationMapper;
import io.metersphere.system.request.ServiceIntegrationUpdateRequest;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static io.metersphere.system.controller.result.SystemResultCode.SERVICE_INTEGRATION_EXIST;
/**
* @author jianxing
* @date : 2023-8-9
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class ServiceIntegrationService {
@Resource
private ServiceIntegrationMapper serviceIntegrationMapper;
public List<ServiceIntegrationDTO> list(String organizationId) {
return Arrays.asList(new ServiceIntegrationDTO());
}
public ServiceIntegration add(ServiceIntegrationUpdateRequest request) {
ServiceIntegration serviceIntegration = new ServiceIntegration();
BeanUtils.copyBean(serviceIntegration, request);
serviceIntegration.setId(UUID.randomUUID().toString());
serviceIntegration.setConfiguration(JSON.toJSONBytes(request.getConfiguration()));
checkAddExist(serviceIntegration);
serviceIntegrationMapper.insert(serviceIntegration);
return serviceIntegration;
}
public ServiceIntegration update(ServiceIntegrationUpdateRequest request) {
ServiceIntegration serviceIntegration = new ServiceIntegration();
BeanUtils.copyBean(serviceIntegration, request);
if (request.getConfiguration() != null) {
serviceIntegration.setConfiguration(JSON.toJSONBytes(request.getConfiguration()));
}
serviceIntegrationMapper.updateByPrimaryKeySelective(serviceIntegration);
return serviceIntegration;
}
public String delete(String id) {
serviceIntegrationMapper.deleteByPrimaryKey(id);
return id;
}
private void checkAddExist(ServiceIntegration serviceIntegration) {
ServiceIntegrationExample example = new ServiceIntegrationExample();
example.createCriteria()
.andOrganizationIdEqualTo(serviceIntegration.getOrganizationId())
.andPluginIdEqualTo(serviceIntegration.getPluginId());
if (CollectionUtils.isNotEmpty(serviceIntegrationMapper.selectByExample(example))) {
throw new MSException(SERVICE_INTEGRATION_EXIST);
}
}
public boolean validate(Map<String, String> serviceIntegrationInfo) {
return serviceIntegrationInfo == null;
}
public boolean validate(String id) {
ServiceIntegration serviceIntegration = serviceIntegrationMapper.selectByPrimaryKey(id);
return serviceIntegration == null;
}
public ServiceIntegration get(String id) {
return serviceIntegrationMapper.selectByPrimaryKey(id);
}
public Object getPluginScript(String pluginId) {
return new ServiceIntegration();
}
}

View File

@ -159,6 +159,24 @@
"id": "ORGANIZATION_MEMBER:READ+DELETE"
}
]
},
{
"id": "SYSTEM_SERVICE_INTEGRATION",
"name": "permission.service_integration.name",
"permissions": [
{
"id": "SYSTEM_SERVICE_INTEGRATION:READ"
},
{
"id": "SYSTEM_SERVICE_INTEGRATION:READ+ADD"
},
{
"id": "SYSTEM_SERVICE_INTEGRATION:READ+UPDATE"
},
{
"id": "SYSTEM_SERVICE_INTEGRATION:READ+DELETE"
}
]
}
]
}

View File

@ -24,9 +24,13 @@ import org.springframework.test.web.servlet.MvcResult;
import org.springframework.util.MultiValueMap;
import java.io.File;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import static io.metersphere.system.controller.result.SystemResultCode.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author jianxing
@ -38,6 +42,7 @@ import static io.metersphere.system.controller.result.SystemResultCode.*;
public class PluginControllerTests extends BaseTest {
private static final String BASE_PATH = "/plugin/";
private static final String SCRIPT_GET = "script/get/{0}/{1}";
private static final String PLUGIN_IMAGE = "/image/{0}?imagePath={1}";
@Resource
private PluginMapper pluginMapper;
@Resource
@ -253,6 +258,14 @@ public class PluginControllerTests extends BaseTest {
@Test
@Order(5)
public void getPluginImg() throws Exception {
// @@请求成功
mockMvc.perform(getRequestBuilder(PLUGIN_IMAGE, "pluginId", "/static/jira.jpg"))
.andExpect(status().isOk());
}
@Test
@Order(6)
public void delete() throws Exception {
// @@请求成功
this.requestGetWithOk(DEFAULT_DELETE, addPlugin.getId());

View File

@ -0,0 +1,135 @@
package io.metersphere.system.controller;
import io.metersphere.sdk.base.BaseTest;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.log.constants.OperationLogType;
import io.metersphere.system.controller.param.ServiceIntegrationUpdateRequestDefinition;
import io.metersphere.system.domain.ServiceIntegration;
import io.metersphere.system.mapper.ServiceIntegrationMapper;
import io.metersphere.system.request.ServiceIntegrationUpdateRequest;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
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.HashMap;
/**
* @author jianxing
* @date : 2023-8-9
*/
@SpringBootTest
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ServiceIntegrationControllerTests extends BaseTest {
private static final String BASE_PATH = "/service/integration/";
private static final String LIST = "/list/{0}";
private static final String VALIDATE_GET = "/validate/{0}";
private static final String VALIDATE_POST = "/validate";
private static final String SCRIPT_GET = "/script/{0}";
@Resource
private ServiceIntegrationMapper serviceIntegrationMapper;
private static ServiceIntegration addServiceIntegration;
@Override
protected String getBasePath() {
return BASE_PATH;
}
@Test
public void list() throws Exception {
// @@请求成功
this.requestGetWithOkAndReturn(LIST, "orgId");
// List<ServiceIntegration> serviceIntegrationList = getResultDataArray(mvcResult, ServiceIntegration.class);
// todo 校验数据是否正确
// @@校验权限
requestGetPermissionTest(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_READ, LIST,"orgId");
}
@Test
@Order(0)
public void add() throws Exception {
// @@请求成功
ServiceIntegrationUpdateRequest request = new ServiceIntegrationUpdateRequest();
request.setEnable(false);
request.setPluginId("pluginId");
request.setConfiguration(new HashMap<>());
request.setOrganizationId("orgId");
// todo 填充数据
MvcResult mvcResult = this.requestPostWithOkAndReturn(DEFAULT_ADD, request);
ServiceIntegration resultData = getResultData(mvcResult, ServiceIntegration.class);
ServiceIntegration serviceIntegration = serviceIntegrationMapper.selectByPrimaryKey(resultData.getId());
this.addServiceIntegration= serviceIntegration;
// todo 校验请求成功数据
// @@校验日志
checkLog(this.addServiceIntegration.getId(), OperationLogType.ADD);
// @@异常参数校验
createdGroupParamValidateTest(ServiceIntegrationUpdateRequestDefinition.class, DEFAULT_ADD);
// @@校验权限
requestPostPermissionTest(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_ADD, DEFAULT_ADD, request);
}
@Test
@Order(1)
public void update() throws Exception {
// @@请求成功
ServiceIntegrationUpdateRequest request = new ServiceIntegrationUpdateRequest();
request.setId(addServiceIntegration.getId());
request.setEnable(false);
request.setPluginId("pluginId");
request.setConfiguration(new HashMap<>());
request.setOrganizationId("orgId");
// todo 填充数据
this.requestPostWithOk(DEFAULT_UPDATE, request);
// 校验请求成功数据
// ServiceIntegration serviceIntegration = serviceIntegrationMapper.selectByPrimaryKey(request.getId());
// todo 校验请求成功数据
// @@校验日志
checkLog(request.getId(), OperationLogType.UPDATE);
// @@异常参数校验
updatedGroupParamValidateTest(ServiceIntegrationUpdateRequestDefinition.class, DEFAULT_UPDATE);
// @@校验权限
requestPostPermissionTest(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_UPDATE, DEFAULT_UPDATE, request);
}
@Test
public void delete() throws Exception {
// @@请求成功
this.requestGetWithOk(DEFAULT_DELETE, addServiceIntegration.getId());
// todo 校验请求成功数据
// @@校验日志
checkLog(addServiceIntegration.getId(), OperationLogType.DELETE);
// @@校验权限
requestGetPermissionTest(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_DELETE, DEFAULT_DELETE, addServiceIntegration.getId());
}
@Test
public void validateGet() throws Exception {
// @@请求成功
this.requestGetWithOk(VALIDATE_GET, addServiceIntegration.getId());
// todo 校验请求成功数据
// @@校验权限
requestGetPermissionTest(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_UPDATE, VALIDATE_GET, addServiceIntegration.getId());
}
@Test
public void validatePost() throws Exception {
// @@请求成功
this.requestPostWithOk(VALIDATE_POST, new HashMap<>());
// todo 校验请求成功数据
// @@校验权限
requestPostPermissionTest(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_UPDATE, VALIDATE_POST, new HashMap<>());
}
@Test
public void getPluginScript() throws Exception {
// @@请求成功
this.requestGetWithOk(SCRIPT_GET, "pluginId");
// todo 校验请求成功数据
// @@校验权限
requestGetPermissionTest(PermissionConstants.SYSTEM_SERVICE_INTEGRATION_READ, SCRIPT_GET, "pluginId");
}
}

View File

@ -0,0 +1,33 @@
package io.metersphere.system.controller.param;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.Map;
@Data
public class ServiceIntegrationUpdateRequestDefinition {
@Schema(title = "ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(groups = {Updated.class})
@Size(min = 1, max = 50, groups = {Created.class, Updated.class})
private String id;
@Schema(title = "插件的ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(groups = {Created.class})
@Size(min = 1, max = 50, groups = {Created.class, Updated.class})
private String pluginId;
@Schema(title = "组织ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(groups = {Created.class})
@Size(min = 1, max = 50, groups = {Created.class, Updated.class})
private String organizationId;
@Schema(title = "配置内容", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(groups = {Created.class})
private Map<String, String> configuration;
}