diff --git a/framework/sdk-parent/frontend/src/api/platform-plugin.js b/framework/sdk-parent/frontend/src/api/platform-plugin.js new file mode 100644 index 0000000000..7fe45cf3a2 --- /dev/null +++ b/framework/sdk-parent/frontend/src/api/platform-plugin.js @@ -0,0 +1,10 @@ +import {post, get} from "../plugins/request"; +const BASE_URL = "/global/platform/plugin/"; + +export function getPlatformAccountInfo() { + return get(BASE_URL + 'account/info'); +} + +export function validateAccountConfig(pluginId, config) { + return post(BASE_URL + `account/validate/${pluginId}`, config); +} diff --git a/framework/sdk-parent/frontend/src/components/personal/PersonRouter.vue b/framework/sdk-parent/frontend/src/components/personal/PersonRouter.vue index 50e13badde..78ca6b73e1 100644 --- a/framework/sdk-parent/frontend/src/components/personal/PersonRouter.vue +++ b/framework/sdk-parent/frontend/src/components/personal/PersonRouter.vue @@ -11,7 +11,8 @@ :label="$t('member.edit_password')" class="setting-item"> - +
+ +
@@ -51,24 +58,26 @@ import {getCurrentUser, getCurrentWorkspaceId} from "../../utils/token"; import {hasLicense, hasPermission} from "../../utils/permission"; import ZentaoUserInfo from "./ZentaoUserInfo"; import TapdUserInfo from "./TapdUserInfo"; -import JiraUserInfo from "./JiraUserInfo"; import AzureDevopsUserInfo from "./AzureDevopsUserInfo"; import {getIntegrationService} from "../../api/workspace"; import {useUserStore} from "@/store"; import {handleAuth as _handleAuth, getUserInfo, getWsAndPj, updateInfo} from "../../api/user"; +import PlatformAccountConfig from "./PlatformAccountConfig"; +import {getPlatformAccountInfo} from "../../api/platform-plugin"; + const userStore = useUserStore(); export default { name: "MsPersonRouter", components: { + PlatformAccountConfig, MsMainContainer, MsPersonFromSetting, MsApiKeys, PasswordInfo, ZentaoUserInfo, TapdUserInfo, - JiraUserInfo, AzureDevopsUserInfo, UiSetting }, @@ -79,7 +88,6 @@ export default { return { activeIndex: '', ruleForm: {}, - hasJira: false, hasTapd: false, hasZentao: false, hasAzure: false, @@ -94,6 +102,7 @@ export default { zentaoPassword: '', azureDevopsPat: '' }, + platformAccountConfigs: [], result: {}, loading: false, workspaceList: [], @@ -118,16 +127,7 @@ export default { }, handleAuth(type) { let param = {...this.currentPlatformInfo}; - if (type === 'Jira') { - if (!param.jiraAccount) { - this.$error(this.$t('organization.integration.input_api_account')); - return - } else if (!param.jiraPassword) { - this.$error(this.$t('organization.integration.input_api_password')); - return - } - - } else if (type === 'Zentao') { + if (type === 'Zentao') { if (!param.zentaoUserName) { this.$error(this.$t('organization.integration.input_api_account')); return @@ -167,9 +167,6 @@ export default { if (platforms.indexOf("Tapd") !== -1) { this.hasTapd = true; } - if (platforms.indexOf("Jira") !== -1) { - this.hasJira = true; - } if (platforms.indexOf("Zentao") !== -1) { this.hasZentao = true; } @@ -194,6 +191,10 @@ export default { }); }, initTableData() { + getPlatformAccountInfo() + .then((r) => { + this.platformAccountConfigs = r.data; + }); this.result = getUserInfo(encodeURIComponent(this.currentUser().id)) .then(response => { let data = response.data; diff --git a/framework/sdk-parent/frontend/src/components/personal/PlatformAccountConfig.vue b/framework/sdk-parent/frontend/src/components/personal/PlatformAccountConfig.vue new file mode 100644 index 0000000000..6f9ecbeac0 --- /dev/null +++ b/framework/sdk-parent/frontend/src/components/personal/PlatformAccountConfig.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/framework/sdk-parent/frontend/src/i18n/lang/en-US.js b/framework/sdk-parent/frontend/src/i18n/lang/en-US.js index bce694a1c9..aa87389cac 100644 --- a/framework/sdk-parent/frontend/src/i18n/lang/en-US.js +++ b/framework/sdk-parent/frontend/src/i18n/lang/en-US.js @@ -774,7 +774,8 @@ const message = { input_azure_url: 'Please enter Azure Devops Url', input_azure_id: 'Please enter Azure Organization ID', use_tip_azure: 'Azure Devops URL+PersonalAccessTokens(User Settings-Personal Access Tokens-New Token)', - jira_prompt_information: 'This information is the user authentication information for submitting defects through Jira. If it is not filled in, the default information configured in the workspace will be used' + jira_prompt_information: 'This information is the user authentication information for submitting defects through Jira. If it is not filled in, the default information configured in the workspace will be used', + jira_information: 'Jira information' } }, project: { diff --git a/framework/sdk-parent/frontend/src/i18n/lang/zh-CN.js b/framework/sdk-parent/frontend/src/i18n/lang/zh-CN.js index d3340222d1..79c732fe1e 100644 --- a/framework/sdk-parent/frontend/src/i18n/lang/zh-CN.js +++ b/framework/sdk-parent/frontend/src/i18n/lang/zh-CN.js @@ -781,7 +781,8 @@ const message = { input_azure_url: '请输入 Azure Devops 地址', input_azure_organization_id: '请输入 Azure 组织ID', use_tip_azure: 'Azure Devops 地址+令牌(账户设置-个人访问令牌-创建令牌)', - jira_prompt_information: '该信息为通过Jira提交缺陷的用户认证信息,若未填写,则使用工作空间中配置的默认信息' + jira_prompt_information: '该信息为通过Jira提交缺陷的用户认证信息,若未填写,则使用工作空间中配置的默认信息', + jira_information: 'Jira 信息' } }, project: { diff --git a/framework/sdk-parent/frontend/src/i18n/lang/zh-TW.js b/framework/sdk-parent/frontend/src/i18n/lang/zh-TW.js index 1546a4807e..06adbbcf9c 100644 --- a/framework/sdk-parent/frontend/src/i18n/lang/zh-TW.js +++ b/framework/sdk-parent/frontend/src/i18n/lang/zh-TW.js @@ -778,7 +778,8 @@ const message = { input_azure_url: '請輸入 Azure Devops 地址', input_azure_organization_id: '請輸入 Azure 組織ID', use_tip_azure: 'Azure Devops 地址+令牌(賬戶設置-個人訪問令牌-創建令牌)', - jira_prompt_information: '該信息為通過Jira提交缺陷的用戶認證信息,若未填寫,則使用工作空間中配置的默認信息' + jira_prompt_information: '該信息為通過Jira提交缺陷的用戶認證信息,若未填寫,則使用工作空間中配置的默認信息', + jira_information: 'Jira 信息', } }, project: { diff --git a/project-management/frontend/src/business/home/platform.js b/framework/sdk-parent/frontend/src/utils/platform.js similarity index 92% rename from project-management/frontend/src/business/home/platform.js rename to framework/sdk-parent/frontend/src/utils/platform.js index 5eb9ac10ed..75fcff55b1 100644 --- a/project-management/frontend/src/business/home/platform.js +++ b/framework/sdk-parent/frontend/src/utils/platform.js @@ -1,4 +1,4 @@ -import i18n from "@/i18n"; +import i18n from "../i18n"; export function getPlatformFormRules(config) { let rules = {}; diff --git a/framework/sdk-parent/sdk/src/main/java/io/metersphere/controller/remote/BasePlatformPluginController.java b/framework/sdk-parent/sdk/src/main/java/io/metersphere/controller/remote/BasePlatformPluginController.java new file mode 100644 index 0000000000..6be4fcf099 --- /dev/null +++ b/framework/sdk-parent/sdk/src/main/java/io/metersphere/controller/remote/BasePlatformPluginController.java @@ -0,0 +1,28 @@ +package io.metersphere.controller.remote; + +import io.metersphere.service.remote.SystemSettingService; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +@RestController +@RequestMapping("/global/platform/plugin") +// 前缀加 global 避免 setting 服务循环调用 +public class BasePlatformPluginController { + + @Resource + SystemSettingService systemSettingService; + + @PostMapping("/**") + public Object list(HttpServletRequest request, @RequestBody Object param) { + String url = request.getRequestURI().replace("/global", ""); + return systemSettingService.post(url, param); + } + + @GetMapping("/**") + public Object get(HttpServletRequest request) { + String url = request.getRequestURI().replace("/global", ""); + return systemSettingService.get(url); + } +} diff --git a/framework/sdk-parent/sdk/src/main/java/io/metersphere/service/remote/SystemSettingService.java b/framework/sdk-parent/sdk/src/main/java/io/metersphere/service/remote/SystemSettingService.java new file mode 100644 index 0000000000..bb9a318b08 --- /dev/null +++ b/framework/sdk-parent/sdk/src/main/java/io/metersphere/service/remote/SystemSettingService.java @@ -0,0 +1,12 @@ +package io.metersphere.service.remote; + +import io.metersphere.commons.constants.MicroServiceName; +import io.metersphere.service.RemoteService; +import org.springframework.stereotype.Service; + +@Service +public class SystemSettingService extends RemoteService { + public SystemSettingService() { + super(MicroServiceName.SYSTEM_SETTING); + } +} diff --git a/project-management/frontend/src/business/home/ProjectPlatformConfig.vue b/project-management/frontend/src/business/home/ProjectPlatformConfig.vue index 05127b92b6..0a0a80535a 100644 --- a/project-management/frontend/src/business/home/ProjectPlatformConfig.vue +++ b/project-management/frontend/src/business/home/ProjectPlatformConfig.vue @@ -39,7 +39,7 @@ import { validateProjectConfig, } from "@/api/platform-plugin"; import CustomFiledComponent from "metersphere-frontend/src/components/template/CustomFiledComponent"; -import {getPlatformFormRules} from "@/business/home/platform"; +import {getPlatformFormRules} from "metersphere-frontend/src/utils/platform"; export default { name: "ProjectPlatformConfig", diff --git a/system-setting/backend/src/main/java/io/metersphere/controller/PlatformPluginController.java b/system-setting/backend/src/main/java/io/metersphere/controller/PlatformPluginController.java index 097e70835f..ede7c8cf29 100644 --- a/system-setting/backend/src/main/java/io/metersphere/controller/PlatformPluginController.java +++ b/system-setting/backend/src/main/java/io/metersphere/controller/PlatformPluginController.java @@ -28,6 +28,11 @@ public class PlatformPluginController { return platformPluginService.getProjectInfo(key); } + @GetMapping("/account/info") + public Object getAccountInfoList() { + return platformPluginService.getAccountInfoList(); + } + @GetMapping("/resource/{pluginId}") public void getPluginResource(@PathVariable("pluginId") String pluginId, @RequestParam("fileName") String fileName, HttpServletResponse response) { platformPluginService.getPluginResource(pluginId, fileName, response); @@ -37,11 +42,17 @@ public class PlatformPluginController { public void validateIntegration(@PathVariable("pluginId") String pluginId, @RequestBody Map config) { platformPluginService.validateIntegration(pluginId, config); } + @PostMapping("/project/validate/{pluginId}") public void validateProjectConfig(@PathVariable("pluginId") String pluginId, @RequestBody Map config) { platformPluginService.validateProjectConfig(pluginId, config); } + @PostMapping("/account/validate/{pluginId}") + public void validateAccountConfig(@PathVariable("pluginId") String pluginId, @RequestBody Map config) { + platformPluginService.validateAccountConfig(pluginId, config); + } + @PostMapping("/project/option") public List getProjectOption(@RequestBody PlatformProjectOptionRequest request) { return platformPluginService.getProjectOption(request); diff --git a/system-setting/backend/src/main/java/io/metersphere/service/PlatformPluginService.java b/system-setting/backend/src/main/java/io/metersphere/service/PlatformPluginService.java index 2489776765..bed0490987 100644 --- a/system-setting/backend/src/main/java/io/metersphere/service/PlatformPluginService.java +++ b/system-setting/backend/src/main/java/io/metersphere/service/PlatformPluginService.java @@ -109,6 +109,21 @@ public class PlatformPluginService { return null; } + public List getAccountInfoList() { + List plugins = basePluginService.getPlugins(PluginScenario.platform.name()); + List configs = new ArrayList<>(); + plugins.forEach(item -> configs.add(getFrontendMetaDataConfig(item, "accountConfig"))); + + // 过滤掉服务集成中没有的 + List integrations = baseIntegrationService.getAll(SessionUtils.getCurrentWorkspaceId()); + return configs.stream() + .filter(config -> + integrations.stream() + .filter(integration -> StringUtils.equals(integration.getPlatform(), config.get("key").toString())) + .collect(Collectors.toList()).size() > 0 + ).collect(Collectors.toList()); + } + public List getProjectOption(PlatformProjectOptionRequest request) { IntegrationRequest integrationRequest = new IntegrationRequest(); BeanUtils.copyBean(integrationRequest, request); @@ -131,10 +146,10 @@ public class PlatformPluginService { public Map getFrontendMetaDataConfig(PluginWithBLOBs plugin, String configName) { Map metaData = JSON.parseMap(plugin.getFormScript()); - Map serviceIntegration = (Map) metaData.get(configName); - serviceIntegration.put("id", metaData.get("id")); - serviceIntegration.put("key", metaData.get("key")); - return serviceIntegration; + Map config = (Map) metaData.get(configName); + config.put("id", metaData.get("id")); + config.put("key", metaData.get("key")); + return config; } public void getImage(InputStream in, HttpServletResponse response) { @@ -181,13 +196,23 @@ public class PlatformPluginService { } public void validateProjectConfig(String pluginId, Map projectConfig) { + Platform platform = getPlatformByPluginId(pluginId); + platform.validateProjectConfig(JSON.toJSONString(projectConfig)); + } + + private Platform getPlatformByPluginId(String pluginId) { PluginMetaInfo pluginMetaInfo = pluginManager.getPluginMetaInfo(pluginId); IntegrationRequest integrationRequest = new IntegrationRequest(); integrationRequest.setPlatform(pluginMetaInfo.getKey()); integrationRequest.setWorkspaceId(SessionUtils.getCurrentWorkspaceId()); ServiceIntegration serviceIntegration = baseIntegrationService.get(integrationRequest); Platform platform = getPlatFormInstance(pluginId, serviceIntegration.getConfiguration()); - platform.validateProjectConfig(JSON.toJSONString(projectConfig)); + return platform; + } + + public void validateAccountConfig(String pluginId, Map accountConfig) { + Platform platform = getPlatformByPluginId(pluginId); + platform.validateUserConfig(JSON.toJSONString(accountConfig)); } public List getPlatformOptions() { diff --git a/system-setting/frontend/src/business/workspace/integration/PlatformConfig.vue b/system-setting/frontend/src/business/workspace/integration/PlatformConfig.vue index 11ee2cadbe..f3f76e2bac 100644 --- a/system-setting/frontend/src/business/workspace/integration/PlatformConfig.vue +++ b/system-setting/frontend/src/business/workspace/integration/PlatformConfig.vue @@ -66,7 +66,7 @@ import { saveServiceIntegration } from "../../../api/workspace"; import {validateServiceIntegration} from "@/api/platform-plugin"; -import {getPlatformFormRules} from "@/business/workspace/integration/platform"; +import {getPlatformFormRules} from "metersphere-frontend/src/utils/platform"; export default { name: "PlatformConfig", diff --git a/system-setting/frontend/src/business/workspace/integration/platform.js b/system-setting/frontend/src/business/workspace/integration/platform.js deleted file mode 100644 index 5eb9ac10ed..0000000000 --- a/system-setting/frontend/src/business/workspace/integration/platform.js +++ /dev/null @@ -1,15 +0,0 @@ -import i18n from "@/i18n"; - -export function getPlatformFormRules(config) { - let rules = {}; - if (config && config.formItems) { - config.formItems.forEach(item => { - rules[item.name] = { - required: item.required, - message: item.i18n ? i18n.t(item.message) : item.message, - trigger: ['change', 'blur'] - } - }); - } - return rules; -} diff --git a/system-setting/frontend/src/business/workspace/project/ProjectPlatformConfig.vue b/system-setting/frontend/src/business/workspace/project/ProjectPlatformConfig.vue index 29a61a3b1c..b101462825 100644 --- a/system-setting/frontend/src/business/workspace/project/ProjectPlatformConfig.vue +++ b/system-setting/frontend/src/business/workspace/project/ProjectPlatformConfig.vue @@ -38,7 +38,7 @@ import { getPlatformProjectOption, validateProjectConfig, } from "@/api/platform-plugin"; -import {getPlatformFormRules} from "@/business/workspace/integration/platform"; +import {getPlatformFormRules} from "metersphere-frontend/src/utils/platform"; import CustomFiledComponent from "metersphere-frontend/src/components/template/CustomFiledComponent"; export default { @@ -62,7 +62,6 @@ export default { }, data() { return { - issueTypes: [], form: {}, rules: {}, config: {}